@echo Making in windows\ms2mit
cd ..\ms2mit
$(MAKE) -$(MFLAGS)
+!if "$(KRB5_KFW_COMPILE)"=="1"
+ @echo Making in windows\identity
+ cd ..\identity
+ $(MAKE) -$(MFLAGS)
+!endif
cd ..
clean-windows::
@echo Making clean in windows\ms2mit
cd ..\ms2mit
$(MAKE) -$(MFLAGS) clean
+!if "$(KRB5_KFW_COMPILE)"=="1"
+ @echo Making clean in windows\identity
+ cd ..\identity
+ $(MAKE) -$(MFLAGS) clean
+!endif
cd ..
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+!ifdef ETAGRUN\r
+all: finale doc\r
+!else\r
+all: finale\r
+!endif\r
+\r
+MODULE=all\r
+!include <config/Makefile.w32>\r
+\r
+!ifndef CLEANRUN\r
+!ifndef TESTRUN\r
+!ifndef ETAGRUN\r
+RMAKE=$(MAKECMD) /nologo all\r
+!else\r
+RMAKE=$(MAKECMD) /nologo etag\r
+!endif\r
+!else\r
+RMAKE=$(MAKECMD) /nologo test\r
+!endif\r
+!else\r
+RMAKE=$(MAKECMD) /nologo clean\r
+!endif\r
+\r
+start:\r
+\r
+config: start\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+include: config\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+util: include\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+kherr: util\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+kconfig: kherr\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+kmq: kconfig\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+kcreddb: kmq\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+kmm: kcreddb\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+help: kmm\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+uilib: help\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+nidmgrdll: uilib\r
+ $(ECHO) Entering $@\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+ui: nidmgrdll\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+# Now build the plugins\r
+plugincommon: ui\r
+ $(ECHO) Entering $@\r
+ $(CD) plugins\common\r
+ $(RMAKE)\r
+ $(CD) ..\..\r
+ $(ECHO) Done with $@\r
+\r
+krb5plugin: plugincommon\r
+ $(ECHO) Entering $@\r
+ $(CD) plugins\krb5\r
+ $(RMAKE)\r
+ $(CD) ..\..\r
+ $(ECHO) Done with $@\r
+\r
+!ifndef NO_KRB4\r
+finale: krb4plugin\r
+\r
+krb4plugin: plugincommon\r
+ $(ECHO) Entering $@\r
+ $(CD) plugins\krb4\r
+ $(RMAKE)\r
+ $(CD) ..\..\r
+ $(ECHO) Done with $@\r
+!endif\r
+\r
+finale: krb5plugin\r
+ $(ECHO) Done.\r
+\r
+pdoc:\r
+\r
+doc: pdoc\r
+ $(ECHO) Entering $@:\r
+ $(CD) $@\r
+ $(RMAKE)\r
+ $(CD) ..\r
+ $(ECHO) Done with $@\r
+\r
+clean::\r
+ $(MAKECMD) /nologo CLEANRUN=1\r
+\r
+test::\r
+ $(MAKECMD) /nologo TESTRUN=1\r
+\r
+etags::\r
+ $(RM) $(TAGFILE)\r
+ $(MAKECMD) /nologo ETAGRUN=1\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=config\r
+!include <Makefile.w32>\r
+\r
+all: mkalldirs mkversion\r
+\r
+mkalldirs:\r
+! if !exist($(DESTROOT))\r
+ -$(MKDIR) $(DESTROOT)\r
+! endif\r
+! if !exist($(OBJROOT))\r
+ -$(MKDIR) $(OBJROOT)\r
+! endif\r
+! if !exist($(DESTDIR))\r
+ -$(MKDIR) $(DESTDIR)\r
+! endif\r
+! if !exist($(OBJDIR))\r
+ -$(MKDIR) $(OBJDIR)\r
+! endif\r
+! if !exist($(INCDIR))\r
+ -$(MKDIR) $(INCDIR)\r
+! endif\r
+! if !exist($(BINDIR))\r
+ -$(MKDIR) $(BINDIR)\r
+! endif\r
+! if !exist($(LIBDIR))\r
+ -$(MKDIR) $(LIBDIR)\r
+! endif\r
+! if !exist($(DOCDIR))\r
+ -$(MKDIR) $(DOCDIR)\r
+! endif\r
+ $(ECHO) Done creating directories.\r
+\r
+VERSIONINC=$(INCDIR)\khimaira_version.h\r
+\r
+# Version related defines\r
+\r
+! if "$(KH_BUILD)"=="RETAIL"\r
+kh_fileflags=0\r
+! else\r
+kh_fileflags=VS_FF_DEBUG\r
+! endif\r
+! if "$(KH_RELEASE)"=="PRERELEASE"\r
+kh_fileflags=$(kh_fileflags) | VS_FF_PRERELEASE\r
+! elseif "$(KH_RELEASE)"=="PRIVATE"\r
+kh_fileflags=$(kh_fileflags) | VS_FF_PRIVATEBUILD\r
+! elseif "$(KH_RELEASE)"=="SPECIAL"\r
+kh_fileflags=$(kh_fileflags) | VS_FF_SPECIALBUILD\r
+! endif\r
+\r
+kh_fileos=VOS_NT_WINDOWS32\r
+kh_filetype_app=VFT_APP\r
+kh_filetype_dll=VFT_DLL\r
+\r
+mkversion: $(VERSIONINC)\r
+\r
+$(VERSIONINC): Makefile\r
+ $(CP) << $(VERSIONINC)\r
+/*\r
+ * This is an autogenerated file. Do not modify directly.\r
+ * \r
+ * File generated by running $(MAKE) in $(MAKEDIR)\r
+ * To regenerate, run "$(MAKE) clean" and "$(MAKE) all" on $(MAKEDIR)\r
+ */\r
+#ifndef __KHIMAIRA_VERSION_H\r
+#define __KHIMAIRA_VERSION_H\r
+\r
+/* Version number macros */\r
+#define KH_VERSION_MAJOR $(KHIMAIRA_VERSION_MAJOR)\r
+#define KH_VERSION_MINOR $(KHIMAIRA_VERSION_MINOR)\r
+#define KH_VERSION_PATCH $(KHIMAIRA_VERSION_PATCH)\r
+#define KH_VERSION_AUX $(KHIMAIRA_VERSION_AUX)\r
+#define KH_VERSION_LIST $(KHIMAIRA_VERSIONC)\r
+#define KH_VERSION_STRING "$(KHIMAIRA_VERSION)"\r
+#define KH_VERSION_STRINGW L"$(KHIMAIRA_VERSION)"\r
+#define KH_VERSION_STRINGC "$(KHIMAIRA_VERSIONC)"\r
+#define KH_VERSION_STRINGCW L"$(KHIMAIRA_VERSIONC)"\r
+\r
+/* Version definition macros */\r
+#define KH_VER_FILEFLAGS $(kh_fileflags)\r
+#define KH_VER_FILEOS $(kh_fileos)\r
+#define KH_VER_FILETYPEDLL $(kh_filetype_dll)\r
+#define KH_VER_FILETYPEAPP $(kh_filetype_app)\r
+\r
+/* Language specific version strings */\r
+#define KH_VERSTR_COMPANY_1033 "$(KHIMAIRA_SRC_COMPANY_1033)"\r
+#define KH_VERSTR_COPYRIGHT_1033 "$(KHIMAIRA_SRC_COPYRIGHT_1033)"\r
+#define KH_VERSTR_PRODUCT_1033 "$(KHIMAIRA_PRODUCT_1033)"\r
+#define KH_VERSTR_VERSION_1033 "$(KHIMAIRA_VERSION_STR_1033)"\r
+\r
+!ifdef KHIMAIRA_COMMENT_STR_1033\r
+#define KH_VERSTR_COMMENT_1033 "$(KHIMAIRA_COMMENT_STR_1033)"\r
+#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_COMMENT_1033\r
+!endif\r
+!ifdef KHIMAIRA_PRIVATE_STR_1033\r
+#define KH_VERSTR_PRIVATE_1033 "$(KHIMAIRA_PRIVATE_STR_1033)"\r
+#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_PRIVATE_1033\r
+!endif\r
+!ifdef KHIMAIRA_SPECIAL_STR_1033\r
+#define KH_VERSTR_SPECIAL_1033 "$(KHIMAIRA_SPECIAL_STR_1033)"\r
+#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_SPECIAL_1033\r
+!endif\r
+#endif\r
+<<\r
+\r
+clean::\r
+! if exist($(VERSIONINC))\r
+ $(RM) $(VERSIONINC)\r
+! endif\r
+\r
--- /dev/null
+#\r
+# Khimaira : Win32 configuration makefile\r
+# This file will be included by all the makefiles\r
+# in the build tree.\r
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+!ifndef KHIMAIRA_WIN32_CONFIG\r
+KHIMAIRA_WIN32_CONFIG=1\r
+\r
+# Environment Variables\r
+# The following environment variables MUST be set:\r
+# KH_ROOT : Root of the source tree.\r
+# KH_BUILD: One of DEBUG or RETAIL\r
+#\r
+# The following environment variables are optional:\r
+# KH_RUNTIME: One of STATIC or DLL, specifies whether the CRT libs\r
+# are linked statically or through MSVCRT.DLL.\r
+# KH_AUXCFLAGS: Optional flags for CL\r
+# KH_RELEASE: Release type. One of OFFICIAL, PRERELEASE, PRIVATE or SPECIAL.\r
+# OFFICIAL : An official release of Khimaira\r
+# PREPRELEASE: A beta/release candidate release\r
+# PRIVATE : Private build\r
+# SPECIAL : Special build. Typically one with non-mainline patches.\r
+\r
+# Version info\r
+KHIMAIRA_VERSION_MAJOR=0\r
+KHIMAIRA_VERSION_MINOR=1\r
+KHIMAIRA_VERSION_PATCH=1\r
+KHIMAIRA_VERSION_AUX=0\r
+KHIMAIRA_VERSION=$(KHIMAIRA_VERSION_MAJOR).$(KHIMAIRA_VERSION_MINOR).$(KHIMAIRA_VERSION_PATCH).$(KHIMAIRA_VERSION_AUX)\r
+KHIMAIRA_VERSIONC=$(KHIMAIRA_VERSION_MAJOR),$(KHIMAIRA_VERSION_MINOR),$(KHIMAIRA_VERSION_PATCH),$(KHIMAIRA_VERSION_AUX)\r
+\r
+# Source information\r
+KHIMAIRA_SRC_COMPANY_1033=Massachusetts Institute of Technology\r
+\r
+KHIMAIRA_SRC_COPYRIGHT_1033=(C) 2005 Massachusetts Institute of Technology\r
+\r
+# Choose the default build type if one is not set\r
+!if ("$(KH_BUILD)" != "DEBUG") && ("$(KH_BUILD)" != "RETAIL")\r
+! if defined(NODEBUG) && "$(NODEBUG)"=="1"\r
+KH_BUILD=RETAIL\r
+! else\r
+KH_BUILD=DEBUG\r
+! endif\r
+!endif\r
+\r
+!if "$(KH_BUILD)"=="DEBUG" && defined(NODEBUG) && "$(NODEBUG)"=="1"\r
+! error The Khimaira build configuration is set for DEBUG while the Platform SDK build environment is set to RETAIL.\r
+!endif\r
+\r
+# The default release type is PRIVATE is no other type is specified\r
+!if ("$(KH_RELEASE)" != "OFFICIAL") && ("$(KH_RELEASE)" != "PRERELEASE") && ("$(KH_RELEASE)" != "PRIVATE") && ("$(KH_RELEASE)" != "SPECIAL")\r
+KH_RELEASE=PRERELEASE\r
+!endif\r
+\r
+# Version and build strings\r
+\r
+!if "$(KH_RELEASE)" == "OFFICIAL"\r
+KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION)\r
+KHIMAIRA_COMMENT_STR_1033=Official build.\r
+!elseif "$(KH_RELEASE)" == "PRERELEASE"\r
+KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION) Alpha\r
+KHIMAIRA_COMMENT_STR_1033=Prerelease build.\r
+!elseif "$(KH_RELEASE)" == "PRIVATE"\r
+KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION).PRIVATE\r
+KHIMAIRA_PRIVATE_STR_1033=Private build.\r
+!elseif "$(KH_RELEASE)" == "SPECIAL"\r
+KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION).SPECIAL\r
+KHIMAIRA_SPECIAL_STR_1033=Special build.\r
+!endif\r
+\r
+!if "$(KH_BUILD)" == "DEBUG"\r
+KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION_STR_1033).DEBUG\r
+!else\r
+!endif\r
+\r
+KHIMAIRA_PRODUCT_1033=NetIDMgr $(KHIMAIRA_VERSION_STR_1033)\r
+\r
+# See what compiler we are using\r
+# TODO: Update this to support other compilers\r
+!if defined(MSVCVer) && "$(MSVCVer)"=="8.0"\r
+KH_CLVER=vc8\r
+!else\r
+KH_CLVER=vc7\r
+!endif\r
+\r
+# Check for required env vars\r
+!ifndef MODULE\r
+! error MODULE must be specified\r
+!endif\r
+!ifndef KH_ROOT\r
+KH_ROOT=$(PISMERE)\athena\auth\krb5\src\windows\identity\r
+!endif\r
+\r
+!ifdef NODEBUG\r
+OUTPRE_DBG=rel\r
+!else\r
+OUTPRE_DBG=dbg\r
+!endif\r
+OUTPRE1=obj\r
+OUTPRE2=$(OUTPRE1)\$(CPU)\r
+OUTPRE3=$(OUTPRE2)\$(OUTPRE_DBG)\r
+OUTPRE=$(OUTPRE3)^\\r
+\r
+\r
+\r
+# Output directory structure\r
+DESTROOT=$(KH_ROOT)\dest\r
+OBJROOT=$(KH_ROOT)\obj\r
+SRC=$(KH_ROOT)\r
+\r
+DESTDIR=$(DESTROOT)\$(CPU)\$(OUTPRE_DBG)\r
+OBJDIR=$(OBJROOT)\$(CPU)\$(OUTPRE_DBG)\r
+\r
+OBJ=$(OBJDIR)\$(MODULE)\r
+INCDIR=$(DESTDIR)\include\r
+#BINDIR=$(DESTDIR)\bin\r
+BINDIR=$(KH_ROOT)\$(OUTPRE)\r
+#LIBDIR=$(DESTDIR)\lib\r
+LIBDIR=$(KH_ROOT)\$(OUTPRE)\r
+DOCDIR=$(DESTDIR)\doc\r
+\r
+# Source directories\r
+CONFDIR=$(SRC)\config\r
+\r
+# Setup environment for win32.mak\r
+\r
+!if "$(KH_BUILD)" == "RETAIL"\r
+NODEBUG=1\r
+!endif\r
+\r
+# Win32.mak\r
+!include <Win32.Mak>\r
+\r
+# Program macros\r
+\r
+CD=cd\r
+RM=del /q\r
+MKDIR=mkdir\r
+RMDIR=rmdir\r
+ECHO=echo\r
+MAKECMD=nmake\r
+CP=copy /y\r
+LINK=link\r
+CCSV=perl $(SRC)\config\ccsv.pl\r
+MC=mc\r
+\r
+!ifdef KH_DOXYFULLPATH\r
+DOXYGEN=$(KH_DOXYFULLPATH)\r
+!else\r
+DOXYGEN=doxygen\r
+!endif\r
+\r
+!ifdef KH_HHCFULLPATH\r
+HHC=$(KH_HHCFULLPATH)\r
+!else\r
+HHC=hhc\r
+!endif\r
+\r
+!ifdef KH_KFWPATH\r
+KFWINCDIR=$(KH_KFWPATH)\inc\r
+kfwincflags = -I$(KFWINCDIR)\krb5 -I$(KFWINCDIR)\krb5\KerberosIV -I$(KFWINCDIR)\loadfuncs -I$(KFWINCDIR)\r
+KFWLIBDIR=$(KH_KFWPATH)\lib\$(CPU)\r
+!else\r
+KFWINCDIR=$(PISMERE)\athena\auth\krb5\src\include\r
+kfwincflags = -I$(KFWINCDIR) -I$(PISMERE)\athena\util\loadfuncs -I$(PISMERE)\athena\auth\krb5\src\include\kerberosIV -I$(PISMERE)\athena\auth\krb4\include\r
+KFWLIBDIR=$(PISMERE)\target\lib\$(CPU)\$(OUTPRE_DBG)\r
+!endif\r
+\r
+!ifdef KH_AFSPATH\r
+AFSINCDIR=$(KH_AFSPATH)\include\r
+AFSLIBDIR=$(KH_AFSPATH)\lib\r
+afsincflags=-I$(AFSINCDIR)\r
+!endif\r
+\r
+#EXTLIBDIR=$(SRC)\ext-lib\$(CPU)\r
+#EXTINCDIR=-I$(SRC)\ext-inc\r
+\r
+incflags= -I$(INCDIR) -I$(SRC)\include -I. -I$(OBJ) $(kfwincflags) $(afsincflags)\r
+rincflags= /i $(INCDIR) /i $(SRC)\include /i .\r
+khdefines=-DUNICODE -D_UNICODE\r
+khcwarn=/Wp64\r
+!ifndef KH_NO_WX\r
+khcwarn=$(khcwarn) /WX\r
+!endif\r
+\r
+khcflags=$(cdebug) $(cflags) $(incflags) $(khdefines) $(khcwarn)\r
+khlguiflags=$(ldebug) $(guilflags)\r
+khlconflags=$(ldebug) $(conlflags)\r
+khldllguiflags=$(ldebug) $(dlllflags)\r
+khldllconflags=$(ldebug) $(dlllflags)\r
+\r
+!if "$(KH_RUNTIME)" == "STATIC"\r
+khcflags=$(khcflags) $(cvarsmt)\r
+khlguiflags=$(khlguiflags) $(guilibsmt)\r
+khlconflags=$(khlconflags) $(conlibsmt)\r
+khldllguiflags=$(khldllguiflags) $(guilibsmt)\r
+khldllconflags=$(khldllconflags) $(conlibsmt)\r
+!else\r
+khcflags=$(khcflags) $(cvarsdll)\r
+khlguiflags=$(khlguiflags) $(guilibsdll)\r
+khlconflags=$(khlconflags) $(conlibsdll)\r
+khldllguiflags=$(khldllguiflags) $(guilibsdll)\r
+khldllconflags=$(khldllconflags) $(conlibsdll)\r
+!endif\r
+\r
+C2OBJ=$(CC) $(khcflags) $(KH_AUXCFLAGS) /Fo"$@" /c $**\r
+\r
+EXECONLINK=$(LINK) /NOLOGO $(khlconflags) /OUT:$@ $**\r
+\r
+EXEGUILINK=$(LINK) /NOLOGO $(khlguiflags) /OUT:$@ $**\r
+\r
+DLLCONLINK=$(LINK) /NOLOGO $(khldllconflags) /OUT:$@ /IMPLIB:$(LIBDIR)\$(@B).lib $**\r
+\r
+DLLGUILINK=$(LINK) /NOLOGO $(khldllguiflags) /OUT:$@ /IMPLIB:$(LIBDIR)\$(@B).lib $**\r
+\r
+DLLRESLINK=$(LINK) /NOLOGO /DLL /NOENTRY /MACHINE:$(PROCESSOR_ARCHITECTURE) /OUT:$@ $**\r
+\r
+RC2RES=$(RC) $(RFLAGS) $(rincflags) /fo $@ $**\r
+\r
+MC2RC=$(MC) $(MCFLAGS) -h $(OBJ)\ -m 1024 -r $(OBJ)\ -x $(OBJ)\ $**\r
+\r
+{}.c{$(OBJ)}.obj:\r
+ $(C2OBJ)\r
+\r
+{$(OBJ)}.c{$(OBJ)}.obj:\r
+ $(C2OBJ)\r
+\r
+{}.h{$(INCDIR)}.h:\r
+ $(CP) $** $@\r
+\r
+{}.rc{$(OBJ)}.res:\r
+ $(RC2RES)\r
+\r
+{$(OBJ)}.rc{$(OBJ)}.res:\r
+ $(RC2RES)\r
+\r
+clean::\r
+!if exist($(OBJ))\r
+ $(RM) $(OBJ)\\r
+!endif\r
+\r
+test::\r
+\r
+mkdirs::\r
+!if !exist($(OBJ))\r
+ $(MKDIR) $(OBJ)\r
+!endif\r
+\r
+TAGFILE = $(SRC)\TAGS\r
+\r
+etag::\r
+ etags -o $(TAGFILE) -a *.c *.h\r
+\r
+.SUFFIXES: .h\r
+\r
+!endif\r
--- /dev/null
+#!/usr/bin/perl\r
+\r
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation\r
+# files (the "Software"), to deal in the Software without\r
+# restriction, including without limitation the rights to use, copy,\r
+# modify, merge, publish, distribute, sublicense, and/or sell copies\r
+# of the Software, and to permit persons to whom the Software is\r
+# furnished to do so, subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+#\r
+\r
+\r
+# This is a simple script that is used for generating C code from CSV\r
+#files. We expect three arguments, the <input> which is the .csv file\r
+#to be parsed, a <config> which is a configuration file and the\r
+#<output>. \r
+\r
+# The configuration file is a perl file which defines the following\r
+#variables :\r
+\r
+# $skip_lines : the number of lines to skip in the csv. The default is 0\r
+\r
+# @pquote : an array of boolean integers that specify whether or not\r
+# to quote the specific field using double quotes. The default is to\r
+# not quote anything.\r
+\r
+# $file_prefix : the prefix for the file\r
+\r
+# $record_prefix : the prefix for each record\r
+\r
+# $field_sep : the field separator. The default is ','\r
+\r
+# $record_postfix : the postfix for each record\r
+\r
+# $record_sep : A record separator. Only shows up between records.\r
+\r
+# $file_postfix : the postfix for the entire file\r
+\r
+use Text::ParseWords;\r
+\r
+sub do_nothingus {\r
+}\r
+\r
+if($#ARGV != 2) {\r
+ print "Usage: ccsv.pl <input-filename> <config-filename> <output-filename>\n";\r
+ die;\r
+}\r
+\r
+$infn=$ARGV[0];\r
+$cfgfn=$ARGV[1];\r
+$outfn=$ARGV[2];\r
+\r
+$skip_lines = 0;\r
+@pquote = {};\r
+$file_prefix = "";\r
+$record_prefix = "";\r
+$field_sep = ",";\r
+$record_postfix = "";\r
+$record_sep = "\n";\r
+$file_postfix = "";\r
+$record_parser = \&do_nothingus;\r
+\r
+($inbase) = ($infn =~ m/^(\w*)/);\r
+\r
+do $cfgfn;\r
+\r
+open(IN, "<".$infn) or die "Can't open input file:".$infn;\r
+open(OUT, ">".$outfn) or die "Can't open output file:".$outfn;\r
+\r
+print OUT $file_prefix;\r
+\r
+$first_line = 1;\r
+\r
+while(<IN>) {\r
+ chomp $_;\r
+ if($skip_lines > 0) {\r
+ $skip_lines--;\r
+ } elsif (m/^\#/) {\r
+ # ignore\r
+ } else {\r
+ if($first_line == 0){\r
+ print OUT $record_sep;\r
+ } else {\r
+ $first_line = 0;\r
+ }\r
+\r
+ @fields = &parse_line(',',0,$_);\r
+ for(@fields) {\r
+ chomp;\r
+ s/^\s*//;\r
+ }\r
+\r
+ &$record_parser(\@fields);\r
+\r
+ print OUT $record_prefix;\r
+ for(my $i=0; $i <= $#fields; $i++) {\r
+ print OUT $field_sep if $i != 0;\r
+ print OUT 'L"' if $pquote[$i] == 1;\r
+ print OUT $fields[$i];\r
+ print OUT '"' if $pquote[$i] == 1;\r
+ }\r
+ print OUT $record_postfix;\r
+ }\r
+}\r
+\r
+print OUT $file_postfix;\r
+\r
+close INF;\r
+close OUT;\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation\r
+# files (the "Software"), to deal in the Software without\r
+# restriction, including without limitation the rights to use, copy,\r
+# modify, merge, publish, distribute, sublicense, and/or sell copies\r
+# of the Software, and to permit persons to whom the Software is\r
+# furnished to do so, subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+#\r
+\r
+$file_prefix = <<EOS;\r
+/*\r
+This file was autogenerated from:\r
+ $cfgfn\r
+ $infn\r
+\r
+Do not modify directly.\r
+*/\r
+#include<kconfig.h>\r
+\r
+kconf_schema schema_$inbase\[] = {\r
+EOS\r
+\r
+$record_prefix = "{";\r
+\r
+$record_sep = ",\n";\r
+\r
+$record_postfix = "}";\r
+\r
+$file_postfix = <<EOS;\r
+\r
+};\r
+\r
+\r
+EOS\r
+\r
+$skip_lines = 1;\r
+\r
+@pquote = (1,0,0,1);\r
+\r
+sub rec_handler {\r
+ $arr = shift;\r
+ if($$arr[1] =~ "KC_STRING") {\r
+ $$arr[2] = "(khm_int64) L\"".$$arr[2]."\"";\r
+ $$arr[2] =~ s/\[\~\]/\\0/g;\r
+ }\r
+\r
+ if($#$arr == 2){\r
+ $$arr[3] = "";\r
+ }\r
+}\r
+\r
+$record_parser = \&rec_handler;\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=doc\r
+!include <../config/Makefile.w32>\r
+\r
+CONFFILE=$(OBJ)\DoxyConf.cfg\r
+\r
+all: mkdirs docs\r
+\r
+docs:\r
+ $(DOXYGEN) <<\r
+@INCLUDE = doxyfile.cfg\r
+\r
+PROJECT_NUMBER = "$(KHIMAIRA_VERSION)"\r
+\r
+OUTPUT_DIRECTORY = "$(DOCDIR)"\r
+\r
+STRIP_FROM_PATH = "$(SRC)"\r
+\r
+INTERNAL_DOCS = NO\r
+\r
+WARN_LOGFILE = "$(OBJ)\doxywarnings.txt"\r
+\r
+INPUT = "$(SRC)\include"\r
+INPUT += "$(SRC)\kconfig"\r
+INPUT += "$(SRC)\kcreddb"\r
+INPUT += "$(SRC)\khlog"\r
+INPUT += "$(SRC)\kmq"\r
+INPUT += "$(SRC)\ui"\r
+INPUT += "$(SRC)\uilib"\r
+INPUT += "$(SRC)\util"\r
+INPUT += "$(SRC)\doc"\r
+INPUT += "$(SRC)\kmm"\r
+INPUT += "$(SRC)\kherr"\r
+\r
+IMAGE_PATH = "$(SRC)\doc\images"\r
+\r
+INCLUDE_PATH = "$(INCDIR)" "$(SRC)\include"\r
+\r
+CHM_FILE = "$(DOCDIR)\devdocs.chm"\r
+<<\r
+ -$(HHC) $(DOCDIR)\html\index.hhp\r
+\r
+clean::\r
+ $(RMDIR) /s $(DOCDIR)\html\r
+ $(RM) $(DOCDIR)\*.*\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page cred_acq Managed credential acquisition\r
+\r
+ Credential providers and the identity provider must participate in\r
+ managed credential acquisition in order to respond to the user's\r
+ requests to obtain new credentials for an identity or to obtain\r
+ new credentials for an existing identity.\r
+\r
+ There are two major processes that result in managed credential\r
+ acuqisition. One is the acquisition of initial credentials, while\r
+ the other is the acquisition of new crednetials. Both processes\r
+ acquire new credentials (or replace existing credentials with new\r
+ ones). The difference between the two processes lie in the way the\r
+ new credentials are obtained. Initial credentials are obtained\r
+ using user supplied username and password while new credentials\r
+ are obtained using other existing credentials.\r
+\r
+ \section cred_acq_init Initial Credentials\r
+\r
+ When a user initiates the process of initial credential\r
+ acquisition, NetIDMgr broadcasts a\r
+ <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> message. Credential\r
+ providers which need to participate in the initial credential\r
+ acquisition should respond to this message as detailed in \r
+ \ref cred_acq_handle.\r
+\r
+ \section cred_acq_new New Credentials\r
+\r
+ When a user initiates the process of obtaining new credentials\r
+ based on existing credentials, NetIDMgr broadcasts a\r
+ <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> message. Credential providers\r
+ which need to participate in the initial credential acquisition\r
+ should respond to this message as detailed in \ref cred_acq_handle.\r
+\r
+ The following pages provide detailed information:\r
+\r
+ - \subpage cred_acq_new_resp\r
+ - \subpage cred_acq_dlgproc\r
+ */\r
+\r
+/*! \page cred_acq_new_resp Handling new credentials acquisition\r
+\r
+ The process of acquiring new credentials whether they are initial\r
+ credentials or not, happen as follows :\r
+\r
+ - NetIDMgr creates a ::khui_new_creds object and a credentials\r
+ acquisition window.\r
+\r
+ - <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> or\r
+ <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> is sent to all the\r
+ credentials providers.\r
+\r
+ - The credential providers create the panels (where appropriate)\r
+ for customizing their respective credential types. The type,\r
+ panel and any dependency information is populated into a\r
+ ::khui_new_creds_by_type structure and added to the\r
+ ::khui_new_creds structure.\r
+\r
+ - <::KMSG_CRED, ::KMSG_CRED_DIALOG_PRESTART> is sent to all the\r
+ credentials providers. Credentials providers should use this\r
+ message to finialize initialization in preparation of showing\r
+ the credentials acquisition window, such as by initializing the\r
+ controls of the individual panels.\r
+\r
+ - <::KMSG_CRED, ::KMSG_CRED_DIALOG_START> is sent to all the\r
+ credentials providers.\r
+\r
+ - The dialog for obtaining credentials is displayed.\r
+ Notifications between the main dialog and the individual panels\r
+ are done through ::KHUI_WM_NC_NOTIFY messages to the dialog\r
+ procedures.\r
+\r
+ - Once the dialog completes, NetIDMgr sends\r
+ <::KMSG_CRED,::KMSG_CRED_DIALOG_END> message to all the\r
+ credentials providers. The UI portion ends here. The\r
+ individual dialog controls are destroyed as a result of the main\r
+ credentials acquisition window being destroyed.\r
+\r
+ - NetIDMgr posts <::KMSG_CRED,::KMSG_CRED_DIALOG_PROCESS> message\r
+ to all the credentials providers. Each provider should check if\r
+ the user cancelled the dialog or indicated that the new\r
+ credentials should be obtained and act accordingly. The\r
+ credentials provider is responsible for removing the\r
+ ::khui_new_creds_by_type structre from the ::khui_new_creds\r
+ structure and freeing up any resources it allocated earlier in\r
+ preparation for obtaining new credentials.\r
+\r
+ \section cred_acq_handle Responding to credential acquisition messages\r
+\r
+ The credential acquisition messages are\r
+ <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> and <::KMSG_CRED,\r
+ ::KMSG_CRED_NEW_CREDS>. They are structured as follows :\r
+\r
+ - \b type : ::KMSG_CRED\r
+ - \b subtype: ::KMSG_CRED_INITIAL_CREDS or ::KMSG_CRED_NEW_CREDS\r
+ - \b uparam : 0 (unused)\r
+ - \b vparam : a pointer to a ::khui_new_creds structure.\r
+\r
+ The \a vparam parameter of the message, as shown above, is a\r
+ pointer to a ::khui_new_creds structure. You can use the \a\r
+ subtype field of this structure to determine whether this is an\r
+ initial credentials acquisition or a new credentials acquisition\r
+ at any point.\r
+\r
+ In response to this message, a credentials provider is expected to\r
+ provide a configuration panel which the user can use to customize\r
+ how the credentials of this type are to be obtained. The panel is\r
+ described by the ::khui_new_cred_panel structure.\r
+\r
+ \subsection cred_acq_panel_spec Specifying the credentials type panel\r
+\r
+ The credentials type panel is used by the user to customize how\r
+ credentials of the specified type are to be obtained. The\r
+ ::khui_new_cred_panel structure that describes the panel can be\r
+ used to specify a number of parameters that guide how the panel is\r
+ to be displayed in the new credentials acquisition dialog.\r
+\r
+ The \a name field defines a localized string that will be\r
+ displayed in the tab control that houses the panel. Optionally,\r
+ an icon can be specified in the \a icon field which will appear\r
+ alongside the name. A tooltip may be provided in the \a tooltip\r
+ field which will be displayed when the user hovers the mouse over\r
+ the tab.\r
+\r
+ In order to assert that the tab appears at a specific position in\r
+ the list of tabs, you can specify a positive number in the \a\r
+ ordinal field. Zero does not count as a valid ordinal. The\r
+ panels with positive ordinals are arranged first in increasing\r
+ order of ordinal (conflicts are resolved by sorting along the \a\r
+ name). Then the panels without a positive ordianl are arranged\r
+ behind these in increasing order of \a name.\r
+\r
+ The \a hwnd_panel field is used to specify the handle to the\r
+ dialog or window of the panel. The parent of this window should\r
+ be set to the \a hwnd parameter of the ::khui_new_creds structure\r
+ which is passed in to the message handler.\r
+\r
+ Following is a code snippet which suggests how this could be done:\r
+\r
+ \code\r
+ // Message handling code for KMSG_CRED_NEW_CREDS or\r
+ // KMSG_CRED_INIT_CREDS\r
+ ...\r
+ khui_new_creds * c;\r
+ khui_new_creds_by_type * t;\r
+\r
+ c = (khui_new_creds *) vparam;\r
+ t = malloc(sizeof(*t));\r
+ ZeroMemory(t, sizeof(*t));\r
+\r
+ t->type = my_cred_type;\r
+\r
+ // set look and feel params\r
+ t->ordinal = 3; // third in line\r
+ t->name = L"My panel name";\r
+ t->icon = LoadIcon(my_hInstance, MAKEINTRESOURCE(IDI_PANEL_ICON));\r
+ t->tooltip = L"Configure credentials of my type";\r
+\r
+ t->hwnd_panel = CreateDialog(\r
+ my_hInstance, \r
+ MAKEINTRESOURCE(IDD_MY_PANEL),\r
+ c->hwnd,\r
+ my_dialog_proc);\r
+\r
+ if(KHM_FAILED(khui_cw_add_type(c,t))) {\r
+ // handle error\r
+ }\r
+ \endcode\r
+\r
+ It is important to note that the ::khui_new_creds_by_type pointer\r
+ that is passed into khui_cw_add_type() points to an allocated\r
+ block of memory which should remain in memory until\r
+ <::KMSG_CRED,::KMSG_CRED_DIALOG_PROCESS> message is received.\r
+\r
+ For information on how the dialog procedure should be written, see\r
+ \ref cred_acq_dlgproc .\r
+ \r
+*/\r
+\r
+/*! \page cred_acq_dlgproc Writing the dialog procedure for a cred type panel\r
+\r
+ \r
+*/\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page cred_data_types Data types in NetIDMgr\r
+\r
+ NetIDMgr's Credentials Database supports several useful data types. In\r
+ addition, plug-ins can define custom data types. Only a few operations\r
+ are expected of these data types since the core KCDB delegates fine grained\r
+ operations to other entities that understand the underlying format.\r
+\r
+ A field in a credential can have any one of these data types, but it must\r
+ have some data type. Each value can be at most \a KCDB_TYPE_MAXCB bytes\r
+ in length regardless of the data type.\r
+\r
+ Some data types have a fixed size (such as \a Int32), while others are\r
+ variable size. The required memory for each field in a credential is\r
+ allocated as needed.\r
+\r
+ \section kcdb_pg_dt Data types\r
+\r
+ Descriptions of individual data types are below.\r
+\r
+ \subsection kcdb_pg_idt Individual data types\r
+\r
+ \subsubsection kcdb_pg_idt_v Void\r
+\r
+ Pretty useless. This data type is used to indicate that the associated\r
+ object doesn't actually contain any data.\r
+\r
+ \subsubsection kcdb_pg_idt_s String\r
+\r
+ A unicode string that is terminated with a unicode NULL (L'\\0'). By\r
+ default, the type has the following flags :\r
+\r
+ \a KCDB_TYPE_FLAG_CB_AUTO\r
+\r
+ This is because, as long as the string is terminated with a unicode NULL,\r
+ the length of the string, and therefore it's size in bytes, can be inferred\r
+ from the data itself.\r
+\r
+ \subsubsection kcdb_pg_idt_d Date\r
+\r
+ Dates and times in NetIDMgr are stored as \a FILETIME structures. Utility\r
+ functions are provided for converting from other formats such as \a time_t.\r
+\r
+ \subsubsection kcdb_pg_idt_i Interval\r
+\r
+ Stores an interval of time. Stored as a 64 bit signed integer. The\r
+ string representation of this data type is different from the \a\r
+ Date data type and designate an interval of time.\r
+\r
+ The special value _I64_MAX (which is defined in limits.h as\r
+ 0x7fffffffffffffff, or in otherwords, the largest positive value\r
+ that can be stored in a 64 bit signed integer) is used to\r
+ represent an interval of unknown length.\r
+\r
+ The string representations of a data value of Interval type are\r
+ defined as follows for English (US):\r
+\r
+ - "(Unknown)" if the value is _I64_MAX\r
+\r
+ - "(Expired)" if the value is less than zero\r
+\r
+ - "%d days %d hours" if the value is greater than 24 hours\r
+\r
+ - "%d hours %d mins" if the value is greater than 1 hour\r
+\r
+ - "%d mins %d secs" if the value is greater than 1 minute\r
+\r
+ - "%d seconds" otherwise\r
+\r
+ \subsubsection kcdb_pg_idt_i32 Int32\r
+\r
+ A signed 32 bit integer.\r
+\r
+ \subsubsection kcdb_pg_idt_i64 Int64\r
+\r
+ A signed 64 bit integer.\r
+\r
+ \subsubsection kcdb_pg_idt_da Data\r
+\r
+ Raw data. Can contain a byte stream. This data type can be used by\r
+ plug-ins to associate raw data with a credential. However, there is no\r
+ built in string representation for this data type. As such, this is not\r
+ meant to be used for storing anything that has to be displayed to the user\r
+ verbatim.\r
+\r
+ \section kcdb_pg_cust Custom data types\r
+\r
+ \subsection kcdb_pg_cb Custom data type call backs\r
+\r
+ Custom data types in the NetIDMgr Credentials Database are defined using\r
+ \a kcdb_type structures which must include several callback functions.\r
+ The expected behavior of these callback functions is documented below.\r
+\r
+ \subsubsection kcdb_pg_cb_ts toString\r
+\r
+ \code\r
+ khm_int32 toString(\r
+ const void * data,\r
+ khm_int32 cb_data,\r
+ wchar_t *buffer,\r
+ khm_int32 *pcb_buffer,\r
+ khm_int32 flags);\r
+ \endcode\r
+\r
+ Produce the localized string representation of the object pointed to by\r
+ \a data. The size of the data block is specified by the \a cb_data\r
+ parameter. If the data type specified the \a KCDB_TYPE_FLAG_CB_AUTO flag\r
+ then \a cb_data can be \a KCDB_CBSIZE_AUTO, in which case the size of the\r
+ data block is to be inferred.\r
+\r
+ \a toString should assume that the block of data pointed to by \a data is\r
+ valid for this data type.\r
+\r
+ The \a pcb_buffer parameter is always a valid pointer to an \a khm_int32\r
+ variable.\r
+\r
+ The \a buffer parameter is a pointer to a \a wchar_t buffer which is to\r
+ receive the unicode string representing the object. \a buffer may be\r
+ \a NULL, in which case the required size of the buffer should be returned\r
+ in \a pcb_buffer. In this case, the function should return\r
+ \a KHM_ERROR_TOO_LONG.\r
+\r
+ If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies\r
+ that the buffer is large enough to hold the string representation, the\r
+ function should copy the string representation to the buffer, set the\r
+ \a pcb_buffer to the number of bytes that were copied including the\r
+ terminating \a NULL, and return \a KHM_ERROR_SUCCESS.\r
+\r
+ If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies\r
+ a buffer that is not large enough, the function should set \a pcb_buffer\r
+ to the required size (including the terminating \a NULL) and then return\r
+ \a KHM_ERROR_TOO_LONG.\r
+\r
+ \subsubsection kcdb_pg_cb_cmp comp\r
+\r
+ \code\r
+ khm_int32 comp(\r
+ const void * data1,\r
+ khm_int32 cb_data1,\r
+ const void * data2,\r
+ khm_int32 cb_d2);\r
+ \endcode\r
+\r
+ Compares two objects and returns a value indicating the relative ordering.\r
+\r
+ Since the KCDB does not interpret any data type, it relies on a loose\r
+ definition of what a relative ordering is. It is left up to each data\r
+ type callback to interpret what 'ascending' and 'descending' mean.\r
+\r
+ The return value \a r should be as follows :\r
+\r
+ \a r < 0 : if \a data1 < \a data2\r
+\r
+ \a r > 0 : if \a data1 > \a data2\r
+\r
+ \a r = 0 : if \a data1 = \a data2 or no relative ordering can be determined\r
+ for the two objects \a data1 and \a data2.\r
+\r
+ The function should assume that both objects are valid for this data type.\r
+\r
+ The size specifiers \a cb_data1 and \a cb_data2 can (either or both) be\r
+ \a KCDB_CBSIZE_AUTO if the data type specified \a KCDB_TYPE_FLAG_CB_AUTO\r
+ flag.\r
+\r
+ \subsubsection kcdb_pg_cb_dup dup\r
+\r
+ \code\r
+ khm_int32 dup(\r
+ const void * d_src,\r
+ khm_int32 cb_src,\r
+ void * d_dst,\r
+ khm_int32 * pcb_dst);\r
+ \endcode\r
+\r
+ Duplicate an object. The object pointed to by \a d_src is to be copied to\r
+ the buffer pointed to by \a d_dst. The function is to assume that \a d_src\r
+ object is valid. The size specifier \a cb_src may be \a KCDB_CBSIZE_AUTO\r
+ if \a KCDB_TYPE_FLAG_CB_AUTO was specified for the data type.\r
+\r
+ If \a d_dst pointer is \a NULL, then the required buffer size should be\r
+ returned in \a pcb_dst. In this case, the function itself should return\r
+ \a KHM_ERROR_TOO_LONG. The same behavior should occur if \a d_dst is non\r
+ \a NULL and \a pcb_dst indicates that the buffer is not sufficient.\r
+\r
+ If \a d_dst is not \a NULL and \a pcb_dst indicates that the buffer is\r
+ sufficient, then a copy of the object in \a d_src should be placed in\r
+ \a d_dst. The function shold return \a KHM_ERROR_SUCCESS and set\r
+ \a pcb_dst to the number of bytes that were copied.\r
+\r
+ This callback will only be called when the credentials database is\r
+ retrieving objects from the outside. Once it receives an object it may be\r
+ copied or moved as required. Hence the object should not assume to reside\r
+ in a specific location of memory. Also, \a dup is not intended to perform\r
+ such functions as reference counting which require knowledge of a precise\r
+ number of instances of an object, as the credentials database may copy\r
+ the object simply by copying the block of memory.\r
+\r
+ Note that whenever \a pcb_dst is to be set, it MUST be set to a valid byte\r
+ count. It can not be assigned \a KCDB_CBSIZE_AUTO even if the data type\r
+ supports it. The \a pcb_dst parameter is used internally to allocate\r
+ memory for the object.\r
+ \r
+ \subsubsection kcdb_pg_cb_iv isValid\r
+\r
+ \code\r
+ khm_boolean isValid(\r
+ const void * data,\r
+ khm_int32 cb_data);\r
+ \endcode\r
+\r
+ Checks if the object pointed to by the \a data pointer is a valid object\r
+ for this data type. If the data type specified the \a KCDB_TYPE_CB_AUTO\r
+ flag, then the \a cb_data parameter may be \a KCDB_CBSIZE_AUTO, in which\r
+ the size of the object should be inferred from the data.\r
+\r
+ The function should be able to determine the validity of the object and\r
+ return \a TRUE if it is valid. Return \a FALSE if it isn't, or if the\r
+ size of the object can not be inferred from the given data, or if the\r
+ inferred size exceeds \a KCDB_TYPE_MAXCB.\r
+\r
+*/\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page cred Credentials Providers \r
+\r
+ \section cred_contents Contents\r
+\r
+ - \subpage cred_data_types\r
+ - \subpage cred_acq\r
+ - \subpage cred_prop_pages\r
+ - \subpage cred_msgs\r
+*/\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page cred_msgs Handling credentials provider messages\r
+\r
+A credentials provider plugin receives a number of messages during the\r
+course of execution. This section describes the appropriate ways of\r
+handling these messages.\r
+\r
+\section pi_credmsg_system System mesages\r
+\r
+There are only two system messages that a credentials provider needs\r
+to handle. Both of these are explained elsewhere as they deal with\r
+initialization and uninitialization of the plugin. See the following\r
+two sections for details on handling these messages.\r
+\r
+- <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> \ref pi_pt_cred_init\r
+- <::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> \ref pi_pt_cred_exit\r
+\r
+\section pi_credmsg_cred Credential messages\r
+\r
+\r
+\r
+*/\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page cred_prop_pages Property Pages for Credentials\r
+\r
+ This section describes the logistics of property pages. When a\r
+ user selects the 'Properties' option from a menu (either the File\r
+ menu or a context menu), then a KHUI_ACTION_PROPERTIES action is\r
+ triggered. This is handled by the credentials window and triggers\r
+ the launch of a property sheet if there is a valid context to\r
+ extract properties from.\r
+\r
+ Sequence of actions:\r
+\r
+ - KHUI_ACTION_PROPERTIES action is triggered.\r
+\r
+ - The main window dispatches the action to the credentials window.\r
+\r
+ - If there is a valid context, then the credentials window calls\r
+ khui_ps_create_sheet() to create an empty property sheet\r
+ structure of type ::khui_property_sheet. The \a ctx member of\r
+ the structure is populated with the property context obtained\r
+ through khui_context_get().\r
+\r
+ - A global message is broadcast of type\r
+ <::KMSG_CRED,::KMSG_CRED_PP_BEGIN> with the parameter blob that\r
+ is a pointer to the ::khui_property_sheet structure.\r
+\r
+ - Subscribers to <::KMSG_CRED> messages handle the message, check\r
+ the \a ctx member of the structure and determine whether or not\r
+ and what type property pages to add to the property sheet. New\r
+ property sheets are added by calling khui_ps_add_page().\r
+\r
+ - Once all the pages are added, a\r
+ <::KMSG_CRED,::KMSG_CRED_PP_PRECREATE> message is broadcast.\r
+ This is a chance for the property page providers to do any\r
+ processing before the property page is created.\r
+\r
+ - The property sheet is created and made visible with a call to\r
+ khui_ps_show_sheet().\r
+\r
+ - The NetIDMgr message loop takes over. Further interaction\r
+ including notifications of 'Ok','Cancel','Apply' and other\r
+ property sheet related actions are handled through WIN32\r
+ messages.\r
+\r
+ - Once the user closes the property sheet, a\r
+ <::KMSG_CRED,::KMSG_CRED_PP_END> message is sent to all\r
+ subscribers. Individual subscribers who added pages to the\r
+ property sheet must free up any associated resources at this\r
+ point.\r
+\r
+ - All the ::khui_property_page structures that were allocated as\r
+ well as the ::khui_property_sheet structure are freed up with a\r
+ call to khui_ps_destroy_sheet().\r
+\r
+The maximum number of property sheets that can be open at one time is\r
+currently set to 256. Each property sheet can have a maximum of 16\r
+property pages.\r
+ */\r
--- /dev/null
+# Doxyfile 1.2.18\r
+\r
+# This file describes the settings to be used by the documentation system\r
+# doxygen (www.doxygen.org) for a project\r
+#\r
+# All text after a hash (#) is considered a comment and will be ignored\r
+# The format is:\r
+# TAG = value [value, ...]\r
+# For lists items can also be appended using:\r
+# TAG += value [value, ...]\r
+# Values that contain spaces should be placed between quotes (" ")\r
+\r
+#---------------------------------------------------------------------------\r
+# General configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \r
+# by quotes) that should identify the project.\r
+\r
+PROJECT_NAME = NetIDMgr\r
+\r
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. \r
+# This could be handy for archiving the generated documentation or \r
+# if some version control system is used.\r
+\r
+PROJECT_NUMBER = \r
+\r
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \r
+# base path where the generated documentation will be put. \r
+# If a relative path is entered, it will be relative to the location \r
+# where doxygen was started. If left blank the current directory will be used.\r
+\r
+OUTPUT_DIRECTORY = \r
+\r
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all \r
+# documentation generated by doxygen is written. Doxygen will use this \r
+# information to generate all constant output in the proper language. \r
+# The default language is English, other supported languages are: \r
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, \r
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en \r
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, \r
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.\r
+\r
+OUTPUT_LANGUAGE = English\r
+\r
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \r
+# documentation are documented, even if no documentation was available. \r
+# Private class members and static file members will be hidden unless \r
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\r
+\r
+EXTRACT_ALL = NO\r
+\r
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \r
+# will be included in the documentation.\r
+\r
+EXTRACT_PRIVATE = NO\r
+\r
+# If the EXTRACT_STATIC tag is set to YES all static members of a file \r
+# will be included in the documentation.\r
+\r
+EXTRACT_STATIC = NO\r
+\r
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \r
+# defined locally in source files will be included in the documentation. \r
+# If set to NO only classes defined in header files are included.\r
+\r
+EXTRACT_LOCAL_CLASSES = YES\r
+\r
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \r
+# undocumented members of documented classes, files or namespaces. \r
+# If set to NO (the default) these members will be included in the \r
+# various overviews, but no documentation section is generated. \r
+# This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_MEMBERS = NO\r
+\r
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \r
+# undocumented classes that are normally visible in the class hierarchy. \r
+# If set to NO (the default) these class will be included in the various \r
+# overviews. This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_CLASSES = NO\r
+\r
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \r
+# friend (class|struct|union) declarations. \r
+# If set to NO (the default) these declarations will be included in the \r
+# documentation.\r
+\r
+HIDE_FRIEND_COMPOUNDS = NO\r
+\r
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \r
+# include brief member descriptions after the members that are listed in \r
+# the file and class documentation (similar to JavaDoc). \r
+# Set to NO to disable this.\r
+\r
+BRIEF_MEMBER_DESC = YES\r
+\r
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will\r
+# prepend the brief description of a member or function before the\r
+# detailed description. Note: if both HIDE_UNDOC_MEMBERS and\r
+# BRIEF_MEMBER_DESC are set to NO, the brief descriptions will be\r
+# completely suppressed.\r
+\r
+REPEAT_BRIEF = YES\r
+\r
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \r
+# Doxygen will generate a detailed section even if there is only a brief \r
+# description.\r
+\r
+ALWAYS_DETAILED_SEC = NO\r
+\r
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show\r
+# all inherited members of a class in the documentation of that class\r
+# as if those members were ordinary class members. Constructors,\r
+# destructors and assignment operators of the base classes will not be\r
+# shown.\r
+\r
+INLINE_INHERITED_MEMB = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \r
+# path before files name in the file list and in the header files. If set \r
+# to NO the shortest path that makes the file name unique will be used.\r
+\r
+FULL_PATH_NAMES = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \r
+# can be used to strip a user defined part of the path. Stripping is \r
+# only done if one of the specified strings matches the left-hand part of \r
+# the path. It is allowed to use relative paths in the argument list.\r
+\r
+STRIP_FROM_PATH = \r
+\r
+# The INTERNAL_DOCS tag determines if documentation \r
+# that is typed after a \internal command is included. If the tag is set \r
+# to NO (the default) then the documentation will be excluded. \r
+# Set it to YES to include the internal documentation.\r
+\r
+INTERNAL_DOCS = YES\r
+\r
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \r
+# doxygen to hide any special comment blocks from generated source code \r
+# fragments. Normal C and C++ comments will always remain visible.\r
+\r
+STRIP_CODE_COMMENTS = YES\r
+\r
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \r
+# file names in lower case letters. If set to YES upper case letters are also \r
+# allowed. This is useful if you have classes or files whose names only differ \r
+# in case and if your file system supports case sensitive file names. Windows \r
+# users are adviced to set this option to NO.\r
+\r
+CASE_SENSE_NAMES = YES\r
+\r
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \r
+# (but less readable) file names. This can be useful is your file systems \r
+# doesn't support long names like on DOS, Mac, or CD-ROM.\r
+\r
+SHORT_NAMES = NO\r
+\r
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \r
+# will show members with their full class and namespace scopes in the \r
+# documentation. If set to YES the scope will be hidden.\r
+\r
+HIDE_SCOPE_NAMES = NO\r
+\r
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \r
+# will generate a verbatim copy of the header file for each class for \r
+# which an include is specified. Set to NO to disable this.\r
+\r
+VERBATIM_HEADERS = NO\r
+\r
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \r
+# will put list of the files that are included by a file in the documentation \r
+# of that file.\r
+\r
+SHOW_INCLUDE_FILES = YES\r
+\r
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \r
+# will interpret the first line (until the first dot) of a JavaDoc-style \r
+# comment as the brief description. If set to NO, the JavaDoc \r
+# comments will behave just like the Qt-style comments (thus requiring an \r
+# explict @brief command for a brief description.\r
+\r
+JAVADOC_AUTOBRIEF = NO\r
+\r
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \r
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// \r
+# comments) as a brief description. This used to be the default behaviour. \r
+# The new default is to treat a multi-line C++ comment block as a detailed \r
+# description. Set this tag to YES if you prefer the old behaviour instead.\r
+\r
+MULTILINE_CPP_IS_BRIEF = NO\r
+\r
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen \r
+# will output the detailed description near the top, like JavaDoc.\r
+# If set to NO, the detailed description appears after the member \r
+# documentation.\r
+\r
+DETAILS_AT_TOP = YES\r
+\r
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \r
+# member inherits the documentation from any documented member that it \r
+# reimplements.\r
+\r
+INHERIT_DOCS = YES\r
+\r
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \r
+# is inserted in the documentation for inline members.\r
+\r
+INLINE_INFO = YES\r
+\r
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \r
+# will sort the (detailed) documentation of file and class members \r
+# alphabetically by member name. If set to NO the members will appear in \r
+# declaration order.\r
+\r
+SORT_MEMBER_DOCS = YES\r
+\r
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \r
+# tag is set to YES, then doxygen will reuse the documentation of the first \r
+# member in the group (if any) for the other members of the group. By default \r
+# all members of a group must be documented explicitly.\r
+\r
+DISTRIBUTE_GROUP_DOC = NO\r
+\r
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. \r
+# Doxygen uses this value to replace tabs by spaces in code fragments.\r
+\r
+TAB_SIZE = 4\r
+\r
+# The GENERATE_TODOLIST tag can be used to enable (YES) or \r
+# disable (NO) the todo list. This list is created by putting \todo \r
+# commands in the documentation.\r
+\r
+GENERATE_TODOLIST = YES\r
+\r
+# The GENERATE_TESTLIST tag can be used to enable (YES) or \r
+# disable (NO) the test list. This list is created by putting \test \r
+# commands in the documentation.\r
+\r
+GENERATE_TESTLIST = YES\r
+\r
+# The GENERATE_BUGLIST tag can be used to enable (YES) or \r
+# disable (NO) the bug list. This list is created by putting \bug \r
+# commands in the documentation.\r
+\r
+GENERATE_BUGLIST = YES\r
+\r
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \r
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.\r
+\r
+GENERATE_DEPRECATEDLIST= YES\r
+\r
+# This tag can be used to specify a number of aliases that acts \r
+# as commands in the documentation. An alias has the form "name=value". \r
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to \r
+# put the command \sideeffect (or @sideeffect) in the documentation, which \r
+# will result in a user defined paragraph with heading "Side Effects:". \r
+# You can put \n's in the value part of an alias to insert newlines.\r
+\r
+ALIASES = \r
+\r
+# The ENABLED_SECTIONS tag can be used to enable conditional \r
+# documentation sections, marked by \if sectionname ... \endif.\r
+\r
+ENABLED_SECTIONS = \r
+\r
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \r
+# the initial value of a variable or define consist of for it to appear in \r
+# the documentation. If the initializer consists of more lines than specified \r
+# here it will be hidden. Use a value of 0 to hide initializers completely. \r
+# The appearance of the initializer of individual variables and defines in the \r
+# documentation can be controlled using \showinitializer or \hideinitializer \r
+# command in the documentation regardless of this setting.\r
+\r
+MAX_INITIALIZER_LINES = 30\r
+\r
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources \r
+# only. Doxygen will then generate output that is more tailored for C. \r
+# For instance some of the names that are used will be different. The list \r
+# of all members will be omitted, etc.\r
+\r
+OPTIMIZE_OUTPUT_FOR_C = YES\r
+\r
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources \r
+# only. Doxygen will then generate output that is more tailored for Java. \r
+# For instance namespaces will be presented as packages, qualified scopes \r
+# will look different, etc.\r
+\r
+OPTIMIZE_OUTPUT_JAVA = NO\r
+\r
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \r
+# at the bottom of the documentation of classes and structs. If set to YES the \r
+# list will mention the files that were used to generate the documentation.\r
+\r
+SHOW_USED_FILES = YES\r
+\r
+SHOW_DIRECTORIES = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to warning and progress messages\r
+#---------------------------------------------------------------------------\r
+\r
+# The QUIET tag can be used to turn on/off the messages that are generated \r
+# by doxygen. Possible values are YES and NO. If left blank NO is used.\r
+\r
+QUIET = NO\r
+\r
+# The WARNINGS tag can be used to turn on/off the warning messages that are \r
+# generated by doxygen. Possible values are YES and NO. If left blank \r
+# NO is used.\r
+\r
+WARNINGS = YES\r
+\r
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \r
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \r
+# automatically be disabled.\r
+\r
+WARN_IF_UNDOCUMENTED = YES\r
+\r
+# The WARN_FORMAT tag determines the format of the warning messages that \r
+# doxygen can produce. The string should contain the $file, $line, and $text \r
+# tags, which will be replaced by the file and line number from which the \r
+# warning originated and the warning text.\r
+\r
+WARN_FORMAT = "$file:$line: $text"\r
+\r
+# The WARN_LOGFILE tag can be used to specify a file to which warning \r
+# and error messages should be written. If left blank the output is written \r
+# to stderr.\r
+\r
+WARN_LOGFILE = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the input files\r
+#---------------------------------------------------------------------------\r
+\r
+# The INPUT tag can be used to specify the files and/or directories that contain \r
+# documented source files. You may enter file names like "myfile.cpp" or \r
+# directories like "/usr/src/myproject". Separate the files or directories \r
+# with spaces.\r
+\r
+INPUT = \r
+\r
+# If the value of the INPUT tag contains directories, you can use the \r
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r
+# and *.h) to filter out the source-files in the directories. If left \r
+# blank the following patterns are tested: \r
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp \r
+# *.h++ *.idl *.odl\r
+\r
+FILE_PATTERNS = \r
+\r
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories \r
+# should be searched for input files as well. Possible values are YES and NO. \r
+# If left blank NO is used.\r
+\r
+RECURSIVE = NO\r
+\r
+# The EXCLUDE tag can be used to specify files and/or directories that should \r
+# excluded from the INPUT source files. This way you can easily exclude a \r
+# subdirectory from a directory tree whose root is specified with the INPUT tag.\r
+\r
+EXCLUDE = \r
+\r
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories \r
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.\r
+\r
+EXCLUDE_SYMLINKS = NO\r
+\r
+# If the value of the INPUT tag contains directories, you can use the \r
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \r
+# certain files from those directories.\r
+\r
+EXCLUDE_PATTERNS = \r
+\r
+# The EXAMPLE_PATH tag can be used to specify one or more files or \r
+# directories that contain example code fragments that are included (see \r
+# the \include command).\r
+\r
+EXAMPLE_PATH = \r
+\r
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the \r
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r
+# and *.h) to filter out the source-files in the directories. If left \r
+# blank all files are included.\r
+\r
+EXAMPLE_PATTERNS = \r
+\r
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \r
+# searched for input files to be used with the \include or \dontinclude \r
+# commands irrespective of the value of the RECURSIVE tag. \r
+# Possible values are YES and NO. If left blank NO is used.\r
+\r
+EXAMPLE_RECURSIVE = NO\r
+\r
+# The IMAGE_PATH tag can be used to specify one or more files or \r
+# directories that contain image that are included in the documentation (see \r
+# the \image command).\r
+\r
+IMAGE_PATH = \r
+\r
+# The INPUT_FILTER tag can be used to specify a program that doxygen should \r
+# invoke to filter for each input file. Doxygen will invoke the filter program \r
+# by executing (via popen()) the command <filter> <input-file>, where <filter> \r
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \r
+# input file. Doxygen will then use the output that the filter program writes \r
+# to standard output.\r
+\r
+INPUT_FILTER = \r
+\r
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \r
+# INPUT_FILTER) will be used to filter the input files when producing source \r
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).\r
+\r
+FILTER_SOURCE_FILES = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to source browsing\r
+#---------------------------------------------------------------------------\r
+\r
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will \r
+# be generated. Documented entities will be cross-referenced with these sources.\r
+\r
+SOURCE_BROWSER = NO\r
+\r
+# Setting the INLINE_SOURCES tag to YES will include the body \r
+# of functions and classes directly in the documentation.\r
+\r
+INLINE_SOURCES = NO\r
+\r
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) \r
+# then for each documented function all documented \r
+# functions referencing it will be listed.\r
+\r
+REFERENCED_BY_RELATION = YES\r
+\r
+# If the REFERENCES_RELATION tag is set to YES (the default) \r
+# then for each documented function all documented entities \r
+# called/used by that function will be listed.\r
+\r
+REFERENCES_RELATION = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the alphabetical class index\r
+#---------------------------------------------------------------------------\r
+\r
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \r
+# of all compounds will be generated. Enable this if the project \r
+# contains a lot of classes, structs, unions or interfaces.\r
+\r
+ALPHABETICAL_INDEX = YES\r
+\r
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \r
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \r
+# in which this list will be split (can be a number in the range [1..20])\r
+\r
+COLS_IN_ALPHA_INDEX = 5\r
+\r
+# In case all classes in a project start with a common prefix, all \r
+# classes will be put under the same header in the alphabetical index. \r
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \r
+# should be ignored while generating the index headers.\r
+\r
+IGNORE_PREFIX = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the HTML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \r
+# generate HTML output.\r
+\r
+GENERATE_HTML = YES\r
+\r
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `html' will be used as the default path.\r
+\r
+HTML_OUTPUT = html\r
+\r
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \r
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \r
+# doxygen will generate files with .html extension.\r
+\r
+HTML_FILE_EXTENSION = .html\r
+\r
+# The HTML_HEADER tag can be used to specify a personal HTML header for \r
+# each generated HTML page. If it is left blank doxygen will generate a \r
+# standard header.\r
+\r
+HTML_HEADER = header.html\r
+\r
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for \r
+# each generated HTML page. If it is left blank doxygen will generate a \r
+# standard footer.\r
+\r
+HTML_FOOTER = footer.html\r
+\r
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading \r
+# style sheet that is used by each HTML page. It can be used to \r
+# fine-tune the look of the HTML output. If the tag is left blank doxygen \r
+# will generate a default style sheet\r
+\r
+HTML_STYLESHEET = stylesheet.css\r
+\r
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \r
+# files or namespaces will be aligned in HTML using tables. If set to \r
+# NO a bullet list will be used.\r
+\r
+HTML_ALIGN_MEMBERS = YES\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files \r
+# will be generated that can be used as input for tools like the \r
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \r
+# of the generated HTML documentation.\r
+\r
+GENERATE_HTMLHELP = YES\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \r
+# be used to specify the file name of the resulting .chm file. You \r
+# can add a path in front of the file if the result should not be \r
+# written to the html output dir.\r
+\r
+CHM_FILE = \r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \r
+# be used to specify the location (absolute path including file name) of \r
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run \r
+# the html help compiler on the generated index.hhp.\r
+\r
+HHC_LOCATION = \r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \r
+# controls if a separate .chi index file is generated (YES) or that \r
+# it should be included in the master .chm file (NO).\r
+\r
+GENERATE_CHI = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \r
+# controls whether a binary table of contents is generated (YES) or a \r
+# normal table of contents (NO) in the .chm file.\r
+\r
+BINARY_TOC = NO\r
+\r
+# The TOC_EXPAND flag can be set to YES to add extra items for group members \r
+# to the contents of the Html help documentation and to the tree view.\r
+\r
+TOC_EXPAND = YES\r
+\r
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \r
+# top of each HTML page. The value NO (the default) enables the index and \r
+# the value YES disables it.\r
+\r
+DISABLE_INDEX = NO\r
+\r
+# This tag can be used to set the number of enum values (range [1..20]) \r
+# that doxygen will group on one line in the generated HTML documentation.\r
+\r
+ENUM_VALUES_PER_LINE = 4\r
+\r
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\r
+# generated containing a tree-like index structure (just like the one\r
+# that is generated for HTML Help). For this to work a browser that\r
+# supports JavaScript and frames is required (for instance Mozilla,\r
+# Netscape 4.0+, or Internet explorer 4.0+). Note that for large\r
+# projects the tree generation can take a very long time. In such\r
+# cases it is better to disable this feature. Windows users are\r
+# probably better off using the HTML help feature.\r
+\r
+GENERATE_TREEVIEW = NO\r
+\r
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \r
+# used to set the initial width (in pixels) of the frame in which the tree \r
+# is shown.\r
+\r
+TREEVIEW_WIDTH = 250\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the LaTeX output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \r
+# generate Latex output.\r
+\r
+GENERATE_LATEX = NO\r
+\r
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `latex' will be used as the default path.\r
+\r
+LATEX_OUTPUT = latex\r
+\r
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.\r
+\r
+LATEX_CMD_NAME = latex\r
+\r
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \r
+# generate index for LaTeX. If left blank `makeindex' will be used as the \r
+# default command name.\r
+\r
+MAKEINDEX_CMD_NAME = makeindex\r
+\r
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \r
+# LaTeX documents. This may be useful for small projects and may help to \r
+# save some trees in general.\r
+\r
+COMPACT_LATEX = NO\r
+\r
+# The PAPER_TYPE tag can be used to set the paper type that is used \r
+# by the printer. Possible values are: a4, a4wide, letter, legal and \r
+# executive. If left blank a4wide will be used.\r
+\r
+PAPER_TYPE = a4wide\r
+\r
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \r
+# packages that should be included in the LaTeX output.\r
+\r
+EXTRA_PACKAGES = \r
+\r
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \r
+# the generated latex document. The header should contain everything until \r
+# the first chapter. If it is left blank doxygen will generate a \r
+# standard header. Notice: only use this tag if you know what you are doing!\r
+\r
+LATEX_HEADER = \r
+\r
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \r
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will \r
+# contain links (just like the HTML output) instead of page references \r
+# This makes the output suitable for online browsing using a pdf viewer.\r
+\r
+PDF_HYPERLINKS = NO\r
+\r
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \r
+# plain latex in the generated Makefile. Set this option to YES to get a \r
+# higher quality PDF documentation.\r
+\r
+USE_PDFLATEX = NO\r
+\r
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. \r
+# command to the generated LaTeX files. This will instruct LaTeX to keep \r
+# running if errors occur, instead of asking the user for help. \r
+# This option is also used when generating formulas in HTML.\r
+\r
+LATEX_BATCHMODE = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the RTF output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \r
+# The RTF output is optimised for Word 97 and may not look very pretty with \r
+# other RTF readers or editors.\r
+\r
+GENERATE_RTF = NO\r
+\r
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `rtf' will be used as the default path.\r
+\r
+RTF_OUTPUT = rtf\r
+\r
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \r
+# RTF documents. This may be useful for small projects and may help to \r
+# save some trees in general.\r
+\r
+COMPACT_RTF = NO\r
+\r
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \r
+# will contain hyperlink fields. The RTF file will \r
+# contain links (just like the HTML output) instead of page references. \r
+# This makes the output suitable for online browsing using WORD or other \r
+# programs which support those fields. \r
+# Note: wordpad (write) and others do not support links.\r
+\r
+RTF_HYPERLINKS = NO\r
+\r
+# Load stylesheet definitions from file. Syntax is similar to doxygen's \r
+# config file, i.e. a series of assigments. You only have to provide \r
+# replacements, missing definitions are set to their default value.\r
+\r
+RTF_STYLESHEET_FILE = \r
+\r
+# Set optional variables used in the generation of an rtf document. \r
+# Syntax is similar to doxygen's config file.\r
+\r
+RTF_EXTENSIONS_FILE = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the man page output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \r
+# generate man pages\r
+\r
+GENERATE_MAN = NO\r
+\r
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `man' will be used as the default path.\r
+\r
+MAN_OUTPUT = man\r
+\r
+# The MAN_EXTENSION tag determines the extension that is added to \r
+# the generated man pages (default is the subroutine's section .3)\r
+\r
+MAN_EXTENSION = .3\r
+\r
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \r
+# then it will generate one additional man file for each entity \r
+# documented in the real man page(s). These additional files \r
+# only source the real man page, but without them the man command \r
+# would be unable to find the correct page. The default is NO.\r
+\r
+MAN_LINKS = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the XML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_XML tag is set to YES Doxygen will \r
+# generate an XML file that captures the structure of \r
+# the code including all documentation. Note that this \r
+# feature is still experimental and incomplete at the \r
+# moment.\r
+\r
+GENERATE_XML = NO\r
+\r
+# The XML_SCHEMA tag can be used to specify an XML schema, \r
+# which can be used by a validating XML parser to check the \r
+# syntax of the XML files.\r
+\r
+XML_SCHEMA = \r
+\r
+# The XML_DTD tag can be used to specify an XML DTD, \r
+# which can be used by a validating XML parser to check the \r
+# syntax of the XML files.\r
+\r
+XML_DTD = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options for the AutoGen Definitions output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \r
+# generate an AutoGen Definitions (see autogen.sf.net) file \r
+# that captures the structure of the code including all \r
+# documentation. Note that this feature is still experimental \r
+# and incomplete at the moment.\r
+\r
+GENERATE_AUTOGEN_DEF = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the preprocessor \r
+#---------------------------------------------------------------------------\r
+\r
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \r
+# evaluate all C-preprocessor directives found in the sources and include \r
+# files.\r
+\r
+ENABLE_PREPROCESSING = YES\r
+\r
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \r
+# names in the source code. If set to NO (the default) only conditional \r
+# compilation will be performed. Macro expansion can be done in a controlled \r
+# way by setting EXPAND_ONLY_PREDEF to YES.\r
+\r
+MACRO_EXPANSION = NO\r
+\r
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \r
+# then the macro expansion is limited to the macros specified with the \r
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.\r
+\r
+EXPAND_ONLY_PREDEF = NO\r
+\r
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \r
+# in the INCLUDE_PATH (see below) will be search if a #include is found.\r
+\r
+SEARCH_INCLUDES = YES\r
+\r
+# The INCLUDE_PATH tag can be used to specify one or more directories that \r
+# contain include files that are not input files but should be processed by \r
+# the preprocessor.\r
+\r
+INCLUDE_PATH = \r
+\r
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \r
+# patterns (like *.h and *.hpp) to filter out the header-files in the \r
+# directories. If left blank, the patterns specified with FILE_PATTERNS will \r
+# be used.\r
+\r
+INCLUDE_FILE_PATTERNS = \r
+\r
+# The PREDEFINED tag can be used to specify one or more macro names that \r
+# are defined before the preprocessor is started (similar to the -D option of \r
+# gcc). The argument of the tag is a list of macros of the form: name \r
+# or name=definition (no spaces). If the definition and the = are \r
+# omitted =1 is assumed.\r
+\r
+PREDEFINED = _WIN32 \\r
+ UNICODE \\r
+ _UNICODE\r
+\r
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then \r
+# this tag can be used to specify a list of macro names that should be expanded. \r
+# The macro definition that is found in the sources will be used. \r
+# Use the PREDEFINED tag if you want to use a different macro definition.\r
+\r
+EXPAND_AS_DEFINED = \r
+\r
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then\r
+# doxygen's preprocessor will remove all function-like macros that are\r
+# alone on a line, have an all uppercase name, and do not end with a\r
+# semicolon. Such function macros are typically used for boiler-plate\r
+# code, and will confuse the parser if not removed.\r
+\r
+SKIP_FUNCTION_MACROS = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::addtions related to external references \r
+#---------------------------------------------------------------------------\r
+\r
+# The TAGFILES tag can be used to specify one or more tagfiles.\r
+\r
+TAGFILES = \r
+\r
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create \r
+# a tag file that is based on the input files it reads.\r
+\r
+GENERATE_TAGFILE = \r
+\r
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed \r
+# in the class index. If set to NO only the inherited external classes \r
+# will be listed.\r
+\r
+ALLEXTERNALS = NO\r
+\r
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \r
+# in the modules index. If set to NO, only the current project's groups will \r
+# be listed.\r
+\r
+EXTERNAL_GROUPS = YES\r
+\r
+# The PERL_PATH should be the absolute path and name of the perl script \r
+# interpreter (i.e. the result of `which perl').\r
+\r
+PERL_PATH = /usr/bin/perl\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the dot tool \r
+#---------------------------------------------------------------------------\r
+\r
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \r
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or \r
+# super classes. Setting the tag to NO turns the diagrams off. Note that this \r
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is \r
+# recommended to install and use dot, since it yield more powerful graphs.\r
+\r
+CLASS_DIAGRAMS = YES\r
+\r
+# If set to YES, the inheritance and collaboration graphs will hide \r
+# inheritance and usage relations if the target is undocumented \r
+# or is not a class.\r
+\r
+HIDE_UNDOC_RELATIONS = YES\r
+\r
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \r
+# available from the path. This tool is part of Graphviz, a graph visualization \r
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section \r
+# have no effect if this option is set to NO (the default)\r
+\r
+HAVE_DOT = NO\r
+\r
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for each documented class showing the direct and \r
+# indirect inheritance relations. Setting this tag to YES will force the \r
+# the CLASS_DIAGRAMS tag to NO.\r
+\r
+CLASS_GRAPH = YES\r
+\r
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for each documented class showing the direct and \r
+# indirect implementation dependencies (inheritance, containment, and \r
+# class references variables) of the class with other documented classes.\r
+\r
+COLLABORATION_GRAPH = YES\r
+\r
+# If set to YES, the inheritance and collaboration graphs will show the \r
+# relations between templates and their instances.\r
+\r
+TEMPLATE_RELATIONS = YES\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \r
+# tags are set to YES then doxygen will generate a graph for each documented \r
+# file showing the direct and indirect include dependencies of the file with \r
+# other documented files.\r
+\r
+INCLUDE_GRAPH = YES\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \r
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \r
+# documented header file showing the documented files that directly or \r
+# indirectly include this file.\r
+\r
+INCLUDED_BY_GRAPH = YES\r
+\r
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \r
+# will graphical hierarchy of all classes instead of a textual one.\r
+\r
+GRAPHICAL_HIERARCHY = YES\r
+\r
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \r
+# generated by dot. Possible values are png, jpg, or gif\r
+# If left blank png will be used.\r
+\r
+DOT_IMAGE_FORMAT = png\r
+\r
+# The tag DOT_PATH can be used to specify the path where the dot tool can be \r
+# found. If left blank, it is assumed the dot tool can be found on the path.\r
+\r
+DOT_PATH = \r
+\r
+# The DOTFILE_DIRS tag can be used to specify one or more directories that \r
+# contain dot files that are included in the documentation (see the \r
+# \dotfile command).\r
+\r
+DOTFILE_DIRS = \r
+\r
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \r
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than \r
+# this value, doxygen will try to truncate the graph, so that it fits within \r
+# the specified constraint. Beware that most browsers cannot cope with very \r
+# large images.\r
+\r
+MAX_DOT_GRAPH_WIDTH = 1024\r
+\r
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \r
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than \r
+# this value, doxygen will try to truncate the graph, so that it fits within \r
+# the specified constraint. Beware that most browsers cannot cope with very \r
+# large images.\r
+\r
+MAX_DOT_GRAPH_HEIGHT = 1024\r
+\r
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \r
+# generate a legend page explaining the meaning of the various boxes and \r
+# arrows in the dot generated graphs.\r
+\r
+GENERATE_LEGEND = YES\r
+\r
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \r
+# remove the intermedate dot files that are used to generate \r
+# the various graphs.\r
+\r
+DOT_CLEANUP = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::addtions related to the search engine \r
+#---------------------------------------------------------------------------\r
+\r
+# The SEARCHENGINE tag specifies whether or not a search engine should be \r
+# used. If set to NO the values of all tags below this one will be ignored.\r
+\r
+SEARCHENGINE = NO\r
+\r
+# The CGI_NAME tag should be the name of the CGI script that \r
+# starts the search engine (doxysearch) with the correct parameters. \r
+# A script with this name will be generated by doxygen.\r
+\r
+CGI_NAME = search.cgi\r
+\r
+# The CGI_URL tag should be the absolute URL to the directory where the \r
+# cgi binaries are located. See the documentation of your http daemon for \r
+# details.\r
+\r
+CGI_URL = \r
+\r
+# The DOC_URL tag should be the absolute URL to the directory where the \r
+# documentation is located. If left blank the absolute path to the \r
+# documentation, with file:// prepended to it, will be used.\r
+\r
+DOC_URL = \r
+\r
+# The DOC_ABSPATH tag should be the absolute path to the directory where the \r
+# documentation is located. If left blank the directory on the local machine \r
+# will be used.\r
+\r
+DOC_ABSPATH = \r
+\r
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary \r
+# is installed.\r
+\r
+BIN_ABSPATH = /usr/local/bin/\r
+\r
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to \r
+# documentation generated for other projects. This allows doxysearch to search \r
+# the documentation for these projects as well.\r
+\r
+EXT_DOC_PATHS = \r
--- /dev/null
+<hr size="1">\r
+\r
+<table width="100%" border="0">\r
+ <tr>\r
+ <td>\r
+ <address style="align:right;">\r
+ <small>Generated on $datetime for $projectname $projectnumber by <a href="http://www.doxygen.org/index.html">Doxygen</a> $doxygenversion<br>\r
+ © 2004 Massachusetts Institute of Technology. Contact <a href="mailto:khimaira@mit.edu">khimaira@mit.edu</a><br>\r
+ </small>\r
+ </address>\r
+ </td>\r
+ <td width="100" align="right">\r
+ <img src="khimaira_logo_small.png" border="0">\r
+ </td>\r
+ </tr>\r
+</table>\r
+\r
+</body>\r
+</html>\r
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">\r
+<title>$title</title>\r
+<link href="$relpath$stylesheet.css" rel="stylesheet" type="text/css">\r
+</head><body>\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \mainpage NetIDMgr\r
+\r
+ \image html khimaira_logo.png\r
+\r
+ \section main_dev Documentation for Developers\r
+\r
+ NetIDMgr is a credentials manager, which currently manages\r
+ Kerberos IV, Kerberos V and AFS credentials. This document\r
+ describes the API that is implemented by the NetIDMgr system.\r
+\r
+ See the following sections for more information :\r
+ - \subpage license\r
+ - \subpage bugs\r
+ - \subpage releases\r
+\r
+ © 2004 Massachusetts Institute of Technology\r
+*/\r
+\r
+/*!\r
+ \page license License agreement and credits\r
+\r
+ NetIDMgr is distributed under the MIT License.\r
+\r
+ \section license_l MIT License\r
+\r
+ Copyright © 2004 Massachusetts Institute of Technology\r
+ \r
+ Permission is hereby granted, free of charge, to any person\r
+ obtaining a copy of this software and associated documentation\r
+ files (the "Software"), to deal in the Software without\r
+ restriction, including without limitation the rights to use, copy,\r
+ modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ of the Software, and to permit persons to whom the Software is\r
+ furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be\r
+ included in all copies or substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\r
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
+ DEALINGS IN THE SOFTWARE.\r
+\r
+ \section license_credits Credits\r
+\r
+ NetIDMgr was developed at the Massachusetts Institute of\r
+ Technology.\r
+\r
+ (Contributor list goes here)\r
+\r
+ <a href="http://web.mit.edu/is">Information Services and\r
+ Technology</a> at <a href="http://web.mit.edu">Massachusetts\r
+ Institute of Technology</a>\r
+*/\r
+\r
+/*! \page bugs Reporting bugs\r
+\r
+ NetIDMgr bugs can be reported to \r
+ <a href="mailto:khimaira@mit.edu">khimaira@mit.edu</a> for now.\r
+\r
+ In the future, there will actually be a place to track NetIDMgr bugs.\r
+\r
+ When reporting bugs, please include as much information as\r
+ possible to help diagnose the problem. More guidelines about\r
+ reporting bugs will appear here at some point in time.\r
+\r
+ \image html khimaira_logo_small.png\r
+*/\r
+\r
+/*! \page releases Prior releases\r
+\r
+ - <b>0.1.1</b> (Charles Manson) <em>[soon]</em>\n\r
+ First alpha release. As stable as Charles Manson, hence the\r
+ name.\r
+\r
+ - <b>0.1.2</b> (tbd) <em>[tbd]</em>\n\r
+ First beta release.\r
+*/\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*!\r
+\page pi_framework Plugin Framework\r
+\r
+\section pi_fw_pnm Plugins and Modules\r
+\r
+\subsection pi_fw_pnm_p Plugins\r
+\r
+A NetIDMgr plugin is a package that implements a defined API that will\r
+perform credentials management or related tasks on behalf of NetIDMgr.\r
+The core NetIDMgr codebase does not interact directly with Kerberos of\r
+AFS or any other external entity directly. Instead, plugins are used\r
+to abstract out this task.\r
+\r
+Each plugin has a name. The name should be unique among the loaded\r
+plugins, or the plugin will fail to load.\r
+\r
+The method in which NetIDMgr communicates with a plugin depends on the\r
+plugin type. For more information on each plugin type, please refer\r
+to \ref pi_pt.\r
+\r
+Most plugin types rely on a message processor for communication.\r
+During plugin registration, the module specifies the message processor\r
+for the plugin, which acts as the only point of contact between the\r
+NetIDMgr core and the plugin. Some other plugins require exporting\r
+specific functions.\r
+\r
+\subsection pi_fw_pnw_m Modules\r
+\r
+One or more plugins can be bundled together into a module. A module\r
+is essentially a dynamically loadable library which contain a specific\r
+set of callbacks. Currently, the only two required callbacks for a\r
+module are :\r
+\r
+- init_module(), and\r
+- exit_module()\r
+\r
+\section pi_fw_pm Plugin/Module Manager\r
+\r
+The plugin manager maintains a separate thread for loading and\r
+registering modules. When a module is successfully loaded and it\r
+registers one or more plugins, a new thread is created for each\r
+plugin. Plugin specific initialization and other callback functions\r
+are called from within this new thread. This is to prevent one plugin\r
+from "hanging" other plugins and the main NetIDMgr UI threads.\r
+\r
+Read more :\r
+- \ref pi_structure\r
+\r
+\subsection pi_fw_pm_load Load sequence\r
+\r
+When kmm_load_module() is called, the following sequence of events\r
+happen.\r
+\r
+- The standard system search path is used to locate the binary.\r
+\r
+- The binary is loaded into the address space of NetIDMgr along with\r
+ any dependencies not already loaded.\r
+\r
+- If the NetIDMgr core binary is signed, then the signature is checked\r
+ against the system and user certificate stores. If this fails, the\r
+ module is unloaded. See \ref pi_fw_pm_unload.\r
+\r
+- init_module() for the loaded module is called. If this function\r
+ returns an error or if no plugins are registered, then the module is\r
+ unloaded. See \ref pi_fw_pm_unload.\r
+\r
+- During processing of init_module(), if any localized resource\r
+ libraries are specified using kmm_set_locale_info(), then one of the\r
+ localized libraries will be loaded. See \ref pi_localization\r
+\r
+- During processing of init_module(), the module registers all the\r
+ plugins that it is implementing by calling kmm_register_plugin() for\r
+ each.\r
+\r
+- Once init_module() returns, each plugin is initialized. The method\r
+ by which a plugin is initialized depends on the plugin type. The\r
+ initialization code for the plugin may indicate that it didn't\r
+ initialize properly, in which case the plugin is immediately\r
+ unregistered. No further calls are made to the plugin.\r
+\r
+- If no plugin is successfully loaded, the module is unloaded. See\r
+ \ref pi_fw_pm_unload.\r
+\r
+- During normal operation, any registered plugins for a module can be\r
+ unloaded explicitly, or the plugin itself may signal that it should\r
+ be unloaded. If at anytime, all the plugins for the module are\r
+ unloaded, then the module itself is also unloaded.\r
+\r
+\subsection pi_fw_pm_unload Unload sequence\r
+\r
+- For each of the plugins that are registered for a module, the exit\r
+ code is invoked. The method by which this happens depends on the\r
+ plugin type. The plugin is not given a chance to object to the\r
+ decision to unload. Each plugin is responsible for performing\r
+ cleanup tasks, freeing resources and unsubscribing from any message\r
+ classes that it has subscribed to.\r
+\r
+- exit_module() is called for the module.\r
+\r
+- If any localized resource libraries were loaded for the module, they\r
+ are unloaded.\r
+\r
+- The module is unloaded.\r
+\r
+ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*!\r
+\page pi_localization Localization\r
+\r
+If a module requires localized resources, it can register the\r
+localized resource libraries with the module manager when it receives\r
+the init_module() callback. Note that you can only register localized\r
+resource libraries during init_module().\r
+\r
+The localized resource library is global to a module. Each plugin is\r
+not allowed to define its own localization library, although it is\r
+free to load and use any library as it sees fit. The module manager\r
+does not manage these libraries for the plugin.\r
+\r
+\section pi_loc_spec Specification of localized resources\r
+\r
+In order to register localized resource libraries, a module calls\r
+kmm_set_locale_info(). The \a locales parameter to the function holds\r
+a pointer to an array of ::kmm_module_locale records. Each record\r
+specifies one language code and a filename of a library that holds the\r
+language resources for that language.\r
+\r
+It is recommended that you use the LOCALE_DEF convenience macro when\r
+defining locale records for use with kmm_set_locale_info(). This will\r
+ensure that future changes in the API will only minimally affect your\r
+code. For example:\r
+\r
+\code\r
+kmm_module_locale my_locales[] = {\r
+LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"english.dll", KMM_MLOC_FLAG_DEFAULT),\r
+LOCALE_DEF(MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH), L"dutch.dll", 0),\r
+LOCALE_DEF(MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MODERN), L"spanish.dll", 0)\r
+};\r
+\r
+int n_locales = sizeof(my_locales)/sizeof(my_locales[0]);\r
+\r
+...\r
+\r
+kmm_set_locale_info(h_module, my_locales, n_locales);\r
+\r
+...\r
+\endcode\r
+\r
+See kmm_set_locale_info() and ::kmm_module_locale for more info.\r
+\r
+\section pi_loc_how Selection of localized resource library\r
+\r
+The module manager searches the array of ::kmm_module_locale objects\r
+passed into the kmm_set_locale_info() function for one that matches\r
+the current user locale (as opposed to the current system locale). A\r
+record matches the locale if it has the same language ID. \r
+\r
+If a match is found, that library is selected. Otherwise, the list is\r
+searched for one that is compatible with the current user locale. A\r
+locale record is compatible with the user locale if the primary\r
+language matches.\r
+\r
+If a match is still not found, the first record in the locale array\r
+that has the ::KMM_MLOC_FLAG_DEFAULT flag set will be selected.\r
+\r
+If a match is still not found, then the kmm_set_locale_info() will\r
+return ::KHM_ERROR_NOT_FOUND.\r
+\r
+\section pi_loc_usage Using localization\r
+\r
+The following convenience macros are available for using a module\r
+handle to load resources from the corresponding resource library.\r
+However, for performance reasons, it is advisable to obtain a handle\r
+to the resource library loaded by the module manager using\r
+kmm_get_resource_module() and then use it to access resources using\r
+the regular WIN32 API.\r
+\r
+- ::kmm_LoadAccelerators\r
+- ::kmm_LoadBitmap\r
+- ::kmm_LoadCursor\r
+- ::kmm_LoadIcon\r
+- ::kmm_LoadImage\r
+- ::kmm_LoadMenu\r
+- ::kmm_LoadString\r
+\r
+*/\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*!\r
+\r
+\page plugins NetIDMgr Modules and Plugins\r
+\r
+Plugins and localization are handled by the NetIDMgr Module Manager\r
+API. Each plugin consists of a dynamically loadable library and zero\r
+or more associated resource libraries.\r
+\r
+For more information about NetIDMgr Plugins, see the following\r
+sections:\r
+\r
+- \subpage pi_framework\r
+- \subpage pi_pt\r
+- \subpage pi_structure\r
+- \subpage pi_localization\r
+*/\r
+\r
+/*! \page pi_pt Plugin Types\r
+\r
+The types of plugins that are currently supported by NetIDMgr are :\r
+\r
+\section pi_pt_cred Credential Provider\r
+\r
+A credential provider plugin essentially acts as an interface between\r
+NetIDMgr and some entity which defines the credentials for the purpose\r
+of managing those credentials.\r
+\r
+There can be more than one credential provider in a module.\r
+\r
+\subsection pi_pt_cred_comm Communication\r
+\r
+Communication between NetIDMgr and a credential provider occurs\r
+through a message processor. When registering a credential provider,\r
+the module initialization code in init_module() specifies\r
+::KHM_PITYPE_CRED as the \a type member and sets \a msg_proc member to\r
+a valid message processor in the ::khm_plugin record.\r
+\r
+\subsection pi_pt_cred_init Initialization\r
+\r
+Once init_module() has completed, the module manager sends a\r
+<::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> message to the message processor.\r
+\r
+For credential provider plugins, <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> is\r
+guaranteed to be the first message it receives.\r
+\r
+The callback function should return KHM_ERROR_SUCCESS if it\r
+initializes properly or some other value otherwise. If the return\r
+value signals an error, then the plugin is assume to not be loaded and\r
+immediately unregistered.\r
+\r
+The message processor is automatically subscribed to the following\r
+message types:\r
+- ::KMSG_SYSTEM\r
+- ::KMSG_KCDB\r
+\r
+Although a plugin can use the <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT>\r
+message enumerate existing credentials in the system, it should not\r
+obtain new credentials. This is because other plugins that may depend\r
+on the new credential messages may not be loaded at this time. See the\r
+section on \ref cred_msgs for more information.\r
+\r
+\r
+\subsection pi_pt_cred_exit Uninitialization\r
+\r
+When the plugin is to be removed, the module manager sends a\r
+<::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> to the message processor. The\r
+plugin must perform any necessary shutdown operations, free up\r
+resources and unsubscribe from any messages that it has subscribed to.\r
+\r
+This message is guaranteed to be the last message received by a\r
+credentials manager plugin if the plugin unsubsribes from all\r
+additional message classes that it subsribed to.\r
+\r
+The message types that the message processor is automatically\r
+subscribed to (See \ref pi_pt_cred_init) do not have to be\r
+unsubscribed from as they are automatically removed.\r
+\r
+\subsection pi_pt_cred_other Other Notes\r
+\r
+Since credential managers may receive privileged information, the\r
+signature requirements for credential managers are specially strict.\r
+\r
+\section pi_pt_conf Configuration Provider\r
+\r
+Provides configuration information.\r
+[TODO: fill in]\r
+\r
+\subsection pi_pt_conf_comm Communication\r
+[TODO: fill in]\r
+\r
+\subsection pi_pt_conf_init Initialization\r
+[TODO: fill in]\r
+\r
+\subsection pi_pt_conf_exit Uninitialization\r
+[TODO: fill in]\r
+\r
+\subsection pi_pt_conf_other Other Notes\r
+\r
+*/\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*!\r
+\r
+\page pi_structure Structure of a module\r
+\r
+A NetIDMgr module is essentially a dynamically loadable library with a\r
+specific set of exported symbols. Each export symbol and general\r
+notes about writing a plugin module are documented below.\r
+\r
+\section pi_str_init Initialization\r
+\r
+Do not use DllMain or other system specific callback routines to\r
+perform intilization tasks other than creating mutexes, initializing\r
+thread local storage and other tasks that must be performed at that\r
+stage. Specifically, do not call any NetIDMgr API functions from\r
+within DllMain.\r
+\r
+\section pi_str_cb Callbacks\r
+\r
+The callbacks that must be implemented by a module are:\r
+\r
+- init_module()\r
+- exit_module()\r
+\r
+ */\r
--- /dev/null
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {\r
+ font-family: Geneva, Arial, Helvetica, sans-serif;\r
+}\r
+H1 {\r
+ text-align: center;\r
+}\r
+CAPTION { font-weight: bold }\r
+DIV.qindex {\r
+ width: 100%;\r
+ background-color: #000000;\r
+ border: 1px solid #000000;\r
+ margin: 2px;\r
+ padding: 2px;\r
+ line-height: 100%;\r
+ color: #ffffff\r
+}\r
+DIV.nav {\r
+ width: 100%;\r
+ background-color: #000000;\r
+ border: 1px solid #000000;\r
+ text-align: center;\r
+ margin: 2px;\r
+ padding: 2px;\r
+ line-height: 100%;\r
+ color: #ffffff;\r
+}\r
+A.qindex {\r
+ text-decoration: none;\r
+ color: #ffffff;\r
+}\r
+A.qindex:visited {\r
+ text-decoration: none;\r
+ color: #ffffff;\r
+}\r
+A.qindex:hover {\r
+ text-decoration: none;\r
+ background-color: #ffffff;\r
+ color: #000000\r
+}\r
+A.qindexHL {\r
+ text-decoration: none;\r
+ font-weight: bold;\r
+}\r
+A.qindexHL:hover {\r
+ text-decoration: none;\r
+ background-color: #333333;\r
+ color: #ffffff;\r
+}\r
+A.qindexHL:visited { text-decoration: none; background-color: #333333; color: #ffffff }\r
+A.el { text-decoration: none; }\r
+A.elRef { }\r
+A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}\r
+A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}\r
+A.codeRef:link { font-weight: normal; color: #0000FF}\r
+A.codeRef:visited { font-weight: normal; color: #0000FF}\r
+A:hover { text-decoration: none; background-color: #cccccc }\r
+DL.el { margin-left: -1cm }\r
+.fragment {\r
+ font-family: monospace\r
+}\r
+PRE.fragment {\r
+ border: 1px solid #CCCCCC;\r
+ background-color: #f5f5f5;\r
+ margin-top: 4px;\r
+ margin-bottom: 4px;\r
+ margin-left: 2px;\r
+ margin-right: 8px;\r
+ padding-left: 6px;\r
+ padding-right: 6px;\r
+ padding-top: 4px;\r
+ padding-bottom: 4px;\r
+}\r
+DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }\r
+TD.md { background-color: #cccccc; font-weight: bold; }\r
+TD.mdname1 { background-color: #cccccc; font-weight: bold; color: #000000; }\r
+TD.mdname { background-color: #cccccc; font-weight: bold; color: #000000; width: 600px; }\r
+DIV.groupHeader {\r
+ margin-left: 16px;\r
+ margin-top: 12px;\r
+ margin-bottom: 6px;\r
+ font-weight: bold;\r
+}\r
+DIV.groupText { margin-left: 16px; font-style: italic; font-size: 14px }\r
+BODY {\r
+ background: white;\r
+ color: black;\r
+ margin-right: 20px;\r
+ margin-left: 20px;\r
+}\r
+TD.indexkey {\r
+ background-color: #cccccc;\r
+ font-weight: bold;\r
+ padding-right : 10px;\r
+ padding-top : 2px;\r
+ padding-left : 10px;\r
+ padding-bottom : 2px;\r
+ margin-left : 0px;\r
+ margin-right : 0px;\r
+ margin-top : 2px;\r
+ margin-bottom : 2px;\r
+ border: 1px solid #CCCCCC;\r
+}\r
+TD.indexvalue {\r
+ background-color: #cccccc;\r
+ font-style: italic;\r
+ padding-right : 10px;\r
+ padding-top : 2px;\r
+ padding-left : 10px;\r
+ padding-bottom : 2px;\r
+ margin-left : 0px;\r
+ margin-right : 0px;\r
+ margin-top : 2px;\r
+ margin-bottom : 2px;\r
+ border: 1px solid #CCCCCC;\r
+}\r
+TR.memlist {\r
+ background-color: #f0f0f0;\r
+}\r
+P.formulaDsp { text-align: center; }\r
+IMG.formulaDsp { }\r
+IMG.formulaInl { vertical-align: middle; }\r
+SPAN.keyword { color: #008000 }\r
+SPAN.keywordtype { color: #604020 }\r
+SPAN.keywordflow { color: #e08000 }\r
+SPAN.comment { color: #800000 }\r
+SPAN.preprocessor { color: #806020 }\r
+SPAN.stringliteral { color: #002080 }\r
+SPAN.charliteral { color: #008080 }\r
+.mdTable {\r
+ border: 1px solid #cccccc;\r
+ background-color: #cccccc;\r
+}\r
+.mdRow {\r
+ padding: 8px 10px;\r
+}\r
+.mdescLeft {\r
+ padding: 0px 8px 4px 8px;\r
+ font-size: 12px;\r
+ font-style: italic;\r
+ background-color: #FAFAFA;\r
+ border-top: 1px none #E0E0E0;\r
+ border-right: 1px none #E0E0E0;\r
+ border-bottom: 1px none #E0E0E0;\r
+ border-left: 1px none #E0E0E0;\r
+ margin: 0px;\r
+}\r
+.mdescRight {\r
+ padding: 0px 8px 4px 8px;\r
+ font-size: 12px;\r
+ font-style: italic;\r
+ background-color: #FAFAFA;\r
+ border-top: 1px none #E0E0E0;\r
+ border-right: 1px none #E0E0E0;\r
+ border-bottom: 1px none #E0E0E0;\r
+ border-left: 1px none #E0E0E0;\r
+ margin: 0px;\r
+}\r
+.memItemLeft {\r
+ padding: 1px 0px 0px 8px;\r
+ margin: 4px;\r
+ border-top-width: 1px;\r
+ border-right-width: 1px;\r
+ border-bottom-width: 1px;\r
+ border-left-width: 1px;\r
+ border-top-color: #E0E0E0;\r
+ border-right-color: #E0E0E0;\r
+ border-bottom-color: #E0E0E0;\r
+ border-left-color: #E0E0E0;\r
+ border-top-style: solid;\r
+ border-right-style: none;\r
+ border-bottom-style: none;\r
+ border-left-style: none;\r
+ background-color: #FAFAFA;\r
+ font-size: 12px;\r
+}\r
+.memItemRight {\r
+ padding: 1px 8px 0px 8px;\r
+ margin: 4px;\r
+ border-top-width: 1px;\r
+ border-right-width: 1px;\r
+ border-bottom-width: 1px;\r
+ border-left-width: 1px;\r
+ border-top-color: #E0E0E0;\r
+ border-right-color: #E0E0E0;\r
+ border-bottom-color: #E0E0E0;\r
+ border-left-color: #E0E0E0;\r
+ border-top-style: solid;\r
+ border-right-style: none;\r
+ border-bottom-style: none;\r
+ border-left-style: none;\r
+ background-color: #FAFAFA;\r
+ font-size: 13px;\r
+}\r
+.memTemplItemLeft {\r
+ padding: 1px 0px 0px 8px;\r
+ margin: 4px;\r
+ border-top-width: 1px;\r
+ border-right-width: 1px;\r
+ border-bottom-width: 1px;\r
+ border-left-width: 1px;\r
+ border-top-color: #E0E0E0;\r
+ border-right-color: #E0E0E0;\r
+ border-bottom-color: #E0E0E0;\r
+ border-left-color: #E0E0E0;\r
+ border-top-style: none;\r
+ border-right-style: none;\r
+ border-bottom-style: none;\r
+ border-left-style: none;\r
+ background-color: #FAFAFA;\r
+ font-size: 12px;\r
+}\r
+.memTemplItemRight {\r
+ padding: 1px 8px 0px 8px;\r
+ margin: 4px;\r
+ border-top-width: 1px;\r
+ border-right-width: 1px;\r
+ border-bottom-width: 1px;\r
+ border-left-width: 1px;\r
+ border-top-color: #E0E0E0;\r
+ border-right-color: #E0E0E0;\r
+ border-bottom-color: #E0E0E0;\r
+ border-left-color: #E0E0E0;\r
+ border-top-style: none;\r
+ border-right-style: none;\r
+ border-bottom-style: none;\r
+ border-left-style: none;\r
+ background-color: #FAFAFA;\r
+ font-size: 13px;\r
+}\r
+.memTemplParams {\r
+ padding: 1px 0px 0px 8px;\r
+ margin: 4px;\r
+ border-top-width: 1px;\r
+ border-right-width: 1px;\r
+ border-bottom-width: 1px;\r
+ border-left-width: 1px;\r
+ border-top-color: #E0E0E0;\r
+ border-right-color: #E0E0E0;\r
+ border-bottom-color: #E0E0E0;\r
+ border-left-color: #E0E0E0;\r
+ border-top-style: solid;\r
+ border-right-style: none;\r
+ border-bottom-style: none;\r
+ border-left-style: none;\r
+ color: #606060;\r
+ background-color: #FAFAFA;\r
+ font-size: 12px;\r
+}\r
+.search { color: #003399;\r
+ font-weight: bold;\r
+}\r
+FORM.search {\r
+ margin-bottom: 0px;\r
+ margin-top: 0px;\r
+}\r
+INPUT.search { font-size: 75%;\r
+ color: #000080;\r
+ font-weight: normal;\r
+ background-color: #ffcc99;\r
+}\r
+TD.tiny { font-size: 75%;\r
+}\r
+a {\r
+ color: #0000ff;\r
+}\r
+a:visited {\r
+ color: #0000ff;\r
+}\r
+.anchor {\r
+ color: #000000;\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page khui_actions Actions\r
+\r
+ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page khui_context Contexts\r
+\r
+ \section khui_context_contents Contents\r
+\r
+ - \ref khui_context_intro "Introduction"\r
+ - \subpage khui_context_using\r
+\r
+ \section khui_context_intro Introduction\r
+\r
+ Several ::KMSG_CRED messages and many messages depend on the\r
+ selections that the user has made on the user interface. The UI\r
+ context functions and data structures provide access to this\r
+ information.\r
+\r
+ The NetIDMgr user interface presents an outline view of all the\r
+ credentials that were provided by credentials providers. This\r
+ view consists of headers representing the outline levels and rows\r
+ representing individual credentials.\r
+\r
+ Users can make multiple selections of credentials or headers from\r
+ this view. If all the credentials and subheaders under a\r
+ particular outline level are selected, then the header itself is\r
+ automatically selected. There may be multiple disjointed\r
+ selections of headers and credentials.\r
+\r
+ In addition, the current cursor position also acts as a selector.\r
+ The credential or header under the cursor may not actually be\r
+ selected. The cursor is not the mouse pointer, but the focus\r
+ rectangle that may be moved either using the keyboard or by\r
+ clicking on a credential or header.\r
+\r
+ Thus there are two independent groups of selections:\r
+\r
+ - Credentials and headers which are in a selected state at some\r
+ specific point in time (the <b>current selection</b>).\r
+\r
+ - The current credential or selection which the cursor is on (the\r
+ <b>cursor selection</b>).\r
+\r
+ There are a few notes on how credentials are selected:\r
+\r
+ - An "empty" header (a header that does not contain any credential\r
+ rows) does not appear in a UI context. However they can appear\r
+ as the current cursor context.\r
+\r
+ - At its current implementation, cursor selections of identity,\r
+ credential type, and individual credentials are treated as\r
+ special cases since they are the most common.\r
+\r
+ How the UI context is used when processing a specific action or\r
+ message depends on the action or message. If an action operates\r
+ on a group of credentials, then the current selection may be used,\r
+ and on the other hand if an action or message relates to just one\r
+ credential, identity or credential type is invoked, then the\r
+ cursor selection is invoked.\r
+\r
+ For example, double-clicking a credential, or right clicking and\r
+ selecting 'Properties' from the context menu launches the property\r
+ window for a credential. This operates on the cursor selection\r
+ since that reflects where the user double clicked. However,\r
+ choosing 'Destroy' from the context menu invokes a command that\r
+ can be applied to a group of credential, and hence uses the\r
+ current selection.\r
+\r
+ Next: \ref khui_context_using "Using Contexts"\r
+ */\r
+\r
+/*! \page khui_context_using Using Contexts \r
+\r
+ \section khui_context_using_1 Obtaining the context\r
+\r
+ Typically, messages sent by actions that rely on UI context will\r
+ obtain and store the context in a location that is accessible to\r
+ the handlers of the message.\r
+\r
+ If a plugin needs to obtain the UI context, it should do so by\r
+ calling khui_context_get() and passing in a pointer to a\r
+ ::khui_action_context structure.\r
+\r
+ Once obtained, the contents of the ::khui_action_context structure\r
+ should be considered read-only. When the plugin is done with the\r
+ structure, it should call ::khui_context_release(). This cleans\r
+ up any additional memory allocated for storing the context as well\r
+ as releasing all the objects that were referenced from the\r
+ context.\r
+\r
+ \section khui_context_sel_ctx Selection context\r
+\r
+ The selection context is specified in the ::khui_action_context\r
+ structure in the \a sel_creds and \a n_sel_creds fields. These\r
+ combined provide an array of handles to credentials which are\r
+ selected.\r
+\r
+ \note If \a n_sel_creds is zero, then \a sel_creds may be NULL.\r
+\r
+ \section khui_context_cur_ctx Cursor context\r
+\r
+ The scope of the cursor context is specified in the \a scope field\r
+ of the ::khui_action_context strucutre. The scope can be one of:\r
+\r
+ - ::KHUI_SCOPE_NONE\r
+ - ::KHUI_SCOPE_IDENT\r
+ - ::KHUI_SCOPE_CREDTYPE\r
+ - ::KHUI_SCOPE_GROUP\r
+ - ::KHUI_SCOPE_CRED\r
+\r
+ Depending on the scope, several other members of the strucre may\r
+ also be set.\r
+\r
+ In general, the cursor context can be a single credential or an\r
+ entire outline level. Unlike the selection context, since this\r
+ specifies a single point of selection it can not be disjointed.\r
+\r
+ The contents of the \a identity, \a cred_type, \a cred, \a headers\r
+ and \a n_headers are described in the documentation of each of the\r
+ scope values above.\r
+\r
+ \subsection khui_context_sel_ctx_grp KHUI_SCOPE_GROUP\r
+\r
+ The ::KHUI_SCOPE_GROUP scope is the generic scope which describes\r
+ a cursor selection that can not be simplified into any other\r
+ scope.\r
+\r
+ In this case, the selection is described by an array of\r
+ ::khui_header elements each of which specify a criterion for\r
+ narrowing down the selection of credentials. The ::khui_header\r
+ structure specifies an attribute in the \a attr_id field and a\r
+ value in the \a data and \a cb_data fields. The credentials that\r
+ are selected are those in the root credential set whose repective\r
+ attributes contain the values specified in each of the\r
+ ::khui_header elements.\r
+\r
+ For example, the following selection:\r
+\r
+ \image html credview-select-outline.jpg\r
+\r
+ will result in the following header specification:\r
+\r
+ \code\r
+ ctx.n_headers = 3;\r
+\r
+ ctx.headers[0].attr_id = KCDB_ATTR_LOCATION;\r
+ ctx.headers[0].data = L"grailauth@KHMTEST";\r
+ ctx.headers[0].cb_data = sizeof(L"grailauth@KHMTEST");\r
+\r
+ ctx.headers[1].attr_id = KCDB_ATTR_ID;\r
+ ctx.headers[1].data = &handle_to_identity;\r
+ ctx.headers[1].cb_data = sizeof(khm_handle);\r
+\r
+ ctx.headers[2].attr_id = KCDB_ATTR_TYPE;\r
+ ctx.headers[2].data = &kerberos_5_credtype;\r
+ ctx.headers[2].cb_data = sizeof(khm_int32);\r
+ \endcode\r
+\r
+ \note The attribute that is used to specify the header is not the\r
+ display attribute, but the canonical attribute. For example,\r
+ in the above, the second header was actually\r
+ KCDB_ATTR_ID_NAME. But KCDB_ATTR_ID was used since that is\r
+ the canonical source for KCDB_ATTR_ID_NAME. See ::kcdb_attrib\r
+ for more information on canonical attributes.\r
+*/\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page khui User Interface Topics\r
+\r
+ \section khui_contents Contents\r
+\r
+ - \subpage khui_actions\r
+ - \subpage khui_menus\r
+ - \subpage khui_context\r
+ */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/*! \page khui_menus Menus\r
+\r
+ */\r
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">\r
+<HTML>\r
+<HEAD>\r
+<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">\r
+<!-- Sitemap 1.0 -->\r
+</HEAD><BODY>\r
+<UL>\r
+</UL>\r
+</BODY></HTML>\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=help\r
+!include <..\config\Makefile.w32>\r
+\r
+CHMFILE=$(DOCDIR)\netidmgr.chm\r
+\r
+INCFILES=$(INCDIR)\khhelp.h\r
+\r
+all: mkdirs $(CHMFILE) $(INCFILES)\r
+\r
+$(CHMFILE): netidmgr.hhp\r
+ -hhc netidmgr.hhp\r
+ $(CP) netidmgr.chm $(CHMFILE)\r
--- /dev/null
+BODY { font-family:helvetica,sans-serif;\r
+ font-size:8pt; \r
+ font-style:normal; \r
+ background-color:white; }\r
+\r
+H1 { font-size: 10pt;\r
+ border:solid 1px black;\r
+ padding:5px;\r
+ background-color:lightgrey \r
+ }\r
+\r
+H2 { }\r
+\r
--- /dev/null
+<html>\r
+<head>\r
+ <title>title</title>\r
+ <meta name="description" content="">\r
+ <meta name="keywords" content="">\r
+ <link rel="stylesheet" type="text/css" href="khm.css">\r
+</head>\r
+\r
+</html>
\ No newline at end of file
--- /dev/null
+<html>\r
+<head>\r
+ <title>File menu</title>\r
+ <meta name="description" content="">\r
+ <meta name="keywords" content="">\r
+ <link rel="stylesheet" type="text/css" href="khm.css">\r
+</head>\r
+\r
+<h1>File menu</h1>\r
+\r
+<p>Menu items</p>\r
+\r
+<ul>\r
+<li><a href="menu_properties.htm">Properties...</a></li>\r
+<li><a href="menu_exit.htm">Exit...</a></li>\r
+</ul>\r
+\r
+</html>
\ No newline at end of file
--- /dev/null
+<html>\r
+<head>\r
+ <title>title</title>\r
+ <meta name="description" content="">\r
+ <meta name="keywords" content="">\r
+ <link rel="stylesheet" type="text/css" href="khm.css">\r
+</head>\r
+\r
+</html>
\ No newline at end of file
--- /dev/null
+<html>\r
+<head>\r
+ <title>title</title>\r
+ <meta name="description" content="">\r
+ <meta name="keywords" content="">\r
+ <link rel="stylesheet" type="text/css" href="khm.css">\r
+</head>\r
+\r
+</html>
\ No newline at end of file
--- /dev/null
+<html>\r
+<head>\r
+ <title>Welcome to Khimaira</title>\r
+ <meta name="description" content="Welcome">\r
+ <meta name="keywords" content="welcome">\r
+ <link rel="stylesheet" type="text/css" href="khm.css">\r
+</head>\r
+\r
+<h1>Welcome to Khimaira</h1>\r
+\r
+<p>Khimaira is a credentials manager that lets you manage Kerberos,\r
+AFS and other types of credentials.\r
+</p>\r
+\r
+<p>The following web sites provide more information about Kerberos and\r
+AFS:</p>\r
+\r
+<ul>\r
+<li><a class="external" href="http://web.mit.edu/kerberos">http://web.mit.edu/kerbeors</a></li>\r
+<li><a class="external" href="http://openafs.org">http://openafs.org</a></li>\r
+</ul>\r
+\r
+\r
+</html>
\ No newline at end of file
--- /dev/null
+\r
+#define IDH_WELCOME 1000\r
+#define IDH_MENU_FILE 1001\r
+#define IDH_MENU_CRED 1002\r
+#define IDH_MENU_VIEW 1003\r
+#define IDH_MENU_OPTIONS 1004\r
+#define IDH_MENU_HELP 1005\r
+\r
+#define IDH_ACTION_PROPERTIES 2000\r
+#define IDH_ACTION_EXIT 2001\r
+#define IDH_ACTION_NEW_ID 2002\r
+#define IDH_ACTION_SET_DEF_ID 2003\r
+#define IDH_ACTION_SET_SRCH_ID 2004\r
+#define IDH_ACTION_DESTROY_ID 2005\r
+#define IDH_ACTION_RENEW_ID 2006\r
+#define IDH_ACTION_PASSWD_ID 2007\r
+#define IDH_ACTION_NEW_CRED 2008\r
+#define IDH_ACTION_CHOOSE_COLS 2009\r
+#define IDH_ACTION_DEBUG_WINDOW 2010\r
+#define IDH_ACTION_VIEW_REFRESH 2011\r
+#define IDH_ACTION_OPT_KHIM 2012\r
+#define IDH_ACTION_OPT_INIT 2013\r
+#define IDH_ACTION_OPT_NOTIF 2014\r
--- /dev/null
+[OPTIONS]\r
+Auto Index=Yes\r
+Compatibility=1.1 or later\r
+Compiled file=netidmgr.chm\r
+Contents file=toc.hhc\r
+Default topic=html/welcome.htm\r
+Display compile progress=No\r
+Index file=Index.hhk\r
+Language=0x409 English (United States)\r
+Title=NetIDMgr\r
+\r
+\r
+[MAP]\r
+#include khhelp.h\r
+\r
+[INFOTYPES]\r
+Category:Concepts\r
+CategoryDesc:Authentication, authorization and related concepts.\r
+Category:Usage\r
+CategoryDesc:Usage instructions for NetIDMgr\r
+\r
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">\r
+<HTML>\r
+<HEAD>\r
+<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">\r
+<!-- Sitemap 1.0 -->\r
+</HEAD><BODY>\r
+<OBJECT type="text/site properties">\r
+ <param name="Category" value="Concepts">\r
+ <param name="CategoryDesc" value="Authentication, authorization and related concepts.">\r
+ <param name="Category" value="Usage">\r
+ <param name="CategoryDesc" value="Usage instructions for Khimaira">\r
+ <param name="Window Styles" value="0x800025">\r
+</OBJECT>\r
+<UL>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="Welcome to Khimaira">\r
+ <param name="Local" value="html\welcome.htm">\r
+ </OBJECT>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="Using Khimaira">\r
+ </OBJECT>\r
+ <UL>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="Menus">\r
+ </OBJECT>\r
+ <UL>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="File...">\r
+ <param name="Local" value="html\menu_file.htm">\r
+ </OBJECT>\r
+ </UL>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="Actions">\r
+ </OBJECT>\r
+ <UL>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="Properties">\r
+ <param name="Local" value="html\menu_properties.htm">\r
+ </OBJECT>\r
+ <LI> <OBJECT type="text/sitemap">\r
+ <param name="Name" value="Exit">\r
+ <param name="Local" value="html\menu_exit.htm">\r
+ </OBJECT>\r
+ </UL>\r
+ </UL>\r
+</UL>\r
+</BODY></HTML>\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=include\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\khdefs.h \\r
+ $(INCDIR)\kherror.h \\r
+ $(INCDIR)\khlist.h \\r
+ $(INCDIR)\khmsgtypes.h\r
+\r
+all: $(INCFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHDEFS_H__\r
+#define __KHIMAIRA_KHDEFS_H__\r
+\r
+/*! \defgroup khdef Core definitions\r
+\r
+ Key type definitions used throughout NetIDMgr.\r
+ */\r
+/*@{*/\r
+#include<stddef.h>\r
+#include<limits.h>\r
+#include<wchar.h>\r
+\r
+/*!\typedef khm_octet\r
+ \brief A byte (8 bit unsigned)*/\r
+\r
+/*!\typedef khm_int16\r
+ \brief A signed 16 bit quantity */\r
+\r
+/*!\typedef khm_ui_2\r
+ \brief An unsigned 16 bit quantity */\r
+\r
+/*!\typedef khm_int32\r
+ \brief A signed 32 bit quantity */\r
+\r
+/*!\typedef khm_ui_4\r
+ \brief An unsigned 32 bit quantity */\r
+\r
+/*!\typedef khm_int64\r
+ \brief A signed 64 bit quantity */\r
+\r
+/*!\typedef khm_ui_8\r
+ \brief An unsigned 64 bit quantity */\r
+\r
+typedef unsigned __int8 khm_octet;\r
+\r
+typedef __int16 khm_int16;\r
+typedef unsigned __int16 khm_ui_2;\r
+\r
+typedef __int32 khm_int32;\r
+typedef unsigned __int32 khm_ui_4;\r
+\r
+typedef __int64 khm_int64;\r
+typedef unsigned __int64 khm_ui_8;\r
+\r
+#define VALID_INT_BITS INT_MAX\r
+#define VALID_UINT_BITS UINT_MAX\r
+\r
+#define KHM_UINT32_MAX 4294967295\r
+\r
+#define KHM_INT32_MAX 2147483647\r
+/* this strange form is necessary since - is a unary operator, not a sign\r
+ indicator */\r
+#define KHM_INT32_MIN (-KHM_INT32_MAX-1)\r
+\r
+#define KHM_UINT16_MAX 65535\r
+\r
+#define KHM_INT16_MAX 32767\r
+/* this strange form is necessary since - is a unary operator, not a sign\r
+ indicator */\r
+#define KHM_INT16_MIN (-KHM_INT16_MAX-1)\r
+\r
+/*! \brief Generic handle type.\r
+\r
+ Handles in NetIDMgr are generic pointers.\r
+*/\r
+typedef void * khm_handle;\r
+\r
+/*! \brief The invalid handle\r
+\r
+ Just used to indicate that this handle does not point to anything useful.\r
+ Usually returned by a function that returns a handle as a signal that the\r
+ operation failed.\r
+*/\r
+#define KHM_INVALID_HANDLE ((khm_handle) NULL)\r
+\r
+/*! \brief Boolean.\r
+*/\r
+typedef khm_int32 khm_boolean;\r
+\r
+/*! \brief A size\r
+ */\r
+typedef size_t khm_size;\r
+\r
+/*! \typedef ssize_t\r
+ \brief Signed size specifier\r
+\r
+ Just a signed version of size_t\r
+ */\r
+\r
+#ifdef _WIN64\r
+typedef __int64 ssize_t;\r
+#else\r
+typedef _W64 int ssize_t;\r
+#endif\r
+\r
+typedef ssize_t khm_ssize;\r
+\r
+#if defined(_WIN64)\r
+typedef unsigned __int64 khm_wparm;\r
+/*TODO: is this enough? */\r
+typedef unsigned __int64 khm_lparm;\r
+#elif defined(_WIN32)\r
+typedef unsigned __int32 khm_wparm;\r
+typedef unsigned __int64 khm_lparm;\r
+#else\r
+#error khm_wparm and khm_lparm need to be defined for this platform\r
+#endif\r
+\r
+/*!\def KHMAPI \r
+ \brief Calling convention for NetIDMgr exported functions\r
+\r
+ The caling convention for all NetIDMgr exported functions is \b\r
+ __stdcall , unless otherwise noted.\r
+ */\r
+\r
+/*!\def KHMEXP\r
+ \brief Export prefix for NetIDMgr exported functions\r
+\r
+ When compiling source that exports functions, those exported\r
+ function declarations will be done as follows:\r
+\r
+ \code\r
+ __declspec(dllexport) khm_int32 __stdcall function_name(arguments...);\r
+ \endcode\r
+\r
+ This eliminates the need for a separate exports definition file.\r
+ However, it doesn't preserve ordinals, but we aren't guaranteeing\r
+ that anyway.\r
+\r
+ On the other hand, if a particular function is going to be imported\r
+ from a DLL, it should declared as follows:\r
+\r
+ \code\r
+ __declspec(dllimport) khm_int32 __stdcall function_name(arguments...);\r
+ \endcode\r
+\r
+ This allows the compiler to properly instrument the import. If the\r
+ function is not declared this way, there will be a stub function\r
+ generated that will just jump to the proper import, generating\r
+ redundant instructions and wasting execution time.\r
+\r
+ This macro encapsulates the proper declaration specifier.\r
+ */\r
+\r
+#ifdef _WIN32\r
+#define KHMAPI __stdcall\r
+\r
+#define KHMEXP_EXP __declspec(dllexport)\r
+#define KHMEXP_IMP __declspec(dllimport)\r
+\r
+#define KHMEXP KHMEXP_EXP\r
+#endif\r
+\r
+/* Generic permission values */\r
+/*! \brief Generic read permission or request */\r
+#define KHM_PERM_READ 0x100\r
+\r
+/*! \brief Generic write permission or request */\r
+#define KHM_PERM_WRITE 0x200\r
+\r
+/* Generic flags */\r
+/*! \brief Generic create request\r
+\r
+ For most lookup functions, specifying this flag indicates that if\r
+ the requested object is not found it should be created.\r
+*/\r
+#define KHM_FLAG_CREATE 0x1000\r
+\r
+/*! \brief Wrap to DWORD boundary\r
+\r
+ Returns the smallest integer greater than or equal to the\r
+ parameter that is a multiple of 4.\r
+ \r
+ \note Only use with positive integers. */\r
+#define UBOUND32(d) ((((d)-1)&~3) + 4)\r
+\r
+/*! \brief Offset a pointer by a number of bytes\r
+\r
+ Given a pointer, returns a void pointer that is a given number of\r
+ bytes offset from the pointer.\r
+ */\r
+#define BYTEOFFSET(p,off) ((void *)(((char *) (p)) + (off)))\r
+\r
+/*! \brief Check for powers of 2\r
+\r
+ Return TRUE if the operand is a positive power of 2 or 0*/\r
+#define IS_POW2(d) ((d)>=0 && !((d) & ((d) - 1)))\r
+\r
+/*! \brief Wrap to upper bound based on start and step size\r
+\r
+ Return the smallest element in the series <tt>s, s+t, s+2*t,\r
+ s+3*t, ...</tt> that is greater than or equal to \c v.\r
+*/\r
+#define UBOUNDSS(v,start,step) (((v)<=(start))?(start):(start)+((((v)-((start)+1))/(step))+1)*(step))\r
+\r
+/* \brief Length of an array\r
+*/\r
+#define ARRAYLENGTH(x) (sizeof(x)/sizeof(x[0]))\r
+\r
+/*! \brief Generic version type*/\r
+typedef struct tag_khm_version {\r
+ khm_ui_2 major; /*!< Major version number */\r
+ khm_ui_2 minor; /*!< Minor version number */\r
+ khm_ui_2 patch; /*!< Patch level */\r
+ khm_ui_2 aux; /*!< Auxilary level (usually carries a build number) */\r
+} khm_version;\r
+\r
+/*@}*/\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Exported */\r
+#ifndef __KHIMAIRA_KHERROR_H\r
+#define __KHIMAIRA_KHERROR_H\r
+\r
+/*! \defgroup kherror NetIDMgr errors\r
+\r
+@{*/\r
+/*! \brief Base for error codes\r
+\r
+ NetIDMgr errors range from \a KHM_ERROR_BASE to KHM_ERROR_BASE +\r
+ KHM_ERROR_RANGE, with the exception of KHM_ERROR_SUCCESS and\r
+ KHM_ERROR_NONE.\r
+ */\r
+#define KHM_ERROR_BASE 0x40000000L\r
+\r
+/*! \brief Range for error codes\r
+\r
+ NetIDMgr errors range from \a KHM_ERROR_BASE to \r
+ KHM_ERROR_BASE + KHM_ERROR_RANGE.\r
+*/\r
+#define KHM_ERROR_RANGE 256L\r
+\r
+/*! \defgroup kherror_codes Error codes\r
+ @{*/\r
+\r
+/*! \brief No error */\r
+#define KHM_ERROR_NONE 0x00000000L\r
+\r
+/*! \brief Success. Same as \a KHM_ERROR_NONE */\r
+#define KHM_ERROR_SUCCESS KHM_ERROR_NONE\r
+\r
+/*! \brief The supplied name was invalid */\r
+#define KHM_ERROR_INVALID_NAME (KHM_ERROR_BASE + 1)\r
+\r
+/*! \brief Too much data\r
+\r
+ A supplied buffer was invalid, was of insufficient size, or a\r
+ buffer was of a larger size than expected\r
+ */\r
+#define KHM_ERROR_TOO_LONG (KHM_ERROR_BASE + 2)\r
+\r
+/*! \brief One or more parameters supplied to a function were invalid */\r
+#define KHM_ERROR_INVALID_PARM (KHM_ERROR_BASE + 3)\r
+\r
+/*! \brief A duplicate.\r
+\r
+ Usually means that something that should have been unique was\r
+ found to be not.\r
+ */\r
+#define KHM_ERROR_DUPLICATE (KHM_ERROR_BASE + 4)\r
+\r
+/*! \brief An object was not found\r
+\r
+ An object referenced in a parameter was not found.\r
+ */\r
+#define KHM_ERROR_NOT_FOUND (KHM_ERROR_BASE + 5)\r
+\r
+/*! \brief The relevant subsystem is not ready\r
+\r
+ Indicates that initialization has not been completed for a\r
+ subsystem.\r
+ */\r
+#define KHM_ERROR_NOT_READY (KHM_ERROR_BASE + 6)\r
+\r
+/*! \brief No more resources\r
+\r
+ A limited resource has been exhausted.\r
+ */\r
+#define KHM_ERROR_NO_RESOURCES (KHM_ERROR_BASE + 7)\r
+\r
+/*! \brief Type mismatch\r
+ */\r
+#define KHM_ERROR_TYPE_MISMATCH (KHM_ERROR_BASE + 8)\r
+\r
+/*! \brief Already exists\r
+\r
+ Usually indicates that an exclusive create operation failed due to\r
+ the existence of a similar object. Subtly different from\r
+ ::KHM_ERROR_DUPLICATE\r
+ */\r
+#define KHM_ERROR_EXISTS (KHM_ERROR_BASE + 9)\r
+\r
+/*! \brief Operation timed out\r
+ */\r
+#define KHM_ERROR_TIMEOUT (KHM_ERROR_BASE + 10)\r
+\r
+/*! \brief An EXIT message was received\r
+ */\r
+#define KHM_ERROR_EXIT (KHM_ERROR_BASE + 11)\r
+\r
+/*! \brief Unknown or unspecified error\r
+ */\r
+#define KHM_ERROR_UNKNOWN (KHM_ERROR_BASE + 12)\r
+\r
+/*! \brief General error\r
+ */\r
+#define KHM_ERROR_GENERAL KHM_ERROR_UNKNOWN\r
+\r
+/*! \brief An index was out of bounds\r
+ */\r
+#define KHM_ERROR_OUT_OF_BOUNDS (KHM_ERROR_BASE + 13)\r
+\r
+/*! \brief Object already deleted\r
+\r
+ One or more objects that were referenced were found to have been\r
+ already deleted.\r
+ */\r
+#define KHM_ERROR_DELETED (KHM_ERROR_BASE + 14)\r
+\r
+/*! \brief Invalid operation\r
+\r
+ The operation was not permitted to continue for some reason.\r
+ Usually because the necessary conditions for the operation haven't\r
+ been met yet or the operation can only be performed at certain\r
+ times during the execution of NetIDMgr.\r
+ */\r
+#define KHM_ERROR_INVALID_OPERATION (KHM_ERROR_BASE + 15)\r
+\r
+/*! \brief Signature check failed\r
+ */\r
+#define KHM_ERROR_INVALID_SIGNATURE (KHM_ERROR_BASE + 16)\r
+\r
+/*! \brief Not implemented yet\r
+\r
+ The operation that was attempted involved invoking functionality\r
+ that has not been implemented yet.\r
+ */\r
+#define KHM_ERROR_NOT_IMPLEMENTED (KHM_ERROR_BASE + 17)\r
+\r
+/*! \brief The objects were equivalent\r
+ */\r
+#define KHM_ERROR_EQUIVALENT (KHM_ERROR_BASE + 18)\r
+\r
+/*! \brief No provider exists to service the request\r
+*/\r
+#define KHM_ERROR_NO_PROVIDER (KHM_ERROR_BASE + 19)\r
+\r
+/*! \brief The operation succeeded, but with errors\r
+*/\r
+#define KHM_ERROR_PARTIAL (KHM_ERROR_BASE + 20)\r
+\r
+/*@}*/ /*kherror_codes*/\r
+\r
+/*! \brief Tests whether a return value indicates success */\r
+#define KHM_SUCCEEDED(rv) ((rv)==KHM_ERROR_NONE)\r
+\r
+/*! \brief Tests whether a return value indicates failure */\r
+#define KHM_FAILED(rv) ((rv)!=KHM_ERROR_NONE)\r
+\r
+/*@}*/\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Not exported */\r
+#ifndef _KHIMAIRA_KHLIST_H\r
+#define _KHIMAIRA_KHLIST_H\r
+\r
+/* Note that most of these are "unsafe" macros. Not for general use */\r
+\r
+/* LIFO lists */\r
+#define LDCL(type) \\r
+ type * next; \\r
+ type * prev\r
+\r
+#define LINIT(pe) \\r
+ do { \\r
+ (pe)->next = NULL; \\r
+ (pe)->prev = NULL; } while(0)\r
+\r
+#define LPUSH(pph,pe) \\r
+ do { \\r
+ (pe)->next = *pph; \\r
+ (pe)->prev = NULL; \\r
+ if(*(pph)) (*(pph))->prev = (pe); \\r
+ (*(pph)) = (pe); } while(0)\r
+\r
+#define LPOP(pph,ppe) \\r
+ do { \\r
+ *(ppe) = *(pph); \\r
+ if(*(pph)) *(pph) = (*(pph))->next; \\r
+ if(*(pph)) (*(pph))->prev = NULL; \\r
+ if(*(ppe)) (*(ppe))->next = NULL; \\r
+ } while(0)\r
+\r
+#define LDELETE(pph,pe) \\r
+ do { \\r
+ if((pe)->prev) (pe)->prev->next = (pe)->next; \\r
+ if((pe)->next) (pe)->next->prev = (pe)->prev; \\r
+ if(*(pph) == (pe)) *(pph) = (pe)->next; \\r
+ (pe)->next = (pe)->prev = NULL; \\r
+ } while(0)\r
+\r
+#define LEMPTY(pph) (*(pph) == NULL)\r
+\r
+#define LNEXT(pe) ((pe)?(pe)->next:NULL)\r
+\r
+#define LPREV(pe) ((pe)?(pe)->prev:NULL)\r
+\r
+/* Trees with LIFO child lists */\r
+#define TDCL(type) \\r
+ LDCL(type); \\r
+ type * children; \\r
+ type * parent\r
+\r
+#define TINIT(pe) \\r
+ do { \\r
+ (pe)->children = NULL; \\r
+ (pe)->parent = NULL; } while(0)\r
+\r
+#define TADDCHILD(pt,pe) \\r
+ do { \\r
+ LPUSH(&((pt)->children),(pe)); \\r
+ (pe)->parent = (pt); } while(0)\r
+\r
+#define TFIRSTCHILD(pt) ((pt)?(pt)->children:NULL)\r
+\r
+#define TPOPCHILD(pt, ppe) \\r
+ do { \\r
+ LPOP(&((pt)->children), ppe); \\r
+ if(*(ppe)) (*(ppe))->parent = NULL; \\r
+ } while(0)\r
+\r
+#define TDELCHILD(pt, pe) \\r
+ do { \\r
+ LDELETE(&((pt)->children), (pe)); \\r
+ (pe)->parent = NULL; } while(0)\r
+\r
+#define TPARENT(pe) ((pe)?(pe)->parent:NULL)\r
+\r
+/* FIFO lists */\r
+#define QDCL(type) \\r
+ type * head; \\r
+ type * tail\r
+\r
+#define QINIT(pq) \\r
+ do { \\r
+ (pq)->head = (pq)->tail = NULL; \\r
+ } while(0)\r
+\r
+#define QPUT(pq, pe) \\r
+ do { \\r
+ LPUSH(&(pq)->tail, (pe)); \\r
+ if(!(pq)->head) (pq)->head = (pe); \\r
+ } while(0)\r
+\r
+#define QGET(pq, ppe) \\r
+ do { \\r
+ *(ppe) = (pq)->head; \\r
+ if(*(ppe)) { \\r
+ (pq)->head = (*(ppe))->prev; \\r
+ if( (*(ppe))->prev ) (*(ppe))->prev->next = NULL; \\r
+ (*(ppe))->prev = NULL; \\r
+ if( (pq)->tail == *(ppe)) (pq)->tail = NULL; \\r
+ } \\r
+ } while(0)\r
+\r
+#define QDEL(pq, pe) \\r
+ do { \\r
+ if((pq)->head == (pe)) (pq)->head = LPREV(pe); \\r
+ LDELETE(&((pq)->tail), (pe)); \\r
+ } while(0)\r
+\r
+\r
+#define QGETT(pq,ppe) \\r
+ do { \\r
+ *(ppe) = (pq)->tail; \\r
+ if(*(ppe)) { \\r
+ (pq)->tail = (*(ppe))->next; \\r
+ if( (*(ppe))->next ) (*(ppe))->next->prev = NULL; \\r
+ (*(ppe))->next = NULL; \\r
+ if( (pq)->head == *(ppe)) (pq)->head = NULL; \\r
+ } \\r
+ } while(0)\r
+\r
+#define QTOP(pq) ((pq)->head)\r
+#define QBOTTOM(pq) ((pq)->tail)\r
+#define QNEXT(pe) ((pe)->prev)\r
+#define QPREV(pe) ((pe)->next)\r
+\r
+/* Trees with FIFO child lists */\r
+#define TQDCL(type) \\r
+ LDCL(type); \\r
+ QDCL(type); \\r
+ type * parent\r
+\r
+#define TQINIT(pe) \\r
+ do { \\r
+ QINIT(pe); \\r
+ (pe)->parent = NULL; } while(0)\r
+\r
+#define TQADDCHILD(pt,pe) \\r
+ do { \\r
+ QPUT((pt), (pe)); \\r
+ (pe)->parent = (pt); } while(0)\r
+\r
+#define TQFIRSTCHILD(pt) ((pt)?QTOP(pt):NULL)\r
+\r
+#define TQPARENT(pe) ((pe)?(pe)->parent:NULL)\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHMSGTYPES_H\r
+#define __KHIMAIRA_KHMSGTYPES_H\r
+\r
+/*! \addtogroup kmq\r
+@{*/\r
+/*! \defgroup kmq_msg Message Types\r
+@{*/\r
+\r
+/*! \name Global message types\r
+@{*/\r
+\r
+/*! \brief System messages.\r
+\r
+ All subscribers are subscribed to the system message class by default.\r
+\r
+ \see \ref kmq_msg_system\r
+*/\r
+#define KMSG_SYSTEM 0\r
+\r
+/*! \brief Ad-hoc messages.\r
+\r
+ These are messages that are sent through add hoc publishers and\r
+ subscribers.\r
+*/\r
+#define KMSG_ADHOC 1\r
+\r
+/*! \brief NetIDMgr Credentials Database messages\r
+\r
+ These messages notify subscribers of events related to the\r
+ credentials database, such as the registration, unregistration and\r
+ modification of identities, attributes, attribute types and\r
+ credential types. It also provides notifications of changes to\r
+ the root crednetial set.\r
+\r
+ \see \ref kmq_msg_kcdb\r
+*/\r
+#define KMSG_KCDB 2\r
+\r
+/*! \brief NetIDMgr Module Manager messages\r
+ \r
+ \see \ref kmq_msg_kmm\r
+*/\r
+#define KMSG_KMM 3\r
+\r
+/*! \brief NetIDMgr Credential messages\r
+\r
+ Notifications of crednetial events. These are the most important\r
+ events that a credentials provider should respond to. The\r
+ notifications provide co-oridination between credential providers\r
+ for performing basic credentials management tasks such as\r
+ obtaining new credentials for an identity, deleting credentials\r
+ for an identity, obtaining or deleting credentials of a particular\r
+ type for an identity etc.\r
+\r
+ \see \ref cred_msgs\r
+ \see \ref kmq_msg_cred\r
+ */\r
+#define KMSG_CRED 4\r
+\r
+/*! \brief Action list messages\r
+\r
+ Notifications of changes in action state.\r
+\r
+ \see \ref kmq_msg_act\r
+ */\r
+#define KMSG_ACT 5\r
+\r
+/*! \brief Alert messages\r
+\r
+ Notifier is the component which displays alerts and error messages\r
+ when the NetIDMgr window is normally in operation and which\r
+ displays balloon prompts when the window is minimized to alert the\r
+ user to important messages such as credentials expiring etc.\r
+\r
+ \note This is an internal message class. Components that are not\r
+ the notifier should not be subscribing to alert messages.\r
+\r
+ \see \ref kmq_msg_alert\r
+ */\r
+#define KMSG_ALERT 6\r
+\r
+/*! \brief Identity messages\r
+\r
+ These are messages that are sent to the identity provider. These\r
+ are generally dispatched through a specific subscription object\r
+ and are not broadcast.\r
+\r
+ \see \ref kmq_msg_ident\r
+ */\r
+#define KMSG_IDENT 7\r
+\r
+/*! \brief Base message type ID for customized message types\r
+ */\r
+#define KMSGBASE_USER 16\r
+\r
+/*@}*/\r
+\r
+/*! \defgroup kmq_msg_system KMSG_SYSTEM subtypes \r
+@{*/\r
+/*! \brief Generic initialization message\r
+\r
+ This message is used by specific components to signal that the\r
+ recipient is to perform initialization tasks. As a convention,\r
+ the recipient should return KHM_ERROR_SUCCESS if it successfully\r
+ performed the initlization tasks or some other value if it failed\r
+ to do so. Failure to successfully initialize is usually taken to\r
+ mean that the recipient component is not able to perform its\r
+ function.\r
+\r
+ Usually this is the first message to be received by the recipient.\r
+\r
+ \see \ref pi_pt_cred_init\r
+ */\r
+#define KMSG_SYSTEM_INIT 1\r
+/*! \brief Generic uninitialization message\r
+\r
+ Used by specific components to signal that the recipient should\r
+ perform uninitilization tasks in preparation of termination. The\r
+ return value of this message is not used.\r
+\r
+ Usually this is the last message to be received by the recipient.\r
+\r
+ \see \ref pi_pt_cred_exit\r
+ */\r
+#define KMSG_SYSTEM_EXIT 2\r
+\r
+/*! \brief Message completion\r
+\r
+ This is an internal message\r
+ */\r
+#define KMSG_SYSTEM_COMPLETION 3\r
+/*@}*/\r
+\r
+/*! \defgroup kmq_msg_kcdb KMSG_KCDB subtypes \r
+@{*/\r
+#define KMSG_KCDB_IDENT 1\r
+#define KMSG_KCDB_CREDTYPE 2\r
+#define KMSG_KCDB_ATTRIB 3\r
+#define KMSG_KCDB_TYPE 4\r
+\r
+/*! \brief Generic credentials request\r
+\r
+ \see ::kcdb_cred_request for more information\r
+ */\r
+#define KMSG_KCDB_REQUEST 256\r
+/*@}*/\r
+\r
+/*! \defgroup kmq_msg_kmm KMSG_KMM subtypes\r
+@{*/\r
+#define KMSG_KMM_I_REG 1\r
+\r
+#define KMSG_KMM_I_DONE 2\r
+/*@}*/\r
+\r
+/*! \defgroup kmq_msg_act KMSG_ACT subtypes\r
+ @{*/\r
+\r
+/*! \brief One or more actions changed state\r
+\r
+ This message is sent in response to a call to\r
+ khui_enable_actions() or khui_enable_action() and indicates that\r
+ one or more actions have changed their state.\r
+ */\r
+#define KMSG_ACT_ENABLE 1\r
+\r
+/*! \brief One or more actions changed check state\r
+\r
+ Sent in response to khui_check_radio_action() or\r
+ khui_check_action() and indicates that one or more actions have\r
+ either been checked or unchecked.\r
+ */\r
+#define KMSG_ACT_CHECK 2\r
+\r
+/*! \brief Refresh action states\r
+\r
+ Sent after a batch of modifications were made to action states.\r
+ */\r
+#define KMSG_ACT_REFRESH 3\r
+\r
+#define KMSG_ACT_BEGIN_CMDLINE 128\r
+\r
+/*@}*/\r
+\r
+/*! \defgroup kmq_msg_cred KMSG_CRED subtypes\r
+ @{*/\r
+/*! \brief Root credential set changed\r
+ \r
+ This message is issued when the root credential set successfully\r
+ collected credentials from another credential set.\r
+\r
+ \a uparam of the message is set to a bitmask indicating the change\r
+ that occured. It is a combination of ::KCDB_DELTA_ADD,\r
+ ::KCDB_DELTA_DEL and ::KCDB_DELTA_MODIFY.\r
+ */\r
+#define KMSG_CRED_ROOTDELTA 1\r
+\r
+/*! \brief Re-enumerate credentials\r
+\r
+ A notice to all credential providers to re-enumerate their\r
+ respective credentials.\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+*/\r
+#define KMSG_CRED_REFRESH 2\r
+\r
+/*! \brief Change the password\r
+\r
+ This message notifies credentials providers that a password change\r
+ request has been received.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+ */\r
+#define KMSG_CRED_PASSWORD 16\r
+\r
+/*! \brief Initiate the process of obtaining new credentials\r
+\r
+ The UI sends this message to start the process of obtaining new\r
+ credentials. See \ref cred_acq for more information about handling this\r
+ message.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \see \ref cred_acq\r
+ */\r
+#define KMSG_CRED_NEW_CREDS 17\r
+\r
+/*! \brief Renew credentials\r
+\r
+ This is a notification sent to individual credentials providers\r
+ that a specified identity's credentials should be renewed.\r
+\r
+ Message parameters:\r
+ - \b vparam : Pointer to a khui_new_creds object\r
+ */\r
+#define KMSG_CRED_RENEW_CREDS 18\r
+\r
+/*! \brief Dialog setup\r
+\r
+ Once KMSG_CRED_NEW_CREDS has been responded to by all the\r
+ credential types, the UI creates the dialog windows using the data\r
+ supplied in the ::khui_new_creds_by_type structures and issues\r
+ this message. Each credentials provider is expected to respond by\r
+ finalizing dialog creation operations.\r
+\r
+ Message parameters:\r
+ - \b vparam : poitner to a ::khui_new_creds structure\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+ */\r
+#define KMSG_CRED_DIALOG_SETUP 19\r
+\r
+/*! \brief Dialog pre-start\r
+\r
+ Sent after all the credentials providers have responded to\r
+ KMSG_CRED_DIALOG_SETUP and all the initialization has been\r
+ completed. Credentials providers are expected to respond to this\r
+ message by loading any default data into the dialog controls for\r
+ each credential type.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+ */\r
+#define KMSG_CRED_DIALOG_PRESTART 20\r
+\r
+/*! \brief Dialog start\r
+\r
+ A notification that the dialog is now in progress.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+ */\r
+#define KMSG_CRED_DIALOG_START 21\r
+\r
+/*! \brief The primary identity of the new credentials dialog has changed\r
+\r
+ This message is not sent out by the UI, but is reserved here for\r
+ use by individual credentials providers. The message may be sent\r
+ from the dialog procedure to the plugin.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \note Be careful when sending this message. All messages that are\r
+ not sent by the system should not be sent via broadcast.\r
+ Instead, create a subscription using kmq_create_subscription()\r
+ for the individual plugin that you want to send the message\r
+ and use one of the per-subscription message functions to send\r
+ the actual message.\r
+ */\r
+#define KMSG_CRED_DIALOG_NEW_IDENTITY 22\r
+\r
+/*! \brief New credentials options have changed.\r
+\r
+ This message is not sent out by the UI, but is reserved here for\r
+ use by individual credentials providers. The message may be sent\r
+ from the dialog procedure to the plugin.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \note Be careful when sending this message. All messages that are\r
+ not sent by the system should not be sent via broadcast.\r
+ Instead, create a subscription using kmq_create_subscription()\r
+ for the individual plugin that you want to send the message\r
+ and use one of the per-subscription message functions to send\r
+ the actual message.\r
+ */\r
+#define KMSG_CRED_DIALOG_NEW_OPTIONS 23\r
+\r
+/*! \brief Process dialog\r
+\r
+ Sent to all the credential providers to look at the contents of\r
+ the given ::khui_new_creds structure and do any required\r
+ processing.\r
+\r
+ If the \a result field in the structure is set to\r
+ KHUI_NC_RESULT_GET_CREDS, then new credentials should be obtained\r
+ using the given data.\r
+\r
+ Set the \a response field in the structure to indicate how the UI\r
+ should proceed from here.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+ */\r
+#define KMSG_CRED_PROCESS 24\r
+\r
+/*! \brief End a credentials acquisition operation\r
+\r
+ A notification that the credentials acquisition operation has\r
+ ended.\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_new_creds structure\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+ */\r
+#define KMSG_CRED_END 25\r
+\r
+/*! \brief Import credentials from the operating system\r
+\r
+ Notification to all credentials providers to import any available\r
+ credentials from the operating system.\r
+\r
+ Message parameters:\r
+ - This message does not have any parameters\r
+*/\r
+#define KMSG_CRED_IMPORT 26\r
+\r
+/*! \brief Destroy credentials\r
+\r
+ Notification that the specified credentials should be destroyed.\r
+ Once this message has completed processing a ::KMSG_CRED_REFRESH\r
+ message will be issued.\r
+\r
+ The credentials that should be destroyed are specified by a\r
+ ::khui_action_context structure. The context that should be used\r
+ is the selection context. Hence, the credentials that must be\r
+ destroyed are the ones lised in the credential set (\a credset).\r
+\r
+ Message parameters:\r
+\r
+ - \b upram : Unused. Zero.\r
+\r
+ - \b vparam : pointer to a ::khui_action_context structure which\r
+ describes which credentials need to be destroyed.\r
+\r
+ */\r
+#define KMSG_CRED_DESTROY_CREDS 32\r
+\r
+#if 0\r
+/*! \brief Parse an identity\r
+\r
+ \note May be sent to individual credential subscriptions.\r
+ */\r
+#define KMSG_CRED_IDENT_PARSE 65\r
+#endif\r
+\r
+/*! \brief A property page is being launced\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_property_sheet structure\r
+ */\r
+#define KMSG_CRED_PP_BEGIN 128\r
+\r
+/*! \brief A property page is about to be created\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_property_sheet structure\r
+\r
+ \note This message is merely a notification that the property\r
+ sheet is being created. Handlers should not modify the state\r
+ of the property sheet or pages at this time.\r
+ */\r
+#define KMSG_CRED_PP_PRECREATE 129\r
+\r
+/*! \brief A property page has finished processing\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_property_sheet structure\r
+ */\r
+#define KMSG_CRED_PP_END 130\r
+\r
+/*! \brief A property page has been destroyed\r
+\r
+ Message parameters:\r
+ - \b vparam : pointer to a ::khui_property_sheet structure\r
+ */\r
+#define KMSG_CRED_PP_DESTROY 131\r
+\r
+/*! \brief Check if a KMSG_CRED subtype is a credentials acquisition message\r
+\r
+ Dialog messages are those that deal with the new or initial\r
+ credentials acquisition dialog, from initial announcement to\r
+ dialog completion.\r
+\r
+ Currently, the dialog messages are:\r
+ - ::KMSG_CRED_INITIAL_CREDS\r
+ - ::KMSG_CRED_NEW_CREDS\r
+ - ::KMSG_CRED_RENEW_CREDS\r
+ - ::KMSG_CRED_DIALOG_SETUP\r
+ - ::KMSG_CRED_DIALOG_PRESTART\r
+ - ::KMSG_CRED_DIALOG_START\r
+ - ::KMSG_CRED_DIALOG_NEW_IDENTITY\r
+ - ::KMSG_CRED_DIALOG_NEW_OPTIONS\r
+ - ::KMSG_CRED_PROCESS\r
+ - ::KMSG_CRED_END\r
+\r
+ All dialog message numbers are allocated in a contigous block.\r
+\r
+ Note that while ::KMSG_CRED_PROCESS and ::KMSG_CRED_END are not\r
+ specific to dialogs, they are still included in this predicate\r
+ because they are also part of the dialog message sequence.\r
+ */\r
+#define IS_CRED_ACQ_MSG(msg) ((msg) >= 16 && (msg) <=31)\r
+\r
+/*@}*/ /* /KMSG_CRED subtypes */ \r
+\r
+/*! \defgroup kmq_msg_alert KMSG_ALERT Subtypes \r
+ @{*/\r
+\r
+/*! \brief Show an alert\r
+\r
+ Message parameters:\r
+ - \b vparam : held pointer to a ::khui_alert object\r
+\r
+ \note The ::khui_alert object will be released when the processing\r
+ of this message completes.\r
+ */\r
+#define KMSG_ALERT_SHOW 1\r
+\r
+/*@}*/\r
+\r
+/*! \defgroup kmq_msg_ident KMSG_IDENT Subtypes\r
+ @{*/\r
+\r
+/*! \brief Initialize and start the identity provider\r
+\r
+\r
+ Sent by the KCDB to notify the identity provider that it is now\r
+ the current identity provider.\r
+\r
+ Note that unlike regular plugins, an identity provider can be\r
+ loaded and inert (not provide any services). Also, the user may\r
+ switch between multiple identity providers on the fly.\r
+ */\r
+#define KMSG_IDENT_INIT 1\r
+\r
+/*! \brief Stop the identity provider\r
+\r
+ Sent by the KCDB as notificaton that the identity provider is no\r
+ longer the current provider.\r
+ */\r
+#define KMSG_IDENT_EXIT 2\r
+\r
+/*! \brief Check if an identity name is valid\r
+\r
+ This message is sent to the identity provider to verify the syntax\r
+ of an identity name. Note that only the syntax of the name is to\r
+ be verfied and not the actual physical existence of said identity.\r
+\r
+ Message parameters:\r
+\r
+ - \b vparam : pointer to ::kcdb_ident_name_xfer object. The\r
+ name to be validated will be in the \a name_src member. The\r
+ buffer will be NULL terminated with a maximum limit of\r
+ KCDB_IDENT_MAXCCH_NAME characters including the terminating\r
+ NULL, consisting only of characters in KCDB_IDENT_VALID_CHARS\r
+ The \a result member should be set to one of the following\r
+ depending on the result of the validation:\r
+\r
+ - KHM_ERROR_SUCCESS : The name was valid\r
+ - KHM_ERROR_INVALID_NAME : The name was invalid\r
+ */\r
+#define KMSG_IDENT_VALIDATE_NAME 3\r
+\r
+/*! \brief Check if an identity is valid\r
+\r
+ Sent to the identity provider to verify the validity of the given\r
+ identity. The provider should verify that the identity exists and\r
+ is in a state where it can be actively used.\r
+\r
+ Depending on the result of the validation, the flags of the\r
+ identity should be updated.\r
+\r
+ Message parameters:\r
+ - \b vparam : Handle to an identity cast as a void pointer.\r
+ */\r
+#define KMSG_IDENT_VALIDATE_IDENTITY 4\r
+\r
+/*! \brief Canonicalize identity name\r
+\r
+ The identity provider will be given a name, which it should put in\r
+ canonical form, adjusting case and any character replacement or\r
+ doing any relevant expansions if applicable, and place it in the\r
+ supplied buffer.\r
+\r
+ Message parameters:\r
+\r
+ - \b vparam : Pointer to a ::kcdb_ident_name_xfer structure\r
+ which provides the identity name to canonicalize in the \a\r
+ name_src member, and the buffer to store the canonical name\r
+ in the \a name_dest member. The \a name_dest buffer is\r
+ guaranteed to be at least KCDB_IDENT_MAXCCH_NAME characters\r
+ in size.\r
+\r
+ If the name cannot be canonicalized for some reason, the\r
+ destination buffer should be set to a zero-length string and the\r
+ \a result member of the ::kcdb_ident_name_xfer structure should be\r
+ set to the error code. If the destination buffer is set to a\r
+ zero-length string and \a result is KHM_ERROR_SUCCESS, then the\r
+ original name provided in \a name_src is assumed to be already in\r
+ canonical form.\r
+ */\r
+#define KMSG_IDENT_CANON_NAME 5\r
+\r
+/*! \brief Compare names\r
+\r
+ Compare two identity names. The names that are given aren't\r
+ guaranteed to be in canonical form. The return value should be\r
+ akin to strcmp().\r
+\r
+ Message parameters: \r
+\r
+ - \b vparam : A pointer to a ::kcdb_ident_name_xfer structure.\r
+ The \a name_src member points at the first name, and the \a\r
+ name_alt member specifies the second name. The result of the\r
+ comparison should be place in \a result.\r
+ */\r
+#define KMSG_IDENT_COMPARE_NAME 6\r
+\r
+/*! \brief Set the default identity\r
+\r
+ Set or unset the default identity. To set the default identity,\r
+ the \a uparam parameter will be set to a non-zero value and a\r
+ handle to the identity will be specified in \a vparam. To unset\r
+ the default identity (i.e. not have a default identity), a zero\r
+ value will be specified in \a uparam and no identities will be\r
+ specified in \a vparam.\r
+\r
+ When setting a default identity, the identity provider will\r
+ receive this message prior to the ::KCDB_IDENT_FLAG_DEFAULT bit\r
+ being set or reset on any identity. It should return\r
+ KHM_ERROR_SUCCESS if the requested operation can be performed.\r
+ Returning any other value will abort the operation and will leave\r
+ the default identity unchanged.\r
+\r
+ When resetting the default identity, this message should be\r
+ treated only as a notification.\r
+\r
+ Message parameters:\r
+\r
+ - \a uparam : Is non-zero if an identity is being made default. If\r
+ this is zero, then identity should be the default.\r
+\r
+ - \a vparam : A handle to the identity to be made default if \a\r
+ uparam is non-zero. NULL otherwise.\r
+\r
+ Return value:\r
+\r
+ - KHM_ERROR_SUCCESS : The identity should be marked as default\r
+ - Any other value : The identity should not be marked as default\r
+\r
+ */\r
+#define KMSG_IDENT_SET_DEFAULT 7\r
+\r
+/*! \brief Set an identity as searchable\r
+\r
+ Set or reset the searchable bit on an identity. If the \a uparam\r
+ parameter is non-zero, then the searchable bit is being set.\r
+ Otherwise it is being reset. The identity provider should return\r
+ KHM_ERROR_SUCCESS in order to indicate that the identity should be\r
+ marked as searchable. Any other value will result in the\r
+ searchable bit being reset on the identity.\r
+\r
+ Message parameters:\r
+\r
+ - \a uparam : Is non-zero if the searchable bit is being set. Zero\r
+ otherwise.\r
+\r
+ - \a vparam : Handle to the identity\r
+\r
+ Return value:\r
+\r
+ - KHM_ERROR_SUCCESS: The identity should be marked as searchable\r
+ - Any other value : The identity should not be marked as default\r
+ */\r
+#define KMSG_IDENT_SET_SEARCHABLE 8\r
+\r
+/*! \brief Get information about an identity\r
+\r
+ */\r
+#define KMSG_IDENT_GET_INFO 9\r
+\r
+/*! \brief Enumerate known and accessible identities\r
+ */\r
+#define KMSG_IDENT_ENUM_KNOWN 10\r
+\r
+/*! \brief Update information about an identity\r
+ */\r
+#define KMSG_IDENT_UPDATE 11\r
+\r
+/*! \brief Retrieve the user interface callback function\r
+\r
+ When obtaining new credentials, the user interface needs to obtain\r
+ a callback function which will provide identity selection\r
+ controls.\r
+\r
+ Message parameters:\r
+\r
+ - \a uparam : Not used\r
+\r
+ - \a vparam : pointer to a ::khui_ident_new_creds_cb which will\r
+ receive the call back.\r
+ */\r
+#define KMSG_IDENT_GET_UI_CALLBACK 12\r
+\r
+/*! \brief Notification of the creation of an identity\r
+\r
+ This should be considered just a notification. The identit\r
+ provider does not have an opportunity to veto the creation of an\r
+ identity whose name has been found to be valid. However, when\r
+ handing this notification, the identity provider can:\r
+\r
+ - Change the flags of the identity and/or marking the identity as\r
+ invalid.\r
+\r
+ - Change the default identity.\r
+\r
+ Note that this notification is sent before the general :;KMSG_KCDB\r
+ notification of the identity creation is sent.\r
+\r
+ Message parameters:\r
+\r
+ - \a uparam : Not used.\r
+\r
+ - \p vparam : handle to the identity\r
+ */\r
+#define KMSG_IDENT_NOTIFY_CREATE 13\r
+\r
+/*@}*/ /* /KMSG_IDENT subtypes */\r
+\r
+/*@}*/ /* / message types */\r
+/*@}*/ /* / kmq */\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Not exported */\r
+#ifndef __KHIMAIRA_KTHREAD_H\r
+#define __KHIMAIRA_KTHREAD_H\r
+\r
+#ifdef _WIN32\r
+#define khm_mutex CRITICAL_SECTION\r
+\r
+#define khp_mutex_init(pcs) InitializeCriticalSection(pcs)\r
+#define khp_mutex_destroy(pcs) DeleteCriticalSection(pcs)\r
+#define khp_mutex_lock(pcs) EnterCriticalSection(pcs)\r
+#define khp_mutex_unlock(pcs) LeaveCriticalSection(pcs)\r
+#define khp_mutex_trylock(pcs) (!TryEnterCriticalSection(pcs))\r
+\r
+#endif\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=kconfig\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\kconfig.h\r
+\r
+OBJFILES= \\r
+ $(OBJ)\kconfigmain.obj \\r
+ $(OBJ)\api.obj\r
+\r
+all: mkdirs $(INCFILES) $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
+\r
+# Tests\r
+\r
+test:: util_test\r
+\r
+util_test: $(OBJ)\utiltest.exe\r
+ $(OBJ)\utiltest.exe\r
+\r
+$(OBJ)\utiltest.exe: $(OBJ)\utiltest.obj\r
+ $(EXECONLINK) $(OBJFILES)\r
+\r
+$(OBJ)\utiltest.obj: test\utiltest.c\r
+ $(C2OBJ)\r
--- /dev/null
+/*\r
+* Copyright (c) 2004 Massachusetts Institute of Technology\r
+*\r
+* Permission is hereby granted, free of charge, to any person\r
+* obtaining a copy of this software and associated documentation\r
+* files (the "Software"), to deal in the Software without\r
+* restriction, including without limitation the rights to use, copy,\r
+* modify, merge, publish, distribute, sublicense, and/or sell copies\r
+* of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be\r
+* included in all copies or substantial portions of the Software.\r
+*\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+* SOFTWARE.\r
+*/\r
+\r
+/* $Id$ */\r
+\r
+#include<kconfiginternal.h>\r
+#include<assert.h>\r
+\r
+kconf_conf_space * conf_root = NULL;\r
+kconf_handle * conf_handles = NULL;\r
+kconf_handle * conf_free_handles = NULL;\r
+\r
+CRITICAL_SECTION cs_conf_global;\r
+CRITICAL_SECTION cs_conf_handle;\r
+LONG conf_init = 0;\r
+LONG conf_status = 0;\r
+\r
+void init_kconf(void) {\r
+ if(InterlockedIncrement(&conf_init) == 1L) {\r
+ /* we are the first */\r
+ InitializeCriticalSection(&cs_conf_global);\r
+ EnterCriticalSection(&cs_conf_global);\r
+ conf_root = khc_create_empty_space();\r
+ conf_root->name = wcsdup(L"Root");\r
+ conf_root->regpath = wcsdup(CONFIG_REGPATHW);\r
+ conf_root->refcount++;\r
+ conf_status = 1;\r
+ InitializeCriticalSection(&cs_conf_handle);\r
+ LeaveCriticalSection(&cs_conf_global);\r
+ }\r
+ /* else assume we are already initialized */\r
+}\r
+\r
+void exit_kconf(void) {\r
+ if(khc_is_config_running()) {\r
+ kconf_handle * h;\r
+\r
+ EnterCriticalSection(&cs_conf_global);\r
+\r
+ conf_init = 0;\r
+ conf_status = 0;\r
+\r
+ khc_free_space(conf_root);\r
+\r
+ EnterCriticalSection(&cs_conf_handle);\r
+ while(conf_free_handles) {\r
+ LPOP(&conf_free_handles, &h);\r
+ if(h) {\r
+ free(h);\r
+ }\r
+ }\r
+\r
+ while(conf_handles) {\r
+ LPOP(&conf_handles, &h);\r
+ if(h) {\r
+ free(h);\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_conf_handle);\r
+ DeleteCriticalSection(&cs_conf_handle);\r
+\r
+ LeaveCriticalSection(&cs_conf_global);\r
+ DeleteCriticalSection(&cs_conf_global);\r
+ }\r
+}\r
+\r
+kconf_handle * khc_handle_from_space(kconf_conf_space * s, khm_int32 flags)\r
+{\r
+ kconf_handle * h;\r
+\r
+ EnterCriticalSection(&cs_conf_handle);\r
+ LPOP(&conf_free_handles, &h);\r
+ if(!h) {\r
+ h = malloc(sizeof(kconf_handle));\r
+ assert(h != NULL);\r
+ }\r
+ ZeroMemory((void *) h, sizeof(kconf_handle));\r
+\r
+ h->magic = KCONF_HANDLE_MAGIC;\r
+ khc_space_hold(s);\r
+ h->space = s;\r
+ h->flags = flags;\r
+\r
+ LPUSH(&conf_handles, h);\r
+ LeaveCriticalSection(&cs_conf_handle);\r
+\r
+ return h;\r
+}\r
+\r
+/* must be called with cs_conf_global held */\r
+void khc_handle_free(kconf_handle * h)\r
+{\r
+ kconf_handle * lower;\r
+\r
+ EnterCriticalSection(&cs_conf_handle);\r
+#ifdef DEBUG\r
+ /* check if the handle is actually in use */\r
+ {\r
+ kconf_handle * a;\r
+ a = conf_handles;\r
+ while(a) {\r
+ if(h == a)\r
+ break;\r
+ a = LNEXT(a);\r
+ }\r
+\r
+ if(a == NULL) {\r
+ DebugBreak();\r
+ }\r
+ }\r
+#endif\r
+ while(h) {\r
+ LDELETE(&conf_handles, h);\r
+ if(h->space) {\r
+ khc_space_release(h->space);\r
+ h->space = NULL;\r
+ }\r
+ lower = h->lower;\r
+ LPUSH(&conf_free_handles, h);\r
+ h = lower;\r
+ }\r
+ LeaveCriticalSection(&cs_conf_handle);\r
+}\r
+\r
+kconf_handle * khc_handle_dup(kconf_handle * o)\r
+{\r
+ kconf_handle * h;\r
+ kconf_handle * r;\r
+\r
+ r = khc_handle_from_space(o->space, o->flags);\r
+ h = r;\r
+\r
+ while(o->lower) {\r
+ h->lower = khc_handle_from_space(o->lower->space, o->lower->flags);\r
+\r
+ o = o->lower;\r
+ h = h->lower;\r
+ }\r
+\r
+ return r;\r
+}\r
+\r
+void khc_space_hold(kconf_conf_space * s) {\r
+ InterlockedIncrement(&(s->refcount));\r
+}\r
+\r
+void khc_space_release(kconf_conf_space * s) {\r
+ LONG l = InterlockedDecrement(&(s->refcount));\r
+ if(!l) {\r
+ EnterCriticalSection(&cs_conf_global);\r
+\r
+ if(s->regkey_machine)\r
+ RegCloseKey(s->regkey_machine);\r
+ if(s->regkey_user)\r
+ RegCloseKey(s->regkey_user);\r
+ s->regkey_machine = NULL;\r
+ s->regkey_user = NULL;\r
+\r
+ LeaveCriticalSection(&cs_conf_global);\r
+ }\r
+}\r
+\r
+/* case sensitive replacement for RegOpenKeyEx */\r
+LONG \r
+khcint_RegOpenKeyEx(HKEY hkey, LPCWSTR sSubKey, DWORD ulOptions,\r
+ REGSAM samDesired, PHKEY phkResult) {\r
+ int i;\r
+ wchar_t sk_name[KCONF_MAXCCH_NAME];\r
+ FILETIME ft;\r
+ size_t cch;\r
+ HKEY hkp;\r
+ const wchar_t * t;\r
+ LONG rv = ERROR_SUCCESS;\r
+\r
+ hkp = hkey;\r
+\r
+ /* descend down the components of the subkey */\r
+ t = sSubKey;\r
+ while(TRUE) {\r
+ wchar_t * slash;\r
+ HKEY hkt;\r
+\r
+ slash = wcschr(t, L'\\');\r
+ if (slash == NULL)\r
+ break;\r
+\r
+ if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name),\r
+ t, slash - t))) {\r
+ rv = ERROR_CANTOPEN;\r
+ goto _cleanup;\r
+ }\r
+\r
+ sk_name[slash - t] = L'\0';\r
+ t = slash+1;\r
+\r
+ if (khcint_RegOpenKeyEx(hkp, sk_name, ulOptions, samDesired, &hkt) ==\r
+ ERROR_SUCCESS) {\r
+\r
+ if (hkp != hkey)\r
+ RegCloseKey(hkp);\r
+ hkp = hkt;\r
+\r
+ } else {\r
+\r
+ rv = ERROR_CANTOPEN;\r
+ goto _cleanup;\r
+\r
+ }\r
+ }\r
+\r
+ /* by now hkp is a handle to the parent of the last component in\r
+ the subkey. t is a pointer to the last component. */\r
+\r
+ if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) {\r
+ rv = ERROR_CANTOPEN;\r
+ goto _cleanup;\r
+ }\r
+\r
+ /* go through and find the case sensitive match for the key */\r
+\r
+ for (i=0; ;i++) {\r
+ LONG l;\r
+ DWORD dw;\r
+\r
+ dw = ARRAYLENGTH(sk_name);\r
+ l = RegEnumKeyEx(hkp, i, sk_name, &dw,\r
+ NULL, NULL, NULL, &ft);\r
+\r
+ if (l != ERROR_SUCCESS) {\r
+ rv = ERROR_CANTOPEN;\r
+ goto _cleanup;\r
+ }\r
+\r
+ if (!(wcsncmp(sk_name, t, cch))) {\r
+ /* bingo! ?? */\r
+ if (cch < KCONF_MAXCCH_NAME &&\r
+ (sk_name[cch] == L'\0' ||\r
+ sk_name[cch] == L'~')) {\r
+ rv = RegOpenKeyEx(hkp, sk_name, ulOptions,\r
+ samDesired, phkResult);\r
+ goto _cleanup;\r
+ }\r
+ }\r
+ }\r
+\r
+ _cleanup:\r
+ if (hkp != hkey && hkp != NULL)\r
+ RegCloseKey(hkp);\r
+\r
+ return rv;\r
+}\r
+\r
+LONG\r
+khcint_RegCreateKeyEx(HKEY hKey,\r
+ LPCTSTR lpSubKey,\r
+ DWORD Reserved,\r
+ LPTSTR lpClass,\r
+ DWORD dwOptions,\r
+ REGSAM samDesired,\r
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,\r
+ PHKEY phkResult,\r
+ LPDWORD lpdwDisposition) {\r
+ LONG l;\r
+ int i;\r
+ long index = 0;\r
+ wchar_t sk_name[KCONF_MAXCCH_NAME]; /* hard limit in Windows */\r
+ FILETIME ft;\r
+ size_t cch;\r
+ const wchar_t * t;\r
+ LONG rv = ERROR_SUCCESS;\r
+ HKEY hkp = NULL;\r
+\r
+ hkp = hKey;\r
+ t = lpSubKey;\r
+ while(TRUE) {\r
+ wchar_t * slash;\r
+ HKEY hkt;\r
+\r
+ slash = wcschr(t, L'\\');\r
+ if (slash == NULL)\r
+ break;\r
+\r
+ if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name),\r
+ t, slash - t))) {\r
+ rv = ERROR_CANTOPEN;\r
+ goto _cleanup;\r
+ }\r
+\r
+ sk_name[slash - t] = L'\0';\r
+ t = slash+1;\r
+\r
+ if (khcint_RegOpenKeyEx(hkp, sk_name, 0, samDesired, &hkt) ==\r
+ ERROR_SUCCESS) {\r
+\r
+ if (hkp != hKey)\r
+ RegCloseKey(hkp);\r
+ hkp = hkt;\r
+\r
+ } else {\r
+\r
+ rv = RegCreateKeyEx(hKey,\r
+ lpSubKey,\r
+ Reserved,\r
+ lpClass,\r
+ dwOptions,\r
+ samDesired,\r
+ lpSecurityAttributes,\r
+ phkResult,\r
+ lpdwDisposition);\r
+ goto _cleanup;\r
+\r
+ }\r
+ }\r
+\r
+ if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) {\r
+ rv = ERROR_CANTOPEN;\r
+ goto _cleanup;\r
+ }\r
+\r
+ for (i=0; ;i++) {\r
+ DWORD dw;\r
+\r
+ dw = ARRAYLENGTH(sk_name);\r
+ l = RegEnumKeyEx(hkp, i, sk_name, &dw,\r
+ NULL, NULL, NULL, &ft);\r
+\r
+ if (l != ERROR_SUCCESS)\r
+ break;\r
+\r
+ if (!(wcsncmp(sk_name, t, cch))) {\r
+ /* bingo! ?? */\r
+ if (sk_name[cch] == L'\0' ||\r
+ sk_name[cch] == L'~') {\r
+ l = RegOpenKeyEx(hkp, sk_name, 0,\r
+ samDesired, phkResult);\r
+ if (l == ERROR_SUCCESS && lpdwDisposition)\r
+ *lpdwDisposition = REG_OPENED_EXISTING_KEY;\r
+ rv = l;\r
+ goto _cleanup;\r
+ }\r
+ }\r
+\r
+ if (!wcsnicmp(sk_name, t, cch) &&\r
+ (sk_name[cch] == L'\0' ||\r
+ sk_name[cch] == L'~')) {\r
+ long new_idx;\r
+\r
+ if (sk_name[cch] == L'\0')\r
+ new_idx = 1;\r
+ else if (cch + 1 < KCONF_MAXCCH_NAME)\r
+ new_idx = wcstol(sk_name + (cch + 1), NULL, 10);\r
+ else\r
+ return ERROR_BUFFER_OVERFLOW;\r
+\r
+ assert(new_idx > 0);\r
+\r
+ if (new_idx > index)\r
+ index = new_idx;\r
+ }\r
+ }\r
+\r
+ if (index != 0) {\r
+ if (FAILED(StringCbPrintf(sk_name, sizeof(sk_name),\r
+ L"%s~%d", t, index)))\r
+ return ERROR_BUFFER_OVERFLOW;\r
+ } else {\r
+ StringCbCopy(sk_name, sizeof(sk_name), t);\r
+ }\r
+\r
+ rv = RegCreateKeyEx(hkp,\r
+ sk_name,\r
+ Reserved,\r
+ lpClass,\r
+ dwOptions,\r
+ samDesired,\r
+ lpSecurityAttributes,\r
+ phkResult,\r
+ lpdwDisposition);\r
+\r
+ _cleanup:\r
+\r
+ if (hkp != hKey && hkp != NULL)\r
+ RegCloseKey(hkp);\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+HKEY khc_space_open_key(kconf_conf_space * s, khm_int32 flags) {\r
+ HKEY hk = NULL;\r
+ int nflags = 0;\r
+ DWORD disp;\r
+ if(flags & KCONF_FLAG_MACHINE) {\r
+ if(s->regkey_machine)\r
+ return s->regkey_machine;\r
+ if((khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, \r
+ KEY_READ | KEY_WRITE, &hk) != \r
+ ERROR_SUCCESS) && \r
+ !(flags & KHM_PERM_WRITE)) {\r
+\r
+ if(khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, \r
+ KEY_READ, &hk) == ERROR_SUCCESS) {\r
+ nflags = KHM_PERM_READ;\r
+ }\r
+\r
+ }\r
+ if(!hk && (flags & KHM_FLAG_CREATE)) {\r
+\r
+ khcint_RegCreateKeyEx(HKEY_LOCAL_MACHINE, \r
+ s->regpath, \r
+ 0,\r
+ NULL,\r
+ REG_OPTION_NON_VOLATILE,\r
+ KEY_READ | KEY_WRITE,\r
+ NULL,\r
+ &hk,\r
+ &disp);\r
+ }\r
+ if(hk) {\r
+ EnterCriticalSection(&cs_conf_global);\r
+ s->regkey_machine = hk;\r
+ s->regkey_machine_flags = nflags;\r
+ LeaveCriticalSection(&cs_conf_global);\r
+ }\r
+\r
+ return hk;\r
+ } else {\r
+ if(s->regkey_user)\r
+ return s->regkey_user;\r
+ if((khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, \r
+ KEY_READ | KEY_WRITE, &hk) != \r
+ ERROR_SUCCESS) && \r
+ !(flags & KHM_PERM_WRITE)) {\r
+ if(khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, \r
+ KEY_READ, &hk) == ERROR_SUCCESS) {\r
+ nflags = KHM_PERM_READ;\r
+ }\r
+ }\r
+ if(!hk && (flags & KHM_FLAG_CREATE)) {\r
+ khcint_RegCreateKeyEx(HKEY_CURRENT_USER, \r
+ s->regpath, \r
+ 0,\r
+ NULL,\r
+ REG_OPTION_NON_VOLATILE,\r
+ KEY_READ | KEY_WRITE,\r
+ NULL,\r
+ &hk,\r
+ &disp);\r
+ }\r
+ if(hk) {\r
+ EnterCriticalSection(&cs_conf_global);\r
+ s->regkey_user = hk;\r
+ s->regkey_user_flags = nflags;\r
+ LeaveCriticalSection(&cs_conf_global);\r
+ }\r
+\r
+ return hk;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_shadow_space(khm_handle upper, khm_handle lower)\r
+{\r
+ kconf_handle * h;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!khc_is_handle(upper))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ h = (kconf_handle *) upper;\r
+\r
+ EnterCriticalSection(&cs_conf_handle);\r
+ if(h->lower) {\r
+ LeaveCriticalSection(&cs_conf_handle);\r
+ EnterCriticalSection(&cs_conf_global);\r
+ khc_handle_free(h->lower);\r
+ LeaveCriticalSection(&cs_conf_global);\r
+ EnterCriticalSection(&cs_conf_handle);\r
+ h->lower = NULL;\r
+ }\r
+\r
+ if(khc_is_handle(lower)) {\r
+ kconf_handle * l;\r
+ kconf_handle * lc;\r
+\r
+ l = (kconf_handle *) lower;\r
+ LeaveCriticalSection(&cs_conf_handle);\r
+ lc = khc_handle_dup(l);\r
+ EnterCriticalSection(&cs_conf_handle);\r
+ h->lower = lc;\r
+ }\r
+ LeaveCriticalSection(&cs_conf_handle);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+kconf_conf_space * khc_create_empty_space(void) {\r
+ kconf_conf_space * r;\r
+\r
+ r = malloc(sizeof(kconf_conf_space));\r
+ assert(r != NULL);\r
+ ZeroMemory(r,sizeof(kconf_conf_space));\r
+\r
+ return r;\r
+}\r
+\r
+void khc_free_space(kconf_conf_space * r) {\r
+ kconf_conf_space * c;\r
+\r
+ if(!r)\r
+ return;\r
+\r
+ LPOP(&r->children, &c);\r
+ while(c) {\r
+ khc_free_space(c);\r
+ LPOP(&r->children, &c);\r
+ }\r
+\r
+ if(r->name)\r
+ free(r->name);\r
+\r
+ if(r->regpath)\r
+ free(r->regpath);\r
+\r
+ if(r->regkey_machine)\r
+ RegCloseKey(r->regkey_machine);\r
+\r
+ if(r->regkey_user)\r
+ RegCloseKey(r->regkey_user);\r
+\r
+ free(r);\r
+}\r
+\r
+khm_int32 khcint_open_space_int(kconf_conf_space * parent, wchar_t * sname, size_t n_sname, khm_int32 flags, kconf_conf_space **result) {\r
+ kconf_conf_space * p;\r
+ kconf_conf_space * c;\r
+ HKEY pkey = NULL;\r
+ HKEY ckey = NULL;\r
+ wchar_t buf[KCONF_MAXCCH_NAME];\r
+\r
+ if(!parent)\r
+ p = conf_root;\r
+ else\r
+ p = parent;\r
+\r
+ if(n_sname >= KCONF_MAXCCH_NAME || n_sname <= 0)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ /*SAFE: buf: buffer size == KCONF_MAXCCH_NAME * wchar_t >\r
+ n_sname * wchar_t */\r
+ wcsncpy(buf, sname, n_sname);\r
+ buf[n_sname] = L'\0';\r
+\r
+ /* see if there is already a config space by this name. if so,\r
+ return it. Note that if the configuration space is specified in a\r
+ schema, we would find it here. */\r
+ EnterCriticalSection(&cs_conf_global);\r
+ c = TFIRSTCHILD(p);\r
+ while(c) {\r
+ if(c->name && !wcscmp(c->name, buf))\r
+ break;\r
+\r
+ c = LNEXT(c);\r
+ }\r
+ LeaveCriticalSection(&cs_conf_global);\r
+\r
+ if(c) {\r
+ khc_space_hold(c);\r
+ *result = c;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ if(!(flags & KHM_FLAG_CREATE)) {\r
+\r
+ /* we are not creating the space, so it must exist in the form of a\r
+ registry key in HKLM or HKCU. If it existed as a schema, we\r
+ would have already retured it above. */\r
+ if(flags & KCONF_FLAG_USER)\r
+ pkey = khc_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_USER);\r
+\r
+ if((!pkey || \r
+ (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != \r
+ ERROR_SUCCESS)) \r
+ && (flags & KCONF_FLAG_MACHINE)) {\r
+\r
+ pkey = khc_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+ if(!pkey || \r
+ (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != \r
+ ERROR_SUCCESS)) {\r
+ *result = NULL;\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ if(ckey) {\r
+ RegCloseKey(ckey);\r
+ ckey = NULL;\r
+ }\r
+ }\r
+\r
+ c = khc_create_empty_space();\r
+ \r
+ /*SAFE: buf: is of known length < KCONF_MAXCCH_NAME */\r
+ c->name = wcsdup(buf);\r
+\r
+ /*SAFE: p->regpath: is valid since it was set using this same\r
+ function. */\r
+ /*SAFE: buf: see above */\r
+ c->regpath = malloc((wcslen(p->regpath) + wcslen(buf) + 2) * sizeof(wchar_t));\r
+\r
+ assert(c->regpath != NULL);\r
+\r
+#pragma warning( push )\r
+#pragma warning( disable: 4995 )\r
+ /*SAFE: c->regpath: allocated above to be big enough */\r
+ /*SAFE: p->regpath: see above */\r
+ wcscpy(c->regpath, p->regpath);\r
+ wcscat(c->regpath, L"\\");\r
+ /*SAFE: buf: see above */\r
+ wcscat(c->regpath, buf);\r
+#pragma warning( pop )\r
+\r
+ khc_space_hold(c);\r
+\r
+ EnterCriticalSection(&cs_conf_global);\r
+ TADDCHILD(p,c);\r
+ LeaveCriticalSection(&cs_conf_global);\r
+\r
+ *result = c;\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, khm_handle * result) {\r
+ kconf_handle * h;\r
+ kconf_conf_space * p;\r
+ kconf_conf_space * c = NULL;\r
+ size_t cbsize;\r
+ wchar_t * str;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running()) {\r
+ return KHM_ERROR_NOT_READY;\r
+ }\r
+\r
+ if(!result || (parent && !khc_is_handle(parent)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(!parent)\r
+ p = conf_root;\r
+ else {\r
+ h = (kconf_handle *) parent;\r
+ p = khc_space_from_handle(parent);\r
+ }\r
+\r
+ khc_space_hold(p);\r
+\r
+ /* if none of these flags are specified, make it seem like all of\r
+ them were */\r
+ if(!(flags & KCONF_FLAG_USER) &&\r
+ !(flags & KCONF_FLAG_MACHINE) &&\r
+ !(flags & KCONF_FLAG_SCHEMA))\r
+ flags |= KCONF_FLAG_USER | KCONF_FLAG_MACHINE | KCONF_FLAG_SCHEMA;\r
+\r
+ if(cspace == NULL) {\r
+ khc_space_release(p);\r
+ *result = (khm_handle) khc_handle_from_space(p, flags);\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ if(FAILED(StringCbLength(cspace, KCONF_MAXCB_PATH, &cbsize))) {\r
+ khc_space_release(p);\r
+ *result = NULL;\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ str = cspace;\r
+ while(TRUE) {\r
+ wchar_t * end = NULL;\r
+\r
+ if (!(flags & KCONF_FLAG_NOPARSENAME)) {\r
+\r
+ end = wcschr(str, L'\\'); /* safe because cspace was\r
+ validated above */\r
+#if 0\r
+ if(!end)\r
+ end = wcschr(str, L'/'); /* safe because cspace was\r
+ validated above */\r
+#endif\r
+ }\r
+\r
+ if(!end) {\r
+ if(flags & KCONF_FLAG_TRAILINGVALUE) {\r
+ /* we are at the value component */\r
+ c = p;\r
+ khc_space_hold(c);\r
+ break;\r
+ } else\r
+ end = str + wcslen(str); /* safe because cspace was\r
+ validated above */\r
+ }\r
+\r
+ rv = khcint_open_space_int(p, str, end - str, flags, &c);\r
+\r
+ if(KHM_SUCCEEDED(rv) && (*end == L'\\'\r
+#if 0\r
+ || *end == L'/'\r
+#endif\r
+ )) {\r
+ khc_space_release(p);\r
+ p = c;\r
+ c = NULL;\r
+ str = end+1;\r
+ }\r
+ else\r
+ break;\r
+ }\r
+\r
+ khc_space_release(p);\r
+ if(KHM_SUCCEEDED(rv)) {\r
+ *result = khc_handle_from_space(c, flags);\r
+ } else\r
+ *result = NULL;\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_close_space(khm_handle csp) {\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!khc_is_handle(csp))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ khc_handle_free((kconf_handle *) csp);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_read_string(khm_handle pconf, \r
+ wchar_t * pvalue, \r
+ wchar_t * buf, \r
+ khm_size * bufsize) \r
+{\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ do {\r
+ HKEY hku = NULL;\r
+ HKEY hkm = NULL;\r
+ wchar_t * value = NULL;\r
+ int free_space = 0;\r
+ khm_handle conf = NULL;\r
+ DWORD size;\r
+ DWORD type;\r
+ LONG hr;\r
+\r
+ int i;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ goto _shadow;\r
+\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, * forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward; /* works for nulls too */\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf))\r
+ goto _shadow;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(khc_is_user_handle(conf))\r
+ hku = khc_space_open_key(c, KHM_PERM_READ);\r
+\r
+ if(khc_is_machine_handle(conf))\r
+ hkm = khc_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+\r
+ size = (DWORD) *bufsize;\r
+ if(hku) {\r
+ hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_SZ) {\r
+ rv = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ *bufsize = size;\r
+ /* if buf==NULL, RegQueryValueEx will return success and just return the\r
+ required buffer size in 'size' */\r
+ rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+ } else {\r
+ if(hr == ERROR_MORE_DATA) {\r
+ *bufsize = size;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ size = (DWORD) *bufsize;\r
+ if(hkm) {\r
+ hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_SZ) {\r
+ rv = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ *bufsize = size;\r
+ rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+ } else {\r
+ if(hr == ERROR_MORE_DATA) {\r
+ *bufsize = size;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ if(c->schema && khc_is_schema_handle(conf)) {\r
+ for(i=0;i<c->nSchema;i++) {\r
+ if(c->schema[i].type == KC_STRING && !wcscmp(value, c->schema[i].name)) {\r
+ /* found it */\r
+ size_t cbsize = 0;\r
+\r
+ if(!c->schema[i].value) {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ goto _exit;\r
+ }\r
+\r
+ if(FAILED(StringCbLength((wchar_t *) c->schema[i].value, KCONF_MAXCB_STRING, &cbsize))) {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ goto _exit;\r
+ }\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buf || *bufsize < cbsize) {\r
+ *bufsize = cbsize;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+\r
+ StringCbCopy(buf, *bufsize, (wchar_t *) c->schema[i].value);\r
+ *bufsize = cbsize;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+_shadow:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+\r
+ if(khc_is_shadowed(pconf)) {\r
+ pconf = khc_shadow(pconf);\r
+ continue;\r
+ } else {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ break;\r
+ }\r
+\r
+_exit:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+ break;\r
+\r
+ } while(TRUE);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_read_int32(khm_handle pconf, wchar_t * pvalue, khm_int32 * buf) {\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!buf || !pvalue)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ do {\r
+ DWORD size;\r
+ DWORD type;\r
+ LONG hr;\r
+ HKEY hku = NULL;\r
+ HKEY hkm = NULL;\r
+\r
+ wchar_t * value = NULL;\r
+ int free_space = 0;\r
+ khm_handle conf = NULL;\r
+\r
+ int i;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ goto _shadow;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, * forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf) || !buf)\r
+ goto _shadow;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(khc_is_user_handle(conf))\r
+ hku = khc_space_open_key(c, KHM_PERM_READ);\r
+\r
+ if(khc_is_machine_handle(conf))\r
+ hkm = khc_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+\r
+ size = sizeof(DWORD);\r
+ if(hku) {\r
+ hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_DWORD) {\r
+ rv = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ size = sizeof(DWORD);\r
+ if(hkm) {\r
+ hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_DWORD) {\r
+ rv= KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ rv= KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ if(c->schema && khc_is_schema_handle(conf)) {\r
+ for(i=0;i<c->nSchema;i++) {\r
+ if(c->schema[i].type == KC_INT32 && !wcscmp(value, c->schema[i].name)) {\r
+ *buf = (khm_int32) c->schema[i].value;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+_shadow:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+\r
+ if(khc_is_shadowed(pconf)) {\r
+ pconf = khc_shadow(pconf);\r
+ continue;\r
+ } else {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ break;\r
+ }\r
+_exit:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+ break;\r
+ }\r
+ while(TRUE);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_read_int64(khm_handle pconf, wchar_t * pvalue, khm_int64 * buf) {\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ do {\r
+ DWORD size;\r
+ DWORD type;\r
+ LONG hr;\r
+ HKEY hku = NULL;\r
+ HKEY hkm = NULL;\r
+\r
+ wchar_t * value = NULL;\r
+ int free_space = 0;\r
+ khm_handle conf = NULL;\r
+\r
+ int i;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ goto _shadow;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, *forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf) || !buf)\r
+ goto _shadow;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(khc_is_user_handle(conf))\r
+ hku = khc_space_open_key(c, KHM_PERM_READ);\r
+\r
+ if(khc_is_machine_handle(conf))\r
+ hkm = khc_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+\r
+ size = sizeof(khm_int64);\r
+ if(hku) {\r
+ hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_QWORD) {\r
+ rv= KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ size = sizeof(khm_int64);\r
+ if(hkm) {\r
+ hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_QWORD) {\r
+ rv = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ if(c->schema && khc_is_schema_handle(conf)) {\r
+ for(i=0;i<c->nSchema;i++) {\r
+ if(c->schema[i].type == KC_INT64 && !wcscmp(value, c->schema[i].name)) {\r
+ *buf = (khm_int64) c->schema[i].value;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+_shadow:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+ if(khc_is_shadowed(pconf)) {\r
+ pconf = khc_shadow(pconf);\r
+ continue;\r
+ } else {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ break;\r
+ }\r
+\r
+_exit:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+ break;\r
+\r
+ } while(TRUE);\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_read_binary(khm_handle pconf, wchar_t * pvalue, void * buf, khm_size * bufsize) {\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ do {\r
+ DWORD size;\r
+ DWORD type;\r
+ LONG hr;\r
+ HKEY hku = NULL;\r
+ HKEY hkm = NULL;\r
+\r
+ wchar_t * value = NULL;\r
+ int free_space = 0;\r
+ khm_handle conf = NULL;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ goto _shadow;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, *forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf))\r
+ goto _shadow;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(khc_is_user_handle(conf))\r
+ hku = khc_space_open_key(c, KHM_PERM_READ);\r
+\r
+ if(khc_is_machine_handle(conf))\r
+ hkm = khc_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+\r
+ size = (DWORD) *bufsize;\r
+ if(hku) {\r
+ hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_BINARY) {\r
+ rv = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ *bufsize = size;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ } else {\r
+ if(hr == ERROR_MORE_DATA) {\r
+ *bufsize = size;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ size = (DWORD) *bufsize;\r
+ if(hkm) {\r
+ hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);\r
+ if(hr == ERROR_SUCCESS) {\r
+ if(type != REG_BINARY) {\r
+ rv = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+ else {\r
+ *bufsize = size;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+ } else {\r
+ if(hr == ERROR_MORE_DATA) {\r
+ *bufsize = size;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* binary values aren't supported in schema */\r
+_shadow:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+ if(khc_is_shadowed(pconf)) {\r
+ pconf = khc_shadow(pconf);\r
+ continue;\r
+ } else {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ break;\r
+ }\r
+\r
+_exit:\r
+ if(free_space && conf)\r
+ khc_close_space(conf);\r
+ break;\r
+\r
+ }while (TRUE);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_write_string(\r
+ khm_handle pconf, \r
+ wchar_t * pvalue, \r
+ wchar_t * buf) \r
+{\r
+ HKEY pk = NULL;\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ LONG hr;\r
+ size_t cbsize;\r
+ wchar_t * value = NULL;\r
+ int free_space;\r
+ khm_handle conf = NULL;\r
+\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, *forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf) || !buf) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(FAILED(StringCbLength(buf, KCONF_MAXCB_STRING, &cbsize))) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(khc_is_user_handle(conf)) {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);\r
+ } else {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);\r
+ }\r
+\r
+ hr = RegSetValueEx(pk, value, 0, REG_SZ, (LPBYTE) buf, (DWORD) cbsize);\r
+\r
+ if(hr != ERROR_SUCCESS)\r
+ rv = KHM_ERROR_INVALID_OPERATION;\r
+\r
+_exit:\r
+ if(free_space)\r
+ khc_close_space(conf);\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_write_int32(\r
+ khm_handle pconf, \r
+ wchar_t * pvalue, \r
+ khm_int32 buf) \r
+{\r
+ HKEY pk = NULL;\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ LONG hr;\r
+ wchar_t * value = NULL;\r
+ int free_space;\r
+ khm_handle conf = NULL;\r
+\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, *forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ c = khc_space_from_handle( conf);\r
+\r
+ if(khc_is_user_handle(conf)) {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);\r
+ } else {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);\r
+ }\r
+\r
+ hr = RegSetValueEx(pk, value, 0, REG_DWORD, (LPBYTE) &buf, sizeof(khm_int32));\r
+\r
+ if(hr != ERROR_SUCCESS)\r
+ rv = KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(free_space)\r
+ khc_close_space(conf);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_write_int64(khm_handle pconf, wchar_t * pvalue, khm_int64 buf) {\r
+ HKEY pk = NULL;\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ LONG hr;\r
+ wchar_t * value = NULL;\r
+ int free_space;\r
+ khm_handle conf = NULL;\r
+\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, *forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ c = khc_space_from_handle( conf);\r
+\r
+ if(khc_is_user_handle(conf)) {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);\r
+ } else {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);\r
+ }\r
+\r
+ hr = RegSetValueEx(pk, value, 0, REG_QWORD, (LPBYTE) &buf, sizeof(khm_int64));\r
+\r
+ if(hr != ERROR_SUCCESS)\r
+ rv = KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(free_space)\r
+ khc_close_space(conf);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_write_binary(khm_handle pconf, wchar_t * pvalue, void * buf, khm_size bufsize) {\r
+ HKEY pk = NULL;\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ LONG hr;\r
+ wchar_t * value = NULL;\r
+ int free_space;\r
+ khm_handle conf = NULL;\r
+\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(wcschr(pvalue, L'\\')\r
+#if 0\r
+ || wcschr(pvalue, L'/')\r
+#endif\r
+ ) {\r
+ if(KHM_FAILED(khc_open_space(\r
+ pconf, \r
+ pvalue, \r
+ KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), \r
+ &conf)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ free_space = 1;\r
+#if 0\r
+ wchar_t * back, *forward;\r
+\r
+ back = wcsrchr(pvalue, L'\\');\r
+ forward = wcsrchr(pvalue, L'/');\r
+ value = (back > forward)?back:forward;\r
+#else\r
+ value = wcsrchr(pvalue, L'\\');\r
+#endif\r
+ } else {\r
+ value = pvalue;\r
+ conf = pconf;\r
+ free_space = 0;\r
+ }\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(khc_is_user_handle(conf)) {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);\r
+ } else {\r
+ pk = khc_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);\r
+ }\r
+\r
+ hr = RegSetValueEx(pk, value, 0, REG_BINARY, buf, (DWORD) bufsize);\r
+\r
+ if(hr != ERROR_SUCCESS)\r
+ rv = KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(free_space)\r
+ khc_close_space(conf);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_get_config_space_name(khm_handle conf, wchar_t * buf, khm_size * bufsize) {\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(!c->name) {\r
+ if(buf && *bufsize > 0)\r
+ buf[0] = L'\0';\r
+ else {\r
+ *bufsize = sizeof(wchar_t);\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ }\r
+ } else {\r
+ size_t cbsize;\r
+\r
+ if(FAILED(StringCbLength(c->name, KCONF_MAXCB_NAME, &cbsize)))\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buf || cbsize > *bufsize) {\r
+ *bufsize = cbsize;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else {\r
+ StringCbCopy(buf, *bufsize, c->name);\r
+ *bufsize = cbsize;\r
+ }\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_get_config_space_parent(khm_handle conf, khm_handle * parent) {\r
+ kconf_conf_space * c;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(c == conf_root || c->parent == conf_root)\r
+ *parent = NULL;\r
+ else\r
+ *parent = khc_handle_from_space(c->parent, khc_handle_flags(conf));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_get_type(khm_handle conf, wchar_t * value) {\r
+ HKEY hkm = NULL;\r
+ HKEY hku = NULL;\r
+ kconf_conf_space * c;\r
+ khm_int32 rv;\r
+ LONG hr;\r
+ DWORD type = 0;\r
+\r
+ if(!khc_is_config_running())\r
+ return KC_NONE;\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KC_NONE;\r
+\r
+ c = (kconf_conf_space *) conf;\r
+\r
+ if(!khc_is_machine_handle(conf))\r
+ hku = khc_space_open_key(c, KHM_PERM_READ);\r
+ hkm = khc_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+\r
+ if(hku)\r
+ hr = RegQueryValueEx(hku, value, NULL, &type, NULL, NULL);\r
+ if(!hku || hr != ERROR_SUCCESS)\r
+ hr = RegQueryValueEx(hkm, value, NULL, &type, NULL, NULL);\r
+ if(((!hku && !hkm) || hr != ERROR_SUCCESS) && c->schema) {\r
+ int i;\r
+\r
+ for(i=0; i<c->nSchema; i++) {\r
+ if(!wcscmp(c->schema[i].name, value)) {\r
+ return c->schema[i].type;\r
+ }\r
+ }\r
+\r
+ return KC_NONE;\r
+ }\r
+\r
+ switch(type) {\r
+ case REG_MULTI_SZ:\r
+ case REG_SZ:\r
+ rv = KC_STRING;\r
+ break;\r
+ case REG_DWORD:\r
+ rv = KC_INT32;\r
+ break;\r
+ case REG_QWORD:\r
+ rv = KC_INT64;\r
+ break;\r
+ case REG_BINARY:\r
+ rv = KC_BINARY;\r
+ break;\r
+ default:\r
+ rv = KC_NONE;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_value_exists(khm_handle conf, wchar_t * value) {\r
+ HKEY hku = NULL;\r
+ HKEY hkm = NULL;\r
+ kconf_conf_space * c;\r
+ khm_int32 rv = 0;\r
+ DWORD t;\r
+ int i;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ c = khc_space_from_handle(conf);\r
+\r
+ if(!khc_is_machine_handle(conf))\r
+ hku = khc_space_open_key(c, KHM_PERM_READ);\r
+ hkm = khc_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+\r
+ if(hku && (RegQueryValueEx(hku, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS))\r
+ rv |= KCONF_FLAG_USER;\r
+ if(hkm && (RegQueryValueEx(hkm, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS))\r
+ rv |= KCONF_FLAG_MACHINE;\r
+\r
+ if(c->schema) {\r
+ for(i=0; i<c->nSchema; i++) {\r
+ if(!wcscmp(c->schema[i].name, value)) {\r
+ rv |= KCONF_FLAG_SCHEMA;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+khm_boolean khc_is_valid_name(wchar_t * name)\r
+{\r
+ size_t cbsize;\r
+ if(FAILED(StringCbLength(name, KCONF_MAXCB_NAME, &cbsize)))\r
+ return FALSE;\r
+ return TRUE;\r
+}\r
+\r
+khm_int32 khc_validate_schema(kconf_schema * schema,\r
+ int begin,\r
+ int *end)\r
+{\r
+ int i;\r
+ int state = 0;\r
+ int end_found = 0;\r
+\r
+ i=begin;\r
+ while(!end_found) {\r
+ switch(state) {\r
+ case 0: /* initial. this record should start a config space */\r
+ if(!khc_is_valid_name(schema[i].name) ||\r
+ schema[i].type != KC_SPACE)\r
+ return KHM_ERROR_INVALID_PARM;\r
+ state = 1;\r
+ break;\r
+\r
+ case 1: /* we are inside a config space, in the values area */\r
+ if(!khc_is_valid_name(schema[i].name))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ if(schema[i].type == KC_SPACE) {\r
+ if(KHM_FAILED(khc_validate_schema(schema, i, &i)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ state = 2;\r
+ } else if(schema[i].type == KC_ENDSPACE) {\r
+ end_found = 1;\r
+ if(end)\r
+ *end = i;\r
+ } else {\r
+ if(schema[i].type != KC_STRING &&\r
+ schema[i].type != KC_INT32 &&\r
+ schema[i].type != KC_INT64 &&\r
+ schema[i].type != KC_BINARY)\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ break;\r
+\r
+ case 2: /* we are inside a config space, in the subspace area */\r
+ if(schema[i].type == KC_SPACE) {\r
+ if(KHM_FAILED(khc_validate_schema(schema, i, &i)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ } else if(schema[i].type == KC_ENDSPACE) {\r
+ end_found = 1;\r
+ if(end)\r
+ *end = i;\r
+ } else {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ /* unreachable */\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ i++;\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 khc_load_schema_i(khm_handle parent, kconf_schema * schema, int begin, int * end)\r
+{\r
+ int i;\r
+ int state = 0;\r
+ int end_found = 0;\r
+ kconf_conf_space * thisconf = NULL;\r
+ khm_handle h;\r
+\r
+ i=begin;\r
+ while(!end_found) {\r
+ switch(state) {\r
+ case 0: /* initial. this record should start a config space */\r
+ if(KHM_FAILED(khc_open_space(parent, schema[i].name, KHM_FLAG_CREATE, &h)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ thisconf = khc_space_from_handle(h);\r
+ thisconf->schema = schema + (begin + 1);\r
+ state = 1;\r
+ break;\r
+\r
+ case 1: /* we are inside a config space, in the values area */\r
+ if(schema[i].type == KC_SPACE) {\r
+ thisconf->nSchema = i - (begin + 1);\r
+ if(KHM_FAILED(khc_load_schema_i(h, schema, i, &i)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ state = 2;\r
+ } else if(schema[i].type == KC_ENDSPACE) {\r
+ thisconf->nSchema = i - (begin + 1);\r
+ end_found = 1;\r
+ if(end)\r
+ *end = i;\r
+ khc_close_space(h);\r
+ }\r
+ break;\r
+\r
+ case 2: /* we are inside a config space, in the subspace area */\r
+ if(schema[i].type == KC_SPACE) {\r
+ if(KHM_FAILED(khc_load_schema_i(h, schema, i, &i)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ } else if(schema[i].type == KC_ENDSPACE) {\r
+ end_found = 1;\r
+ if(end)\r
+ *end = i;\r
+ khc_close_space(h);\r
+ } else {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ /* unreachable */\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ i++;\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_load_schema(khm_handle conf, kconf_schema * schema)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(conf && !khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(KHM_FAILED(khc_validate_schema(schema, 0, NULL)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_conf_global);\r
+ rv = khc_load_schema_i(conf, schema, 0, NULL); \r
+ LeaveCriticalSection(&cs_conf_global);\r
+\r
+ return rv;\r
+}\r
+\r
+khm_int32 khc_unload_schema_i(khm_handle parent, kconf_schema * schema, int begin, int * end)\r
+{\r
+ int i;\r
+ int state = 0;\r
+ int end_found = 0;\r
+ kconf_conf_space * thisconf = NULL;\r
+ khm_handle h;\r
+\r
+ i=begin;\r
+ while(!end_found) {\r
+ switch(state) {\r
+ case 0: /* initial. this record should start a config space */\r
+ if(KHM_FAILED(khc_open_space(parent, schema[i].name, 0, &h)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ thisconf = khc_space_from_handle(h);\r
+ if(thisconf->schema == (schema + (begin + 1))) {\r
+ thisconf->schema = NULL;\r
+ thisconf->nSchema = 0;\r
+ }\r
+ state = 1;\r
+ break;\r
+\r
+ case 1: /* we are inside a config space, in the values area */\r
+ if(schema[i].type == KC_SPACE) {\r
+ if(KHM_FAILED(khc_unload_schema_i(h, schema, i, &i)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ state = 2;\r
+ } else if(schema[i].type == KC_ENDSPACE) {\r
+ end_found = 1;\r
+ if(end)\r
+ *end = i;\r
+ khc_close_space(h);\r
+ }\r
+ break;\r
+\r
+ case 2: /* we are inside a config space, in the subspace area */\r
+ if(schema[i].type == KC_SPACE) {\r
+ if(KHM_FAILED(khc_unload_schema_i(h, schema, i, &i)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ } else if(schema[i].type == KC_ENDSPACE) {\r
+ end_found = 1;\r
+ if(end)\r
+ *end = i;\r
+ khc_close_space(h);\r
+ } else {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ /* unreachable */\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ i++;\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_unload_schema(khm_handle conf, kconf_schema * schema)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(conf && !khc_is_handle(conf))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(KHM_FAILED(khc_validate_schema(schema, 0, NULL)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_conf_global);\r
+ rv = khc_unload_schema_i(conf, schema, 0, NULL); \r
+ LeaveCriticalSection(&cs_conf_global);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_enum_subspaces(\r
+ khm_handle conf,\r
+ khm_handle prev,\r
+ khm_handle * next)\r
+{\r
+ kconf_conf_space * s;\r
+ kconf_conf_space * c;\r
+ kconf_conf_space * p;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!khc_is_handle(conf) || next == NULL ||\r
+ (prev != NULL && !khc_is_handle(prev)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ s = khc_space_from_handle(conf);\r
+\r
+ if(prev == NULL) {\r
+ /* first off, we enumerate all the registry spaces regardless of\r
+ whether the handle is applicable for some registry space or not.\r
+ See notes for khc_begin_enum_subspaces() for reasons as to why\r
+ this is done (notes are in kconfig.h)*/\r
+\r
+ /* go through the user hive first */\r
+ {\r
+ HKEY hk_conf;\r
+\r
+ hk_conf = khc_space_open_key(s, 0);\r
+ if(hk_conf) {\r
+ wchar_t name[KCONF_MAXCCH_NAME];\r
+ khm_handle h;\r
+ int idx;\r
+\r
+ idx = 0;\r
+ while(RegEnumKey(hk_conf, idx, \r
+ name, ARRAYLENGTH(name)) == ERROR_SUCCESS) {\r
+ wchar_t * tilde;\r
+ tilde = wcschr(name, L'~');\r
+ if (tilde)\r
+ *tilde = 0;\r
+ if(KHM_SUCCEEDED(khc_open_space(conf, name, 0, &h)))\r
+ khc_close_space(h);\r
+ idx++;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* go through the machine hive next */\r
+ {\r
+ HKEY hk_conf;\r
+\r
+ hk_conf = khc_space_open_key(s, KCONF_FLAG_MACHINE);\r
+ if(hk_conf) {\r
+ wchar_t name[KCONF_MAXCCH_NAME];\r
+ khm_handle h;\r
+ int idx;\r
+\r
+ idx = 0;\r
+ while(RegEnumKey(hk_conf, idx, \r
+ name, ARRAYLENGTH(name)) == ERROR_SUCCESS) {\r
+ wchar_t * tilde;\r
+ tilde = wcschr(name, L'~');\r
+ if (tilde)\r
+ *tilde = 0;\r
+\r
+ if(KHM_SUCCEEDED(khc_open_space(conf, name, \r
+ KCONF_FLAG_MACHINE, &h)))\r
+ khc_close_space(h);\r
+ idx++;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* don't need to go through schema, because that was already\r
+ done when the schema was loaded. */\r
+ }\r
+\r
+ /* at last we are now ready to return the results */\r
+ EnterCriticalSection(&cs_conf_global);\r
+ if(prev == NULL) {\r
+ c = TFIRSTCHILD(s);\r
+ rv = KHM_ERROR_SUCCESS;\r
+ } else {\r
+ p = khc_space_from_handle(prev);\r
+ if(TPARENT(p) == s)\r
+ c = LNEXT(p);\r
+ else\r
+ c = NULL;\r
+ }\r
+ LeaveCriticalSection(&cs_conf_global);\r
+\r
+ if(prev != NULL)\r
+ khc_close_space(prev);\r
+\r
+ if(c) {\r
+ *next = khc_handle_from_space(c, khc_handle_flags(conf));\r
+ rv = KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *next = NULL;\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_write_multi_string(khm_handle conf, wchar_t * value, wchar_t * buf)\r
+{\r
+ size_t cb;\r
+ wchar_t *tb;\r
+ khm_int32 rv;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+ if(!khc_is_handle(conf) || buf == NULL || value == NULL)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(multi_string_to_csv(NULL, &cb, buf) != KHM_ERROR_TOO_LONG)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ tb = malloc(cb);\r
+ assert(tb != NULL);\r
+ multi_string_to_csv(tb, &cb, buf);\r
+ rv = khc_write_string(conf, value, tb);\r
+\r
+ free(tb);\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khc_read_multi_string(khm_handle conf, wchar_t * value, wchar_t * buf, khm_size * bufsize)\r
+{\r
+ wchar_t * tb;\r
+ khm_size cbbuf;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!khc_is_config_running())\r
+ return KHM_ERROR_NOT_READY;\r
+\r
+ if(!bufsize)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ rv = khc_read_string(conf, value, NULL, &cbbuf);\r
+ if(rv != KHM_ERROR_TOO_LONG)\r
+ return rv;\r
+\r
+ tb = malloc(cbbuf);\r
+ assert(tb != NULL);\r
+ rv = khc_read_string(conf, value, tb, &cbbuf);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ rv = csv_to_multi_string(buf, bufsize, tb);\r
+\r
+_exit:\r
+ free(tb);\r
+\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCONFIG_H\r
+#define __KHIMAIRA_KCONFIG_H\r
+\r
+#include<khdefs.h>\r
+#include<mstring.h>\r
+\r
+/*! \defgroup kconf NetIDMgr Configuration Provider */\r
+/*@{*/\r
+\r
+/*! \brief Configuration schema descriptor record \r
+\r
+ The schema descriptor is a convenient way to provide a default set\r
+ of configuration options for a part of an application. It\r
+ describes the configuration spaces and the values and subspaces\r
+ contained in each space.\r
+\r
+ \see kconf_load_schema()\r
+*/\r
+typedef struct kconf_schema_t {\r
+ wchar_t * name; /*!< name of the object being described.\r
+ Optional for KC_ENDSPACE type object,\r
+ but required for everything else.\r
+ Names can be upto KCONF_MAXCCH_NAME\r
+ characters in length. */\r
+ khm_int32 type; /*!< type of the object. Can be one of\r
+ KC_SPACE, KC_ENDSPACE, KC_INT32,\r
+ KC_INT64, KC_STRING or KC_BINARY */\r
+ khm_ui_8 value; /*!< the value of the object. It is not\r
+ used for KC_SPACE and KC_ENDSPACE\r
+ typed objects. For a KC_STRING, this\r
+ contains a pointer to the string\r
+ value. The string should not be\r
+ longer than KCONF_MAXCCH_STRING\r
+ characters. KC_INT32 and KC_INT64\r
+ objects store the value directly in\r
+ this field, while KC_BINARY objects do\r
+ not support defining a default value\r
+ here. */\r
+ wchar_t * description;/*!< a friendly description of the value\r
+ or configuration space */\r
+} kconf_schema;\r
+\r
+/*! \name Configuration data types\r
+ @{*/\r
+/*! \brief Not a known type */\r
+#define KC_NONE 0\r
+\r
+/*! \brief When used as ::kconf_schema \a type, defines the start of a configuration space.\r
+\r
+ There should be a subsequent KC_ENDSPACE record in the schema\r
+ which defines the end of this configuration space.\r
+\r
+ \a name specifies the name of the configuration space. Optionally\r
+ use \a description to provide a description.*/\r
+#define KC_SPACE 1\r
+\r
+/*! \brief Ends a configuration space started with KC_SPACE */\r
+#define KC_ENDSPACE 2\r
+\r
+/*! \brief A 32 bit integer\r
+\r
+ Specifies a configuration parameter named \a name which is of this\r
+ type. Use \a description to provide an optional description of\r
+ the value.\r
+\r
+ \a value specifies a default value for this parameter in the lower\r
+ 32 bits.\r
+*/\r
+#define KC_INT32 3\r
+\r
+/*! \brief A 64 bit integer \r
+\r
+ Specifies a configuration parameter named \a name which is of this\r
+ type. Use \a description to provide an optional description of\r
+ the value.\r
+\r
+ \a value specifies a default value for this parameter.\r
+*/\r
+#define KC_INT64 4\r
+\r
+/*! \brief A unicode string \r
+\r
+ Specifies a configuration parameter named \a name which is of this\r
+ type. Use \a description to provide an optional description of\r
+ the value.\r
+\r
+ \a value specifies a default value for this parameter which should\r
+ be a pointer to a NULL terminated unicode string of no more than\r
+ ::KCONF_MAXCCH_STRING characters.\r
+*/\r
+#define KC_STRING 5\r
+\r
+/*! \brief An unparsed binary stream \r
+\r
+ Specifies a configuration parameter named \a name which is of this\r
+ type. Use \a description to provide an optional description of\r
+ the value.\r
+\r
+ Default values are not supported for binary streams. \a value is\r
+ ignored.\r
+*/\r
+#define KC_BINARY 6\r
+/*@}*/\r
+\r
+/*! \brief This is the root configuration space */\r
+#define KCONF_FLAG_ROOT 0x00000001\r
+\r
+/*! \brief Indicates the configuration store which stores user-specific information */\r
+#define KCONF_FLAG_USER 0x00000002\r
+\r
+/*! \brief Indicates the configuration store which stores machine-specific information */\r
+#define KCONF_FLAG_MACHINE 0x00000004\r
+\r
+/*! \brief Indicates the configuration store which stores the schema */\r
+#define KCONF_FLAG_SCHEMA 0x00000008\r
+\r
+/*! \brief Indicates that the last component of the given configuration path is to be considered to be a configuration value */\r
+#define KCONF_FLAG_TRAILINGVALUE 0x00000020\r
+\r
+/*! \brief Do not parse the configuration space name\r
+\r
+ If set, disables the parsing of the configuration space for\r
+ subspaces. The space name is taken verbatim to be a configuration\r
+ space name. This can be used when there can be forward slashes or\r
+ backslahes in the name which are not escaped.\r
+\r
+ By default, the configuration space name,\r
+\r
+ \code\r
+ L"foo/bar"\r
+ \endcode\r
+\r
+ is taken to mean the configuration space \a bar which is a\r
+ subspace of \a foo. If ::KCONF_FLAG_NOPARSENAME is set, then this\r
+ is taken to mean configuration space \a foo/bar.\r
+ */\r
+#define KCONF_FLAG_NOPARSENAME 0x00000040\r
+\r
+/*! \brief Maximum number of allowed characters (including terminating NULL) in a name \r
+\r
+ \note This is a hard limit in Windows, since we are mapping\r
+ configuration spaces to registry keys.\r
+*/\r
+#define KCONF_MAXCCH_NAME 256\r
+\r
+/*! \brief Maximum number of allowed bytes (including terminating NULL) in a name */\r
+#define KCONF_MAXCB_NAME (KCONF_MAXCCH_NAME * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum level of nesting for configuration spaces\r
+ */\r
+#define KCONF_MAX_DEPTH 16\r
+\r
+/*! \brief Maximum number of allowed characters (including terminating NULL) in a configuration path */\r
+#define KCONF_MAXCCH_PATH (KCONF_MAXCCH_NAME * KCONF_MAX_DEPTH)\r
+\r
+/*! \brief Maximum number of allowed bytes (including terminating NULL) in a configuration path */\r
+#define KCONF_MAXCB_PATH (KCONF_MAXCCH_PATH * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum number of allowed characters (including terminating NULL) in a string */\r
+#define KCONF_MAXCCH_STRING KHM_MAXCCH_STRING\r
+\r
+/*! \brief Maximum number of allowed bytes (including terminating NULL) in a string */\r
+#define KCONF_MAXCB_STRING (KCONF_MAXCCH_STRING * sizeof(wchar_t))\r
+\r
+/*! \brief Open a configuration space\r
+\r
+ Opens the configuration space specified by \a cspace. By default,\r
+ the opened space includes user,machine and schema configuration\r
+ stores. However, you can specify a subset of these.\r
+\r
+ If the configuration space does not exist and the \a flags specify\r
+ KHM_FLAG_CREATE, then the configuration space is created. The\r
+ stores that are affected by the create operation depend on \a\r
+ flags. If the \a flags only specifies ::KCONF_FLAG_MACHINE, then\r
+ the configuration space is created in the machine store. If \a\r
+ flags specifies any combination of stores including \a\r
+ ::KCONF_FLAG_USER, then the configuration space is created in the\r
+ user store. Note that ::KCONF_FLAG_SCHEMA is readonly.\r
+\r
+ Once opened, use khc_close_space() to close the configuration\r
+ space.\r
+\r
+ \param[in] parent The parent configuration space. The path\r
+ specified in \a cspace is relative to the parent. Set this to\r
+ NULL to indicate the root configuration space. \r
+\r
+ \param[in] cspace The confiuration path. This can be up to\r
+ ::KCONF_MAXCCH_PATH characters in length. Use either\r
+ backslashes or forward slashes to specify hiearchy. Set this\r
+ to NULL to reopen the parent configuration space.\r
+\r
+ \param[in] flags Flags. This can be a combination of KCONF_FLAG_*\r
+ constants and KHM_FLAG_CREATE. If none of ::KCONF_FLAG_USER,\r
+ ::KCONF_FLAG_MACHINE or ::KCONF_FLAG_SCHEMA is specified, then\r
+ it defaults to all three.\r
+\r
+ \param[out] result Pointer to a handle which receives the handle\r
+ to the opened configuration space if the call succeeds.\r
+\r
+ \note You can re-open a configuration space with different flags\r
+ such as ::KCONF_FLAG_MACHINE by specifying NULL for \a cspace\r
+ and settings \a flags to the required flags.\r
+\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, khm_handle * result);\r
+\r
+/*! \brief Set the shadow space for a configuration handle\r
+\r
+ The handle specified by \a lower becomes a shadow for the handle\r
+ specified by \a upper. Any configuration value that is queried in\r
+ \a upper that does not exist in \a upper will be queried in \a\r
+ lower.\r
+\r
+ If \a upper already had a shadow handle, that handle will be\r
+ replaced by \a lower. The handle \a lower still needs to be\r
+ closed by a call to khc_close_space(). However, closing \a lower\r
+ will not affect \a upper which will still treat the configuration\r
+ space pointed to by \a lower to be it's shadow.\r
+\r
+ Shadows are specific to handles and not configuration spaces.\r
+ Shadowing a configuration space using one handle does not affect\r
+ any other handles which may be obtained for the same configuration\r
+ space.\r
+\r
+ Specify NULL for \a lower to remove any prior shadow.\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_shadow_space(khm_handle upper, khm_handle lower);\r
+\r
+/*! \brief Close a handle opened with khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_close_space(khm_handle conf);\r
+\r
+/*! \brief Read a string value from a configuration space\r
+\r
+ The \a value parameter specifies the value to read from the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to access the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema\r
+ store.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three.\r
+\r
+ \param[in] buf Buffer to copy the string to. Specify NULL to just\r
+ retrieve the number of required bytes.\r
+ \r
+ \param[in,out] bufsize On entry, specifies the number of bytes of\r
+ space available at the location specified by \a buf. On exit\r
+ specifies the number of bytes actually copied or the size of\r
+ the required buffer if \a buf is NULL or insufficient.\r
+\r
+ \retval KHM_ERROR_NOT_READY The configuration provider has not started\r
+ \retval KHM_ERROR_INVALID_PARM One or more of the supplied parameters are not valid\r
+ \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string\r
+ \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize.\r
+ \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_read_string(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ wchar_t * buf, \r
+ khm_size * bufsize);\r
+\r
+/*! \brief Read a multi-string value from a configuration space\r
+\r
+ The \a value parameter specifies the value to read from the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to access the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema\r
+ store.\r
+\r
+ A multi-string is a pseudo data type. The value in the\r
+ configuration store should contain a CSV string. Each comma\r
+ separated value in the CSV string is considered to be a separate\r
+ value. Empty values are not allowed. The buffer pointed to by \a\r
+ buf will receive these values in the form of a series of NULL\r
+ terminated strings terminated by an empty string (or equivalently,\r
+ the last string will be terminated by a double NULL).\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three.\r
+\r
+ \param[in] buf Buffer to copy the multi-string to. Specify NULL\r
+ to just retrieve the number of required bytes.\r
+ \r
+ \param[in,out] bufsize On entry, specifies the number of bytes of\r
+ space available at the location specified by \a buf. On exit\r
+ specifies the number of bytes actually copied or the size of\r
+ the required buffer if \a buf is NULL or insufficient.\r
+\r
+ \retval KHM_ERROR_NOT_READY The configuration provider has not started\r
+ \retval KHM_ERROR_INVALID_PARM One or more of the supplied parameters are not valid\r
+ \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string\r
+ \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize.\r
+ \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_read_multi_string(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ wchar_t * buf, \r
+ khm_size * bufsize);\r
+\r
+/*! \brief Read a 32 bit integer value from a configuration space\r
+\r
+ The \a value parameter specifies the value to read from the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to access the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema\r
+ store.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three.\r
+\r
+ \param[in] conf Handle to a configuration space\r
+ \param[in] value The value to query\r
+ \param[out] buf The buffer to receive the value\r
+\r
+ \retval KHM_ERROR_NOT_READY The configuration provider has not started.\r
+ \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf\r
+ \retval KHM_ERROR_NOT_FOUND The specified value was not found\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not of the correct type.\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_read_int32(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ khm_int32 * buf);\r
+\r
+/*! \brief Read a 64 bit integer value from a configuration space\r
+\r
+ The \a value parameter specifies the value to read from the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to access the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema\r
+ store.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three.\r
+\r
+ \param[in] conf Handle to a configuration space\r
+ \param[in] value The value to query\r
+ \param[out] buf The buffer to receive the value\r
+\r
+ \retval KHM_ERROR_NOT_READY The configuration provider has not started\r
+ \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf\r
+ \retval KHM_ERROR_NOT_FOUND The specified value was not found\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not the correct data type.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_read_int64(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ khm_int64 * buf);\r
+\r
+/*! \brief Read a binary value from a configuration space\r
+\r
+ The \a value parameter specifies the value to read from the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to access the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three. Also note that the schema store (KCONF_FLAG_SCHEMA) does\r
+ not support binary values.\r
+\r
+ \param[in] buf Buffer to copy the string to. Specify NULL to just\r
+ retrieve the number of required bytes.\r
+ \r
+ \param[in,out] bufsize On entry, specifies the number of bytes of\r
+ space available at the location specified by \a buf. On exit\r
+ specifies the number of bytes actually copied or the size of\r
+ the required buffer if \a buf is NULL or insufficient.\r
+\r
+ \retval KHM_ERROR_SUCCESS Success. The data was copied to \a buf. The number of bytes copied is stored in \a bufsize\r
+ \retval KHM_ERROR_NOT_FOUND The specified value was not found\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_read_binary(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ void * buf, \r
+ khm_size * bufsize);\r
+\r
+/*! \brief Write a string value to a configuration space\r
+\r
+ The \a value parameter specifies the value to write to the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to write the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three. Also note that the schema store (KCONF_FLAG_SCHEMA) is\r
+ readonly.\r
+\r
+ \param[in] conf Handle to a configuration space\r
+ \param[in] value Name of value to write\r
+ \param[in] buf A NULL terminated unicode string not exceeding KCONF_MAXCCH_STRING in characters including terminating NULL\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_write_string(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ wchar_t * buf);\r
+\r
+/*! \brief Write a multi-string value to a configuration space\r
+\r
+ The \a value parameter specifies the value to write to the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to write the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ A multi-string is a pseudo data type. The buffer pointed to by \a\r
+ buf should contain a sequence of NULL terminated strings\r
+ terminated by an empty string (or equivalently, the last string\r
+ should terminate with a double NULL). This will be stored in the\r
+ value as a CSV string.\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three. Also note that the schema store (KCONF_FLAG_SCHEMA) is\r
+ readonly.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_write_multi_string(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ wchar_t * buf);\r
+\r
+/*! \brief Write a 32 bit integer value to a configuration space\r
+\r
+ The \a value parameter specifies the value to write to the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to write the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three. Also note that the schema store (KCONF_FLAG_SCHEMA) is\r
+ readonly.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_write_int32(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ khm_int32 buf);\r
+\r
+/*! \brief Write a 64 bit integer value to a configuration space\r
+\r
+ The \a value parameter specifies the value to write to the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to write the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three. Also note that the schema store (KCONF_FLAG_SCHEMA) is\r
+ readonly.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_write_int64(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ khm_int64 buf);\r
+\r
+/*! \brief Write a binary value to a configuration space\r
+\r
+ The \a value parameter specifies the value to write to the\r
+ configuration space. This can be either a value name or a value\r
+ path consisting of a series nested configuration space names\r
+ followed by the value name all separated by backslashes or forward\r
+ slashes.\r
+\r
+ For example: If \a conf is a handle to the configuration space \c\r
+ 'A/B/C', then the value name \c 'D/E/v' refers to the value named\r
+ \c 'v' in the configuration space \c 'A/B/C/D/E'.\r
+\r
+ The specific configuration store that is used to write the value\r
+ depends on the flags that were specified in the call to\r
+ khc_open_space(). The precedence of configuration stores are as\r
+ follows:\r
+\r
+ - If KCONF_FLAG_USER was specified, then the user configuration\r
+ space.\r
+\r
+ - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine\r
+ configuration space.\r
+\r
+ Note that not specifying any of the configuration store specifiers\r
+ in the call to khc_open_space() is equivalent to specifying all\r
+ three. Also note that the schema store (KCONF_FLAG_SCHEMA) is\r
+ readonly.\r
+\r
+ \see khc_open_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI khc_write_binary(\r
+ khm_handle conf, \r
+ wchar_t * value, \r
+ void * buf, \r
+ khm_size bufsize);\r
+\r
+/*! \brief Get the type of a value in a configuration space\r
+\r
+ \return The return value is the type of the specified value, or\r
+ KC_NONE if the value does not exist.\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_get_type(khm_handle conf, wchar_t * value);\r
+\r
+/*! \brief Check which configuration stores contain a specific value.\r
+\r
+ Each value in a configuration space can be contained in zero or\r
+ more configuration stores. Use this function to determine which\r
+ configuration stores contain the specific value.\r
+\r
+ The returned bitmask always indicates a subset of the\r
+ configuration stores that were specified when opening the\r
+ configuration space corresponding to \a conf.\r
+\r
+ \return A combination of ::KCONF_FLAG_MACHINE, ::KCONF_FLAG_USER\r
+ and ::KCONF_FLAG_SCHEMA indicating which stores contain the\r
+ value.\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_value_exists(khm_handle conf, wchar_t * value);\r
+\r
+/*! \brief Get the name of a configuration space\r
+\r
+ \param[in] conf Handle to a configuration space\r
+\r
+ \param[out] buf The buffer to receive the name. Set to NULL if\r
+ only the size of the buffer is required.\r
+\r
+ \param[in,out] bufsize On entry, holds the size of the buffer\r
+ pointed to by \a buf. On exit, holds the number of bytes\r
+ copied into the buffer including the NULL terminator.\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_get_config_space_name(\r
+ khm_handle conf, \r
+ wchar_t * buf, \r
+ khm_size * bufsize);\r
+\r
+/*! \brief Get a handle to the parent space\r
+\r
+ \param[in] conf Handle to a configuration space\r
+\r
+ \param[out] parent Handle to the parent configuration space if the\r
+ call succeeds. Receives NULL otherwise. The returned handle\r
+ must be closed using khc_close_space()\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_get_config_space_parent(\r
+ khm_handle conf, \r
+ khm_handle * parent);\r
+\r
+/*! \brief Load a configuration schema into the specified configuration space\r
+\r
+ \param[in] conf Handle to a configuration space or NULL to use the\r
+ root configuration space.\r
+\r
+ \param[in] schema The schema to load. The schema is assumed to be\r
+ well formed.\r
+\r
+ \see khc_unload_schema()\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_load_schema(\r
+ khm_handle conf, \r
+ kconf_schema * schema);\r
+\r
+/*! \brief Unload a schema from a configuration space\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_unload_schema(\r
+ khm_handle conf, \r
+ kconf_schema * schema);\r
+\r
+/*! \brief Enumerate the subspaces of a configuration space\r
+\r
+ Prepares a configuration space for enumeration and returns the\r
+ child spaces in no particular order.\r
+\r
+ \param[in] conf The configuration space to enumerate child spaces\r
+\r
+ \param[in] prev The previous configuration space returned by\r
+ khc_enum_subspaces() or NULL if this is the first call. If\r
+ this is not NULL, then the handle passed in \a prev will be\r
+ freed.\r
+\r
+ \param[out] next If \a prev was NULL, receives the first sub space\r
+ found in \a conf. You must \b either call\r
+ khc_enum_subspaces() again with the returned handle or call\r
+ khc_close_space() to free the returned handle if no more\r
+ subspaces are required. \a next can point to the same handle\r
+ specified in \a prev.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded. There is a valid\r
+ handle to a configuration space in \a first_subspace.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM Either \a conf or \a prev was not a\r
+ valid configuration space handle or \a first_subspace is NULL.\r
+ Note that \a prev can be NULL.\r
+\r
+ \retval KHM_ERROR_NOT_FOUND There were no subspaces in the\r
+ configuration space pointed to by \a conf.\r
+\r
+ \note The configuration spaces that are enumerated directly belong\r
+ to the configuration space given by \a conf. This function\r
+ does not enumerate subspaces of shadowed configuration spaces\r
+ (see khc_shadow_space()). Even if \a conf was obtained on a\r
+ restricted domain (i.e. you specified one or more\r
+ configuration stores when you openend the handle and didn't\r
+ include all the configuration stores. See khc_open_space()),\r
+ the subspaces that are returned are the union of all\r
+ configuration spaces in all the configuration stores. This is\r
+ not a bug. This is a feature. In NetIDMgr, a configuartion\r
+ space exists if some configuration store defines it (or it was\r
+ created with a call to khc_open_space() even if no\r
+ configuration store defines it yet). This is the tradeoff you\r
+ make when using a layered configuration system.\r
+\r
+ However, the returned handle has the same domain restrictions\r
+ as \a conf.\r
+ */\r
+KHMEXP khm_int32 KHMAPI khc_enum_subspaces(\r
+ khm_handle conf,\r
+ khm_handle prev,\r
+ khm_handle * next);\r
+\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCONFIGINTERNAL_H\r
+#define __KHIMAIRA_KCONFIGINTERNAL_H\r
+\r
+#include<windows.h>\r
+#include<strsafe.h>\r
+#include<kconfig.h>\r
+#include<khlist.h>\r
+#include<kherror.h>\r
+#include<utils.h>\r
+\r
+/* TODO: Implement configuration provider interfaces\r
+\r
+typedef struct kconf_provider_t {\r
+\r
+} kconf_provider;\r
+*/\r
+\r
+typedef struct kconf_conf_space_t {\r
+ wchar_t * name;\r
+\r
+ /* kconf_provider * provider; */\r
+\r
+ /* the regpath is the cumulative path starting from a hive root */\r
+ wchar_t * regpath;\r
+ HKEY regkey_user;\r
+ khm_int32 regkey_user_flags;\r
+ HKEY regkey_machine;\r
+ khm_int32 regkey_machine_flags;\r
+\r
+ khm_int32 refcount;\r
+ khm_int32 flags;\r
+\r
+ kconf_schema * schema;\r
+ khm_int32 nSchema;\r
+\r
+ TDCL(struct kconf_conf_space_t);\r
+} kconf_conf_space;\r
+\r
+#define KCONF_SPACE_FLAG_SCHEMA 32\r
+\r
+typedef struct kconf_conf_handle_t {\r
+ khm_int32 magic;\r
+ khm_int32 flags;\r
+ kconf_conf_space * space;\r
+\r
+ struct kconf_conf_handle_t * lower;\r
+\r
+ LDCL(struct kconf_conf_handle_t);\r
+} kconf_handle;\r
+\r
+#define KCONF_HANDLE_MAGIC 0x38eb49d2\r
+#define khc_is_handle(h) ((h) && ((kconf_handle *)h)->magic == KCONF_HANDLE_MAGIC)\r
+#define khc_shadow(h) (((kconf_handle *)h)->lower)\r
+#define khc_is_shadowed(h) (khc_is_handle(h) && khc_shadow(h) != NULL)\r
+\r
+extern kconf_conf_space * conf_root;\r
+extern kconf_handle * conf_handles;\r
+extern kconf_handle * conf_free_handles;\r
+extern CRITICAL_SECTION cs_conf_global;\r
+extern LONG conf_init;\r
+extern LONG conf_status;\r
+\r
+#define khc_is_config_running() (conf_init && conf_status)\r
+\r
+#define CONFIG_REGPATHW L"Software\\MIT\\NetIDMgr"\r
+\r
+void init_kconf(void);\r
+void exit_kconf(void);\r
+\r
+/* handle operations */\r
+#define khc_space_from_handle(h) (((kconf_handle *) h)->space)\r
+#define khc_is_schema_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_SCHEMA)\r
+#define khc_is_user_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_USER)\r
+#define khc_is_machine_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_MACHINE)\r
+#define khc_handle_flags(h) (((kconf_handle *) h)->flags)\r
+\r
+kconf_handle * khc_handle_from_space(kconf_conf_space * s, khm_int32 flags);\r
+void khc_handle_free(kconf_handle * h);\r
+\r
+kconf_conf_space * khc_create_empty_space(void);\r
+void khc_free_space(kconf_conf_space * r);\r
+\r
+void khc_space_hold(kconf_conf_space * s);\r
+void khc_space_release(kconf_conf_space * s);\r
+\r
+HKEY khc_space_open_key(kconf_conf_space * s, khm_int32 flags);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kconfiginternal.h>\r
+\r
+void\r
+kconfig_process_attach(void) {\r
+ init_kconf();\r
+}\r
+\r
+void\r
+kconfig_process_detach(void) {\r
+ exit_kconf();\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kconfiginternal.h>\r
+\r
--- /dev/null
+#include<stdio.h>\r
+#include<kconfig.h>\r
+#include<strsafe.h>\r
+\r
+struct string_pair {\r
+ wchar_t * ms;\r
+ wchar_t * csv;\r
+};\r
+\r
+struct string_pair strings[] = {\r
+ {L"foo\0bar\0baz,quux\0ab\"cd\0", L"foo,bar,\"baz,quux\",\"ab\"\"cd\""},\r
+ {L"a\0b\0c\0d\0e\0", L"a,b,c,d,e"},\r
+ {L"1\0", L"1"},\r
+ {L"\0", L""},\r
+ {L"b\0a\0", L"b,a"},\r
+ {L"c\0a\0b\0", L"c,a,b"},\r
+ {L"c\0a\0B\0", L"c,a,B"},\r
+ {L"sdf\0Bar\0Foo\0BBB\0", L"sdf,Bar,Foo,BBB"}\r
+};\r
+\r
+int n_strings = ARRAYLENGTH(strings);\r
+\r
+void print_ms(wchar_t * ms) {\r
+ wchar_t * s;\r
+ size_t cch;\r
+\r
+ s = ms;\r
+ while(*s) {\r
+ printf("%S\\0", s);\r
+ StringCchLength(s, 512, &cch);\r
+ s += cch + 1;\r
+ }\r
+}\r
+\r
+int ms_to_csv_test(void) {\r
+ wchar_t wbuf[512];\r
+ int i;\r
+ khm_int32 code = 0;\r
+ size_t cbbuf;\r
+ size_t cbr;\r
+ size_t cbnull;\r
+\r
+ printf("khc_multi_string_to_csv() test:\n");\r
+\r
+ for(i=0; i<n_strings; i++) {\r
+ cbbuf = sizeof(wbuf);\r
+ printf("Multi string:[");\r
+ print_ms(strings[i].ms);\r
+ printf("]->");\r
+ code = khc_multi_string_to_csv(NULL, &cbnull, strings[i].ms);\r
+ code = khc_multi_string_to_csv(wbuf, &cbbuf, strings[i].ms);\r
+ if(code) {\r
+ printf(" returned %d\n", code);\r
+ return code;\r
+ }\r
+ printf("CSV[%S]", wbuf);\r
+ if(wcscmp(wbuf, strings[i].csv)) {\r
+ printf(" MISMATCH!");\r
+ return 1;\r
+ }\r
+\r
+ StringCbLength(wbuf, sizeof(wbuf), &cbr);\r
+ cbr+= sizeof(wchar_t);\r
+\r
+ if(cbr != cbbuf) {\r
+ printf(" Length mismatch");\r
+ return 1;\r
+ }\r
+\r
+ if(cbnull != cbr) {\r
+ printf(" NULL length mismatch");\r
+ return 1;\r
+ }\r
+\r
+ printf("\n");\r
+ }\r
+\r
+ return code;\r
+}\r
+\r
+int csv_to_ms_test(void) {\r
+ wchar_t wbuf[512];\r
+ int i;\r
+ khm_int32 code = 0;\r
+ size_t cbbuf;\r
+ size_t cbr;\r
+ size_t cbnull;\r
+\r
+ printf("khc_csv_to_multi_string() test:\n");\r
+\r
+ for(i=0; i<n_strings; i++) {\r
+ cbbuf = sizeof(wbuf);\r
+ printf("CSV:[%S]->", strings[i].csv);\r
+ code = khc_csv_to_multi_string(NULL, &cbnull, strings[i].csv);\r
+ code = khc_csv_to_multi_string(wbuf, &cbbuf, strings[i].csv);\r
+ if(code) {\r
+ printf(" returned %d\n", code);\r
+ return code;\r
+ }\r
+ printf("MS[");\r
+ print_ms(wbuf);\r
+ printf("]");\r
+\r
+ if(cbnull != cbbuf) {\r
+ printf(" NULL length mismatch");\r
+ return 1;\r
+ }\r
+\r
+ printf("\n");\r
+\r
+ printf(" Byte length:%d\n", cbbuf);\r
+ }\r
+\r
+ return code;\r
+}\r
+\r
+int ms_append_test(void)\r
+{\r
+ wchar_t wbuf[512];\r
+ size_t cbbuf;\r
+ khm_int32 code;\r
+ int i;\r
+\r
+ printf("khc_multi_string_append() test:\n");\r
+\r
+ for(i=0; i<n_strings; i++) {\r
+ cbbuf = sizeof(wbuf);\r
+ khc_csv_to_multi_string(wbuf, &cbbuf, strings[i].csv);\r
+\r
+ printf("MS[");\r
+ print_ms(wbuf);\r
+ printf("] + [foo]=[");\r
+ \r
+ cbbuf = sizeof(wbuf);\r
+ code = khc_multi_string_append(wbuf, &cbbuf, L"foo");\r
+\r
+ if(code) {\r
+ printf(" returned %d\n", code);\r
+ return code;\r
+ }\r
+\r
+ print_ms(wbuf);\r
+ printf("]\n");\r
+\r
+ printf(" byte length: %d\n", cbbuf);\r
+ }\r
+ return code;\r
+}\r
+\r
+int ms_delete_test(void)\r
+{\r
+ int code = 0;\r
+ wchar_t wbuf[512];\r
+ int i;\r
+ size_t cbs;\r
+\r
+ printf("khc_multi_string_delete() test:\n");\r
+ for(i=0; i<n_strings; i++) {\r
+ cbs = sizeof(wbuf);\r
+ khc_csv_to_multi_string(wbuf, &cbs, strings[i].csv);\r
+\r
+ printf("MS[");\r
+ print_ms(wbuf);\r
+ printf("] - [b]=[");\r
+\r
+ printf("cs:");\r
+ code = khc_multi_string_delete(wbuf, L"b", KHC_CASE_SENSITIVE);\r
+ if(code) {\r
+ printf("ci:");\r
+ code = khc_multi_string_delete(wbuf, L"b", 0);\r
+ }\r
+ if(code) {\r
+ printf("pcs:");\r
+ code = khc_multi_string_delete(wbuf, L"b", KHC_CASE_SENSITIVE | KHC_PREFIX);\r
+ }\r
+ if(code) {\r
+ printf("pci:");\r
+ code = khc_multi_string_delete(wbuf, L"b", KHC_PREFIX);\r
+ }\r
+\r
+ if(!code)\r
+ print_ms(wbuf);\r
+ else\r
+ printf(" returned %d\n", code);\r
+\r
+ printf("]\n");\r
+ }\r
+\r
+ return code;\r
+}\r
+\r
+int main(int argc, char ** argv) {\r
+\r
+ if(ms_to_csv_test())\r
+ return 1;\r
+\r
+ if(csv_to_ms_test())\r
+ return 1;\r
+\r
+ if(ms_append_test())\r
+ return 1;\r
+\r
+ if(ms_delete_test())\r
+ return 1;\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=kcreddb\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\kcreddb.h\r
+\r
+OBJFILES= \\r
+ $(OBJ)\buf.obj \\r
+ $(OBJ)\attrib.obj \\r
+ $(OBJ)\credential.obj \\r
+ $(OBJ)\credset.obj \\r
+ $(OBJ)\credtype.obj \\r
+ $(OBJ)\identity.obj \\r
+ $(OBJ)\init.obj \\r
+ $(OBJ)\kcreddbmain.obj \\r
+ $(OBJ)\type.obj \\r
+ $(OBJ)\kcdbconfig.obj\r
+\r
+$(OBJ)\kcdbconfig.c: kcdbconfig.csv $(CONFDIR)\csvschema.cfg\r
+ $(CCSV) $** $@\r
+\r
+$(OBJ)\kcredres.res: lang\en_us\kcredres.rc\r
+ $(RC2RES)\r
+\r
+all: mkdirs $(INCFILES) $(OBJ)\kcredres.res $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+#include<assert.h>\r
+\r
+CRITICAL_SECTION cs_attrib;\r
+hashtable * kcdb_attrib_namemap = NULL;\r
+kcdb_attrib_i ** kcdb_attrib_tbl = NULL;\r
+kcdb_attrib_i ** kcdb_property_tbl = NULL;\r
+kcdb_attrib_i * kcdb_attribs = NULL;\r
+\r
+void kcdb_attrib_add_ref_func(const void * key, void * va)\r
+{\r
+ kcdb_attrib_hold((kcdb_attrib_i *) va);\r
+}\r
+\r
+void kcdb_attrib_del_ref_func(const void * key, void * va)\r
+{\r
+ kcdb_attrib_release((kcdb_attrib_i *) va);\r
+}\r
+\r
+void kcdb_attrib_msg_completion(kmq_message * m) \r
+{\r
+ if(m && m->vparam) {\r
+ kcdb_attrib_release((kcdb_attrib_i *) m->vparam);\r
+ }\r
+}\r
+\r
+khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai)\r
+{\r
+ if(!ai)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ ai->refcount++;\r
+ LeaveCriticalSection(&cs_attrib);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai)\r
+{\r
+ if(!ai)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ ai->refcount--;\r
+ LeaveCriticalSection(&cs_attrib);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai)\r
+{\r
+ kcdb_attrib_hold(ai);\r
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_ATTRIB, op, (void *) ai);\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle vcred, \r
+ khm_int32 attr, \r
+ void * buf, \r
+ khm_size * pcb_buf)\r
+{\r
+ kcdb_cred * c;\r
+\r
+ c = (kcdb_cred *) vcred;\r
+\r
+ switch(attr) {\r
+ case KCDB_ATTR_NAME:\r
+ return kcdb_cred_get_name(vcred, buf, pcb_buf);\r
+\r
+ case KCDB_ATTR_ID:\r
+ if(buf && *pcb_buf >= sizeof(khm_ui_8)) {\r
+ *pcb_buf = sizeof(khm_int64);\r
+ *((khm_ui_8 *) buf) = (khm_ui_8) c->identity;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *pcb_buf = sizeof(khm_ui_8);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ case KCDB_ATTR_ID_NAME:\r
+ return kcdb_identity_get_name((khm_handle) c->identity, \r
+ (wchar_t *) buf, pcb_buf);\r
+\r
+ case KCDB_ATTR_TYPE:\r
+ if(buf && *pcb_buf >= sizeof(khm_int32)) {\r
+ *pcb_buf = sizeof(khm_int32);\r
+ *((khm_int32 *) buf) = c->type;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *pcb_buf = sizeof(khm_int32);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ case KCDB_ATTR_TYPE_NAME:\r
+ return kcdb_credtype_describe(c->type, buf, \r
+ pcb_buf, KCDB_TS_SHORT);\r
+\r
+ case KCDB_ATTR_TIMELEFT:\r
+ {\r
+ /* we are going to make liberal use of __int64 here. It\r
+ is equivalent to FILETIME and also the MSDN docs say we\r
+ should use it if the compiler supports it */\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ unsigned __int64 ftc;\r
+ SYSTEMTIME st;\r
+\r
+ if(!buf || *pcb_buf < sizeof(__int64)) {\r
+ *pcb_buf = sizeof(__int64);\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_EXPIRE)) {\r
+ *pcb_buf = sizeof(__int64);\r
+ /* setting the timeleft to _I64_MAX has the\r
+ interpretation that this credential does not\r
+ expire, which is the default behavior if the\r
+ expiration time is not known */\r
+ *((__int64 *) buf) = _I64_MAX;\r
+ } else {\r
+ GetSystemTime(&st);\r
+ SystemTimeToFileTime(&st, (LPFILETIME) &ftc);\r
+ *((__int64 *) buf) =\r
+ *((__int64 *) kcdb_cred_buf_get(c,KCDB_ATTR_EXPIRE)) - ftc;\r
+ }\r
+\r
+ return rv;\r
+ }\r
+\r
+ case KCDB_ATTR_RENEW_TIMELEFT:\r
+ {\r
+ /* we are going to make liberal use of __int64 here. It\r
+ is equivalent to FILETIME and also the MSDN docs say we\r
+ should use it if the compiler supports it */\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ unsigned __int64 ftc;\r
+ SYSTEMTIME st;\r
+\r
+ if(!buf || *pcb_buf < sizeof(__int64)) {\r
+ *pcb_buf = sizeof(__int64);\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_RENEW_EXPIRE)) {\r
+ *pcb_buf = sizeof(__int64);\r
+ /* setting the timeleft to _I64_MAX has the\r
+ interpretation that this credential does not\r
+ expire, which is the default behavior if the\r
+ expiration time is not known */\r
+ *((__int64 *) buf) = _I64_MAX;\r
+ } else {\r
+ GetSystemTime(&st);\r
+ SystemTimeToFileTime(&st, (LPFILETIME) &ftc);\r
+ *((__int64 *) buf) =\r
+ *((__int64 *) kcdb_cred_buf_get(c,KCDB_ATTR_RENEW_EXPIRE)) - ftc;\r
+ }\r
+\r
+ return rv;\r
+ }\r
+\r
+ case KCDB_ATTR_FLAGS:\r
+ if(buf && *pcb_buf >= sizeof(khm_int32)) {\r
+ *pcb_buf = sizeof(khm_int32);\r
+ *((khm_int32 *) buf) = c->flags;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *pcb_buf = sizeof(khm_int32);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ default:\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+}\r
+\r
+void kcdb_attrib_init(void)\r
+{\r
+ kcdb_attrib attrib;\r
+ wchar_t sbuf[256];\r
+\r
+ InitializeCriticalSection(&cs_attrib);\r
+ kcdb_attrib_namemap = hash_new_hashtable(\r
+ KCDB_ATTRIB_HASH_SIZE,\r
+ hash_string,\r
+ hash_string_comp,\r
+ kcdb_attrib_add_ref_func,\r
+ kcdb_attrib_del_ref_func);\r
+\r
+ kcdb_attrib_tbl = \r
+ malloc(sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1));\r
+ assert(kcdb_attrib_tbl != NULL);\r
+ ZeroMemory(kcdb_attrib_tbl, \r
+ sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1));\r
+\r
+ kcdb_property_tbl = \r
+ malloc(sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS);\r
+ assert(kcdb_property_tbl != NULL);\r
+ ZeroMemory(kcdb_property_tbl, \r
+ sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS);\r
+\r
+ kcdb_attribs = NULL;\r
+\r
+ /* register standard attributes */\r
+ \r
+ /* Name */\r
+ attrib.id = KCDB_ATTR_NAME;\r
+ attrib.name = KCDB_ATTRNAME_NAME;\r
+ attrib.type = KCDB_TYPE_STRING;\r
+ LoadString(hinst_kcreddb, IDS_NAME, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = \r
+ KCDB_ATTR_FLAG_REQUIRED | \r
+ KCDB_ATTR_FLAG_COMPUTED | \r
+ KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(wchar_t);\r
+ attrib.compute_max_cbsize = KCDB_MAXCB_NAME;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* ID */\r
+ attrib.id = KCDB_ATTR_ID;\r
+ attrib.name = KCDB_ATTRNAME_ID;\r
+ attrib.type = KCDB_TYPE_INT64;\r
+ LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = \r
+ KCDB_ATTR_FLAG_REQUIRED | \r
+ KCDB_ATTR_FLAG_COMPUTED | \r
+ KCDB_ATTR_FLAG_SYSTEM |\r
+ KCDB_ATTR_FLAG_HIDDEN;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(khm_int32);\r
+ attrib.compute_max_cbsize = sizeof(khm_int32);\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* ID Name */\r
+ attrib.id = KCDB_ATTR_ID_NAME;\r
+ attrib.alt_id = KCDB_ATTR_ID;\r
+ attrib.name = KCDB_ATTRNAME_ID_NAME;\r
+ attrib.type = KCDB_TYPE_STRING;\r
+ LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = \r
+ KCDB_ATTR_FLAG_REQUIRED | \r
+ KCDB_ATTR_FLAG_COMPUTED | \r
+ KCDB_ATTR_FLAG_ALTVIEW |\r
+ KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(wchar_t);\r
+ attrib.compute_max_cbsize = KCDB_IDENT_MAXCB_NAME;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Type */\r
+ attrib.id = KCDB_ATTR_TYPE;\r
+ attrib.name = KCDB_ATTRNAME_TYPE;\r
+ attrib.type = KCDB_TYPE_INT32;\r
+ LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = \r
+ KCDB_ATTR_FLAG_REQUIRED | \r
+ KCDB_ATTR_FLAG_COMPUTED | \r
+ KCDB_ATTR_FLAG_SYSTEM |\r
+ KCDB_ATTR_FLAG_HIDDEN;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(khm_int32);\r
+ attrib.compute_max_cbsize = sizeof(khm_int32);\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Type Name */\r
+ attrib.id = KCDB_ATTR_TYPE_NAME;\r
+ attrib.alt_id = KCDB_ATTR_TYPE;\r
+ attrib.name = KCDB_ATTRNAME_TYPE_NAME;\r
+ attrib.type = KCDB_TYPE_STRING;\r
+ LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = \r
+ KCDB_ATTR_FLAG_REQUIRED | \r
+ KCDB_ATTR_FLAG_COMPUTED |\r
+ KCDB_ATTR_FLAG_ALTVIEW |\r
+ KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(wchar_t);\r
+ attrib.compute_max_cbsize = KCDB_MAXCB_NAME;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Parent Name */\r
+ attrib.id = KCDB_ATTR_PARENT_NAME;\r
+ attrib.name = KCDB_ATTRNAME_PARENT_NAME;\r
+ attrib.type = KCDB_TYPE_STRING;\r
+ LoadString(hinst_kcreddb, IDS_PARENT, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Issed On */\r
+ attrib.id = KCDB_ATTR_ISSUE;\r
+ attrib.name = KCDB_ATTRNAME_ISSUE;\r
+ attrib.type = KCDB_TYPE_DATE;\r
+ LoadString(hinst_kcreddb, IDS_ISSUED, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Expires On */\r
+ attrib.id = KCDB_ATTR_EXPIRE;\r
+ attrib.name = KCDB_ATTRNAME_EXPIRE;\r
+ attrib.type = KCDB_TYPE_DATE;\r
+ LoadString(hinst_kcreddb, IDS_EXPIRES, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Renewable Time Expires On */\r
+ attrib.id = KCDB_ATTR_RENEW_EXPIRE;\r
+ attrib.name = KCDB_ATTRNAME_RENEW_EXPIRE;\r
+ attrib.type = KCDB_TYPE_DATE;\r
+ LoadString(hinst_kcreddb, IDS_RENEW_EXPIRES, \r
+ sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Time Left */\r
+ attrib.id = KCDB_ATTR_TIMELEFT;\r
+ attrib.alt_id = KCDB_ATTR_EXPIRE;\r
+ attrib.name = KCDB_ATTRNAME_TIMELEFT;\r
+ attrib.type = KCDB_TYPE_INTERVAL;\r
+ LoadString(hinst_kcreddb, IDS_TIMELEFT, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM |\r
+ KCDB_ATTR_FLAG_COMPUTED |\r
+ KCDB_ATTR_FLAG_ALTVIEW |\r
+ KCDB_ATTR_FLAG_VOLATILE;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(__int64);\r
+ attrib.compute_max_cbsize = sizeof(__int64);\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Renewable Time Left */\r
+ attrib.id = KCDB_ATTR_RENEW_TIMELEFT;\r
+ attrib.alt_id = KCDB_ATTR_RENEW_EXPIRE;\r
+ attrib.name = KCDB_ATTRNAME_RENEW_TIMELEFT;\r
+ attrib.type = KCDB_TYPE_INTERVAL;\r
+ LoadString(hinst_kcreddb, \r
+ IDS_RENEW_TIMELEFT, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM |\r
+ KCDB_ATTR_FLAG_COMPUTED |\r
+ KCDB_ATTR_FLAG_ALTVIEW |\r
+ KCDB_ATTR_FLAG_VOLATILE;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(__int64);\r
+ attrib.compute_max_cbsize = sizeof(__int64);\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Location of Credential */\r
+ attrib.id = KCDB_ATTR_LOCATION;\r
+ attrib.name = KCDB_ATTRNAME_LOCATION;\r
+ attrib.type = KCDB_TYPE_STRING;\r
+ LoadString(hinst_kcreddb, IDS_LOCATION, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Lifetime */\r
+ attrib.id = KCDB_ATTR_LIFETIME;\r
+ attrib.name = KCDB_ATTRNAME_LIFETIME;\r
+ attrib.type = KCDB_TYPE_INTERVAL;\r
+ LoadString(hinst_kcreddb, IDS_LIFETIME, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Renewable Lifetime */\r
+ attrib.id = KCDB_ATTR_RENEW_LIFETIME;\r
+ attrib.name = KCDB_ATTRNAME_RENEW_LIFETIME;\r
+ attrib.type = KCDB_TYPE_INTERVAL;\r
+ LoadString(hinst_kcreddb, \r
+ IDS_RENEW_LIFETIME, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;\r
+ attrib.compute_cb = NULL;\r
+ attrib.compute_min_cbsize = 0;\r
+ attrib.compute_max_cbsize = 0;\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+\r
+ /* Flags */\r
+ attrib.id = KCDB_ATTR_FLAGS;\r
+ attrib.name = KCDB_ATTRNAME_FLAGS;\r
+ attrib.type = KCDB_TYPE_INT32;\r
+ LoadString(hinst_kcreddb, IDS_FLAGS, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ attrib.flags = \r
+ KCDB_ATTR_FLAG_REQUIRED | \r
+ KCDB_ATTR_FLAG_COMPUTED | \r
+ KCDB_ATTR_FLAG_SYSTEM |\r
+ KCDB_ATTR_FLAG_HIDDEN;\r
+ attrib.compute_cb = kcdb_attr_sys_cb;\r
+ attrib.compute_min_cbsize = sizeof(khm_int32);\r
+ attrib.compute_max_cbsize = sizeof(khm_int32);\r
+\r
+ kcdb_attrib_register(&attrib, NULL);\r
+}\r
+\r
+void kcdb_attrib_exit(void)\r
+{\r
+ DeleteCriticalSection(&cs_attrib);\r
+ \r
+ if(kcdb_attrib_tbl)\r
+ free(kcdb_attrib_tbl);\r
+\r
+ if(kcdb_property_tbl)\r
+ free(kcdb_property_tbl);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_id(wchar_t *name, khm_int32 * id)\r
+{\r
+ kcdb_attrib_i * ai;\r
+\r
+ if(!name)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ ai = hash_lookup(kcdb_attrib_namemap, (void *) name);\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ if(ai) {\r
+ *id = ai->attr.id;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *id = KCDB_ATTR_INVALID;\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_register(kcdb_attrib * attrib, khm_int32 * new_id)\r
+{\r
+ kcdb_attrib_i * ai;\r
+ size_t cb_name;\r
+ size_t cb_short_desc;\r
+ size_t cb_long_desc;\r
+ khm_int32 attr_id;\r
+ khm_boolean prop = FALSE;\r
+\r
+ if(!attrib ||\r
+ KHM_FAILED(kcdb_type_get_info(attrib->type, NULL)) ||\r
+ !attrib->name)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(FAILED(StringCbLength(attrib->name, KCDB_MAXCB_NAME, &cb_name)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cb_name += sizeof(wchar_t);\r
+\r
+ if(attrib->short_desc) {\r
+ if(FAILED(StringCbLength(attrib->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cb_short_desc += sizeof(wchar_t);\r
+ } else\r
+ cb_short_desc = 0;\r
+\r
+ if(attrib->long_desc) {\r
+ if(FAILED(StringCbLength(attrib->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cb_long_desc += sizeof(wchar_t);\r
+ } else\r
+ cb_long_desc = 0;\r
+\r
+ if((attrib->flags & KCDB_ATTR_FLAG_COMPUTED) && \r
+ (!attrib->compute_cb ||\r
+ attrib->compute_min_cbsize <= 0 ||\r
+ attrib->compute_max_cbsize < attrib->compute_min_cbsize))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if ((attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) &&\r
+ KHM_FAILED(kcdb_attrib_get_info(attrib->alt_id,\r
+ NULL)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ prop = !!(attrib->flags & KCDB_ATTR_FLAG_PROPERTY);\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+\r
+ if(\r
+ !prop && \r
+ (attrib->id < 0 || attrib->id > KCDB_ATTR_MAX_ID)) \r
+ {\r
+ if(KHM_FAILED(kcdb_attrib_next_free_id(&attr_id))) {\r
+ LeaveCriticalSection(&cs_attrib);\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+ } else if (\r
+ prop &&\r
+ (attrib->id < KCDB_ATTR_MIN_PROP_ID || attrib->id > KCDB_ATTR_MAX_PROP_ID))\r
+ {\r
+ if(KHM_FAILED(kcdb_attrib_next_free_prop_id(&attr_id))) {\r
+ LeaveCriticalSection(&cs_attrib);\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+ } else {\r
+ attr_id = attrib->id;\r
+ }\r
+\r
+#ifdef DEBUG\r
+ assert(!prop || (attr_id >= KCDB_ATTR_MIN_PROP_ID && attr_id <= KCDB_ATTR_MAX_PROP_ID));\r
+ assert(prop || (attr_id >= 0 && attr_id <= KCDB_ATTR_MAX_ID));\r
+#endif\r
+\r
+ if((!prop && kcdb_attrib_tbl[attr_id]) ||\r
+ (prop && kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID])) \r
+ {\r
+ LeaveCriticalSection(&cs_attrib);\r
+ return KHM_ERROR_DUPLICATE;\r
+ }\r
+\r
+ ai = malloc(sizeof(kcdb_attrib_i));\r
+ ZeroMemory(ai, sizeof(kcdb_attrib_i));\r
+\r
+ ai->attr.type = attrib->type;\r
+ ai->attr.id = attr_id;\r
+ ai->attr.alt_id = attrib->alt_id;\r
+ ai->attr.flags = attrib->flags;\r
+ ai->attr.compute_cb = attrib->compute_cb;\r
+ ai->attr.compute_max_cbsize = attrib->compute_max_cbsize;\r
+ ai->attr.compute_min_cbsize = attrib->compute_min_cbsize;\r
+ ai->attr.name = malloc(cb_name);\r
+ StringCbCopy(ai->attr.name, cb_name, attrib->name);\r
+ if(cb_short_desc) {\r
+ ai->attr.short_desc = malloc(cb_short_desc);\r
+ StringCbCopy(ai->attr.short_desc, cb_short_desc, attrib->short_desc);\r
+ }\r
+ if(cb_long_desc) {\r
+ ai->attr.long_desc = malloc(cb_long_desc);\r
+ StringCbCopy(ai->attr.long_desc, cb_long_desc, attrib->long_desc);\r
+ }\r
+\r
+ LINIT(ai);\r
+\r
+ if(!prop)\r
+ kcdb_attrib_tbl[attr_id] = ai;\r
+ else\r
+ kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID] = ai;\r
+\r
+ LPUSH(&kcdb_attribs, ai);\r
+\r
+ hash_add(kcdb_attrib_namemap, (void *) ai->attr.name, ai);\r
+\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ kcdb_attrib_post_message(KCDB_OP_INSERT, ai);\r
+\r
+ if(new_id)\r
+ *new_id = attr_id;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_info(\r
+ khm_int32 id, \r
+ kcdb_attrib ** attrib)\r
+{\r
+ kcdb_attrib_i * ai;\r
+ khm_boolean prop;\r
+\r
+ if(id >= 0 && id <= KCDB_ATTR_MAX_ID)\r
+ prop = FALSE;\r
+ else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID)\r
+ prop = TRUE;\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ if(prop)\r
+ ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID];\r
+ else\r
+ ai = kcdb_attrib_tbl[id];\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ if(ai) {\r
+ if(attrib) {\r
+ *attrib = &(ai->attr);\r
+ kcdb_attrib_hold(ai);\r
+ }\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ if(attrib)\r
+ *attrib = NULL;\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_release_info(kcdb_attrib * attrib)\r
+{\r
+ if(attrib)\r
+ kcdb_attrib_release((kcdb_attrib_i *) attrib);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_unregister(khm_int32 id)\r
+{\r
+ /*TODO: implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_describe(\r
+ khm_int32 id, \r
+ wchar_t * buffer, \r
+ khm_size * cbsize, \r
+ khm_int32 flags)\r
+{\r
+ kcdb_attrib_i * ai;\r
+ size_t cb_size = 0;\r
+ khm_boolean prop;\r
+\r
+ if(!cbsize)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(id >= 0 && id <= KCDB_ATTR_MAX_ID)\r
+ prop = FALSE;\r
+ else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID)\r
+ prop = TRUE;\r
+\r
+ if(prop)\r
+ ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID];\r
+ else\r
+ ai = kcdb_attrib_tbl[id];\r
+\r
+ if(!ai)\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ if((flags & KCDB_TS_SHORT) &&\r
+ ai->attr.short_desc) \r
+ {\r
+ if(FAILED(StringCbLength(ai->attr.short_desc, KCDB_MAXCB_SHORT_DESC, &cb_size)))\r
+ return KHM_ERROR_UNKNOWN;\r
+ cb_size += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cbsize < cb_size) {\r
+ *cbsize = cb_size;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cbsize, ai->attr.short_desc);\r
+\r
+ *cbsize = cb_size;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ if(FAILED(StringCbLength(ai->attr.long_desc, KCDB_MAXCB_LONG_DESC, &cb_size)))\r
+ return KHM_ERROR_UNKNOWN;\r
+ cb_size += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cbsize < cb_size) {\r
+ *cbsize = cb_size;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cbsize, ai->attr.long_desc);\r
+\r
+ *cbsize = cb_size;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+}\r
+\r
+khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id)\r
+{\r
+ int i;\r
+\r
+ if(!id)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ for(i=0;i < KCDB_ATTR_MAX_PROPS; i++) {\r
+ if(!kcdb_property_tbl[i])\r
+ break;\r
+ }\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ if(i < KCDB_ATTR_MAX_PROPS) {\r
+ *id = i + KCDB_ATTR_MIN_PROP_ID;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *id = KCDB_ATTR_INVALID;\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+}\r
+\r
+khm_int32 kcdb_attrib_next_free_id(khm_int32 * id)\r
+{\r
+ int i;\r
+\r
+ if(!id)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ for(i=0;i<= KCDB_ATTR_MAX_ID; i++) {\r
+ if(!kcdb_attrib_tbl[i])\r
+ break;\r
+ }\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ if(i <= KCDB_ATTR_MAX_ID) {\r
+ *id = i;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *id = KCDB_ATTR_INVALID;\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_count(\r
+ khm_int32 and_flags,\r
+ khm_int32 eq_flags,\r
+ khm_size * pcount)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_size count = 0;\r
+ int i;\r
+\r
+ if(pcount == NULL)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ eq_flags &= and_flags;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) {\r
+ if(kcdb_attrib_tbl[i] &&\r
+ (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags)\r
+ count++;\r
+ }\r
+\r
+ for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) {\r
+ if(kcdb_property_tbl[i] &&\r
+ (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags)\r
+ count++;\r
+ }\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ *pcount = count;\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_ids(\r
+ khm_int32 and_flags,\r
+ khm_int32 eq_flags,\r
+ khm_int32 * plist,\r
+ khm_size * pcsize)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_size count = 0;\r
+ int i;\r
+\r
+ if(plist == NULL || pcsize == NULL)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ eq_flags &= and_flags;\r
+\r
+ EnterCriticalSection(&cs_attrib);\r
+ for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) {\r
+ if(kcdb_attrib_tbl[i] &&\r
+ (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) {\r
+ if(count >= *pcsize) {\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ count++;\r
+ } else\r
+ plist[count++] = i;\r
+ }\r
+ }\r
+\r
+ for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) {\r
+ if(kcdb_property_tbl[i] &&\r
+ (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) {\r
+ if(count >= *pcsize) {\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ count++;\r
+ } else\r
+ plist[count++] = i + KCDB_ATTR_MIN_PROP_ID;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_attrib);\r
+\r
+ *pcsize = count;\r
+\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_ATTRIB_H\r
+#define __KHIMAIRA_KCDB_ATTRIB_H\r
+\r
+/* Attributes */\r
+\r
+typedef struct kcdb_attrib_i_t {\r
+ kcdb_attrib attr;\r
+\r
+ khm_int32 refcount;\r
+\r
+ struct kcdb_attrib_i_t * next;\r
+ struct kcdb_attrib_i_t * prev;\r
+} kcdb_attrib_i;\r
+\r
+#define KCDB_ATTRIB_HASH_SIZE 31\r
+\r
+void kcdb_attrib_init(void);\r
+void kcdb_attrib_exit(void);\r
+void kcdb_attrib_add_ref_func(const void * key, void * va);\r
+void kcdb_attrib_del_ref_func(const void * key, void * va);\r
+void kcdb_attrib_msg_completion(kmq_message * m);\r
+khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id);\r
+khm_int32 kcdb_attrib_next_free_id(khm_int32 * id);\r
+khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai);\r
+khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai);\r
+void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai);\r
+khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle cred, khm_int32 attr, void * buf, khm_size * pcb_buf);\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+#include<assert.h>\r
+\r
+void kcdb_buf_new(kcdb_buf * buf, khm_size n_fields)\r
+{\r
+ buf->buffer = malloc(KCDB_BUF_CBBUF_INITIAL);\r
+ buf->cb_buffer = KCDB_BUF_CBBUF_INITIAL;\r
+ buf->cb_used = 0;\r
+\r
+ if(n_fields == KCDB_BUF_DEFAULT)\r
+ n_fields = KCDB_BUF_FIELDS_INITIAL;\r
+\r
+ assert(n_fields < KCDB_BUF_MAX_SLOTS);\r
+\r
+ buf->n_fields = n_fields;\r
+ buf->nc_fields = UBOUNDSS(n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH);\r
+ buf->fields = malloc(sizeof(buf->fields[0]) * buf->n_fields);\r
+ ZeroMemory(buf->fields, sizeof(buf->fields[0]) * buf->n_fields);\r
+}\r
+\r
+void kcdb_buf_delete(kcdb_buf * buf)\r
+{\r
+ buf->cb_buffer = 0;\r
+ buf->cb_used = 0;\r
+ if(buf->buffer)\r
+ free(buf->buffer);\r
+ buf->buffer = NULL;\r
+\r
+ buf->n_fields = 0;\r
+ buf->nc_fields = 0;\r
+ if(buf->fields)\r
+ free(buf->fields);\r
+ buf->fields = NULL;\r
+}\r
+\r
+static void kcdb_buf_assert_size(kcdb_buf * buf, khm_size cbsize)\r
+{\r
+ khm_size new_size;\r
+ void * new_buf;\r
+\r
+ /* should be less than or equal to the max signed 32 bit int */\r
+ assert(cbsize <= KHM_INT32_MAX);\r
+ if(cbsize <= buf->cb_buffer)\r
+ return;\r
+\r
+ new_size = UBOUNDSS(cbsize, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH);\r
+\r
+ assert(new_size > buf->cb_buffer && new_size > 0);\r
+\r
+ new_buf = malloc(new_size);\r
+ assert(new_buf != NULL);\r
+\r
+ memcpy(new_buf, buf->buffer, buf->cb_used);\r
+ free(buf->buffer);\r
+ buf->buffer = new_buf;\r
+}\r
+\r
+void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize)\r
+{\r
+ khm_size cbnew;\r
+ khm_ssize cbdelta;\r
+ khm_size cbold;\r
+ kcdb_buf_field * f;\r
+\r
+ cbnew = UBOUND32(cbsize);\r
+\r
+ assert(slot <= KCDB_BUF_APPEND);\r
+\r
+ if(slot == KCDB_BUF_APPEND) {\r
+ slot = kcdb_buf_slot_by_id(buf, id);\r
+ if(slot == KCDB_BUF_INVALID_SLOT)\r
+ slot = buf->n_fields;\r
+ }\r
+\r
+ assert(slot < KCDB_BUF_MAX_SLOTS);\r
+\r
+ if((slot + 1) > buf->nc_fields) {\r
+ kcdb_buf_field * nf;\r
+ khm_size ns;\r
+\r
+ ns = UBOUNDSS((slot + 1), KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH);\r
+\r
+ nf = malloc(sizeof(buf->fields[0]) * ns);\r
+ memcpy(nf, buf->fields, sizeof(buf->fields[0]) * buf->n_fields);\r
+\r
+ if(ns > buf->n_fields)\r
+ memset(&(nf[buf->n_fields]), 0, sizeof(buf->fields[0]) * (ns - buf->n_fields));\r
+\r
+ free(buf->fields);\r
+ buf->fields = nf;\r
+ buf->nc_fields = ns;\r
+ }\r
+\r
+ if((slot + 1) > buf->n_fields)\r
+ buf->n_fields = slot + 1;\r
+\r
+ f = &(buf->fields[slot]);\r
+\r
+ if(f->flags & KCDB_CREDF_FLAG_ALLOCD) {\r
+ /* there's already an allocation. we have to resize it to\r
+ accomodate the new size */\r
+ cbold = UBOUND32(f->cbsize);\r
+ /* demote before substraction */\r
+ cbdelta = ((khm_ssize) cbnew) - (khm_ssize) cbold;\r
+\r
+ if(cbnew > cbold) {\r
+ kcdb_buf_assert_size(buf, buf->cb_used + cbdelta);\r
+ }\r
+\r
+ if(buf->cb_used > f->offset + cbold) {\r
+ int i;\r
+\r
+ memmove(\r
+ ((BYTE *) buf->buffer) + (f->offset + cbnew),\r
+ ((BYTE *) buf->buffer) + (f->offset + cbold),\r
+ buf->cb_used - (f->offset + cbold));\r
+\r
+ for(i=0; i < (int) buf->n_fields; i++) {\r
+ if(i != slot && \r
+ (buf->fields[i].flags & KCDB_CREDF_FLAG_ALLOCD) &&\r
+ buf->fields[i].offset > f->offset) \r
+ {\r
+ buf->fields[i].offset = \r
+ (khm_ui_4)(((khm_ssize) buf->fields[i].offset) + cbdelta);\r
+ }\r
+ }\r
+ }\r
+\r
+ /* demote integer before adding signed quantity */\r
+ buf->cb_used = (khm_size)(((khm_ssize) buf->cb_used) + cbdelta);\r
+\r
+ f->cbsize = (khm_ui_4) cbsize;\r
+\r
+ } else {\r
+ kcdb_buf_assert_size(buf, buf->cb_used + cbnew);\r
+ f->offset = (khm_ui_4) buf->cb_used;\r
+ f->cbsize = (khm_ui_4) cbsize;\r
+ buf->cb_used += cbnew;\r
+ }\r
+\r
+ if(cbsize == 0) {\r
+ f->flags &= ~KCDB_CREDF_FLAG_ALLOCD;\r
+ f->flags &= ~KCDB_CREDF_FLAG_DATA;\r
+ f->id = KCDB_BUFF_ID_INVALID;\r
+ } else {\r
+ f->flags |= KCDB_CREDF_FLAG_ALLOCD;\r
+ f->id = id;\r
+ }\r
+}\r
+\r
+void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src)\r
+{\r
+ khm_size cb_buf;\r
+ khm_size nc_fields;\r
+\r
+ cb_buf = UBOUNDSS(src->cb_used, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH);\r
+#if 0\r
+ /* replaced by UBOUNDSS() above */\r
+ (src->cb_used <= kcdb_cred_initial_size)? kcdb_cred_initial_size:\r
+ kcdb_cred_initial_size + \r
+ (((src->cb_used - (kcdb_cred_initial_size + 1)) / kcdb_cred_growth_factor + 1) * kcdb_cred_growth_factor);\r
+#endif\r
+\r
+ kcdb_buf_delete(dest);\r
+\r
+ dest->cb_buffer = cb_buf;\r
+ dest->cb_used = src->cb_used;\r
+ dest->buffer = malloc(cb_buf);\r
+ memcpy(dest->buffer, src->buffer, src->cb_used);\r
+\r
+ nc_fields = UBOUNDSS(src->n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH);\r
+ dest->nc_fields = nc_fields;\r
+ dest->n_fields = src->n_fields;\r
+ dest->fields = malloc(nc_fields * sizeof(dest->fields[0]));\r
+ memcpy(dest->fields, src->fields, src->n_fields * sizeof(dest->fields[0]));\r
+ if(dest->n_fields < dest->nc_fields)\r
+ memset(&(dest->fields[dest->n_fields]), 0, (src->nc_fields - src->n_fields) * sizeof(dest->fields[0]));\r
+}\r
+\r
+void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src)\r
+{\r
+ void * dest;\r
+ kcdb_buf_alloc(buf, slot, id, cb_src);\r
+ if(slot == KCDB_BUF_APPEND) {\r
+ slot = kcdb_buf_slot_by_id(buf, id);\r
+ if(slot == KCDB_BUF_INVALID_SLOT) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return;\r
+#endif\r
+ }\r
+ }\r
+ if(kcdb_buf_exist(buf, slot)) {\r
+ dest = kcdb_buf_get(buf, slot);\r
+ memcpy(dest, src, cb_src);\r
+\r
+ buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA;\r
+ }\r
+}\r
+\r
+int kcdb_buf_exist(kcdb_buf * buf, khm_size slot)\r
+{\r
+ if(slot >= buf->n_fields)\r
+ return 0;\r
+ return (buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD);\r
+}\r
+\r
+int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot)\r
+{\r
+ if(slot >= buf->n_fields)\r
+ return 0;\r
+ return (buf->fields[slot].flags & KCDB_CREDF_FLAG_DATA);\r
+}\r
+\r
+void * kcdb_buf_get(kcdb_buf * buf, khm_size slot)\r
+{\r
+ if(slot >= buf->n_fields || \r
+ !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD))\r
+ return NULL;\r
+ return (((BYTE *) buf->buffer) + buf->fields[slot].offset);\r
+}\r
+\r
+khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot)\r
+{\r
+ if(slot >= buf->n_fields || \r
+ !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD))\r
+ return 0;\r
+ return (buf->fields[slot].cbsize);\r
+}\r
+\r
+void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot)\r
+{\r
+ if(slot >= buf->n_fields || \r
+ !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD))\r
+ return;\r
+\r
+ (buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA);\r
+}\r
+\r
+khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id)\r
+{\r
+ int i;\r
+\r
+ for(i=0; i < (int) buf->n_fields; i++) {\r
+ if(buf->fields[i].id == id)\r
+ break;\r
+ }\r
+\r
+ if(i < (int) buf->n_fields)\r
+ return i;\r
+ else\r
+ return KCDB_BUF_INVALID_SLOT;\r
+}\r
+\r
+/* API for accessing generic buffers */\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr(\r
+ khm_handle record, \r
+ khm_int32 attr_id, \r
+ khm_int32 * attr_type, \r
+ void * buffer, \r
+ khm_size * pcb_buf)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_get_attr(record, attr_id, attr_type, buffer, pcb_buf);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_get_attr(record, attr_id, attr_type, buffer, pcb_buf);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib(\r
+ khm_handle record,\r
+ wchar_t * attr_name,\r
+ khm_int32 * attr_type,\r
+ void * buffer,\r
+ khm_size * pcb_buf)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_get_attrib(record, attr_name, attr_type, buffer, pcb_buf);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_get_attrib(record, attr_name, attr_type, buffer, pcb_buf);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr_string(\r
+ khm_handle record,\r
+ khm_int32 attr_id,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_get_attr_string(record, attr_id, buffer, pcbbuf, flags);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_get_attr_string(record, attr_id, buffer, pcbbuf, flags);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib_string(\r
+ khm_handle record,\r
+ wchar_t * attr_name,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_get_attrib_string(record, attr_name, buffer, pcbbuf, flags);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_get_attrib_string(record, attr_name, buffer, pcbbuf, flags);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_set_attr(\r
+ khm_handle record,\r
+ khm_int32 attr_id,\r
+ void * buffer,\r
+ khm_size cbbuf)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_set_attr(record, attr_id, buffer, cbbuf);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_set_attr(record, attr_id, buffer, cbbuf);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_set_attrib(\r
+ khm_handle record,\r
+ wchar_t * attr_name,\r
+ void * buffer,\r
+ khm_size cbbuf)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_set_attrib(record, attr_name, buffer, cbbuf);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_set_attrib(record, attr_name, buffer, cbbuf);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_hold(khm_handle record)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_hold(record);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_hold(record);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_buf_release(khm_handle record)\r
+{\r
+ if(kcdb_cred_is_active_cred(record))\r
+ return kcdb_cred_release(record);\r
+ else if(kcdb_is_active_identity(record))\r
+ return kcdb_identity_release(record);\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_BUF_H\r
+#define __KHIMAIRA_KCDB_BUF_H\r
+\r
+typedef struct tag_kcdb_buf_field {\r
+ khm_ui_2 id;\r
+ khm_ui_2 flags;\r
+ khm_ui_4 offset;\r
+ khm_ui_4 cbsize;\r
+} kcdb_buf_field;\r
+\r
+#define KCDB_CREDF_FLAG_EMPTY 0\r
+#define KCDB_CREDF_FLAG_DATA 1\r
+#define KCDB_CREDF_FLAG_INLINE 2\r
+#define KCDB_CREDF_FLAG_ALLOCD 4\r
+\r
+#define KCDB_BUFF_ID_INVALID 0xffff\r
+\r
+typedef struct tag_kcdb_buf {\r
+ void * buffer;\r
+ khm_size cb_buffer;\r
+ khm_size cb_used;\r
+\r
+ kcdb_buf_field * fields;\r
+ khm_size n_fields;\r
+ khm_size nc_fields;\r
+} kcdb_buf;\r
+\r
+#define KCDB_BUF_CBBUF_INITIAL 4096\r
+#define KCDB_BUF_CBBUF_GROWTH 4096\r
+#define KCDB_BUF_FIELDS_INITIAL 16\r
+#define KCDB_BUF_FIELDS_GROWTH 16\r
+\r
+#define KCDB_BUF_APPEND 0x8000\r
+\r
+#define KCDB_BUF_INVALID_SLOT 0xf0000000\r
+#define KCDB_BUF_DEFAULT 0xe0000000\r
+\r
+#define KCDB_BUF_MAX_SLOTS 0x00004000\r
+\r
+void kcdb_buf_new(kcdb_buf * buf, khm_size n_slots);\r
+void kcdb_buf_delete(kcdb_buf * buf);\r
+void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize);\r
+void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src);\r
+void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src);\r
+int kcdb_buf_exist(kcdb_buf * buf, khm_size slot);\r
+int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot);\r
+void * kcdb_buf_get(kcdb_buf * buf, khm_size slot);\r
+khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot);\r
+void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot);\r
+khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+#include<assert.h>\r
+\r
+/* cs_creds protects the *collection* of credentials, while l_creds\r
+ protects the *contents* of individual credentials. */\r
+CRITICAL_SECTION cs_creds;\r
+kcdb_cred * kcdb_creds = NULL;\r
+\r
+/* a read lock must be obtained when querying any existing credential.\r
+ a write lock must be obtained when modifying any existing credential.\r
+ */\r
+RWLOCK l_creds;\r
+\r
+/* serial number */\r
+khm_ui_8 kcdb_cred_id = 0;\r
+\r
+void kcdb_cred_init(void)\r
+{\r
+ InitializeCriticalSection(&cs_creds);\r
+ InitializeRwLock(&l_creds);\r
+ kcdb_cred_id = 0;\r
+}\r
+\r
+void kcdb_cred_exit(void)\r
+{\r
+ /*TODO: Free the credentials */\r
+ DeleteCriticalSection(&cs_creds);\r
+ DeleteRwLock(&l_creds);\r
+}\r
+\r
+/*! \internal\r
+\r
+ can be called by kcdb_cred_dup with a write lock on l_creds and in other\r
+ places with a read lock on l_creds. New credentials must be creatable while\r
+ holding either lock. */\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_create(\r
+ wchar_t * name, \r
+ khm_handle identity,\r
+ khm_int32 cred_type,\r
+ khm_handle * result) \r
+{\r
+ kcdb_cred * cred;\r
+ size_t cb_name;\r
+\r
+ if(!name || !result ||\r
+ FAILED(StringCbLength(name, KCDB_CRED_MAXCB_NAME, &cb_name)) ||\r
+ KHM_FAILED(kcdb_credtype_get_info(cred_type, NULL)) ||\r
+ KHM_FAILED(kcdb_identity_hold(identity))\r
+ )\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ cb_name += sizeof(wchar_t);\r
+\r
+ cred = malloc(sizeof(kcdb_cred));\r
+ ZeroMemory(cred, sizeof(kcdb_cred));\r
+\r
+ cred->magic = KCDB_CRED_MAGIC;\r
+ cred->identity = identity;\r
+ cred->name = malloc(cb_name);\r
+ StringCbCopy(cred->name, cb_name, name);\r
+ cred->type = cred_type;\r
+\r
+ cred->refcount = 1; /* initially held */\r
+ \r
+ LINIT(cred);\r
+\r
+ kcdb_buf_new(&cred->buf, KCDB_ATTR_MAX_ID + 1);\r
+\r
+ /* Not obtaining a write lock on l_cred on purpose.\r
+ Well, because no one should be referencing this credential until\r
+ this function returns. */\r
+ EnterCriticalSection(&cs_creds);\r
+ cred->id = kcdb_cred_id++;\r
+ LPUSH(&kcdb_creds, cred);\r
+ LeaveCriticalSection(&cs_creds);\r
+\r
+ *result = cred;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_update(\r
+ khm_handle vdest,\r
+ khm_handle vsrc)\r
+{\r
+ khm_int32 rv = KHM_ERROR_EQUIVALENT;\r
+ kcdb_cred * src;\r
+ kcdb_cred * dest;\r
+ kcdb_type * t;\r
+ kcdb_attrib * a;\r
+ void * srcbuf;\r
+ void * destbuf;\r
+ khm_size cbsrcbuf;\r
+ khm_size cbdestbuf;\r
+\r
+ int i;\r
+\r
+ kcdb_cred_lock_write();\r
+\r
+ if(!kcdb_cred_is_active_cred(vsrc) ||\r
+ !kcdb_cred_is_active_cred(vdest))\r
+ goto _exit;\r
+\r
+ src = (kcdb_cred *) vsrc;\r
+ dest = (kcdb_cred *) vdest;\r
+\r
+ for(i=0;i<KCDB_ATTR_MAX_ID;i++) {\r
+ if(kcdb_cred_val_exist(src, i)) {\r
+ /*NOTE: the logic here has to reflect the logic in\r
+ kcdb_cred_set_attr() */\r
+ if(KHM_FAILED(kcdb_attrib_get_info(i, &a)))\r
+ continue;\r
+\r
+ if((a->flags & KCDB_ATTR_FLAG_COMPUTED) ||\r
+ KHM_FAILED(kcdb_type_get_info(a->type, &t))) {\r
+ kcdb_attrib_release_info(a);\r
+ continue;\r
+ }\r
+\r
+ srcbuf = kcdb_cred_buf_get(src,i);\r
+ cbsrcbuf = kcdb_cred_buf_size(src, i);\r
+\r
+ if(kcdb_cred_val_exist(dest, i)) {\r
+ destbuf = kcdb_cred_buf_get(dest, i);\r
+ cbdestbuf = kcdb_cred_buf_size(dest, i);\r
+\r
+ if(!t->comp(srcbuf, cbsrcbuf, destbuf, cbdestbuf))\r
+ goto _skip_copy;\r
+ }\r
+\r
+ kcdb_buf_set_value(&dest->buf, i, i, srcbuf, cbsrcbuf);\r
+ rv = KHM_ERROR_SUCCESS;\r
+\r
+_skip_copy:\r
+ kcdb_attrib_release_info(a);\r
+ kcdb_type_release_info(t);\r
+ }\r
+ }\r
+\r
+ if (dest->flags != src->flags) {\r
+ khm_int32 old_flags;\r
+\r
+ old_flags = dest->flags;\r
+\r
+ dest->flags = (src->flags & ~KCDB_CRED_FLAGMASK_ADDITIVE) |\r
+ ((src->flags | dest->flags) & KCDB_CRED_FLAGMASK_ADDITIVE);\r
+\r
+ if (dest->flags != old_flags)\r
+ rv = KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+_exit:\r
+ kcdb_cred_unlock_write();\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_dup(\r
+ khm_handle vcred,\r
+ khm_handle * pnewcred)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+ kcdb_cred * newcred;\r
+ khm_handle vnewcred;\r
+\r
+ if(!pnewcred)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ *pnewcred = NULL;\r
+\r
+ kcdb_cred_lock_write();\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ if(KHM_FAILED(kcdb_cred_create(\r
+ cred->name,\r
+ cred->identity,\r
+ cred->type,\r
+ &vnewcred))) \r
+ {\r
+ code = KHM_ERROR_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ newcred = (kcdb_cred *) vnewcred;\r
+\r
+ newcred->flags = cred->flags;\r
+\r
+ kcdb_buf_dup(&newcred->buf, &cred->buf);\r
+\r
+ /* newcred is already held from the call to kcdb_cred_create */\r
+ *pnewcred = (khm_handle) newcred;\r
+\r
+_exit:\r
+ kcdb_cred_unlock_write();\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_serial(\r
+ khm_handle vcred,\r
+ khm_ui_8 * pserial)\r
+{\r
+ kcdb_cred * c;\r
+\r
+ if(!pserial)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ LockObtainRead(&l_creds);\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ LockReleaseRead(&l_creds);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ c = (kcdb_cred *) vcred;\r
+\r
+ *pserial = c->id;\r
+\r
+ LockReleaseRead(&l_creds);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_identity(\r
+ khm_handle vcred,\r
+ khm_handle id)\r
+{\r
+ kcdb_cred * c;\r
+\r
+ if(!kcdb_is_identity(id))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ kcdb_cred_lock_write();\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ kcdb_cred_unlock_write();\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ c = (kcdb_cred *) vcred;\r
+\r
+ if(c->identity) {\r
+ kcdb_identity_release((khm_handle) c->identity);\r
+ }\r
+ kcdb_identity_hold(id);\r
+ c->identity = (kcdb_identity *) id;\r
+\r
+ kcdb_cred_unlock_write();\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_type(\r
+ khm_handle vcred,\r
+ khm_int32 * type)\r
+{\r
+ kcdb_cred * c;\r
+\r
+ if(!type)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ LockObtainRead(&l_creds);\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ LockReleaseRead(&l_creds);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ c = (kcdb_cred *) vcred;\r
+\r
+ *type = c->type;\r
+\r
+ LockReleaseRead(&l_creds);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_attrib(\r
+ khm_handle cred, \r
+ wchar_t * name, \r
+ void * buffer, \r
+ khm_size cbbuf)\r
+{\r
+ khm_int32 attr_id = -1;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ return kcdb_cred_set_attr(\r
+ cred,\r
+ attr_id,\r
+ buffer,\r
+ cbbuf);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_attr(\r
+ khm_handle vcred, \r
+ khm_int32 attr_id, \r
+ void * buffer, \r
+ khm_size cbbuf)\r
+{\r
+ kcdb_cred * cred;\r
+ kcdb_type * type = NULL;\r
+ kcdb_attrib * attrib = NULL;\r
+ khm_size cbdest;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+\r
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ kcdb_cred_lock_write();\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ kcdb_cred_unlock_write();\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {\r
+ kcdb_cred_unlock_write();\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)\r
+ {\r
+ kcdb_cred_unlock_write();\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+ }\r
+\r
+ if (buffer == 0) {\r
+ /* we are removing the value */\r
+ kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0);\r
+ code = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {\r
+ kcdb_cred_unlock_write();\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(!(type->isValid(buffer,cbbuf))) {\r
+ code = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+\r
+ if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ kcdb_buf_alloc(&cred->buf, attr_id, attr_id, cbdest);\r
+ if(!kcdb_cred_buf_exist(cred, attr_id)) {\r
+ code = KHM_ERROR_NO_RESOURCES;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(code =\r
+ type->dup(buffer, cbbuf, kcdb_cred_buf_get(cred,attr_id), &cbdest))) \r
+ {\r
+ kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0);\r
+ goto _exit;\r
+ }\r
+\r
+ kcdb_buf_set_value_flag(&cred->buf, attr_id);\r
+\r
+_exit:\r
+ kcdb_cred_unlock_write();\r
+\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib(\r
+ khm_handle cred, \r
+ wchar_t * name, \r
+ khm_int32 * attr_type,\r
+ void * buffer, \r
+ khm_size * cbbuf) \r
+{\r
+ khm_int32 attr_id = -1;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ return kcdb_cred_get_attr(\r
+ cred,\r
+ attr_id,\r
+ attr_type,\r
+ buffer,\r
+ cbbuf);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib_string(\r
+ khm_handle cred, \r
+ wchar_t * name, \r
+ wchar_t * buffer, \r
+ khm_size * cbbuf,\r
+ khm_int32 flags) \r
+{\r
+ khm_int32 attr_id = -1;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ return kcdb_cred_get_attr_string(\r
+ cred,\r
+ attr_id,\r
+ buffer,\r
+ cbbuf,\r
+ flags);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr(\r
+ khm_handle vcred, \r
+ khm_int32 attr_id,\r
+ khm_int32 * attr_type,\r
+ void * buffer, \r
+ khm_size * pcbbuf)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred = NULL;\r
+ kcdb_attrib * attrib = NULL;\r
+ kcdb_type * type = NULL;\r
+\r
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_UNKNOWN;\r
+ }\r
+\r
+ if(attr_type)\r
+ *attr_type = attrib->type;\r
+\r
+ LockObtainRead(&l_creds);\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ if(!buffer && !pcbbuf) {\r
+ /* in this case the caller is only trying to determine if the\r
+ field contains data. We assume that computed fields are\r
+ always non-null. */\r
+ code = (kcdb_cred_val_exist(cred, attr_id) ||\r
+ (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;\r
+ goto _exit;\r
+ }\r
+\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {\r
+ code = attrib->compute_cb(\r
+ vcred,\r
+ attr_id,\r
+ buffer,\r
+ pcbbuf);\r
+ } else if (kcdb_cred_val_exist(cred, attr_id)) {\r
+ code = type->dup(\r
+ kcdb_cred_buf_get(cred, attr_id),\r
+ kcdb_cred_buf_size(cred, attr_id),\r
+ buffer,\r
+ pcbbuf);\r
+ } else {\r
+ code = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+_exit:\r
+ LockReleaseRead(&l_creds);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr_string(\r
+ khm_handle vcred, \r
+ khm_int32 attr_id,\r
+ wchar_t * buffer, \r
+ khm_size * pcbbuf,\r
+ khm_int32 flags)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred = NULL;\r
+ kcdb_attrib * attrib = NULL;\r
+ kcdb_type * type = NULL;\r
+\r
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {\r
+ code = KHM_ERROR_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ LockObtainRead(&l_creds);\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ if(!buffer && !pcbbuf) {\r
+ /* in this case the caller is only trying to determine if the field\r
+ contains data. We assume that computed fields are always non-null. */\r
+ code = (kcdb_cred_val_exist(cred, attr_id) ||\r
+ (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;\r
+ goto _exit;\r
+ }\r
+\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {\r
+ void * buf;\r
+ khm_size cbbuf;\r
+\r
+ code = attrib->compute_cb(\r
+ vcred,\r
+ attr_id,\r
+ NULL,\r
+ &cbbuf);\r
+ if(code == KHM_ERROR_TOO_LONG) {\r
+ buf = malloc(cbbuf);\r
+ code = attrib->compute_cb(\r
+ vcred,\r
+ attr_id,\r
+ buf,\r
+ &cbbuf);\r
+ if(KHM_SUCCEEDED(code)) {\r
+ code = type->toString(\r
+ buf,\r
+ cbbuf,\r
+ buffer,\r
+ pcbbuf,\r
+ flags);\r
+ }\r
+ free(buf);\r
+ }\r
+ } else {\r
+ if(kcdb_cred_buf_exist(cred, attr_id)) {\r
+ code = type->toString(\r
+ kcdb_cred_buf_get(cred, attr_id),\r
+ kcdb_cred_buf_size(cred, attr_id),\r
+ buffer,\r
+ pcbbuf,\r
+ flags);\r
+ } else\r
+ code = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+_exit:\r
+ LockReleaseRead(&l_creds);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+\r
+ return code;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_name(\r
+ khm_handle vcred, \r
+ wchar_t * buffer, \r
+ khm_size * cbbuf)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred = NULL;\r
+ size_t cbsize;\r
+\r
+ if(!cbbuf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ LockObtainRead(&l_creds);\r
+ \r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ if(FAILED(StringCbLength(cred->name, KCDB_CRED_MAXCB_NAME, &cbsize))) {\r
+ code = KHM_ERROR_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cbbuf < cbsize) {\r
+ *cbbuf = cbsize;\r
+ code = KHM_ERROR_TOO_LONG;\r
+ goto _exit;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cbbuf, cred->name);\r
+\r
+ *cbbuf = cbsize;\r
+\r
+_exit:\r
+\r
+ LockReleaseRead(&l_creds);\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_identity(\r
+ khm_handle vcred, \r
+ khm_handle * identity)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+\r
+ if(!identity)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ LockObtainRead(&l_creds);\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ kcdb_identity_hold((khm_handle) cred->identity);\r
+\r
+ *identity = cred->identity;\r
+ \r
+_exit:\r
+ LockReleaseRead(&l_creds);\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_hold(khm_handle vcred)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+\r
+ kcdb_cred_lock_write();\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ cred->refcount++;\r
+\r
+_exit:\r
+ kcdb_cred_unlock_write();\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_release(khm_handle vcred)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+\r
+ kcdb_cred_lock_write();\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ cred->refcount--;\r
+\r
+_exit:\r
+ kcdb_cred_unlock_write();\r
+\r
+ kcdb_cred_check_and_delete(vcred);\r
+ \r
+ return code;\r
+}\r
+\r
+void kcdb_cred_check_and_delete(khm_handle vcred)\r
+{\r
+ kcdb_cred * cred;\r
+\r
+ LockObtainRead(&l_creds);\r
+ if(!kcdb_cred_is_cred(vcred)) {\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ if(!(cred->flags & KCDB_CRED_FLAG_DELETED))\r
+ goto _exit;\r
+\r
+ if(cred->refcount)\r
+ goto _exit;\r
+\r
+ LockReleaseRead(&l_creds);\r
+ kcdb_cred_lock_write();\r
+ if(!kcdb_cred_is_cred(vcred)) {\r
+ /* did we lose the race? */\r
+ goto _exit2;\r
+ }\r
+\r
+ cred->magic = 0; /* no longer a cred */\r
+ kcdb_identity_release(cred->identity);\r
+\r
+ EnterCriticalSection(&cs_creds);\r
+ LDELETE(&kcdb_creds, cred);\r
+ LeaveCriticalSection(&cs_creds);\r
+\r
+ kcdb_buf_delete(&cred->buf);\r
+ free(cred->name);\r
+ free(cred);\r
+\r
+ /*TODO: notifications */\r
+\r
+_exit2:\r
+ kcdb_cred_unlock_write();\r
+ return;\r
+\r
+_exit:\r
+ LockReleaseRead(&l_creds);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_delete(khm_handle vcred)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+\r
+ kcdb_cred_lock_write();\r
+\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = (kcdb_cred *) vcred;\r
+\r
+ cred->flags |= KCDB_CRED_FLAG_DELETED;\r
+\r
+_exit:\r
+ kcdb_cred_unlock_write();\r
+\r
+ kcdb_cred_check_and_delete(vcred);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_creds_comp_attrib(\r
+ khm_handle cred1, \r
+ khm_handle cred2, \r
+ wchar_t * name)\r
+{\r
+ khm_int32 attr_id;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))\r
+ return 0;\r
+\r
+ return kcdb_creds_comp_attr(cred1, cred2, attr_id);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_creds_comp_attr(\r
+ khm_handle vcred1, \r
+ khm_handle vcred2, \r
+ khm_int32 attr_id)\r
+{\r
+ khm_int32 code = 0;\r
+ kcdb_cred * cred1;\r
+ kcdb_cred * cred2;\r
+ kcdb_attrib * attrib = NULL;\r
+ kcdb_type * type = NULL;\r
+\r
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)\r
+ return 0;\r
+\r
+ cred1 = (kcdb_cred *) vcred1;\r
+ cred2 = (kcdb_cred *) vcred2;\r
+\r
+ LockObtainRead(&l_creds);\r
+ if(\r
+ !kcdb_cred_is_active_cred(vcred1) ||\r
+ !kcdb_cred_is_active_cred(vcred2))\r
+ goto _exit;\r
+\r
+ cred1 = (kcdb_cred *) vcred1;\r
+ cred2 = (kcdb_cred *) vcred2;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib)))\r
+ goto _exit;\r
+\r
+ if(!(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)) {\r
+ int nc = 0;\r
+\r
+ if(!kcdb_cred_val_exist(cred1, attr_id)) {\r
+ code = -1;\r
+ nc = 1;\r
+ }\r
+ if(!kcdb_cred_val_exist(cred2, attr_id)) {\r
+ code += 1;\r
+ nc = 1;\r
+ }\r
+\r
+ if(nc)\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type)))\r
+ goto _exit;\r
+\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {\r
+ void * buf1 = NULL;\r
+ void * buf2 = NULL;\r
+ khm_size cb1;\r
+ khm_size cb2;\r
+\r
+ code = 0;\r
+\r
+ if(attrib->compute_cb(vcred1, attr_id, NULL, &cb1) != KHM_ERROR_TOO_LONG)\r
+ goto _exit_1;\r
+\r
+ if(attrib->compute_cb(vcred2, attr_id, NULL, &cb2) != KHM_ERROR_TOO_LONG)\r
+ goto _exit_1;\r
+\r
+ if(cb1) {\r
+ buf1 = malloc(cb1);\r
+ if(KHM_FAILED(attrib->compute_cb(vcred1, attr_id, buf1, &cb1)))\r
+ goto _exit_1;\r
+ }\r
+ if(cb2) {\r
+ buf2 = malloc(cb2);\r
+ if(KHM_FAILED(attrib->compute_cb(vcred2, attr_id, buf2, &cb2)))\r
+ goto _exit_1;\r
+ }\r
+ code = type->comp(\r
+ buf1, cb1,\r
+ buf2, cb2);\r
+_exit_1:\r
+ if(buf1)\r
+ free(buf1);\r
+ if(buf2)\r
+ free(buf2);\r
+\r
+ } else {\r
+ code = type->comp(\r
+ kcdb_cred_buf_get(cred1, attr_id),\r
+ kcdb_cred_buf_size(cred1, attr_id),\r
+ kcdb_cred_buf_get(cred2, attr_id),\r
+ kcdb_cred_buf_size(cred2, attr_id));\r
+ }\r
+\r
+_exit:\r
+ LockReleaseRead(&l_creds);\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_creds_is_equal(\r
+ khm_handle vcred1,\r
+ khm_handle vcred2)\r
+{\r
+ khm_int32 code = 0;\r
+ kcdb_cred * cred1;\r
+ kcdb_cred * cred2;\r
+\r
+ LockObtainRead(&l_creds);\r
+ if(!kcdb_cred_is_active_cred(vcred1) ||\r
+ !kcdb_cred_is_active_cred(vcred2))\r
+ goto _exit;\r
+\r
+ if(vcred1 == vcred2) {\r
+ code = TRUE;\r
+ goto _exit;\r
+ }\r
+\r
+ cred1 = vcred1;\r
+ cred2 = vcred2;\r
+\r
+ if(cred1->identity == cred2->identity &&\r
+ cred1->type == cred2->type &&\r
+ !wcscmp(cred1->name, cred2->name)) {\r
+ code = TRUE;\r
+ }\r
+\r
+_exit:\r
+ LockReleaseRead(&l_creds);\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_flags(\r
+ khm_handle vcred,\r
+ khm_int32 * pflags)\r
+{\r
+ khm_int32 f;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+ int release_lock = TRUE;\r
+\r
+ if (pflags == NULL)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ LockObtainRead(&l_creds);\r
+ if (!kcdb_cred_is_active_cred(vcred)) {\r
+ *pflags = 0;\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = vcred;\r
+ f = cred->flags;\r
+\r
+ /* Update flags if necessary */\r
+\r
+ if (!(f & KCDB_CRED_FLAG_EXPIRED) && \r
+ kcdb_cred_buf_exist(cred, KCDB_ATTR_EXPIRE)) {\r
+\r
+ khm_int64 ftc;\r
+ \r
+ GetSystemTimeAsFileTime((LPFILETIME) &ftc);\r
+ if (ftc > *((khm_int64 *) \r
+ kcdb_cred_buf_get(cred, KCDB_ATTR_EXPIRE)))\r
+ f |= KCDB_CRED_FLAG_EXPIRED;\r
+ }\r
+\r
+#if 0\r
+ /* Commented out: if the credential has expired, then checking the\r
+ renewable time is not useful */\r
+ if (!(f & KCDB_CRED_FLAG_INVALID)) {\r
+ if (f & KCDB_CRED_FLAG_RENEWABLE) {\r
+ if (kcdb_cred_buf_exist(cred, KCDB_ATTR_RENEW_EXPIRE)) {\r
+ khm_int64 ftc;\r
+\r
+ GetSystemTimeAsFileTime((LPFILETIME) &ftc);\r
+ if (ftc > *((khm_int64 *) kcdb_cred_buf_get(cred, KCDB_ATTR_RENEW_EXPIRE)))\r
+ f |= KCDB_CRED_FLAG_INVALID;\r
+ }\r
+ } else {\r
+ if (f & KCDB_CRED_FLAG_EXPIRED)\r
+ f |= KCDB_CRED_FLAG_INVALID;\r
+ }\r
+ }\r
+\r
+ /* Commented out: this is a read operation. We shouldn't attempt\r
+ to lock for writing */\r
+ if (f != cred->flags) {\r
+ LockReleaseRead(&l_creds);\r
+ LockObtainWrite(&l_creds);\r
+ /* Did we lose a race? */\r
+ if (kcdb_cred_is_active_cred(vcred))\r
+ cred->flags = f;\r
+ else {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ f = 0;\r
+ }\r
+ LockReleaseWrite(&l_creds);\r
+ release_lock = FALSE;\r
+ }\r
+#endif\r
+\r
+ *pflags = f;\r
+\r
+ _exit:\r
+ if (release_lock)\r
+ LockReleaseRead(&l_creds);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_flags(\r
+ khm_handle vcred,\r
+ khm_int32 flags,\r
+ khm_int32 mask)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ kcdb_cred * cred;\r
+\r
+ LockObtainWrite(&l_creds);\r
+ if(!kcdb_cred_is_active_cred(vcred)) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ cred = vcred;\r
+\r
+ flags &= ~(KCDB_CRED_FLAG_DELETED);\r
+ mask &= ~(KCDB_CRED_FLAG_DELETED);\r
+\r
+ cred->flags =\r
+ (cred->flags & (~mask)) |\r
+ (flags & mask);\r
+\r
+ _exit:\r
+ LockReleaseWrite(&l_creds);\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_CREDENTIAL_H\r
+#define __KHIMAIRA_KCDB_CREDENTIAL_H\r
+\r
+/* Credentials */\r
+\r
+typedef struct kcdb_cred_t {\r
+ khm_int32 magic;\r
+ khm_ui_8 id; /* serial number */\r
+ kcdb_identity * identity;\r
+ khm_int32 type;\r
+ wchar_t * name;\r
+\r
+ khm_int32 flags;\r
+ khm_int32 refcount;\r
+\r
+ kcdb_buf buf;\r
+\r
+ LDCL(struct kcdb_cred_t);\r
+} kcdb_cred;\r
+\r
+#define KCDB_CRED_MAGIC 0x38fb84a6\r
+\r
+extern CRITICAL_SECTION cs_creds;\r
+extern kcdb_cred * kcdb_creds;\r
+extern RWLOCK l_creds;\r
+extern khm_ui_8 kcdb_cred_id;\r
+\r
+#define kcdb_cred_val_exist(c,a) kcdb_buf_val_exist(&(c)->buf, a)\r
+#define kcdb_cred_buf_exist(c,a) kcdb_buf_exist(&(c)->buf, a)\r
+#define kcdb_cred_buf_get(c,a) kcdb_buf_get(&(c)->buf, a)\r
+#define kcdb_cred_buf_size(c,a) kcdb_buf_size(&(c)->buf, a)\r
+\r
+#define kcdb_cred_is_cred(c) ((c) && ((kcdb_cred *) c)->magic == KCDB_CRED_MAGIC)\r
+#define kcdb_cred_is_active_cred(c) (kcdb_cred_is_cred(c) && !(((kcdb_cred *) c)->flags & KCDB_CRED_FLAG_DELETED))\r
+#define kcdb_cred_lock_read() (LockObtainRead(&l_creds))\r
+#define kcdb_cred_unlock_read() (LockReleaseRead(&l_creds))\r
+#define kcdb_cred_lock_write() (LockObtainWrite(&l_creds))\r
+#define kcdb_cred_unlock_write() (LockReleaseWrite(&l_creds))\r
+\r
+void kcdb_cred_init(void);\r
+void kcdb_cred_exit(void);\r
+void kcdb_cred_check_and_delete(khm_handle vcred);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+#include<assert.h>\r
+\r
+CRITICAL_SECTION cs_credset;\r
+kcdb_credset * kcdb_credsets = NULL;\r
+kcdb_credset * kcdb_root_credset = NULL;\r
+\r
+void kcdb_credset_init(void)\r
+{\r
+ khm_handle rc;\r
+\r
+ InitializeCriticalSection(&cs_credset);\r
+ kcdb_credsets = NULL;\r
+\r
+ kcdb_credset_create(&rc);\r
+ kcdb_root_credset = (kcdb_credset *) rc;\r
+ kcdb_root_credset->flags |= KCDB_CREDSET_FLAG_ROOT;\r
+}\r
+\r
+void kcdb_credset_exit(void)\r
+{\r
+ /*TODO: free the credsets */\r
+ DeleteCriticalSection(&cs_credset);\r
+}\r
+\r
+/* called on an unreleased credset, or with credset::cs held */\r
+void kcdb_credset_buf_new(kcdb_credset * cs)\r
+{\r
+ cs->clist = malloc(KCDB_CREDSET_INITIAL_SIZE * sizeof(kcdb_credset_credref));\r
+ ZeroMemory(cs->clist, KCDB_CREDSET_INITIAL_SIZE * sizeof(kcdb_credset_credref));\r
+ cs->nc_clist = KCDB_CREDSET_INITIAL_SIZE;\r
+ cs->nclist = 0;\r
+}\r
+\r
+/* called on an unreleased credset, or with credset::cs held */\r
+void kcdb_credset_buf_delete(kcdb_credset * cs)\r
+{\r
+ free(cs->clist);\r
+ cs->nc_clist = 0;\r
+ cs->nclist = 0;\r
+}\r
+\r
+void kcdb_credset_buf_assert_size(kcdb_credset * cs, khm_int32 nclist)\r
+{\r
+ if(cs->nc_clist < nclist) {\r
+ kcdb_credset_credref * new_clist;\r
+ \r
+ /* nclist had better be greater than KCDB_CREDSET_INITIAL_SIZE */\r
+ nclist = KCDB_CREDSET_INITIAL_SIZE + \r
+ (((nclist - (KCDB_CREDSET_INITIAL_SIZE + 1)) / KCDB_CREDSET_GROWTH_FACTOR) + 1) *\r
+ KCDB_CREDSET_GROWTH_FACTOR;\r
+\r
+ new_clist = calloc(nclist, sizeof(kcdb_credset_credref));\r
+\r
+ memcpy(new_clist, cs->clist, cs->nclist * sizeof(kcdb_credset_credref));\r
+\r
+ free(cs->clist);\r
+\r
+ cs->clist = new_clist;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result)\r
+{\r
+ kcdb_credset * cs;\r
+\r
+ cs = malloc(sizeof(kcdb_credset));\r
+ ZeroMemory(cs, sizeof(kcdb_credset));\r
+\r
+ cs->magic = KCDB_CREDSET_MAGIC;\r
+ InitializeCriticalSection(&(cs->cs));\r
+ LINIT(cs);\r
+ kcdb_credset_buf_new(cs);\r
+ cs->version = 0;\r
+ cs->seal_count = 0;\r
+\r
+ EnterCriticalSection(&cs_credset);\r
+ LPUSH(&kcdb_credsets, cs);\r
+ LeaveCriticalSection(&cs_credset);\r
+\r
+ *result = (khm_handle) cs;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_delete(khm_handle vcredset)\r
+{\r
+ kcdb_credset * cs;\r
+ int i;\r
+\r
+ if(!kcdb_credset_is_credset(vcredset)) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ cs = (kcdb_credset *) vcredset;\r
+\r
+ EnterCriticalSection(&cs_credset);\r
+ LDELETE(&kcdb_credsets, cs);\r
+ LeaveCriticalSection(&cs_credset);\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+ cs->magic = 0;\r
+\r
+ for(i=0;i<cs->nclist;i++) {\r
+ if(cs->clist[i].cred) {\r
+ kcdb_cred_release((khm_handle) cs->clist[i].cred);\r
+ }\r
+ }\r
+ kcdb_credset_buf_delete(cs);\r
+\r
+ LeaveCriticalSection(&(cs->cs));\r
+ DeleteCriticalSection(&(cs->cs));\r
+\r
+ free(cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/*! \internal\r
+\r
+Collect credentials from cs2 to cs1 which have already been selected into\r
+cl1 and cl2.\r
+\r
+- Credentials in cl2 that are not in cl1 will get added to cs1\r
+- Credentials in cl1 that are not in cl2 will get removed from cs1\r
+- Credentials in cl1 and cl2 will be updated in cs1\r
+\r
+cl1 and cl2 will be modified.\r
+*/\r
+khm_int32 kcdb_credset_collect_core(\r
+ kcdb_credset * cs1,\r
+ kcdb_cred ** cl1,\r
+ khm_int32 ncl1,\r
+ kcdb_credset * cs2,\r
+ kcdb_cred ** cl2,\r
+ khm_int32 ncl2,\r
+ khm_int32 * delta)\r
+{\r
+ int i, j;\r
+ int ldelta = 0;\r
+ khm_int32 rv;\r
+\r
+ /* find matching creds and update them */\r
+ for(i=0; i<ncl1; i++) \r
+ if(cl1[i]) {\r
+ for(j=0; j<ncl2; j++) \r
+ if(cl2[j] && kcdb_creds_is_equal((khm_handle) cl1[i], (khm_handle) cl2[j])) {\r
+ /* they are equivalent. make them equal */\r
+\r
+ /* depending on whether any changes were made,\r
+ update ldelta with the proper bit flag */\r
+\r
+ rv = kcdb_cred_update(cl1[i], cl2[j]);\r
+ if (rv == KHM_ERROR_SUCCESS) {\r
+ kcdb_credset_update_cred_ref((khm_handle) cs1, (khm_handle) cl1[i]);\r
+ ldelta |= KCDB_DELTA_MODIFY;\r
+ }\r
+\r
+ cl2[j] = NULL;\r
+ cl1[i] = NULL;\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* all the creds that are left in cl1 need to be removed */\r
+ for(i=0; i<ncl1; i++)\r
+ if(cl1[i]) {\r
+ kcdb_credset_del_cred_ref((khm_handle) cs1, (khm_handle) cl1[i]);\r
+ cl1[i] = NULL;\r
+ ldelta |= KCDB_DELTA_DEL;\r
+ }\r
+\r
+ /* all the creds in cl2 need to be added to cs1 */\r
+ for(j=0; j<ncl2; j++)\r
+ if(cl2[j]) {\r
+ /* duplicate the credential and add it if we are adding it to the\r
+ root credential store. */\r
+ if(cs1 == kcdb_root_credset) {\r
+ khm_handle h;\r
+\r
+ if(KHM_SUCCEEDED(kcdb_cred_dup((khm_handle) cl2[j], &h))) {\r
+ kcdb_credset_add_cred((khm_handle) cs1, h, -1);\r
+ kcdb_cred_release(h);\r
+ }\r
+ } else\r
+ kcdb_credset_add_cred((khm_handle) cs1, cl2[j], -1);\r
+ cl2[j] = NULL;\r
+ ldelta |= KCDB_DELTA_ADD;\r
+ }\r
+\r
+ if(delta)\r
+ *delta = ldelta;\r
+\r
+ if((cs1 == kcdb_root_credset) && ldelta) {\r
+ /* something changed in the root credential set */\r
+ kmq_post_message(KMSG_CRED,KMSG_CRED_ROOTDELTA,ldelta,NULL);\r
+ }\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_collect(\r
+ khm_handle cs_dest,\r
+ khm_handle cs_src, \r
+ khm_handle identity, \r
+ khm_int32 type,\r
+ khm_int32 * delta)\r
+{\r
+ kcdb_credset * cs;\r
+ kcdb_credset * rcs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred ** r_sel = NULL;\r
+ kcdb_cred ** c_sel = NULL;\r
+ int nr_sel, nc_sel;\r
+ int i;\r
+\r
+ if((cs_src && !kcdb_credset_is_credset(cs_src)) ||\r
+ (cs_dest && !kcdb_credset_is_credset(cs_dest)) ||\r
+ (cs_src == cs_dest)) /* works because credsets use shared\r
+ handles */\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(identity && !kcdb_is_active_identity(identity))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(cs_src)\r
+ cs = (kcdb_credset *) cs_src;\r
+ else\r
+ cs = kcdb_root_credset;\r
+\r
+ if(cs_dest)\r
+ rcs = (kcdb_credset *) cs_dest;\r
+ else\r
+ rcs = kcdb_root_credset;\r
+\r
+ if (kcdb_credset_is_sealed(rcs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+ EnterCriticalSection(&(rcs->cs));\r
+\r
+ /* enumerate through the root and given credential sets and select\r
+ the ones we want */\r
+\r
+ if(rcs->nclist > 0)\r
+ r_sel = malloc(sizeof(kcdb_cred *) * rcs->nclist);\r
+ if(cs->nclist > 0)\r
+ c_sel = malloc(sizeof(kcdb_cred *) * cs->nclist);\r
+ nr_sel = 0;\r
+ nc_sel = 0;\r
+\r
+ for(i=0; i<rcs->nclist; i++) {\r
+ if(rcs->clist[i].cred &&\r
+ (!identity || rcs->clist[i].cred->identity == identity) &&\r
+ (type==KCDB_CREDTYPE_ALL || rcs->clist[i].cred->type == type))\r
+ {\r
+ r_sel[nr_sel++] = rcs->clist[i].cred;\r
+ }\r
+ }\r
+\r
+ for(i=0; i<cs->nclist; i++) {\r
+ if(cs->clist[i].cred &&\r
+ (!identity || cs->clist[i].cred->identity == identity) &&\r
+ (type==KCDB_CREDTYPE_ALL || cs->clist[i].cred->type == type))\r
+ {\r
+ c_sel[nc_sel++] = cs->clist[i].cred;\r
+ }\r
+ }\r
+\r
+ rcs->version++;\r
+\r
+ code = kcdb_credset_collect_core(\r
+ rcs,\r
+ r_sel,\r
+ nr_sel,\r
+ cs,\r
+ c_sel,\r
+ nc_sel,\r
+ delta);\r
+\r
+ LeaveCriticalSection(&(rcs->cs));\r
+ LeaveCriticalSection(&(cs->cs));\r
+\r
+ if(r_sel)\r
+ free(r_sel);\r
+ if(c_sel)\r
+ free(c_sel);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_collect_filtered(\r
+ khm_handle cs_dest,\r
+ khm_handle cs_src,\r
+ kcdb_cred_filter_func filter,\r
+ void * rock,\r
+ khm_int32 * delta)\r
+{\r
+ kcdb_credset * cs;\r
+ kcdb_credset * rcs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_cred ** r_sel = NULL;\r
+ kcdb_cred ** c_sel = NULL;\r
+ int nr_sel, nc_sel;\r
+ int i;\r
+ khm_int32 cs_f = 0;\r
+ khm_int32 rcs_f = 0;\r
+\r
+ if((cs_src && !kcdb_credset_is_credset(cs_src)) ||\r
+ (cs_dest && !kcdb_credset_is_credset(cs_dest)) ||\r
+ (cs_src == cs_dest)) /* works because credsets use shared\r
+ handles */\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(cs_src)\r
+ cs = (kcdb_credset *) cs_src;\r
+ else {\r
+ cs = kcdb_root_credset;\r
+ cs_f = KCDB_CREDCOLL_FILTER_ROOT;\r
+ }\r
+\r
+ if(cs_dest)\r
+ rcs = (kcdb_credset *) cs_dest;\r
+ else {\r
+ rcs = kcdb_root_credset;\r
+ rcs_f = KCDB_CREDCOLL_FILTER_ROOT;\r
+ }\r
+\r
+ if (kcdb_credset_is_sealed(rcs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+ EnterCriticalSection(&(rcs->cs));\r
+\r
+#ifdef DEBUG\r
+ assert(!(rcs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ if(rcs->nclist)\r
+ r_sel = malloc(sizeof(kcdb_cred *) * rcs->nclist);\r
+ if(cs->nclist)\r
+ c_sel = malloc(sizeof(kcdb_cred *) * cs->nclist);\r
+ nr_sel = 0;\r
+ nc_sel = 0;\r
+\r
+ rcs->flags |= KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ for(i=0; i<rcs->nclist; i++) {\r
+ if(rcs->clist[i].cred && \r
+ (*filter)((khm_handle)rcs->clist[i].cred, \r
+ KCDB_CREDCOLL_FILTER_DEST | rcs_f, \r
+ rock))\r
+ {\r
+ r_sel[nr_sel++] = rcs->clist[i].cred;\r
+ }\r
+ }\r
+\r
+ rcs->flags &= ~KCDB_CREDSET_FLAG_ENUM;\r
+ cs->flags |= KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ for(i=0; i<cs->nclist; i++) {\r
+ if(cs->clist[i].cred && filter((khm_handle)rcs->clist[i].cred, KCDB_CREDCOLL_FILTER_SRC | cs_f, rock))\r
+ {\r
+ c_sel[nc_sel++] = cs->clist[i].cred;\r
+ }\r
+ }\r
+\r
+ cs->flags &= ~KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ rcs->version++;\r
+\r
+ code = kcdb_credset_collect_core(\r
+ rcs,\r
+ r_sel,\r
+ nr_sel,\r
+ cs,\r
+ c_sel,\r
+ nc_sel,\r
+ delta);\r
+\r
+ LeaveCriticalSection(&(rcs->cs));\r
+ LeaveCriticalSection(&(cs->cs));\r
+\r
+ if(r_sel)\r
+ free(r_sel);\r
+ if(c_sel)\r
+ free(c_sel);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_flush(khm_handle vcredset)\r
+{\r
+ int i;\r
+ kcdb_credset * cs;\r
+\r
+ if(!kcdb_credset_is_credset(vcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) vcredset;\r
+\r
+ if (kcdb_credset_is_sealed(cs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+\r
+#ifdef DEBUG\r
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ for(i=0;i<cs->nclist;i++) {\r
+ if(cs->clist[i].cred) {\r
+ kcdb_cred_release((khm_handle) cs->clist[i].cred);\r
+ }\r
+ }\r
+ cs->nclist = 0;\r
+ LeaveCriticalSection(&(cs->cs));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_extract(\r
+ khm_handle destcredset, \r
+ khm_handle sourcecredset, \r
+ khm_handle identity, \r
+ khm_int32 type)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_credset * dest;\r
+ kcdb_credset * src;\r
+ int isRoot = 0;\r
+ khm_size srcSize = 0;\r
+ int i;\r
+\r
+ if(!kcdb_credset_is_credset(destcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(sourcecredset) {\r
+ if(!kcdb_credset_is_credset(sourcecredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ } else {\r
+ sourcecredset = kcdb_root_credset;\r
+ }\r
+\r
+ if (sourcecredset == kcdb_root_credset)\r
+ isRoot = 1;\r
+\r
+ src = (kcdb_credset *) sourcecredset;\r
+ dest = (kcdb_credset *) destcredset;\r
+\r
+ if (kcdb_credset_is_sealed(dest))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(src->cs));\r
+ EnterCriticalSection(&(dest->cs));\r
+\r
+#ifdef DEBUG\r
+ assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) {\r
+ code = KHM_ERROR_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ kcdb_cred_lock_read();\r
+\r
+ for(i=0; i < (int) srcSize; i++) {\r
+ kcdb_cred * c;\r
+\r
+ c = src->clist[i].cred;\r
+ if(kcdb_cred_is_active_cred((khm_handle) c) &&\r
+ (!identity || c->identity == identity) &&\r
+ (type==KCDB_TYPE_INVALID || c->type == type))\r
+ {\r
+ if(isRoot) {\r
+ khm_handle newcred;\r
+\r
+ kcdb_cred_unlock_read();\r
+ kcdb_cred_dup((khm_handle) c, &newcred);\r
+ kcdb_credset_add_cred(destcredset, newcred, -1);\r
+ kcdb_cred_release(newcred);\r
+ kcdb_cred_lock_read();\r
+ } else {\r
+ kcdb_cred_unlock_read();\r
+ kcdb_credset_add_cred(destcredset, (khm_handle) c, -1);\r
+ kcdb_cred_lock_read();\r
+ }\r
+ }\r
+ }\r
+\r
+ kcdb_cred_unlock_read();\r
+\r
+_exit:\r
+ LeaveCriticalSection(&(dest->cs));\r
+ LeaveCriticalSection(&(src->cs));\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_extract_filtered(\r
+ khm_handle destcredset,\r
+ khm_handle sourcecredset,\r
+ kcdb_cred_filter_func filter,\r
+ void * rock)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_credset * dest;\r
+ kcdb_credset * src;\r
+ int isRoot = 0;\r
+ khm_size srcSize = 0;\r
+ int i;\r
+\r
+ if(!kcdb_credset_is_credset(destcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(sourcecredset) {\r
+ if(!kcdb_credset_is_credset(sourcecredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ } else {\r
+ sourcecredset = kcdb_root_credset;\r
+ isRoot = 1;\r
+ }\r
+\r
+ src = (kcdb_credset *) sourcecredset;\r
+ dest = (kcdb_credset *) destcredset;\r
+\r
+ if (kcdb_credset_is_sealed(dest))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(src->cs));\r
+ EnterCriticalSection(&(dest->cs));\r
+\r
+#ifdef DEBUG\r
+ assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) {\r
+ code = KHM_ERROR_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ kcdb_cred_lock_read();\r
+\r
+ dest->flags |= KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ for(i=0; i < (int) srcSize; i++) {\r
+ kcdb_cred * c;\r
+\r
+ c = src->clist[i].cred;\r
+ if(kcdb_cred_is_active_cred((khm_handle) c) &&\r
+ filter(c, 0, rock))\r
+ {\r
+ if(isRoot) {\r
+ khm_handle newcred;\r
+\r
+ kcdb_cred_unlock_read();\r
+ kcdb_cred_dup((khm_handle) c, &newcred);\r
+ kcdb_credset_add_cred(destcredset, newcred, -1);\r
+ kcdb_cred_release(newcred);\r
+ kcdb_cred_lock_read();\r
+ } else {\r
+ kcdb_cred_unlock_read();\r
+ kcdb_credset_add_cred(destcredset, (khm_handle) c, -1);\r
+ kcdb_cred_lock_read();\r
+ }\r
+ }\r
+ }\r
+\r
+ dest->flags &= ~KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ kcdb_cred_unlock_read();\r
+\r
+_exit:\r
+ LeaveCriticalSection(&(dest->cs));\r
+ LeaveCriticalSection(&(src->cs));\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_apply(khm_handle vcredset, kcdb_cred_apply_func f, void * rock)\r
+{\r
+ kcdb_credset * cs;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ int i;\r
+\r
+ if(vcredset != NULL && !kcdb_credset_is_credset(vcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(vcredset == NULL) {\r
+ cs = kcdb_root_credset;\r
+ } else {\r
+ cs = (kcdb_credset *) vcredset;\r
+ }\r
+\r
+ EnterCriticalSection(&cs->cs);\r
+\r
+#ifdef DEBUG\r
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ cs->flags |= KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ for(i=0; i<cs->nclist; i++) {\r
+ if(!kcdb_cred_is_active_cred(cs->clist[i].cred))\r
+ continue;\r
+\r
+ if(KHM_FAILED(f((khm_handle) cs->clist[i].cred, rock)))\r
+ break;\r
+ }\r
+\r
+ cs->flags &= ~KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ LeaveCriticalSection(&cs->cs);\r
+\r
+ if(i<cs->nclist)\r
+ rv = KHM_ERROR_EXIT;\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_get_cred(\r
+ khm_handle vcredset,\r
+ khm_int32 idx,\r
+ khm_handle * cred)\r
+{\r
+ kcdb_credset * cs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+\r
+ if(!kcdb_credset_is_credset(vcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) vcredset;\r
+\r
+ *cred = NULL;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+ if(idx < 0 || idx >= cs->nclist)\r
+ code = KHM_ERROR_OUT_OF_BOUNDS;\r
+ else if(!cs->clist[idx].cred || !kcdb_cred_is_active_cred((khm_handle) cs->clist[idx].cred)) {\r
+ code = KHM_ERROR_DELETED;\r
+ if(cs->clist[idx].cred) {\r
+ kcdb_cred_release((khm_handle) cs->clist[idx].cred);\r
+ cs->clist[idx].cred = NULL;\r
+ }\r
+ }\r
+ else {\r
+ kcdb_cred_hold((khm_handle) cs->clist[idx].cred);\r
+ *cred = cs->clist[idx].cred;\r
+ }\r
+ LeaveCriticalSection(&(cs->cs));\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_find_filtered(\r
+ khm_handle credset,\r
+ khm_int32 idx_start,\r
+ kcdb_cred_filter_func f,\r
+ void * rock,\r
+ khm_handle * cred,\r
+ khm_int32 * idx)\r
+{\r
+ kcdb_credset * cs;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ int i;\r
+\r
+ if((credset && !kcdb_credset_is_credset(credset)) ||\r
+ (!f || !cred))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(credset)\r
+ cs = (kcdb_credset *) credset;\r
+ else\r
+ cs = kcdb_root_credset;\r
+\r
+ EnterCriticalSection(&cs->cs);\r
+\r
+ if(idx_start < 0)\r
+ i = 0;\r
+ else\r
+ i = idx_start + 1;\r
+\r
+#ifdef DEBUG\r
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ cs->flags |= KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ for(; i < cs->nclist; i++) {\r
+ if(kcdb_cred_is_active_cred(cs->clist[i].cred) &&\r
+ (*f)((khm_handle) cs->clist[i].cred, 0, rock) != 0)\r
+ break;\r
+ }\r
+\r
+ cs->flags &= ~KCDB_CREDSET_FLAG_ENUM;\r
+\r
+ if(i < cs->nclist) {\r
+ *cred = (khm_handle) cs->clist[i].cred;\r
+ kcdb_cred_hold(*cred);\r
+ if(idx)\r
+ *idx = i;\r
+ } else {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ LeaveCriticalSection(&cs->cs);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_find_cred(khm_handle vcredset,\r
+ khm_handle vcred_src,\r
+ khm_handle *cred_dest) {\r
+ kcdb_credset * cs;\r
+ khm_handle cred = NULL;\r
+ int idx;\r
+\r
+ if (!kcdb_credset_is_credset(vcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if (!kcdb_cred_is_active_cred(vcred_src))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) vcredset;\r
+\r
+ EnterCriticalSection(&cs->cs);\r
+ for (idx = 0; idx < cs->nclist; idx++) {\r
+ if (cs->clist[idx].cred &&\r
+ kcdb_creds_is_equal(vcred_src, cs->clist[idx].cred)) {\r
+ cred = cs->clist[idx].cred;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (cred)\r
+ kcdb_cred_hold(cred);\r
+\r
+ LeaveCriticalSection(&cs->cs);\r
+\r
+ if (cred) {\r
+ if (cred_dest)\r
+ *cred_dest = cred;\r
+ else\r
+ kcdb_cred_release(cred);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred(\r
+ khm_handle vcredset,\r
+ khm_int32 idx)\r
+{\r
+ kcdb_credset * cs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+\r
+ if(!kcdb_credset_is_credset(vcredset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) vcredset;\r
+\r
+ if (kcdb_credset_is_sealed(cs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+ if(idx < 0 || idx >= cs->nclist) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ if(cs->clist[idx].cred)\r
+ kcdb_cred_release((khm_handle) cs->clist[idx].cred);\r
+\r
+ if (!(cs->flags & KCDB_CREDSET_FLAG_ENUM)) {\r
+\r
+ if(idx + 1 < cs->nclist)\r
+ memmove(&(cs->clist[idx]), \r
+ &(cs->clist[idx+1]), \r
+ sizeof(kcdb_credset_credref) * \r
+ (cs->nclist - (idx + 1)));\r
+\r
+ cs->nclist--;\r
+ } else {\r
+ cs->clist[idx].cred = NULL;\r
+ }\r
+\r
+_exit:\r
+ LeaveCriticalSection(&(cs->cs));\r
+\r
+ return code;\r
+}\r
+\r
+khm_int32 kcdb_credset_update_cred_ref(\r
+ khm_handle credset,\r
+ khm_handle cred)\r
+{\r
+ kcdb_credset * cs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ int i;\r
+\r
+ if(!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+\r
+ for(i=0; i<cs->nclist; i++) {\r
+ if(cs->clist[i].cred == cred)\r
+ break;\r
+ }\r
+\r
+ if(i<cs->nclist) {\r
+ cs->clist[i].version = cs->version;\r
+ } else {\r
+ code = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ LeaveCriticalSection(&(cs->cs));\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred_ref(\r
+ khm_handle credset,\r
+ khm_handle cred)\r
+{\r
+ kcdb_credset * cs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ int i;\r
+\r
+ if(!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ if (kcdb_credset_is_sealed(cs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+\r
+ for(i=0; i<cs->nclist; i++) {\r
+ if(cs->clist[i].cred == cred)\r
+ break;\r
+ }\r
+\r
+ if(i<cs->nclist) {\r
+ code = kcdb_credset_del_cred(credset, i);\r
+ } else {\r
+ code = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ LeaveCriticalSection(&(cs->cs));\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_add_cred(\r
+ khm_handle credset,\r
+ khm_handle cred,\r
+ khm_int32 idx)\r
+{\r
+ int new_idx;\r
+ kcdb_credset * cs;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+\r
+ if(!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ if (kcdb_credset_is_sealed(cs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+\r
+ kcdb_credset_buf_assert_size(cs, cs->nclist + 1);\r
+\r
+ if(idx < 0 || idx > cs->nclist)\r
+ new_idx = cs->nclist;\r
+ else if(idx < cs->nclist){\r
+#ifdef DEBUG\r
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+ memmove(&(cs->clist[idx+1]), &(cs->clist[idx]), (cs->nclist - idx)*sizeof(cs->clist[0]));\r
+ new_idx = idx;\r
+ } else\r
+ new_idx = idx;\r
+\r
+ kcdb_cred_hold(cred);\r
+\r
+ cs->clist[new_idx].cred = (kcdb_cred *) cred;\r
+ cs->clist[new_idx].version = cs->version;\r
+ cs->nclist++;\r
+\r
+ LeaveCriticalSection(&(cs->cs));\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_get_size(\r
+ khm_handle credset,\r
+ khm_size * size)\r
+{\r
+ kcdb_credset * cs;\r
+\r
+ *size = 0;\r
+\r
+ /* we don't rely on this working, since we can't purge a sealed\r
+ credset, although we can measure its size. */\r
+ kcdb_credset_purge(credset);\r
+\r
+ if (credset == NULL)\r
+ cs = kcdb_root_credset;\r
+ else\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+ /* while it may seem a bit redundant to get a lock, it ensures that\r
+ that the size that we return is consistent with the current state\r
+ of the credential set */\r
+ *size = cs->nclist;\r
+ LeaveCriticalSection(&(cs->cs));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_purge(khm_handle credset)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_credset * cs;\r
+ int i,j;\r
+\r
+ if(!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ if (kcdb_credset_is_sealed(cs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+\r
+ /* we can't purge a credset while an enumeration operation is in\r
+ progress. */\r
+ if (cs->flags & KCDB_CREDSET_FLAG_ENUM) {\r
+ code = KHM_ERROR_INVALID_OPERATION;\r
+ goto _exit;\r
+ }\r
+\r
+ for(i=0,j=0; i < cs->nclist; i++) {\r
+ if(cs->clist[i].cred) {\r
+ if(!kcdb_cred_is_active_cred((khm_handle) cs->clist[i].cred)) {\r
+ kcdb_cred_release((khm_handle) cs->clist[i].cred);\r
+ } else if(i != j) {\r
+ cs->clist[j++] = cs->clist[i];\r
+ } else\r
+ j++;\r
+ }\r
+ }\r
+ cs->nclist = j;\r
+\r
+ _exit:\r
+ LeaveCriticalSection(&(cs->cs));\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_seal(khm_handle credset) {\r
+ kcdb_credset * cs;\r
+\r
+ if (!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ EnterCriticalSection(&cs->cs);\r
+ cs->seal_count++;\r
+ LeaveCriticalSection(&cs->cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kcdb_credset_unseal(khm_handle credset) {\r
+ kcdb_credset * cs;\r
+ khm_int32 rv;\r
+\r
+ if (!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ EnterCriticalSection(&cs->cs);\r
+ if (cs->seal_count > 0) {\r
+ cs->seal_count--;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ } else {\r
+ rv = KHM_ERROR_INVALID_OPERATION;\r
+ }\r
+ LeaveCriticalSection(&cs->cs);\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+/* wrapper for qsort and also parameter gobbling FSM. */\r
+int __cdecl kcdb_creds_comp_wrapper(const void * a, const void * b)\r
+{\r
+ static void * rock = NULL;\r
+ static kcdb_cred_comp_func comp = NULL;\r
+\r
+ if(!b) {\r
+ rock = (void *) a;\r
+ return 0;\r
+ }\r
+\r
+ if(!a) {\r
+ comp = (kcdb_cred_comp_func) b;\r
+ return 0;\r
+ }\r
+\r
+ return comp((khm_handle) ((kcdb_credset_credref *)a)->cred, (khm_handle) ((kcdb_credset_credref *)b)->cred, rock);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credset_sort(\r
+ khm_handle credset,\r
+ kcdb_cred_comp_func comp,\r
+ void * rock)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_credset * cs;\r
+\r
+ if(!kcdb_credset_is_credset(credset))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cs = (kcdb_credset *) credset;\r
+\r
+ if (kcdb_credset_is_sealed(cs))\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ EnterCriticalSection(&(cs->cs));\r
+\r
+#ifdef DEBUG\r
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));\r
+#endif\r
+\r
+ kcdb_creds_comp_wrapper(rock, NULL);\r
+ kcdb_creds_comp_wrapper(NULL, (void *) comp);\r
+\r
+ qsort(cs->clist, cs->nclist, sizeof(kcdb_credset_credref), kcdb_creds_comp_wrapper);\r
+\r
+ LeaveCriticalSection(&(cs->cs));\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_cred_comp_generic(\r
+ khm_handle cred1, \r
+ khm_handle cred2, \r
+ void * rock)\r
+{\r
+ kcdb_cred_comp_order * o = (kcdb_cred_comp_order *) rock;\r
+ int i;\r
+ khm_int32 r = 0;\r
+ khm_int32 f1, f2;\r
+ khm_int32 pt;\r
+\r
+ for(i=0; i<o->nFields; i++) {\r
+ if (o->fields[i].order & KCDB_CRED_COMP_INITIAL_FIRST) {\r
+\r
+ kcdb_cred_get_flags(cred1, &f1);\r
+ kcdb_cred_get_flags(cred2, &f2);\r
+\r
+ if (((f1 ^ f2) & KCDB_CRED_FLAG_INITIAL) == 0) {\r
+ kcdb_cred_get_type(cred1, &f1);\r
+ kcdb_cred_get_type(cred2, &f2);\r
+ kcdb_identity_get_type(&pt);\r
+\r
+ if (f1 == f2)\r
+ r = 0;\r
+ else if (f1 == pt)\r
+ r = -1;\r
+ else if (f2 == pt)\r
+ r = 1;\r
+ else\r
+ r = 0;\r
+ } else if (f1 & KCDB_CRED_FLAG_INITIAL)\r
+ r = -1;\r
+ else\r
+ r = 1;\r
+ } else {\r
+ r = 0;\r
+ }\r
+\r
+ if (r == 0)\r
+ r = kcdb_creds_comp_attr(cred1,cred2,o->fields[i].attrib);\r
+\r
+ if(r != 0) {\r
+ if(o->fields[i].order & KCDB_CRED_COMP_DECREASING)\r
+ r = -r;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return r;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_CREDSET_H\r
+#define __KHIMAIRA_KCDB_CREDSET_H\r
+\r
+/* credset */\r
+\r
+typedef struct kcdb_credset_credref_t {\r
+ khm_int32 version;\r
+ kcdb_cred * cred;\r
+} kcdb_credset_credref;\r
+\r
+typedef struct kcdb_credset_t {\r
+ khm_int32 magic;\r
+ khm_int32 flags;\r
+ CRITICAL_SECTION cs;\r
+\r
+ kcdb_credset_credref * clist;\r
+ khm_int32 nc_clist; /* total capacity */\r
+ khm_int32 nclist; /* current load */\r
+\r
+ khm_int32 version; /* data version */\r
+\r
+ khm_int32 seal_count; /* number of seals applied to the\r
+ credset */\r
+\r
+ struct kcdb_credset_t * next;\r
+ struct kcdb_credset_t * prev;\r
+} kcdb_credset;\r
+\r
+#define KCDB_CREDSET_MAGIC 0x63a84f8b\r
+\r
+#define KCDB_CREDSET_FLAG_ROOT 1\r
+\r
+/* the credset is in the process of being enumerated */\r
+#define KCDB_CREDSET_FLAG_ENUM 2\r
+\r
+#define kcdb_credset_is_credset(c) ((c) && ((kcdb_credset *)c)->magic == KCDB_CREDSET_MAGIC)\r
+\r
+#define kcdb_credset_is_sealed(c) ((c)->seal_count != 0)\r
+\r
+#define KCDB_CREDSET_INITIAL_SIZE 1024\r
+#define KCDB_CREDSET_GROWTH_FACTOR 1024\r
+\r
+void kcdb_credset_init(void);\r
+void kcdb_credset_exit(void);\r
+khm_int32 kcdb_credset_update_cred_ref(\r
+ khm_handle credset,\r
+ khm_handle cred);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+\r
+CRITICAL_SECTION cs_credtype;\r
+kcdb_credtype_i ** kcdb_credtype_tbl = NULL;\r
+kcdb_credtype_i * kcdb_credtypes = NULL;\r
+\r
+void kcdb_credtype_init(void)\r
+{\r
+ InitializeCriticalSection(&cs_credtype);\r
+ kcdb_credtypes = NULL;\r
+ kcdb_credtype_tbl = malloc(sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1));\r
+ ZeroMemory(kcdb_credtype_tbl, sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1));\r
+}\r
+\r
+void kcdb_credtype_exit(void)\r
+{\r
+ /*TODO:Free up the cred types */\r
+ free(kcdb_credtype_tbl);\r
+ DeleteCriticalSection(&cs_credtype);\r
+}\r
+\r
+/* Called with cs_credtype held */\r
+void kcdb_credtype_check_and_delete(khm_int32 id)\r
+{\r
+ kcdb_credtype_i * ict;\r
+ ict = kcdb_credtype_tbl[id];\r
+ if(!ict)\r
+ return;\r
+\r
+ if((ict->flags & KCDB_CTI_FLAG_DELETED) &&\r
+ !ict->refcount)\r
+ {\r
+ kcdb_credtype_tbl[id] = NULL;\r
+ LDELETE(&kcdb_credtypes, ict);\r
+\r
+ free(ict->ct.name);\r
+ if(ict->ct.short_desc)\r
+ free(ict->ct.short_desc);\r
+ if(ict->ct.long_desc)\r
+ free(ict->ct.long_desc);\r
+ if(ict->ct.sub)\r
+ kmq_delete_subscription(ict->ct.sub);\r
+\r
+ free(ict);\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_register(kcdb_credtype * type, khm_int32 * new_id) \r
+{\r
+ khm_int32 id;\r
+ kcdb_credtype_i * ict;\r
+ size_t cb_name;\r
+ size_t cb_short_desc;\r
+ size_t cb_long_desc;\r
+ int i;\r
+\r
+ if(!type)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(type->id >= KCDB_CREDTYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(type->name) {\r
+ if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cb_name)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cb_name += sizeof(wchar_t);\r
+ } else\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(type->short_desc) {\r
+ if(FAILED(StringCbLength(type->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cb_short_desc += sizeof(wchar_t);\r
+ } else\r
+ cb_short_desc = 0;\r
+\r
+ if(type->long_desc) {\r
+ if(FAILED(StringCbLength(type->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cb_long_desc += sizeof(wchar_t);\r
+ } else\r
+ cb_long_desc = 0;\r
+\r
+ if(type->sub == NULL)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+\r
+ if(type->id < 0) {\r
+ if(KHM_FAILED(kcdb_credtype_get_next_free_id(&id))) {\r
+ LeaveCriticalSection(&cs_credtype);\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+ }\r
+ else\r
+ id = type->id;\r
+\r
+ if(kcdb_credtype_tbl[id]) {\r
+ LeaveCriticalSection(&cs_credtype);\r
+ return KHM_ERROR_DUPLICATE;\r
+ }\r
+\r
+ for(i=0;i<=KCDB_CREDTYPE_MAX_ID;i++) {\r
+ if(kcdb_credtype_tbl[i] && !wcscmp(kcdb_credtype_tbl[i]->ct.name, type->name)) {\r
+ LeaveCriticalSection(&cs_credtype);\r
+ return KHM_ERROR_DUPLICATE;\r
+ }\r
+ }\r
+\r
+ ict = malloc(sizeof(kcdb_credtype_i));\r
+ ZeroMemory(ict, sizeof(kcdb_credtype_i));\r
+\r
+ ict->ct.name = malloc(cb_name);\r
+ StringCbCopy(ict->ct.name, cb_name, type->name);\r
+\r
+ if(cb_short_desc) {\r
+ ict->ct.short_desc = malloc(cb_short_desc);\r
+ StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc);\r
+ }\r
+\r
+ if(cb_long_desc) {\r
+ ict->ct.long_desc = malloc(cb_long_desc);\r
+ StringCbCopy(ict->ct.long_desc, cb_long_desc, type->long_desc);\r
+ }\r
+\r
+ ict->ct.id = id;\r
+\r
+ ict->ct.icon = type->icon;\r
+\r
+ ict->ct.sub = type->sub;\r
+\r
+ kcdb_credtype_tbl[id] = ict;\r
+\r
+ LPUSH(&kcdb_credtypes, ict);\r
+\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ kcdb_credtype_post_message(KCDB_OP_INSERT, &(ict->ct));\r
+\r
+ if (new_id)\r
+ *new_id = id;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_get_info(\r
+ khm_int32 id, \r
+ kcdb_credtype ** type)\r
+{\r
+ int found = 0;\r
+\r
+ if(id < 0 || id > KCDB_CREDTYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ if(kcdb_credtype_tbl[id] && \r
+ !(kcdb_credtype_tbl[id]->flags & KCDB_CTI_FLAG_DELETED)) \r
+ {\r
+ found = 1;\r
+ if(type) {\r
+ *type = &(kcdb_credtype_tbl[id]->ct);\r
+ kcdb_credtype_hold(kcdb_credtype_tbl[id]);\r
+ }\r
+ } else {\r
+ if(type)\r
+ *type = NULL;\r
+ }\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ if(found)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_release_info(kcdb_credtype * type) \r
+{\r
+ kcdb_credtype_i * ict;\r
+\r
+ if(!type)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ ict = (kcdb_credtype_i *) type;\r
+ return kcdb_credtype_release(ict);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_unregister(khm_int32 id) \r
+{\r
+ kcdb_credtype_i * ict;\r
+\r
+ if(id < 0 || id > KCDB_CREDTYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ ict = kcdb_credtype_tbl[id];\r
+ ict->flags |= KCDB_CTI_FLAG_DELETED;\r
+ kcdb_credtype_check_and_delete(id);\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ //kcdb_credtype_post_message(KCDB_OP_DELETE, &(ict->ct));\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_handle KHMAPI kcdb_credtype_get_sub(khm_int32 id)\r
+{\r
+ kcdb_credtype_i * t;\r
+ khm_handle s;\r
+\r
+ if(id < 0 || id > KCDB_CREDTYPE_MAX_ID)\r
+ return NULL;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ t = kcdb_credtype_tbl[id];\r
+ if(t)\r
+ s = t->ct.sub;\r
+ else\r
+ s = NULL;\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ return s;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_describe(\r
+ khm_int32 id,\r
+ wchar_t * buf,\r
+ khm_size * cbbuf,\r
+ khm_int32 flags)\r
+{\r
+ size_t s;\r
+ size_t maxs;\r
+ wchar_t * str;\r
+ kcdb_credtype_i * t;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ t = kcdb_credtype_tbl[id];\r
+ if(t) {\r
+ if(flags & KCDB_TS_SHORT) {\r
+ str = (t->ct.short_desc)?t->ct.short_desc:t->ct.name;\r
+ maxs = (t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME;\r
+ } else {\r
+ str = (t->ct.long_desc)?t->ct.long_desc:((t->ct.short_desc)?t->ct.short_desc:t->ct.name);\r
+ maxs = (t->ct.long_desc)?KCDB_MAXCB_LONG_DESC:((t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME);\r
+ }\r
+ StringCbLength(str, maxs, &s);\r
+ s += sizeof(wchar_t);\r
+ if(!buf || *cbbuf < s) {\r
+ *cbbuf = s;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else {\r
+#pragma warning(push)\r
+#pragma warning(disable:4995)\r
+ wcscpy(buf, str); /* str is one of the string fields in t->ct which has \r
+ been validated when the type was registered. */\r
+#pragma warning(pop)\r
+ *cbbuf = s;\r
+ }\r
+ } else {\r
+ if(buf && *cbbuf > 0)\r
+ *buf = L'\0';\r
+ *cbbuf = 0;\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ }\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_get_name(\r
+ khm_int32 id,\r
+ wchar_t * buf,\r
+ khm_size * cbbuf)\r
+{\r
+ size_t s;\r
+ kcdb_credtype_i * t;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ t = kcdb_credtype_tbl[id];\r
+ if(t) {\r
+ StringCbLength(t->ct.name, KCDB_MAXCB_NAME, &s);\r
+ s += sizeof(wchar_t);\r
+ if(!buf || *cbbuf < s) {\r
+ *cbbuf = s;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4995)\r
+ wcscpy(buf, t->ct.name); /* t->ct.name was validated when the type was registered */\r
+#pragma warning(pop)\r
+ *cbbuf = s;\r
+ }\r
+ } else {\r
+ *cbbuf = 0;\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ }\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_credtype_get_id(\r
+ wchar_t * name, \r
+ khm_int32 * id)\r
+{\r
+ int i;\r
+\r
+ *id = 0;\r
+ if(!name)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) {\r
+ if(kcdb_credtype_tbl[i] && !wcscmp(name, kcdb_credtype_tbl[i]->ct.name))\r
+ break;\r
+ }\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ if(i <= KCDB_CREDTYPE_MAX_ID) {\r
+ *id = i;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id) \r
+{\r
+ int i;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) {\r
+ if(!kcdb_credtype_tbl[i])\r
+ break;\r
+ }\r
+ LeaveCriticalSection(&cs_credtype);\r
+\r
+ if(i <= KCDB_CREDTYPE_MAX_ID) {\r
+ *id = i;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *id = -1;\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+}\r
+\r
+khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict) {\r
+ \r
+ if(!ict)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ ict->refcount++;\r
+ LeaveCriticalSection(&cs_credtype);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict) {\r
+ \r
+ if(!ict)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_credtype);\r
+ ict->refcount--;\r
+ kcdb_credtype_check_and_delete(ict->ct.id);\r
+ LeaveCriticalSection(&cs_credtype);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+void kcdb_credtype_msg_completion(kmq_message * m) \r
+{\r
+ kcdb_credtype_release((kcdb_credtype_i *) m->vparam);\r
+}\r
+\r
+void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type)\r
+{\r
+ kcdb_credtype_hold((kcdb_credtype_i *) type);\r
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_CREDTYPE, op, (void *) type);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_CREDTYPE_H\r
+#define __KHIMAIRA_KCDB_CREDTYPE_H \r
+\r
+/* credtype */\r
+typedef struct kcdb_credtype_i_t {\r
+ kcdb_credtype ct;\r
+ khm_int32 refcount;\r
+ khm_int32 flags;\r
+\r
+ struct kcdb_credtype_i_t * next;\r
+ struct kcdb_credtype_i_t * prev;\r
+} kcdb_credtype_i;\r
+\r
+#define KCDB_CTI_FLAG_DELETED 8\r
+\r
+extern CRITICAL_SECTION cs_credtype;\r
+extern kcdb_credtype_i * kcdb_credtypes;\r
+extern kcdb_credtype_i ** kcdb_credtype_tbl;\r
+\r
+void kcdb_credtype_init(void);\r
+void kcdb_credtype_exit(void);\r
+void kcdb_credtype_check_and_delete(khm_int32 id);\r
+khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict);\r
+khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict);\r
+void kcdb_credtype_msg_completion(kmq_message * m);\r
+void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type);\r
+khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id);\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+#include<assert.h>\r
+\r
+CRITICAL_SECTION cs_ident;\r
+hashtable * kcdb_identities_namemap = NULL;\r
+khm_int32 kcdb_n_identities = 0;\r
+kcdb_identity * kcdb_identities = NULL;\r
+kcdb_identity * kcdb_def_identity = NULL;\r
+khm_handle kcdb_ident_sub = NULL; /* identity provider */\r
+khm_int32 kcdb_ident_cred_type = KCDB_CREDTYPE_INVALID; \r
+/* primary credentials type */\r
+khm_ui_4 kcdb_ident_refresh_cycle = 0;\r
+khm_boolean kcdb_checked_config = FALSE;\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_provider(khm_handle sub)\r
+{\r
+ EnterCriticalSection(&cs_ident);\r
+ if (sub != kcdb_ident_sub) {\r
+ if(kcdb_ident_sub != NULL) {\r
+ kmq_post_sub_msg(kcdb_ident_sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_EXIT,\r
+ 0,\r
+ 0);\r
+ kmq_delete_subscription(kcdb_ident_sub);\r
+ }\r
+ kcdb_ident_sub = sub;\r
+\r
+ if (kcdb_ident_sub)\r
+ kmq_post_sub_msg(kcdb_ident_sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_INIT,\r
+ 0,\r
+ 0);\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_provider(khm_handle * sub)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL)\r
+ rv = KHM_ERROR_SUCCESS;\r
+ else\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ if(sub != NULL)\r
+ *sub = kcdb_ident_sub;\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_type(khm_int32 cred_type)\r
+{\r
+ EnterCriticalSection(&cs_ident);\r
+ kcdb_ident_cred_type = cred_type;\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_type(khm_int32 * ptype)\r
+{\r
+ if (!ptype)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ *ptype = kcdb_ident_cred_type;\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if (*ptype >= 0)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+/* message completion routine */\r
+void \r
+kcdbint_ident_msg_completion(kmq_message * m) {\r
+ kcdb_identity_release(m->vparam);\r
+}\r
+\r
+void \r
+kcdbint_ident_add_ref(const void * key, void * vid) {\r
+ /* References in the hashtable are not refcounted */\r
+\r
+ // kcdb_identity_hold(vid);\r
+}\r
+\r
+void \r
+kcdbint_ident_del_ref(const void * key, void * vid) {\r
+ /* References in the hashtable are not refcounted */\r
+\r
+ // kcdb_identity_release(vid);\r
+}\r
+\r
+void \r
+kcdbint_ident_init(void) {\r
+ InitializeCriticalSection(&cs_ident);\r
+ kcdb_identities_namemap = hash_new_hashtable(\r
+ KCDB_IDENT_HASHTABLE_SIZE,\r
+ hash_string,\r
+ hash_string_comp,\r
+ kcdbint_ident_add_ref,\r
+ kcdbint_ident_del_ref);\r
+}\r
+\r
+void \r
+kcdbint_ident_exit(void) {\r
+ EnterCriticalSection(&cs_ident);\r
+ hash_del_hashtable(kcdb_identities_namemap);\r
+ LeaveCriticalSection(&cs_ident);\r
+ DeleteCriticalSection(&cs_ident);\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI \r
+kcdb_identity_is_valid_name(const wchar_t * name)\r
+{\r
+ khm_int32 rv;\r
+\r
+ /* special case. Note since the string we are comparing with is\r
+ of a known length we don't need to check the length of name. */\r
+ if (!wcscmp(name, L"_Schema"))\r
+ return FALSE;\r
+\r
+ rv = kcdb_identpro_validate_name(name);\r
+\r
+ if(rv == KHM_ERROR_NO_PROVIDER ||\r
+ rv == KHM_ERROR_NOT_IMPLEMENTED)\r
+ return TRUE;\r
+ else\r
+ return KHM_SUCCEEDED(rv);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_create(const wchar_t *name, \r
+ khm_int32 flags, \r
+ khm_handle * result) {\r
+ kcdb_identity * id;\r
+ kcdb_identity * id_tmp;\r
+ size_t namesize;\r
+\r
+ if(!result || !name)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ *result = NULL;\r
+\r
+ /* is it there already? */\r
+ EnterCriticalSection(&cs_ident);\r
+ id = hash_lookup(kcdb_identities_namemap, (void *) name);\r
+ if(id)\r
+ kcdb_identity_hold((khm_handle) id);\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(id) {\r
+ *result = (khm_handle) id;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else if(!(flags & KCDB_IDENT_FLAG_CREATE)) {\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ flags &= ~KCDB_IDENT_FLAG_CREATE;\r
+\r
+ /* nope. create it */\r
+ if((flags & ~KCDB_IDENT_FLAGMASK_RDWR) ||\r
+ (flags & (KCDB_IDENT_FLAG_DEFAULT |\r
+ KCDB_IDENT_FLAG_SEARCHABLE))) {\r
+ /* can't specify this flag in create */\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(!kcdb_identity_is_valid_name(name)) {\r
+ return KHM_ERROR_INVALID_NAME;\r
+ }\r
+\r
+ /* we expect the following will succeed since the above\r
+ test passed */\r
+ StringCbLength(name, KCDB_IDENT_MAXCB_NAME, &namesize);\r
+ namesize += sizeof(wchar_t);\r
+\r
+ id = malloc(sizeof(kcdb_identity));\r
+ ZeroMemory(id, sizeof(kcdb_identity));\r
+ id->magic = KCDB_IDENT_MAGIC;\r
+ id->name = malloc(namesize);\r
+ StringCbCopy(id->name, namesize, name);\r
+\r
+ id->flags = (flags & KCDB_IDENT_FLAGMASK_LOCAL);\r
+ id->flags |= KCDB_IDENT_FLAG_ACTIVE;\r
+ LINIT(id);\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ id_tmp = hash_lookup(kcdb_identities_namemap, (void *) id->name);\r
+ if(id_tmp) {\r
+ /* lost a race */\r
+ kcdb_identity_hold((khm_handle) id_tmp);\r
+ *result = (khm_handle) id_tmp;\r
+\r
+ free(id->name);\r
+ free(id);\r
+\r
+ id = NULL;\r
+ } else {\r
+ khm_handle h_cfg;\r
+\r
+ kcdb_identity_hold((khm_handle) id);\r
+ hash_add(kcdb_identities_namemap, \r
+ (void *) id->name, \r
+ (void *) id);\r
+ LPUSH(&kcdb_identities, id);\r
+\r
+ if(KHM_SUCCEEDED(kcdb_identity_get_config((khm_handle) id, \r
+ 0,\r
+ &h_cfg))) {\r
+ /* don't need to set the KCDB_IDENT_FLAG_CONFIG flags\r
+ since kcdb_identity_get_conifg() sets it for us. */\r
+ khm_int32 sticky;\r
+\r
+ if (KHM_SUCCEEDED(khc_read_int32(h_cfg, L"Sticky", &sticky)) &&\r
+ sticky) {\r
+ id->flags |= KCDB_IDENT_FLAG_STICKY;\r
+ }\r
+\r
+ khc_close_space(h_cfg);\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(id != NULL) {\r
+ *result = (khm_handle) id;\r
+\r
+ kcdb_identpro_notify_create((khm_handle) id);\r
+\r
+ kcdbint_ident_post_message(KCDB_OP_INSERT, id);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_delete(khm_handle vid) {\r
+ kcdb_identity * id;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(!kcdb_is_identity(vid)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ if (kcdb_is_active_identity(vid)) {\r
+\r
+ id->flags &= ~KCDB_IDENT_FLAG_ACTIVE;\r
+\r
+ hash_del(kcdb_identities_namemap, (void *) id->name);\r
+\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ kcdbint_ident_post_message(KCDB_OP_DELETE, id);\r
+\r
+ /* Once everybody finishes dealing with the identity deletion,\r
+ we will get called again. */\r
+ return KHM_ERROR_SUCCESS;\r
+ } else if (id->refcount == 0) {\r
+ /* If the identity is not active, it is not in the hashtable\r
+ either */\r
+ LDELETE(&kcdb_identities, id);\r
+\r
+ if (id->name)\r
+ free(id->name);\r
+ free(id);\r
+ }\r
+ /* else, we have an identity that is not active, but has\r
+ outstanding references. We have to wait until those references\r
+ are freed. Once they are released, kcdb_identity_delete() will\r
+ be called again. */\r
+\r
+#if 0\r
+ EnterCriticalSection(&cs_ident);\r
+ if(id->refcount == 0) {\r
+ /*TODO: free up the identity */\r
+ }\r
+#endif\r
+ _exit:\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_flags(khm_handle vid, \r
+ khm_int32 flag) {\r
+ kcdb_identity * id;\r
+ khm_int32 oldflags;\r
+ khm_int32 newflags;\r
+ khm_int32 delta = 0;\r
+ khm_int32 rv;\r
+\r
+ if(!kcdb_is_active_identity(vid))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ if((flag & ~(KCDB_IDENT_FLAGMASK_RDWR | KCDB_IDENT_FLAG_INVERT)) ||\r
+ ((flag & KCDB_IDENT_FLAG_INVALID) && (flag & KCDB_IDENT_FLAG_VALID)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(flag & KCDB_IDENT_FLAG_DEFAULT) {\r
+ /* kcdb_identity_set_default already does checking for\r
+ redundant transitions */\r
+ rv = kcdb_identity_set_default((flag & KCDB_IDENT_FLAG_INVERT)?NULL: vid);\r
+\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ flag &= ~KCDB_IDENT_FLAG_DEFAULT;\r
+ }\r
+\r
+ if(flag & KCDB_IDENT_FLAG_SEARCHABLE) {\r
+ if(flag & KCDB_IDENT_FLAG_INVERT) {\r
+ EnterCriticalSection(&cs_ident);\r
+ if(id->flags & KCDB_IDENT_FLAG_SEARCHABLE) {\r
+ LeaveCriticalSection(&cs_ident);\r
+ rv = kcdb_identpro_set_searchable(vid, FALSE);\r
+ EnterCriticalSection(&cs_ident);\r
+ if(rv == KHM_ERROR_NO_PROVIDER ||\r
+ KHM_SUCCEEDED(rv)) {\r
+ id->flags &= ~KCDB_IDENT_FLAG_SEARCHABLE;\r
+ delta |= KCDB_IDENT_FLAG_SEARCHABLE;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+ } else {\r
+ EnterCriticalSection(&cs_ident);\r
+ if(!(id->flags & KCDB_IDENT_FLAG_SEARCHABLE)) {\r
+ LeaveCriticalSection(&cs_ident);\r
+ rv = kcdb_identpro_set_searchable(vid, TRUE);\r
+ EnterCriticalSection(&cs_ident);\r
+ if(rv == KHM_ERROR_NO_PROVIDER ||\r
+ KHM_SUCCEEDED(rv)) {\r
+ id->flags |= KCDB_IDENT_FLAG_SEARCHABLE;\r
+ delta |= KCDB_IDENT_FLAG_SEARCHABLE;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+ }\r
+\r
+ flag &= ~KCDB_IDENT_FLAG_SEARCHABLE;\r
+ }\r
+\r
+ /* deal with every other flag */\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ oldflags = id->flags;\r
+ if(flag & KCDB_IDENT_FLAG_INVERT) {\r
+ flag &= ~KCDB_IDENT_FLAG_INVERT;\r
+ id->flags &= ~flag;\r
+ } else {\r
+ id->flags |= flag;\r
+\r
+ if(flag & KCDB_IDENT_FLAG_VALID)\r
+ id->flags &= ~KCDB_IDENT_FLAG_INVALID;\r
+ if(flag & KCDB_IDENT_FLAG_INVALID)\r
+ id->flags &= ~KCDB_IDENT_FLAG_VALID;\r
+ }\r
+ newflags = id->flags;\r
+ LeaveCriticalSection(&cs_ident);\r
+ delta |= newflags ^ oldflags;\r
+\r
+ if((delta & KCDB_IDENT_FLAG_HIDDEN)) {\r
+ kcdbint_ident_post_message(\r
+ (newflags & KCDB_IDENT_FLAG_HIDDEN)?KCDB_OP_HIDE:KCDB_OP_UNHIDE, \r
+ vid);\r
+ }\r
+\r
+ if((delta & KCDB_IDENT_FLAG_SEARCHABLE)) {\r
+ kcdbint_ident_post_message(\r
+ (newflags & KCDB_IDENT_FLAG_SEARCHABLE)?KCDB_OP_SETSEARCH:KCDB_OP_UNSETSEARCH, \r
+ vid);\r
+ }\r
+\r
+ if(delta != 0)\r
+ kcdbint_ident_post_message(KCDB_OP_MODIFY, vid);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_flags(khm_handle vid, \r
+ khm_int32 * flags) {\r
+ kcdb_identity * id;\r
+\r
+ *flags = 0;\r
+\r
+ if(!kcdb_is_active_identity(vid))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ *flags = id->flags;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_name(khm_handle vid, \r
+ wchar_t * buffer, \r
+ khm_size * pcbsize) {\r
+ size_t namesize;\r
+ kcdb_identity * id;\r
+\r
+ if(!kcdb_is_active_identity(vid) || !pcbsize)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ if(FAILED(StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &namesize)))\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ namesize += sizeof(wchar_t);\r
+\r
+ if(!buffer || namesize > *pcbsize) {\r
+ *pcbsize = namesize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *pcbsize, id->name);\r
+ *pcbsize = namesize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_default(khm_handle * pvid) {\r
+ khm_handle def;\r
+\r
+ if (pvid == NULL)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ def = kcdb_def_identity;\r
+ if (def != NULL)\r
+ kcdb_identity_hold(def);\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ *pvid = def;\r
+\r
+ if (def != NULL)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+static khm_int32\r
+kcdbint_ident_set_default(khm_handle vid,\r
+ khm_boolean invoke_identpro) {\r
+ kcdb_identity * new_def;\r
+ kcdb_identity * old_def;\r
+ khm_int32 rv;\r
+\r
+ if(vid != NULL && !kcdb_is_active_identity(vid))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ new_def = (kcdb_identity *)vid;\r
+\r
+ if(new_def != NULL && (new_def->flags & KCDB_IDENT_FLAG_DEFAULT))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if(new_def == NULL && kcdb_def_identity == NULL)\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ /* first check with the identity provider if this operation\r
+ is permitted. */\r
+ if (invoke_identpro) {\r
+ rv = kcdb_identpro_set_default(vid);\r
+ if(rv != KHM_ERROR_NO_PROVIDER && KHM_FAILED(rv))\r
+ return rv;\r
+ }\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ old_def = kcdb_def_identity;\r
+ kcdb_def_identity = new_def;\r
+\r
+ if(old_def != new_def) {\r
+ if(old_def) {\r
+ old_def->flags &= ~KCDB_IDENT_FLAG_DEFAULT;\r
+ kcdb_identity_release((khm_handle) old_def);\r
+ }\r
+\r
+ if(new_def) {\r
+ new_def->flags |= KCDB_IDENT_FLAG_DEFAULT;\r
+ kcdb_identity_hold((khm_handle) new_def);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if (invoke_identpro)\r
+ kcdbint_ident_post_message(KCDB_OP_NEW_DEFAULT, new_def);\r
+ } else {\r
+ LeaveCriticalSection(&cs_ident);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_default(khm_handle vid) {\r
+ return kcdbint_ident_set_default(vid, TRUE);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kcdb_identity_set_default_int(khm_handle vid) {\r
+ return kcdbint_ident_set_default(vid, FALSE);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_config(khm_handle vid, \r
+ khm_int32 flags,\r
+ khm_handle * result) {\r
+ khm_handle hkcdb;\r
+ khm_handle hidents = NULL;\r
+ khm_handle hident = NULL;\r
+ khm_int32 rv;\r
+ kcdb_identity * id;\r
+\r
+ if(kcdb_is_active_identity(vid)) {\r
+ id = (kcdb_identity *) vid;\r
+ } else {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ hkcdb = kcdb_get_config();\r
+ if(hkcdb) {\r
+ rv = khc_open_space(hkcdb, L"Identity", 0, &hidents);\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ rv = khc_open_space(hidents,\r
+ id->name, \r
+ flags | KCONF_FLAG_NOPARSENAME,\r
+ &hident);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ id->flags |= KCDB_IDENT_FLAG_CONFIG;\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ *result = hident;\r
+ } else\r
+ rv = KHM_ERROR_UNKNOWN;\r
+\r
+_exit:\r
+ if(hidents)\r
+ khc_close_space(hidents);\r
+ if(hkcdb)\r
+ khc_close_space(hkcdb);\r
+ return rv;\r
+}\r
+\r
+/*! \note cs_ident must be available. */\r
+void \r
+kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id) {\r
+ kcdb_identity_hold(id);\r
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_IDENT, op, (void *) id);\r
+}\r
+\r
+/*! \note cs_ident must be available. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_hold(khm_handle vid) {\r
+ kcdb_identity * id;\r
+ if(kcdb_is_active_identity(vid)) {\r
+ id = vid;\r
+ InterlockedIncrement(&(id->refcount));\r
+ } else\r
+ return KHM_ERROR_INVALID_PARM;\r
+ return ERROR_SUCCESS;\r
+}\r
+\r
+/*! \note cs_ident must be available. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_release(khm_handle vid) {\r
+ kcdb_identity * id;\r
+ khm_int32 refcount;\r
+ if(kcdb_is_identity(vid)) {\r
+ id = vid;\r
+ refcount = InterlockedDecrement(&(id->refcount));\r
+ if(refcount == 0) {\r
+ EnterCriticalSection(&cs_ident);\r
+ /* We only delete identities which do not have a\r
+ configuration. */\r
+ if (id->refcount == 0 &&\r
+ !(id->flags & KCDB_IDENT_FLAG_CONFIG))\r
+ kcdb_identity_delete(vid);\r
+ LeaveCriticalSection(&cs_ident);\r
+ }\r
+ } else\r
+ return KHM_ERROR_INVALID_PARM;\r
+ return ERROR_SUCCESS;\r
+}\r
+\r
+struct kcdb_idref_result {\r
+ kcdb_identity * ident;\r
+ khm_int32 flags;\r
+ khm_size count;\r
+};\r
+\r
+static khm_int32 KHMAPI \r
+kcdbint_idref_proc(khm_handle cred, void * r) {\r
+ khm_handle vid;\r
+ struct kcdb_idref_result *result;\r
+ khm_int32 flags;\r
+\r
+ result = (struct kcdb_idref_result *) r;\r
+\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, &vid))) {\r
+ if (result->ident == (kcdb_identity *) vid) {\r
+ result->count++;\r
+ kcdb_cred_get_flags(cred, &flags);\r
+\r
+ if (flags & KCDB_CRED_FLAG_RENEWABLE) {\r
+ result->flags |= KCDB_IDENT_FLAG_CRED_RENEW;\r
+ if (flags & KCDB_CRED_FLAG_INITIAL) {\r
+ result->flags |= KCDB_IDENT_FLAG_RENEWABLE;\r
+ }\r
+ }\r
+\r
+ if (flags & KCDB_CRED_FLAG_EXPIRED) {\r
+ result->flags |= KCDB_IDENT_FLAG_CRED_EXP;\r
+ if (flags & KCDB_CRED_FLAG_INITIAL) {\r
+ result->flags |= KCDB_IDENT_FLAG_EXPIRED;\r
+ }\r
+ }\r
+\r
+ if (flags & KCDB_CRED_FLAG_INITIAL) {\r
+ result->flags |= KCDB_IDENT_FLAG_VALID;\r
+ }\r
+ }\r
+\r
+ kcdb_identity_release(vid);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_refresh(khm_handle vid) {\r
+ kcdb_identity * ident;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ struct kcdb_idref_result result;\r
+ khm_int32 flags;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ if (!kcdb_is_active_identity(vid)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ ident = (kcdb_identity *) vid;\r
+\r
+ result.ident = ident;\r
+ result.flags = 0;\r
+ result.count = 0;\r
+\r
+ kcdb_credset_apply(NULL, kcdbint_idref_proc, &result);\r
+\r
+ if (result.count == 0)\r
+ result.flags |= KCDB_IDENT_FLAG_EMPTY;\r
+\r
+ kcdb_identity_set_flags(vid, result.flags);\r
+ kcdb_identity_get_flags(vid, &flags);\r
+ flags &= KCDB_IDENT_FLAGMASK_RDWR;\r
+ flags &= ~(KCDB_IDENT_FLAG_DEFAULT |\r
+ KCDB_IDENT_FLAG_SEARCHABLE);\r
+ flags ^= result.flags;\r
+ if (flags != 0)\r
+ kcdb_identity_set_flags(vid, flags | KCDB_IDENT_FLAG_INVERT);\r
+\r
+ ident->refresh_cycle = kcdb_ident_refresh_cycle;\r
+\r
+ _exit:\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if (code == 0)\r
+ code = kcdb_identpro_update(vid);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_refresh_all(void) {\r
+ kcdb_identity * ident;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ int hit_count;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ kcdb_ident_refresh_cycle++;\r
+\r
+ /* The do-while loop is here to account for race conditions. We\r
+ release cs_ident in the for loop, so we don't actually have a\r
+ guarantee that we traversed the whole identity list at the end.\r
+ We repeat until all the identities are uptodate. */\r
+\r
+ do {\r
+ hit_count = 0;\r
+\r
+ for (ident = kcdb_identities; \r
+ ident != NULL;\r
+ ident = LNEXT(ident)) {\r
+\r
+ if (!kcdb_is_active_identity(ident) ||\r
+ ident->refresh_cycle == kcdb_ident_refresh_cycle)\r
+ continue;\r
+\r
+ kcdb_identity_hold((khm_handle) ident);\r
+\r
+ LeaveCriticalSection(&cs_ident);\r
+ kcdb_identity_refresh((khm_handle) ident);\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ kcdb_identity_release((khm_handle) ident);\r
+\r
+ hit_count++;\r
+ }\r
+ } while (hit_count > 0);\r
+\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ return code;\r
+}\r
+\r
+/*****************************************/\r
+/* Custom property functions */\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_attr(khm_handle vid,\r
+ khm_int32 attr_id,\r
+ void * buffer,\r
+ khm_size cbbuf)\r
+{\r
+ kcdb_identity * id;\r
+ kcdb_attrib * attrib;\r
+ kcdb_type * type;\r
+ khm_size slot;\r
+ khm_size cbdest;\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(!kcdb_is_active_identity(vid)) {\r
+ LeaveCriticalSection(&cs_ident);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS)) {\r
+ kcdb_buf_new(&id->buf, KCDB_BUF_DEFAULT);\r
+ id->flags |= KCDB_IDENT_FLAG_ATTRIBS;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {\r
+ LeaveCriticalSection(&cs_ident);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+#if 0\r
+ /* actually, even if an attribute is computed, we still allow\r
+ those values to be set. This is because computing values\r
+ is only for credentials. If a computed value is used as a\r
+ property in any other object, it is treated as a regular value\r
+ */\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)\r
+ {\r
+ LeaveCriticalSection(&cs_ident);\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+ }\r
+#endif\r
+\r
+ if (buffer == NULL) {\r
+ /* we are removing a value */\r
+ slot = kcdb_buf_slot_by_id(&id->buf, attr_id);\r
+ if (slot != KCDB_BUF_INVALID_SLOT &&\r
+ kcdb_buf_exist(&id->buf, slot))\r
+ kcdb_buf_alloc(&id->buf, slot, attr_id, 0);\r
+ code = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {\r
+ LeaveCriticalSection(&cs_ident);\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(!(type->isValid(buffer,cbbuf))) {\r
+ code = KHM_ERROR_TYPE_MISMATCH;\r
+ goto _exit;\r
+ }\r
+\r
+ if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ kcdb_buf_alloc(&id->buf, KCDB_BUF_APPEND, attr_id, cbdest);\r
+ slot = kcdb_buf_slot_by_id(&id->buf, attr_id);\r
+ if(slot == KCDB_BUF_INVALID_SLOT || !kcdb_buf_exist(&id->buf, slot)) {\r
+ code = KHM_ERROR_NO_RESOURCES;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(code =\r
+ type->dup(buffer, cbbuf, kcdb_buf_get(&id->buf, slot), &cbdest)))\r
+ {\r
+ kcdb_buf_alloc(&id->buf, slot, attr_id, 0);\r
+ goto _exit;\r
+ }\r
+\r
+ kcdb_buf_set_value_flag(&id->buf, slot);\r
+\r
+_exit:\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_attrib(\r
+ khm_handle vid,\r
+ wchar_t * attr_name,\r
+ void * buffer,\r
+ khm_size cbbuf)\r
+{\r
+ khm_int32 attr_id = -1;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ return kcdb_identity_set_attr(\r
+ vid,\r
+ attr_id,\r
+ buffer,\r
+ cbbuf);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attr(\r
+ khm_handle vid,\r
+ khm_int32 attr_id,\r
+ khm_int32 * attr_type,\r
+ void * buffer,\r
+ khm_size * pcbbuf)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_identity * id = NULL;\r
+ kcdb_attrib * attrib = NULL;\r
+ kcdb_type * type = NULL;\r
+ khm_size slot;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_UNKNOWN;\r
+ }\r
+\r
+ if(attr_type)\r
+ *attr_type = attrib->type;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ if(!kcdb_is_active_identity(vid)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) ||\r
+ (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT ||\r
+ !kcdb_buf_val_exist(&id->buf, slot)) \r
+ {\r
+ code = KHM_ERROR_NOT_FOUND;\r
+ goto _exit;\r
+ }\r
+\r
+ if(!buffer && !pcbbuf) {\r
+ /* in this case the caller is only trying to determine if the field\r
+ contains data. If we get here, then the value exists. */\r
+ code = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+\r
+#if 0\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {\r
+ /* we should never hit this case */\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ code = KHM_ERROR_INVALID_OPERATION;\r
+#endif\r
+ } else {\r
+#endif\r
+ code = type->dup(\r
+ kcdb_buf_get(&id->buf, slot),\r
+ kcdb_buf_size(&id->buf, slot),\r
+ buffer,\r
+ pcbbuf);\r
+#if 0\r
+ }\r
+#endif\r
+\r
+_exit:\r
+ LeaveCriticalSection(&cs_ident);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attrib(\r
+ khm_handle vid,\r
+ wchar_t * attr_name,\r
+ khm_int32 * attr_type,\r
+ void * buffer,\r
+ khm_size * pcbbuf)\r
+{\r
+ khm_int32 attr_id = -1;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id)))\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ return kcdb_identity_get_attr(\r
+ vid,\r
+ attr_id,\r
+ attr_type,\r
+ buffer,\r
+ pcbbuf);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attr_string(\r
+ khm_handle vid,\r
+ khm_int32 attr_id,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags)\r
+{\r
+ khm_int32 code = KHM_ERROR_SUCCESS;\r
+ kcdb_identity * id = NULL;\r
+ kcdb_attrib * attrib = NULL;\r
+ kcdb_type * type = NULL;\r
+ khm_size slot;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {\r
+ kcdb_attrib_release_info(attrib);\r
+ return KHM_ERROR_UNKNOWN;\r
+ }\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ if(!kcdb_is_active_identity(vid)) {\r
+ code = KHM_ERROR_INVALID_PARM;\r
+ goto _exit;\r
+ }\r
+\r
+ id = (kcdb_identity *) vid;\r
+\r
+ if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) ||\r
+ (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT ||\r
+ !kcdb_buf_val_exist(&id->buf, slot)) \r
+ {\r
+ code = KHM_ERROR_NOT_FOUND;\r
+ goto _exit;\r
+ }\r
+\r
+ if(!buffer && !pcbbuf) {\r
+ /* in this case the caller is only trying to determine if the field\r
+ contains data. If we get here, then the value exists */\r
+ code = KHM_ERROR_SUCCESS;\r
+ goto _exit;\r
+ }\r
+\r
+#if 0\r
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ code = KHM_ERROR_INVALID_OPERATION;\r
+#endif\r
+ } else {\r
+#endif\r
+ if(kcdb_buf_exist(&id->buf, slot)) {\r
+ code = type->toString(\r
+ kcdb_buf_get(&id->buf, slot),\r
+ kcdb_buf_size(&id->buf, slot),\r
+ buffer,\r
+ pcbbuf,\r
+ flags);\r
+ } else\r
+ code = KHM_ERROR_NOT_FOUND;\r
+#if 0\r
+ }\r
+#endif\r
+\r
+_exit:\r
+ LeaveCriticalSection(&cs_ident);\r
+ if(type)\r
+ kcdb_type_release_info(type);\r
+ if(attrib)\r
+ kcdb_attrib_release_info(attrib);\r
+\r
+ return code;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attrib_string(\r
+ khm_handle vid,\r
+ wchar_t * attr_name,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags)\r
+{\r
+ khm_int32 attr_id = -1;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id)))\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ return kcdb_identity_get_attr_string(\r
+ vid,\r
+ attr_id,\r
+ buffer,\r
+ pcbbuf,\r
+ flags);\r
+}\r
+\r
+/*****************************************/\r
+/* Identity provider interface functions */\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_validate_name(const wchar_t * name)\r
+{\r
+ kcdb_ident_name_xfer namex;\r
+ khm_handle sub;\r
+ khm_size cch;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ /* we need to verify the length and the contents of the string\r
+ before calling the identity provider */\r
+ if(FAILED(StringCchLength(name, KCDB_IDENT_MAXCCH_NAME, &cch)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ if(wcsspn(name, KCDB_IDENT_VALID_CHARS) != cch)\r
+ return KHM_ERROR_INVALID_NAME;\r
+ \r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ ZeroMemory(&namex, sizeof(namex));\r
+\r
+ namex.name_src = name;\r
+ namex.result = KHM_ERROR_NOT_IMPLEMENTED;\r
+\r
+ kmq_send_sub_msg(sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_VALIDATE_NAME,\r
+ 0,\r
+ (void *) &namex);\r
+\r
+ rv = namex.result;\r
+ }\r
+ \r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_validate_identity(khm_handle identity)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle sub;\r
+\r
+ if(!kcdb_is_active_identity(identity))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+ \r
+ if(sub != NULL) {\r
+ rv = kmq_send_sub_msg(sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_VALIDATE_IDENTITY,\r
+ 0,\r
+ (void *) identity);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_canon_name(\r
+ const wchar_t * name_in, \r
+ wchar_t * name_out, \r
+ khm_size * cb_name_out)\r
+{\r
+ khm_handle sub;\r
+ kcdb_ident_name_xfer namex;\r
+ wchar_t name_tmp[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_size cch;\r
+\r
+ if(cb_name_out == 0 ||\r
+ FAILED(StringCchLength(name_in, KCDB_IDENT_MAXCCH_NAME, &cch)) ||\r
+ wcsspn(name_in, KCDB_IDENT_VALID_CHARS) != cch)\r
+ return KHM_ERROR_INVALID_NAME;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ ZeroMemory(&namex, sizeof(namex));\r
+ ZeroMemory(name_tmp, sizeof(name_tmp));\r
+\r
+ namex.name_src = name_in;\r
+ namex.name_dest = name_tmp;\r
+ namex.cb_name_dest = sizeof(name_tmp);\r
+ namex.result = KHM_ERROR_NOT_IMPLEMENTED;\r
+\r
+ rv = kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_CANON_NAME,\r
+ 0,\r
+ (void *) &namex);\r
+ \r
+ if(KHM_SUCCEEDED(namex.result)) {\r
+ const wchar_t * name_result;\r
+ khm_size cb;\r
+\r
+ if(name_in[0] != 0 && name_tmp[0] == 0)\r
+ name_result = name_tmp;\r
+ else\r
+ name_result = name_in;\r
+ \r
+ if(FAILED(StringCbLength(name_result, KCDB_IDENT_MAXCB_NAME, &cb)))\r
+ rv = KHM_ERROR_UNKNOWN;\r
+ else {\r
+ cb += sizeof(wchar_t);\r
+ if(name_out == 0 || *cb_name_out < cb) {\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ *cb_name_out = cb;\r
+ } else {\r
+ StringCbCopy(name_out, *cb_name_out, name_result);\r
+ *cb_name_out = cb;\r
+ rv = KHM_ERROR_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_compare_name(\r
+ const wchar_t * name1,\r
+ const wchar_t * name2)\r
+{\r
+ khm_handle sub;\r
+ kcdb_ident_name_xfer namex;\r
+ khm_int32 rv = 0;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ /* Generally in kcdb_identpro_* functions we don't emulate\r
+ any behavior if the provider is not available, but lacking\r
+ a way to make this known, we emulate here */\r
+ rv = wcscmp(name1, name2);\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ ZeroMemory(&namex, sizeof(namex));\r
+ namex.name_src = name1;\r
+ namex.name_alt = name2;\r
+\r
+ kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_COMPARE_NAME,\r
+ 0,\r
+ (void *) &namex);\r
+\r
+ rv = namex.result;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_set_default(\r
+ khm_handle identity)\r
+{\r
+ khm_handle sub;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if((identity != NULL) && \r
+ !kcdb_is_active_identity(identity))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ rv = kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_SET_DEFAULT,\r
+ (identity != NULL),\r
+ (void *) identity);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_set_searchable(\r
+ khm_handle identity,\r
+ khm_boolean searchable)\r
+{\r
+ khm_handle sub;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!kcdb_is_active_identity(identity))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ rv = kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_SET_SEARCHABLE,\r
+ searchable,\r
+ (void *) identity);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_update(khm_handle identity)\r
+{\r
+ khm_handle sub;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!kcdb_is_active_identity(identity))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ rv = kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_UPDATE,\r
+ 0,\r
+ (void *) identity);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_notify_create(khm_handle identity)\r
+{\r
+ khm_handle sub;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!kcdb_is_active_identity(identity))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ rv = kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_NOTIFY_CREATE,\r
+ 0,\r
+ (void *) identity);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_identpro_get_ui_cb(void * rock)\r
+{\r
+ khm_handle sub;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+ if(kcdb_ident_sub != NULL) {\r
+ sub = kcdb_ident_sub;\r
+ } else {\r
+ sub = NULL;\r
+ rv = KHM_ERROR_NO_PROVIDER;\r
+ }\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ if(sub != NULL) {\r
+ rv = kmq_send_sub_msg(\r
+ sub,\r
+ KMSG_IDENT,\r
+ KMSG_IDENT_GET_UI_CALLBACK,\r
+ 0,\r
+ rock);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_identity_enum(\r
+ khm_int32 and_flags,\r
+ khm_int32 eq_flags,\r
+ wchar_t * name_buf,\r
+ khm_size * pcb_buf,\r
+ khm_size * pn_idents)\r
+{\r
+ kcdb_identity * id;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_size cb_req = 0;\r
+ khm_size n_idents = 0;\r
+ size_t cb_curr;\r
+ size_t cch_curr;\r
+ size_t cch_left;\r
+ HRESULT hr;\r
+\r
+ if ((name_buf == NULL && pcb_buf == NULL && pn_idents == NULL) ||\r
+ (name_buf != NULL && pcb_buf == NULL))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ eq_flags &= and_flags;\r
+\r
+ EnterCriticalSection(&cs_ident);\r
+\r
+ if (!kcdb_checked_config) {\r
+ khm_handle h_kcdb = NULL;\r
+ khm_handle h_idents = NULL;\r
+ khm_handle h_ident = NULL;\r
+\r
+ h_kcdb = kcdb_get_config();\r
+ if (!h_kcdb)\r
+ goto _config_check_cleanup;\r
+ if(KHM_FAILED(khc_open_space(h_kcdb, L"Identity", 0, &h_idents)))\r
+ goto _config_check_cleanup;\r
+\r
+ while(KHM_SUCCEEDED(khc_enum_subspaces(h_idents,\r
+ h_ident,\r
+ &h_ident))) {\r
+\r
+ wchar_t wname[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_size cb;\r
+ khm_handle t_id;\r
+\r
+ cb = sizeof(wname);\r
+ if (KHM_FAILED(khc_get_config_space_name(h_ident,\r
+ wname,\r
+ &cb)))\r
+ continue;\r
+\r
+ if (KHM_SUCCEEDED(kcdb_identity_create(wname,\r
+ KCDB_IDENT_FLAG_CREATE,\r
+ &t_id)))\r
+ kcdb_identity_release(t_id);\r
+ }\r
+\r
+ _config_check_cleanup:\r
+ if (h_kcdb)\r
+ khc_close_space(h_kcdb);\r
+ if (h_idents)\r
+ khc_close_space(h_idents);\r
+\r
+ kcdb_checked_config = TRUE;\r
+ }\r
+\r
+ for ( id = kcdb_identities;\r
+ id != NULL;\r
+ id = LNEXT(id) ) {\r
+ if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == \r
+ KCDB_IDENT_FLAG_ACTIVE) &&\r
+ ((id->flags & and_flags) == eq_flags)) {\r
+ n_idents ++;\r
+ hr = StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &cb_curr);\r
+#ifdef DEBUG\r
+ assert(SUCCEEDED(hr));\r
+#endif\r
+ cb_req += cb_curr + sizeof(wchar_t);\r
+ } \r
+ }\r
+\r
+ cb_req += sizeof(wchar_t);\r
+\r
+ if (pn_idents != NULL)\r
+ *pn_idents = n_idents;\r
+\r
+ if (pcb_buf != NULL && (name_buf == NULL || *pcb_buf < cb_req)) {\r
+ *pcb_buf = cb_req;\r
+\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else if(name_buf != NULL) {\r
+ cch_left = (*pcb_buf) / sizeof(wchar_t);\r
+\r
+ for (id = kcdb_identities;\r
+ id != NULL;\r
+ id = LNEXT(id)) {\r
+ if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == \r
+ KCDB_IDENT_FLAG_ACTIVE) &&\r
+ ((id->flags & and_flags) == eq_flags)) {\r
+ StringCchLength(id->name, KCDB_IDENT_MAXCCH_NAME, \r
+ &cch_curr);\r
+ cch_curr++;\r
+ StringCchCopy(name_buf, cch_left, id->name);\r
+ cch_left -= cch_curr;\r
+ name_buf += cch_curr; \r
+ }\r
+ }\r
+\r
+ *name_buf = L'\0';\r
+ *pcb_buf = cb_req;\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_ident);\r
+\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_IDENTITY_H\r
+#define __KHIMAIRA_KCDB_IDENTITY_H\r
+\r
+/* Identity */\r
+\r
+#define KCDB_IDENT_HASHTABLE_SIZE 31\r
+\r
+typedef struct kcdb_identity_t {\r
+ khm_int32 magic;\r
+ wchar_t * name;\r
+ khm_int32 flags;\r
+ khm_int32 refcount;\r
+ kcdb_buf buf;\r
+ khm_ui_4 refresh_cycle;\r
+ struct kcdb_identity_t * next;\r
+ struct kcdb_identity_t * prev;\r
+} kcdb_identity;\r
+\r
+#define KCDB_IDENT_MAGIC 0x31938d4f\r
+\r
+extern CRITICAL_SECTION cs_ident;\r
+extern hashtable * kcdb_identities_namemap;\r
+extern khm_int32 kcdb_n_identities;\r
+extern kcdb_identity * kcdb_identities; /* all identities */\r
+extern kcdb_identity * kcdb_def_identity; /* default identity */\r
+extern khm_ui_4 kcdb_ident_refresh_cycle;\r
+\r
+void kcdbint_ident_init(void);\r
+void kcdbint_ident_exit(void);\r
+void kcdbint_ident_msg_completion(kmq_message * m);\r
+void kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id);\r
+\r
+#define kcdb_is_identity(id) ((id) && ((kcdb_identity *)(id))->magic == KCDB_IDENT_MAGIC)\r
+#define kcdb_is_active_identity(id) (kcdb_is_identity(id) && (((kcdb_identity *)(id))->flags & KCDB_IDENT_FLAG_ACTIVE))\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+\r
+/* set to TRUE when the configuration is loaded */\r
+static int kcdb_config_loaded = 0;\r
+\r
+/* global state cs */\r
+static CRITICAL_SECTION cs_kcdb_global;\r
+\r
+/* forward dcl */\r
+void KHMAPI kcdb_msg_completion(kmq_message * m);\r
+\r
+void kcdb_init(void) {\r
+ /* setup the critical sections */\r
+ InitializeCriticalSection(&cs_kcdb_global);\r
+\r
+ kmq_set_completion_handler(KMSG_KCDB, kcdb_msg_completion);\r
+\r
+ kcdb_credtype_init();\r
+ kcdbint_ident_init();\r
+ kcdb_credset_init();\r
+ kcdb_cred_init();\r
+ kcdb_type_init();\r
+ kcdb_attrib_init();\r
+}\r
+\r
+void kcdb_exit(void) {\r
+\r
+ kcdb_attrib_exit();\r
+ kcdb_type_exit();\r
+ kcdb_cred_exit();\r
+ kcdb_credset_exit();\r
+ kcdbint_ident_exit();\r
+ kcdb_credtype_exit();\r
+\r
+ kmq_set_completion_handler(KMSG_KCDB, NULL);\r
+\r
+ DeleteCriticalSection(&cs_kcdb_global);\r
+}\r
+\r
+khm_handle kcdb_get_config(void) {\r
+ khm_handle space = NULL;\r
+\r
+ EnterCriticalSection(&cs_kcdb_global);\r
+ if(!kcdb_config_loaded) {\r
+ khc_load_schema(NULL, schema_kcdbconfig);\r
+ kcdb_config_loaded = 1;\r
+ }\r
+ khc_open_space(NULL, L"KCDB", 0, &space);\r
+ LeaveCriticalSection(&cs_kcdb_global);\r
+\r
+ return space;\r
+}\r
+\r
+void KHMAPI kcdb_msg_completion(kmq_message * m) {\r
+ if(!m)\r
+ return;\r
+ if(m->subtype == KMSG_KCDB_IDENT)\r
+ kcdbint_ident_msg_completion(m);\r
+ else if(m->subtype == KMSG_KCDB_ATTRIB)\r
+ kcdb_attrib_msg_completion(m);\r
+ else if(m->subtype == KMSG_KCDB_TYPE)\r
+ kcdb_type_msg_completion(m);\r
+ else if(m->subtype == KMSG_KCDB_CREDTYPE)\r
+ kcdb_credtype_msg_completion(m);\r
+}\r
--- /dev/null
+Name,Type,Value,Description\r
+KCDB,KC_SPACE,0,Khimaira Configuration DB\r
+ Identity,KC_SPACE,0,Configuration space for identities\r
+ _Schema,KC_SPACE,0,Schema for identities\r
+ Sticky,KC_INT32,0,Boolean. Is this a sticky identity?\r
+ Monitor,KC_INT32,1,Boolean. Enables monitoring the identity\r
+ WarnThreshold,KC_INT32,900,In seconds\r
+ AllowWarn,KC_INT32,1,Boolean. Allow warning.\r
+ CriticalThreshold,KC_INT32,60,In seconds\r
+ AllowCritical,KC_INT32,1,Boolean. Allow critical.\r
+ AutoRenewThreshold,KC_INT32,60,In seconds\r
+ AllowAutoRenew,KC_INT32,1,Boolean.\r
+ _Schema,KC_ENDSPACE,0,\r
+ Identity,KC_ENDSPACE,0,\r
+KCDB,KC_ENDSPACE,0,\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCREDDB_H__\r
+#define __KHIMAIRA_KCREDDB_H__\r
+\r
+#include<khdefs.h>\r
+#include<time.h>\r
+\r
+\r
+/*! \defgroup kcdb NetIDMgr Credentials Database */\r
+/*@{*/\r
+\r
+/*! \brief Maximum length in characters of short description \r
+\r
+ The length includes the terminating \a NULL character.\r
+ */\r
+#define KCDB_MAXCCH_SHORT_DESC 256\r
+\r
+/*! \brief Maximum length in bytes of short description \r
+\r
+ The length includes the terminating \a NULL character.\r
+ */\r
+#define KCDB_MAXCB_SHORT_DESC (sizeof(wchar_t) * KCDB_MAXCCH_SHORT_DESC)\r
+\r
+/*! \brief Maximum length in characters of long description \r
+\r
+ The length includes the terminating \a NULL character.\r
+ */\r
+#define KCDB_MAXCCH_LONG_DESC 8192\r
+\r
+/*! \brief Maximum length in characters of long description \r
+\r
+ The length includes the terminating \a NULL character.\r
+ */\r
+#define KCDB_MAXCB_LONG_DESC (sizeof(wchar_t) * KCDB_MAXCCH_LONG_DESC)\r
+\r
+/*! \brief Maximum length in characters of name \r
+\r
+ The length includes the terminating \a NULL character.\r
+ */\r
+#define KCDB_MAXCCH_NAME 256\r
+\r
+/*! \brief Maximum length in bytes of short description \r
+\r
+ The length includes the terminating \a NULL character.\r
+ */\r
+#define KCDB_MAXCB_NAME (sizeof(wchar_t) * KCDB_MAXCCH_NAME)\r
+\r
+/*! \brief Automatically determine the number of bytes required\r
+\r
+ Can be used in most places where a count of bytes is required.\r
+ For many objects, the number of bytes that are required can be\r
+ determined through context and may be ommited. In such cases you\r
+ can use the \a KCDB_CBSIZE_AUTO value to specify that the function\r
+ is to determine the size automatically.\r
+\r
+ \note Not all functions that take a count of bytes support the \a\r
+ KCDB_CBSIZE_AUTO value.\r
+*/\r
+#define KCDB_CBSIZE_AUTO (-1)\r
+\r
+/*!\r
+\defgroup kcdb_ident Identities\r
+\r
+Functions, macros etc. for manipulating identities.\r
+*/\r
+\r
+/*@{*/\r
+\r
+/*! \brief The maximum number of characters (including terminator) that can\r
+ be specified as an identity name */\r
+#define KCDB_IDENT_MAXCCH_NAME 256\r
+\r
+/*! \brief The maximum number of bytes that can be specified as an identity\r
+ name */\r
+#define KCDB_IDENT_MAXCB_NAME (sizeof(wchar_t) * KCDB_IDENT_MAXCCH_NAME)\r
+\r
+/*! \brief Valid characters in an identity name */\r
+#define KCDB_IDENT_VALID_CHARS L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._@-/"\r
+\r
+/*!\r
+\name Flags for identities */\r
+/*@{*/\r
+\r
+/*! \brief Create the identity if it doesn't already exist. \r
+ \note Only to be used with kcdb_identity_create() */\r
+#define KCDB_IDENT_FLAG_CREATE 0x10000000L\r
+\r
+/*! \brief Inverts the accompanying flags.\r
+\r
+ \note Only to be used with kcdb_identity_set_flags()\r
+ \see kcdb_identity_set_flags() */\r
+#define KCDB_IDENT_FLAG_INVERT 0x40000000L\r
+\r
+/*! \brief Has configuration information\r
+\r
+ Indicates that the identity has persistent configuration\r
+ information associated with it.\r
+ */\r
+#define KCDB_IDENT_FLAG_CONFIG 0x00800000L\r
+\r
+/*! \brief Marks the identity as active.\r
+\r
+ An active identity is one that is in active use within NetIDMgr.\r
+\r
+ \note This flag is readonly and cannot be specified when creating\r
+ or modifying an identity. Once an identity is deleted, it will\r
+ no longer have this flag. */\r
+#define KCDB_IDENT_FLAG_ACTIVE 0x02000000L\r
+\r
+/*! \brief Sticky identity\r
+\r
+ Sticky identities are identities that are always visible in the\r
+ credentials display even if no credentials are associated with it.\r
+ */\r
+#define KCDB_IDENT_FLAG_STICKY 0x04000000L\r
+\r
+/*! \brief The identity has custom attributes assigned\r
+ */\r
+#define KCDB_IDENT_FLAG_ATTRIBS 0x08000000L\r
+\r
+/*! \brief This is the default identity. \r
+\r
+ At most one identity will have this flag set at any given time.\r
+ To set or reset the flag, use kcdb_identity_set_default() */\r
+#define KCDB_IDENT_FLAG_DEFAULT 0x00000001L\r
+\r
+/*! \brief This identity can be searched.\r
+\r
+ The meaning of this flag is left to be interpreted by individual\r
+ plugins. */\r
+#define KCDB_IDENT_FLAG_SEARCHABLE 0x00000002L\r
+\r
+/*! \brief Hidden identity.\r
+\r
+ The identity will not show up in the identity list window. Once\r
+ the hidden is switched off, the identity (and all associated\r
+ credentials) will re-appear in the window */\r
+#define KCDB_IDENT_FLAG_HIDDEN 0x00000004L\r
+\r
+/*! \brief Invalid identity\r
+\r
+ For one reason or another, this identity is invalid. This flag\r
+ can be set by an identity provider to indicate that this identity\r
+ does not correspond to an actual identity because an external\r
+ entity (such as a KDC) has denied it's existence.\r
+\r
+ The absence of this flag does not imply that the identity is\r
+ valid. The ::KCDB_IDENT_FLAG_VALID bit must be set for that to be\r
+ the case. If neither flag is set, then the status of the identity\r
+ is not known.\r
+*/\r
+#define KCDB_IDENT_FLAG_INVALID 0x00000008L\r
+\r
+/*! \brief Valid identity\r
+\r
+ The identity has been validated through an external entity, or\r
+ it's validity implied through the existence of credentials for the\r
+ identity.\r
+\r
+ The absence of this flag does not imply that the identity is\r
+ invalid. The ::KCDB_IDENT_FLAG_INVALID bit must be set for that\r
+ to be the case. If neither flag is set, then the status of the\r
+ identity is not known.\r
+ */\r
+#define KCDB_IDENT_FLAG_VALID 0x00000010L\r
+\r
+/*! \brief Expired identity\r
+\r
+ This identity has expired and can not be actively used to obtain\r
+ credentials. This determination is made based on the input of\r
+ some external entity. This flag may only be set by an identity\r
+ provider.\r
+*/\r
+#define KCDB_IDENT_FLAG_EXPIRED 0x00000020L\r
+\r
+/*! \brief Empty identity\r
+\r
+ The identity does not have actual credentials associated with it.\r
+ */\r
+#define KCDB_IDENT_FLAG_EMPTY 0x00000040L\r
+\r
+/*! \brief Renewable identity\r
+\r
+ The initial credentials associated with this identity are\r
+ renewable. Thus making the whole identity renewable.\r
+ */\r
+#define KCDB_IDENT_FLAG_RENEWABLE 0x00000080L\r
+\r
+/*! \brief Required user interaction\r
+\r
+ The identity is in a state which requires user interaction to\r
+ activate. Currently, the identity may not be in a state where it\r
+ can be used to obtain credentials.\r
+\r
+ A typical example of this is when the primary password for an\r
+ identity has expired.\r
+ */\r
+#define KCDB_IDENT_FLAG_INTERACT 0x00000100L\r
+\r
+/*! \brief Has expired credentials\r
+\r
+ The identity has expired credentials associated with it.\r
+ */\r
+#define KCDB_IDENT_FLAG_CRED_EXP 0x00000200L\r
+\r
+/*! \brief Has renewable credentials\r
+\r
+ The identity has renewable credentials associated with it. If the\r
+ initial credentials of the identity are renewable, then identity\r
+ is renewable. Hence the ::KCDB_IDENT_FLAG_RENEWABLE should also\r
+ be set.\r
+ */\r
+#define KCDB_IDENT_FLAG_CRED_RENEW 0x00000400L\r
+\r
+/*! \brief Bit mask for local flags\r
+\r
+ Local flags are those local to the KCDB.\r
+ */\r
+#define KCDB_IDENT_FLAGMASK_LOCAL 0x0000ffffL\r
+\r
+/*! \brief Read/write flags mask.\r
+\r
+ A bitmask that correspond to all the read/write flags in the mask.\r
+*/\r
+#define KCDB_IDENT_FLAGMASK_RDWR 0x000007ffL\r
+\r
+/*@}*/\r
+\r
+/*! \name Identity Provider Data Structures\r
+@{*/\r
+\r
+/*! \brief Name transfer structure\r
+\r
+ Used when the KCDB is communicating with the identity provider to\r
+ exchange string names of identities. See individual ::KMSG_IDENT\r
+ message subtypes for the usage of this structure.\r
+ */\r
+typedef struct tag_kcdb_ident_name_xfer {\r
+ const wchar_t * name_src; /*!< An identity name. Does not\r
+ exceed KCDB_IDENT_MAXCCH_NAME\r
+ characters including terminating\r
+ NULL. */\r
+ const wchar_t * name_alt; /*!< An identity name. Does not\r
+ exceed KCDB_IDENT_MAXCCH_NAME\r
+ characters including terminating\r
+ NULL. */\r
+ wchar_t * name_dest; /*!< Pointer to a buffer that is to\r
+ receive a response string. The\r
+ size of the buffer in bytes is\r
+ specified in \a cb_name_dest. */\r
+ khm_size cb_name_dest; /*!< Size of buffer pointed to by \a\r
+ name_dest in bytes. */\r
+ khm_int32 result; /*!< Receives a result value, which is\r
+ usually an error code defined in\r
+ kherror.h, though it is not\r
+ always. */\r
+} kcdb_ident_name_xfer;\r
+\r
+typedef struct tag_kcdb_ident_info {\r
+ khm_handle identity;\r
+ khm_int32 fields;\r
+\r
+ FILETIME expiration;\r
+} kcdb_ident_info;\r
+\r
+/*@}*/\r
+\r
+/*! \name Identity provider interface functions\r
+\r
+ These functions encapsulate safe calls to the current identity\r
+ provider. While these functions are exported, applications should\r
+ not call these functions directly. They are provided for use by\r
+ the NetIDMgr core application.\r
+@{*/\r
+\r
+/*! \brief Validate an identity name\r
+\r
+ The name that is provided will be passed through sets of\r
+ validations. One set, which doesn't depend on the identity\r
+ provider checks whether the length of the identity name and\r
+ whether there are any invalid characters in the identity name. If\r
+ the name passes those tests, then the name is passed down to the\r
+ identity provider's name validation handler.\r
+\r
+ \retval KHM_ERROR_SUCCESS The name is valid\r
+ \retval KHM_ERROR_TOO_LONG Too many characters in name\r
+ \retval KHM_ERROR_INVALID_NAME There were invalid characters in the name.\r
+ \retval KHM_ERROR_NO_PROVIDER There is no identity provider;\r
+ however the name passed the length and character tests.\r
+ \retval KHM_ERROR_NOT_IMPLEMENTED The identity provider doesn't\r
+ implement a name validation handler; however the name passed\r
+ the length and character tests.\r
+\r
+ \see ::KMSG_IDENT_VALIDATE_NAME\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_validate_name(const wchar_t * name);\r
+\r
+/*! \brief Validate an identity\r
+\r
+ The identity itself needs to be validated. This may involve\r
+ communicating with an external entity.\r
+\r
+ \see ::KMSG_IDENT_VALIDATE_IDENTITY\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_validate_identity(khm_handle identity);\r
+\r
+/*! \brief Canonicalize the name \r
+\r
+\r
+ \see ::KMSG_IDENT_CANON_NAME\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_canon_name(const wchar_t * name_in, \r
+ wchar_t * name_out, \r
+ khm_size * cb_name_out);\r
+\r
+/*! \brief Compare two identity names \r
+\r
+ \see ::KMSG_IDENT_COMPARE_NAME\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_compare_name(const wchar_t * name1,\r
+ const wchar_t * name2);\r
+\r
+/*! \brief Set the specified identity as the default \r
+\r
+ \see ::KMSG_IDENT_SET_DEFAULT\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_set_default(khm_handle identity);\r
+\r
+/*! \brief Set the specified identity as searchable \r
+\r
+ \see ::KMSG_IDENT_SET_SEARCHABLE\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_set_searchable(khm_handle identity,\r
+ khm_boolean searchable);\r
+\r
+/*! \brief Update the specified identity \r
+\r
+ \see ::KMSG_IDENT_UPDATE\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_update(khm_handle identity);\r
+\r
+/*! \brief Obtain the UI callback\r
+\r
+ \a rock is actually a pointer to a ::khui_ident_new_creds_cb which\r
+ is to receive the callback.\r
+\r
+ \see ::KMSG_IDENT_GET_UI_CALLBACK\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_get_ui_cb(void * rock);\r
+\r
+/*! \brief Notify an identity provider of the creation of a new identity \r
+\r
+ \see ::KMSG_IDENT_NOTIFY_CREATE\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identpro_notify_create(khm_handle identity);\r
+\r
+/*@}*/\r
+\r
+/*! \brief Check if the given name is a valid identity name\r
+\r
+ \return TRUE or FALSE to the question, is this valid?\r
+*/\r
+KHMEXP khm_boolean KHMAPI \r
+kcdb_identity_is_valid_name(const wchar_t * name);\r
+\r
+/*! \brief Create or open an identity.\r
+\r
+ If the KCDB_IDENT_FLAG_CREATE flag is specified in the flags\r
+ parameter a new identity will be created if one does not already\r
+ exist with the given name. If an identity by that name already\r
+ exists, then the existing identity will be opened. The result\r
+ parameter will receive a held reference to the opened identity.\r
+ Use kcdb_identity_release() to release the handle.\r
+\r
+ \param[in] name Name of identity to create\r
+ \param[in] flags If KCDB_IDENT_FLAG_CREATE is specified, then the\r
+ identity will be created if it doesn't already exist.\r
+ Additional flags can be set here which will be assigned to the\r
+ identity if it is created. Additional flags have no effect if\r
+ an existing identity is opened.\r
+ \param[out] result If the call is successful, this receives a held\r
+ reference to the identity. The caller should call\r
+ kcdb_identity_release() to release the identity once it is no\r
+ longer needed.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_create(const wchar_t *name, \r
+ khm_int32 flags, \r
+ khm_handle * result);\r
+\r
+/*! \brief Mark an identity for deletion.\r
+\r
+ The identity will be marked for deletion. The\r
+ KCDB_IDENT_FLAG_ACTIVE will no longer be present for this\r
+ identity. Once all references to the identity are released, it\r
+ will be removed from memory. All associated credentials will also\r
+ be removed. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_delete(khm_handle id);\r
+\r
+/*! \brief Set or unset the specified flags in the specified identity.\r
+\r
+ Only flags that are in KCDB_IDENT_FLAGMASK_RDWR can be specifed\r
+ in the flags parameter. The only exception is the\r
+ KCDB_IDENT_FLAG_INVERT flag which controls whether the flags are\r
+ to be set or reset.\r
+\r
+ If the ::KCDB_IDENT_FLAG_INVERT flag is not specified in \a flags,\r
+ then any flags set in \a flags will also be set in the identity.\r
+ If the ::KCDB_IDENT_FLAG_INVERT is specified, then any flag set in\r
+ \a flags will be reset in the identity.\r
+\r
+ If ::KCDB_IDENT_FLAG_INVALID is set using this function, then the\r
+ ::KCDB_IDENT_FLAG_VALID will be automatically reset, and vice\r
+ versa. Resetting either bit does not undo this change, and will\r
+ leave the identity's validity unspecified.\r
+\r
+ Note that setting or resetting certain flags have other semantic\r
+ side-effects:\r
+\r
+ - ::KCDB_IDENT_FLAG_DEFAULT : Setting this is equivalent to\r
+ calling kcdb_identity_set_default() with \a id. Resetting this\r
+ is equivalent to calling kcdb_identity_set_default() with NULL.\r
+\r
+ - ::KCDB_IDENT_FLAG_SEARCHABLE : Setting this will result in the\r
+ identity provider getting notified of the change. If the\r
+ identity provider indicates that searchable flag should not be\r
+ set or reset (according to KCDB_IDENT_FLAG_INVERT setting) on\r
+ the identity, then kcdb_identity_set_flags() will return an\r
+ error.\r
+\r
+ \note kcdb_identity_set_flags() is not atomic. Even if the\r
+ function returns a failure code, some flags in the identity may\r
+ have been set. When calling kcdb_identity_set_flags() always\r
+ check the flags in the identity using kcdb_identity_get_flags() to\r
+ check which flags have been set and which have failed.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_flags(khm_handle id, \r
+ khm_int32 flags);\r
+\r
+/*! \brief Return all the flags for the identity\r
+\r
+ The returned flags may include internal flags.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_flags(khm_handle id, \r
+ khm_int32 * flags);\r
+\r
+/*! \brief Return the name of the identity \r
+\r
+ \param[out] buffer Buffer to copy the identity name into. The\r
+ maximum size of an identity name is \a KCDB_IDENT_MAXCB_NAME.\r
+ If \a buffer is \a NULL, then the required size of the buffer\r
+ is returned in \a pcbsize.\r
+\r
+ \param[in,out] pcbsize Size of buffer in bytes. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_name(khm_handle id, \r
+ wchar_t * buffer, \r
+ khm_size * pcbsize);\r
+\r
+/*! \brief Set the specified identity as the default.\r
+\r
+ Specifying NULL effectively makes none of the identities the\r
+ default.\r
+\r
+ \see kcdb_identity_set_flags()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_default(khm_handle id);\r
+\r
+/*! \brief Mark the specified identity as the default.\r
+\r
+ This API is reserved for use by identity providers as a means of\r
+ specifying which identity is default. The difference between\r
+ kcdb_identity_set_default() and kcdb_identity_set_default_int() is\r
+ in semantics. \r
+\r
+ - kcdb_identity_set_default() is used to request the KCDB to\r
+ designate the specified identity as the default. When\r
+ processing the request, the KCDB invokes the identity provider\r
+ to do the necessary work to make the identity the default.\r
+\r
+ - kcdb_identity_set_default_int() is used by the identity provider\r
+ to notify the KCDB that the specified identity is the default.\r
+ This does not result in the invocation of any other semantics to\r
+ make the identity the default other than releasing the previous\r
+ defualt identity and making the specified one the default. As\r
+ an additional side effect, the notification <::KMSG_KCDB,\r
+ ::KMSG_KCDB_IDENT, ::KCDB_OP_NEW_DEFAULT> will also not be sent.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kcdb_identity_set_default_int(khm_handle id);\r
+\r
+/*! \brief Get the default identity\r
+\r
+ Obtain a held handle to the default identity if there is one. The\r
+ handle must be freed using kcdb_identity_release().\r
+\r
+ If there is no default identity, then the handle pointed to by \a\r
+ pvid is set to \a NULL and the function returns\r
+ KHM_ERROR_NOT_FOUND. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_default(khm_handle * pvid);\r
+\r
+/*! \brief Get the configuration space for the identity. \r
+\r
+ \param[in] id Identity for which the configuraiton space is requested\r
+\r
+ \param[in] flags Flags used when calling khc_open_space(). If \a\r
+ flags specifies KHM_FLAG_CREATE, then the configuration space\r
+ is created.\r
+\r
+ \param[out] result The resulting handle. If the call is\r
+ successful, this receives a handle to the configuration space.\r
+ Use khc_close_space() to close the handle.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_config(khm_handle id,\r
+ khm_int32 flags,\r
+ khm_handle * result);\r
+\r
+/*! \brief Hold a reference to an identity.\r
+\r
+ A reference to an identity (a handle) is only valid while it is\r
+ held. \note Once the handle is released, it can not be\r
+ revalidated by calling kcdb_identity_hold(). Doing so would lead\r
+ to unpredictable consequences. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_hold(khm_handle id);\r
+\r
+/*! \brief Release a reference to an identity.\r
+ \see kcdb_identity_hold() */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_release(khm_handle id);\r
+\r
+/*! \brief Set the identity provider subscription\r
+\r
+ If there was a previous subscription, that subscription will be\r
+ automatically deleted.\r
+\r
+ \param[in] sub New identity provider subscription\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_provider(khm_handle sub);\r
+\r
+/*! \brief Set the primary credentials type\r
+\r
+ The primary credentials type is designated by the identity\r
+ provider. As such, this function should only be called by an\r
+ identity provider.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_type(khm_int32 cred_type);\r
+\r
+/*! \brief Retrieve the identity provider subscription\r
+\r
+ \param[out] sub Receives the current identity provider\r
+ subscription. Set to NULL if only the existence of an\r
+ identity provider needs to be checked.\r
+\r
+ \retval KHM_ERROR_SUCCESS An identity provider exists. If \a sub\r
+ was not NULL, the subscription has been copied there.\r
+\r
+ \retval KHM_ERROR_NOT_FOUND There is currently no registered\r
+ identity provider. If \a sub was not NULL, the handle it\r
+ points to has been set to NULL.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_provider(khm_handle * sub);\r
+\r
+/*! \brief Retrieve the identity provider credentials type\r
+\r
+ This is the credentials type that the identity provider has\r
+ designated as the primary credentials type.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_type(khm_int32 * ptype);\r
+\r
+/*! \brief Set an attribute in an identity by attribute id\r
+\r
+ \param[in] buffer A pointer to a buffer containing the data to\r
+ assign to the attribute. Setting \a buffer to NULL has the\r
+ effect of removing any data that is already assigned to the\r
+ attribute. If \a buffer is non-NULL, then \a cbbuf should\r
+ specify the number of bytes in \a buffer.\r
+\r
+ \param[in] cbbuf Number of bytes of data in \a buffer. The\r
+ individual data type handlers may copy in less than this many\r
+ bytes in to the credential.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_attr(khm_handle identity,\r
+ khm_int32 attr_id,\r
+ void * buffer,\r
+ khm_size cbbuf);\r
+\r
+/*! \brief Set an attribute in an identity by name\r
+\r
+ The attribute name has to be a KCDB registered attribute or\r
+ property.\r
+\r
+ \param[in] cbbuf Number of bytes of data in \a buffer. The\r
+ individual data type handlers may copy in less than this many\r
+ bytes in to the credential.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_set_attrib(khm_handle identity,\r
+ wchar_t * attr_name,\r
+ void * buffer,\r
+ khm_size cbbuf);\r
+\r
+/*! \brief Get an attribute from an identity by attribute id.\r
+\r
+ \param[in] buffer The buffer that is to receive the attribute\r
+ value. Set this to NULL if only the required buffer size is\r
+ to be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+\r
+ \param[out] attr_type Receives the data type of the attribute.\r
+ Set this to NULL if the type is not required.\r
+\r
+ \note Set both \a buffer and \a cbbuf to NULL if only the\r
+ existence of the attribute is to be checked. If the attribute\r
+ exists in this identity then the function will return\r
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attr(khm_handle identity,\r
+ khm_int32 attr_id,\r
+ khm_int32 * attr_type,\r
+ void * buffer,\r
+ khm_size * pcbbuf);\r
+\r
+/*! \brief Get an attribute from an identity by name.\r
+\r
+ \param[in] buffer The buffer that is to receive the attribute\r
+ value. Set this to NULL if only the required buffer size is\r
+ to be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+\r
+ \note Set both \a buffer and \a cbbuf to NULL if only the\r
+ existence of the attribute is to be checked. If the attribute\r
+ exists in this identity then the function will return\r
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attrib(khm_handle identity,\r
+ wchar_t * attr_name,\r
+ khm_int32 * attr_type,\r
+ void * buffer,\r
+ khm_size * pcbbuf);\r
+\r
+/*! \brief Get the string representation of an identity attribute.\r
+\r
+ A shortcut function which generates the string representation of\r
+ an identity attribute directly.\r
+\r
+ \param[in] identity A handle to an identity\r
+\r
+ \param[in] attr_id The attribute to retrieve\r
+\r
+ \param[out] buffer A pointer to a string buffer which receives the\r
+ string form of the attribute. Set this to NULL if you only\r
+ want to determine the size of the required buffer.\r
+\r
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,\r
+ holds the size of the buffer pointed to by \a buffer, and on\r
+ exit, receives the actual number of bytes that were copied.\r
+\r
+ \param[in] flags Flags for the string conversion. Can be set to\r
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is\r
+ KCDB_TS_LONG.\r
+\r
+ \retval KHM_ERROR_SUCCESS Success\r
+ \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid\r
+ or was not defined for this identity\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the\r
+ supplied buffer was insufficient\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attr_string(khm_handle identity,\r
+ khm_int32 attr_id,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Get the string representation of an identity attribute by name.\r
+\r
+ A shortcut function which generates the string representation of\r
+ an identity attribute directly.\r
+\r
+ \param[in] identity A handle to an identity\r
+\r
+ \param[in] attrib The name of the attribute to retrieve\r
+\r
+ \param[out] buffer A pointer to a string buffer which receives the\r
+ string form of the attribute. Set this to NULL if you only\r
+ want to determine the size of the required buffer.\r
+\r
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,\r
+ holds the size of the buffer pointed to by \a buffer, and on\r
+ exit, receives the actual number of bytes that were copied.\r
+\r
+ \param[in] flags Flags for the string conversion. Can be set to\r
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is\r
+ KCDB_TS_LONG.\r
+\r
+ \see kcdb_identity_get_attr_string()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_get_attrib_string(khm_handle identity,\r
+ wchar_t * attr_name,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Enumerate identities\r
+\r
+ Enumerates all the active identities that match the criteria\r
+ specified using \a and_flags and \a eq_flags. The condition is\r
+ applied to all active identities as follows:\r
+\r
+ \code\r
+ (identity->flags & and_flags) == (eq_flags & and_flags)\r
+ \endcode\r
+\r
+ Essentially, if a flag is set in \a and_flags, then that flag in\r
+ the identity should equal the setting in \a eq_flags.\r
+\r
+ \param[in] and_flags See above\r
+\r
+ \param[in] eq_flags See above\r
+\r
+ \param[out] name_buf Buffer to receive the list of identity names.\r
+ Can be NULL if only the required size of the buffer or the\r
+ number of matching identities is required. The list is\r
+ returned as a multi string.\r
+\r
+ \param[in,out] pcb_buf Number of bytes in buffer pointed to by \a\r
+ name_buf on entry. On exit, will receive the number of bytes\r
+ copied. Can be NULL only if \a name_buf is also NULL. If \a\r
+ name_buf is NULL or if \a pcb_buf indicates that the buffer is\r
+ insufficient, this will receive the number of bytes required\r
+ and the return value of the function will be\r
+ KHM_ERROR_TOO_LONG\r
+\r
+ \param[out] pn_idents Receives the number of identities that match\r
+ the given criteria.\r
+\r
+ \retval KHM_ERROR_SUCCESS If \a name_buf was valid, the buffer now\r
+ contains a multi string of identities that matched. If \a\r
+ pn_idents was valid, it contains the number of identities\r
+ matched.\r
+\r
+ \retval KHM_ERROR_TOO_LONG No buffer was supplied or the supplied\r
+ buffer was insufficient. If \a pn_idents was valid, it\r
+ contains the number of identities.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM None of the parameters \a name_buf,\r
+ \a pcb_buf and \a pn_idents were supplied, or \a pcb_buf was\r
+ NULL when \a name_buf was not.\r
+\r
+ \note Calling this function to obtain the required size of the\r
+ buffer and then calling it with a that sized buffer is not\r
+ guaranteed to work since the list of identities may change\r
+ between the two calls.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_enum(khm_int32 and_flags,\r
+ khm_int32 eq_flags,\r
+ wchar_t * name_buf,\r
+ khm_size * pcb_buf,\r
+ khm_size * pn_idents);\r
+\r
+/*! \brief Refresh identity attributes based on root credential set\r
+\r
+ Several flags in an identity are dependent on the credentials that\r
+ are associated with it in the root credential set. In addition,\r
+ other flags in an identity depend on external factors that need to\r
+ be verfied once in a while. This API goes through the root\r
+ credential set as well as consulting the identity provider to\r
+ update an identity.\r
+\r
+ \see kcdb_identity_refresh()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_refresh(khm_handle vid);\r
+\r
+/*! \brief Refresh all identities\r
+\r
+ Equivalent to calling kcdb_identity_refresh() for all active\r
+ identities.\r
+\r
+ \see kcdb_identityt_refresh()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_identity_refresh_all(void);\r
+\r
+/* KSMG_KCDB_IDENT notifications are structured as follows:\r
+ type=KMSG_KCDB\r
+ subtype=KMSG_KCDB_IDENT\r
+ uparam=one of KCDB_OP_*\r
+ blob=handle to identity in question */\r
+\r
+/*@}*/\r
+\r
+\r
+/*********************************************************************/\r
+\r
+\r
+/*!\r
+\defgroup kcdb_creds Credential sets and individual credentials\r
+\r
+@{\r
+*/\r
+\r
+\r
+/*! \brief Credentials process function\r
+\r
+ This function is called for each credential in a credential set\r
+ when supplied to kcdb_credset_apply(). It should return\r
+ KHM_ERROR_SUCCESS to continue the operation, or any other value to\r
+ terminate the processing.\r
+\r
+ \see kcdb_credset_apply()\r
+*/\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_cred_apply_func)(khm_handle cred, \r
+ void * rock);\r
+\r
+/*! \brief Credentials filter function.\r
+\r
+ Should return non-zero if the credential passed as \a cred is to\r
+ be "accepted". The precise consequence of a non-zero return value\r
+ is determined by the individual function that this call back is\r
+ passed into.\r
+\r
+ This function should not call any other function which may modify\r
+ \a cred.\r
+\r
+ \see kcdb_credset_collect_filtered()\r
+ \see kcdb_credset_extract_filtered()\r
+*/\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_cred_filter_func)(khm_handle cred, \r
+ khm_int32 flags, \r
+ void * rock);\r
+\r
+/*! \brief Credentials compare function.\r
+\r
+ Asserts a weak ordering on the credentials that are passed in as\r
+ \a cred1 and \a cred2. It should return:\r
+\r
+ - a negative value if \a cred1 < \a cred2\r
+ - zero if \a cred1 == \a cred2\r
+ - a postive value if \a cred1 > \a cred2\r
+ \see kcdb_credset_sort()\r
+*/\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_cred_comp_func)(khm_handle cred1, \r
+ khm_handle cred2, \r
+ void * rock);\r
+\r
+/*! \defgroup kcdb_credset Credential sets */\r
+/*@{*/\r
+\r
+/*! \brief Create a credential set.\r
+\r
+ Credential sets are temporary containers for credentials. These\r
+ can be used by plug-ins to store credentials while they are being\r
+ enumerated from an external source. Once all the credentials have\r
+ been collected into the credential set, the plug-in may call\r
+ kcdb_credset_collect() to collect the credentials into the root\r
+ credential store.\r
+\r
+ The user interface will only display credentials that are in the\r
+ root credential store. No notifications are generated for changes\r
+ to a non-root credential set.\r
+\r
+ Use kcdb_credset_delete() to delete the credential set once it is\r
+ created.\r
+\r
+ \see kcdb_credset_delete()\r
+ \see kcdb_credset_collect()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_create(khm_handle * result);\r
+\r
+/** \brief Delete a credential set\r
+\r
+ \see kcdb_credset_create()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_delete(khm_handle credset);\r
+\r
+/** \brief Collect credentials from a credential set to another credential set.\r
+\r
+ Collecting a subset of credentials from credential set \a cs_src\r
+ into credential set \a cs_dest involves the following steps:\r
+\r
+ - Select all credentials from \a cs_src that matches the \a\r
+ identity and \a type specified in the function call and add them\r
+ to the \a cs_dest credential set if they are not there already.\r
+ Note that if neither credential set is not the root credential\r
+ store, then the credentials will be added by reference, while if\r
+ it is the root credential store, the credentials will be\r
+ duplicated, and the copies will be added to \a cs_dest.\r
+\r
+ - If a selected credential in \a cs_src already exists in \a\r
+ cs_dest, then update the credential in \a cs_dest with the\r
+ credential fields in \a cs_src. In other words, once a\r
+ credential is found to exist in both \a cs_src and \a cs_dest,\r
+ all the non-null fields from the credential in \a cs_src will be\r
+ copied to the credential in \a cs_dest. Fields which are null\r
+ (undefined) in \a cs_src and are non-null in \a cs_dest will be\r
+ left unmodified in \a cs_dest.\r
+\r
+ One notable exception is the credentials' flags. All flags in\r
+ \a cs_src which are not included in\r
+ ::KCDB_CRED_FLAGMASK_ADDITIVE will be copied to the\r
+ corresponding bits in the flags of \a cs_dest. However, flags\r
+ that are included in ::KCDB_CRED_FLAGMASK_ADDITIVE will be added\r
+ to the corresponding bits in \a cs_dest.\r
+\r
+ (See notes below)\r
+\r
+ - Remove all credentials from \a cs_dest that match the \a\r
+ identity and \a type that do not appear in \a cs_src. (see notes\r
+ below)\r
+\r
+ For performance reasons, plugins should use kcdb_credset_collect()\r
+ to update the root credentials store instead of adding and\r
+ removing individual credentials from the root store.\r
+\r
+ Only credentials that are associated with active identities are\r
+ affected by kcdb_credset_collect().\r
+\r
+ \param[in] cs_dest A handle to the destination credential set. If\r
+ this is \a NULL, then it is assumed to refer to the root\r
+ credential store.\r
+\r
+ \param[in] cs_src A handle to the source credential set. If this\r
+ is NULL, then it is assumed to refer to the root credential\r
+ store.\r
+\r
+ \param[in] identity A handle to an identity. Setting this to NULL\r
+ collects all identities in the credential set.\r
+\r
+ \param[in] type A credentials type. Setting this to\r
+ KCDB_CREDTYPE_ALL collects all credential types in the set.\r
+\r
+ \param[out] delta A bit mask that indicates the modifications that\r
+ were made to \a cs_dest as a result of the collect operation.\r
+ This is a combination of KCDB_DELTA_* values. This parameter\r
+ can be \a NULL if the value is not required.\r
+\r
+ \warning If \a identity and \a type is set to a wildcard, all\r
+ credentials in the root store that are not in this credentials\r
+ set will be deleted.\r
+\r
+ \note Two credentials \a A and \a B are considered equal if:\r
+ - They refer to the same identity\r
+ - Both have the same credential type\r
+ - Both have the same name\r
+\r
+ \note This is the only supported way of modifying the root\r
+ credential store.\r
+\r
+ \note \a cs_src and \a cs_dest can not refer to the same\r
+ credentials set.\r
+\r
+ \note The destination credential set cannot be sealed.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_collect(khm_handle cs_dest,\r
+ khm_handle cs_src,\r
+ khm_handle identity, \r
+ khm_int32 type,\r
+ khm_int32 * delta);\r
+\r
+/*! \brief Credentials were added\r
+ \see kcdb_credset_collect() */\r
+#define KCDB_DELTA_ADD 1\r
+\r
+/*! \brief Credentials were deleted \r
+ \see kcdb_credset_collect() */\r
+#define KCDB_DELTA_DEL 2\r
+\r
+/*! \brief Credentials were modified\r
+ \see kcdb_credset_collect() */\r
+#define KCDB_DELTA_MODIFY 4\r
+\r
+/*! \brief Indicates that the credential to be filtered is from the root store.\r
+\r
+ \see kcdb_credset_collect_filtered()\r
+*/\r
+#define KCDB_CREDCOLL_FILTER_ROOT 1\r
+\r
+/*! \brief Indicates that the credential to be filtered is from the source\r
+ credential set \r
+ \r
+ \see kcdb_credset_collect_filtered() */\r
+#define KCDB_CREDCOLL_FILTER_SRC 2\r
+\r
+/*! \brief Indicates that the credential to be filtered is from the destination\r
+ credential set \r
+ \r
+ \see kcdb_credset_collect_filtered() */\r
+#define KCDB_CREDCOLL_FILTER_DEST 4\r
+\r
+/*! \brief Collect credentials from one credential set to another using a filter.\r
+\r
+ Similar to kcdb_credset_collect() except instead of selecting\r
+ credentials by matching against an identity and/or type, a filter\r
+ function is called. If the filter function returns non-zero for a\r
+ credential, that credential is selected.\r
+\r
+ Credentials in the source and destination credential sets are\r
+ passed into the filter function. Depending on whether the\r
+ credential is in the source credential set or destination\r
+ credential set, the \a flag parameter may have either \a\r
+ KCDB_CREDCOLL_FILTER_SRC or \a KCDB_CREDCOLL_FILTER_DEST bits set.\r
+ Also, if either one of the credential sets is the root credential\r
+ store, then additionally \a KCDB_CREDCOLL_FILTER_ROOT would also\r
+ be set.\r
+\r
+ See the kcdb_credset_collect() documentation for explanations of\r
+ the \a cs_src, \a cs_dest and \a delta parameters which perform\r
+ identical functions.\r
+\r
+ \param[in] filter The filter of type ::kcdb_cred_filter_func\r
+ \param[in] rock A custom argument to be passed to the filter function.\r
+\r
+ \see kcdb_credset_collect()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_collect_filtered(khm_handle cs_dest,\r
+ khm_handle cs_src,\r
+ kcdb_cred_filter_func filter,\r
+ void * rock,\r
+ khm_int32 * delta);\r
+\r
+/*! \brief Flush all credentials from a credential set\r
+\r
+ Deletes all the crednetials from the credential set.\r
+\r
+ \param[in] credset A handle to a credential set. Cannot be NULL.\r
+\r
+ \note The credential set cannot be sealed\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_flush(khm_handle credset);\r
+\r
+/*! \brief Extract credentials from one credential set to another\r
+\r
+ Credentials from the source credential set are selected based on\r
+ the \a identity and \a type arguements. If a credential is\r
+ matched, then it is added to the \a destcredset.\r
+\r
+ If the \a sourcecredset is the root credential set, the added\r
+ credentials are copies of the actual credentials in the root\r
+ credential set. Otherwise the credentials are references to the\r
+ original credentials in the \a sourcecredset .\r
+\r
+ \param[in] destcredset Destination credential set. Must be valid.\r
+\r
+ \param[in] sourcecredset The source credential set. If set to\r
+ NULL, extracts from the root credential set.\r
+\r
+ \param[in] identity The identity to match in the source credential\r
+ set. If set to NULL, matches all identities.\r
+\r
+ \param[in] type The credential type to match in the source credential set.\r
+ If set to KCDB_TYPE_INVALID, matches all types.\r
+\r
+ \note This function does not check for duplicate credentials.\r
+\r
+ \note The destination credential set cannot be sealed.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_extract(khm_handle destcredset, \r
+ khm_handle sourcecredset, \r
+ khm_handle identity, \r
+ khm_int32 type);\r
+\r
+/*! \brief Extract credentials from one credential set to another using a filter.\r
+\r
+ Similar to kcdb_credset_extract() except a filter function is used\r
+ to determine which credentials should be selected.\r
+\r
+ \param[in] rock A custom argument to be passed in to the filter function.\r
+\r
+ \note The destination credential set cannot be sealed.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_extract_filtered(khm_handle destcredset,\r
+ khm_handle sourcecredset,\r
+ kcdb_cred_filter_func filter,\r
+ void * rock);\r
+\r
+/*! \brief Retrieve a held reference to a credential in a credential set based on index.\r
+\r
+ \param[in] idx The index of the credential to retrieve. This is a\r
+ zero based index which goes from 0 ... (size of credset - 1).\r
+\r
+ \param[out] cred The held reference to a credential. Call \r
+ kcdb_cred_release() to release the credential.\r
+\r
+ \retval KHM_ERROR_SUCCESS Success. \a cred has a held reference to the credential.\r
+ \retval KHM_ERROR_OUT_OF_BOUNDS The index specified in \a idx is out of bounds.\r
+ \retval KHM_ERROR_DELETED The credential at index \a idx has been marked as deleted.\r
+\r
+ \see kcdb_cred_release()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_get_cred(khm_handle credset,\r
+ khm_int32 idx,\r
+ khm_handle * cred);\r
+\r
+/*! \brief Search a credential set for a specific credential\r
+\r
+ The credential set indicated by \a credset is searched for a\r
+ credential that satisfies the predicate function \a f. Each\r
+ credential starting at \a idx_start is passed into the predicate\r
+ function until it returns a non-zero value. At this point, that\r
+ credential is passed in to the \a cred parameter, and the index of\r
+ the credential is passed into the \a idx parameter.\r
+\r
+ \param[in] credset The credential set to search on. Specify NULL\r
+ if you want to search teh root credential set.\r
+\r
+ \param[in] idx_start The index at which to start the search after.\r
+ The first credential passed to the predicate function will be\r
+ at \a idx_start + 1. Specify -1 to start from the beginning\r
+ of the credential set.\r
+\r
+ \param[in] f The predicate function. The \a flags parameter of\r
+ the predicate function will always receive 0.\r
+\r
+ \param[in] rock An opaque parameter to be passed to the predicate\r
+ function \a f.\r
+\r
+ \param[out] cred A held reference to the credential that satisfied\r
+ the predicate function or NULL if no such credential was\r
+ found. Note that if a valid credential is returned, the\r
+ calling function must release the credential using\r
+ kcdb_cred_release().\r
+\r
+ \param[out] idx The index of the credential passed in \a cred.\r
+ Specify NULL if the index is not required.\r
+\r
+ \retval KHM_ERROR_SUCCESS A credential that satisfied the\r
+ predicate function was found and was assigned to \a cred.\r
+\r
+ \retval KHM_ERROR_NOT_FOUND No credential was found that matched\r
+ the predicate function.\r
+\r
+ \note When querying credential sets that are shared between\r
+ threads, it is possible that another thread modifies the\r
+ credential set between successive calls to\r
+ kcdb_credset_find_filtered(). Therefore a continued sequences of\r
+ searches are not guaranteed to exhastively cover the\r
+ credential set nor to not return duplicate matches. Duplicate\r
+ matches are possible if the order of the credentials in the\r
+ set was changed.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_find_filtered(khm_handle credset,\r
+ khm_int32 idx_start,\r
+ kcdb_cred_filter_func f,\r
+ void * rock,\r
+ khm_handle * cred,\r
+ khm_int32 * idx);\r
+\r
+/*! \brief Find matching credential\r
+\r
+ Searches a credential set for a credential that matches the\r
+ specified credential. For a credential to be a match, it must\r
+ have the same identity, credential type and name.\r
+\r
+ \param[in] credset Credential set to search \r
+\r
+ \param[in] cred_src Credetial to search on\r
+\r
+ \param[out] cred_dest receieves the matching credential if the\r
+ search is successful. If a handle is returend, the\r
+ kcdb_cred_release() must be used to release the handle. If\r
+ the matching credential is not required, you can pass in NULL.\r
+\r
+ \retval KHM_ERROR_SUCCESS The search was successful. A credential\r
+ was assigned to \a cred_dest\r
+\r
+ \retval KHM_ERROR_NOT_FOUND A matching credential was not found.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_find_cred(khm_handle credset,\r
+ khm_handle cred_src,\r
+ khm_handle *cred_dest);\r
+ \r
+\r
+/*! \brief Delete a credential from a credential set.\r
+\r
+ The credential at index \a idx will be deleted. All the\r
+ credentials that are at indices \a idx + 1 and above will be moved\r
+ down to fill the gap and the size of the credential set will\r
+ decrease by one.\r
+\r
+ Use kcdb_credset_del_cred_ref() to delete a credential by\r
+ reference. Using kcdb_credset_del_cred() is faster than\r
+ kcdb_credset_del_cred_ref().\r
+\r
+ If you call kcdb_credset_del_cred() or kcdb_credset_del_cred_ref()\r
+ from within kcdb_credset_apply(), the credential will only be\r
+ marked as deleted. They will not be removed. This means that the\r
+ size of the credential set will not decrease. To purge the\r
+ deleted credentials from the set, call kcdb_credset_purge() after\r
+ kcdb_credset_apply() completes.\r
+\r
+ \note The credential set cannot be sealed.\r
+\r
+ \see kcdb_credset_del_cred_ref()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_del_cred(khm_handle credset,\r
+ khm_int32 idx);\r
+\r
+/*! \brief Delete a credential from a credential set by reference.\r
+\r
+ See kcdb_credset_del_cred() for description of what happens when a\r
+ credential is deleted from a credential set.\r
+\r
+ \note The credential set cannot be sealed.\r
+\r
+ \see kcdb_credset_del_cred()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_del_cred_ref(khm_handle credset,\r
+ khm_handle cred);\r
+\r
+/*! \brief Add a credential to a credential set.\r
+\r
+ The credential is added by reference. In other words, no copy of\r
+ the credential is made.\r
+\r
+ \param[in] idx Index of the new credential. This must be a value\r
+ in the range 0..(previous size of credential set) or -1. If\r
+ -1 is specifed, then the credential is appended at the end of\r
+ the set.\r
+\r
+ \note The credential set cannot be sealed.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_add_cred(khm_handle credset,\r
+ khm_handle cred,\r
+ khm_int32 idx);\r
+\r
+/*! \brief Get the number of credentials in a credential set.\r
+\r
+ Credentials in a credential set may be volatile. When\r
+ kcdb_credeset_get_size() is called, the credential set is\r
+ compacted to only include credentials that are active at the time.\r
+ However, when you are iterating through the credential set, it\r
+ might be the case that some credentials would get marked as\r
+ deleted. These credentials will remain in the credential set\r
+ until the credential set is discarded or another call to\r
+ kcdb_credset_get_size() or kdcb_credset_purge() is made.\r
+\r
+ If the credential set is sealed, then it will not be compacted and\r
+ will include deleted credentials as well.\r
+\r
+ \see kcdb_credset_purge()\r
+ \see kcdb_credset_get_cred()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_get_size(khm_handle credset,\r
+ khm_size * size);\r
+\r
+/*! \brief Removes credentials that have been marked as deleted from a credential set.\r
+\r
+ See description of \a kcdb_credset_purge() for a description of\r
+ what happens when credntials that are contained in a credential\r
+ set are deleted by an external entity.\r
+\r
+ \note The credential set cannot be sealed.\r
+\r
+ \see kcdb_credset_get_size()\r
+ \see kcdb_credset_get_cred()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_purge(khm_handle credset);\r
+\r
+/*! \brief Applies a function to all the credentials in a credentials set\r
+\r
+ The given function is called for each credential in a credential\r
+ set. With each iteration, the function is called with a handle to\r
+ the credential and the user defined parameter \a rock. If the\r
+ function returns anything other than KHM_ERROR_SUCCESS, the\r
+ processing stops.\r
+\r
+ \param[in] credset The credential set to apply the function to, or\r
+ NULL if you want to apply this to the root credential set.\r
+\r
+ \param[in] f Function to call for each credential\r
+\r
+ \param[in] rock An opaque parameter which is to be passed to 'f'\r
+ as the second argument.\r
+\r
+ \retval KHM_ERROR_SUCCESS All the credentials were processed.\r
+\r
+ \retval KHM_ERROR_EXIT The supplied function signalled the\r
+ processing to be aborted.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_apply(khm_handle credset, \r
+ kcdb_cred_apply_func f, \r
+ void * rock);\r
+\r
+/*! \brief Sort the contents of a credential set.\r
+\r
+ \param[in] rock A custom argument to be passed in to the \a comp function.\r
+\r
+ \note The credential set cannot be sealed.\r
+\r
+ \see kcdb_cred_comp_generic()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_sort(khm_handle credset,\r
+ kcdb_cred_comp_func comp,\r
+ void * rock);\r
+\r
+/*! \brief Seal a credential set\r
+\r
+ Sealing a credential set makes it read-only. To unseal a\r
+ credential set, call kcdb_credset_unseal().\r
+\r
+ Sealing is an additive operation. kcdb_credset_seal() can be\r
+ called muliple times. However, for every call to\r
+ kcdb_credset_seal() a call to kcdb_credset_unseal() must be made\r
+ to undo the seal. The credential set will become unsealed when\r
+ all the seals are released.\r
+\r
+ Once sealed, the credential set will not allow any operation that\r
+ might change its contents. However, a selaed credential set can\r
+ still be delted.\r
+\r
+ \see kcdb_credset_unseal()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credset_seal(khm_handle credset);\r
+\r
+/*! \brief Unseal a credential set\r
+\r
+ Undoes what kcdb_credset_seal() did. This does not guarantee that\r
+ the credential set is unsealed since there may be other seals.\r
+\r
+ \see kcdb_credset_seal()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kcdb_credset_unseal(khm_handle credset);\r
+\r
+/*! \brief Defines a sort criterion for kcdb_cred_comp_generic()\r
+\r
+ \see kcdb_cred_comp_generic()\r
+*/\r
+typedef struct tag_kcdb_cred_comp_field {\r
+ khm_int32 attrib; /*!< a valid attribute ID */\r
+ khm_int32 order; /*!< one of KCDB_CRED_COMP_INCREASING or\r
+ KCDB_CRED_COMP_DECREASING. Optionally,\r
+ KCDB_CRED_COMP_INITIAL_FIRST may be combined\r
+ with either. */\r
+} kcdb_cred_comp_field;\r
+\r
+/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field \r
+\r
+ Sorts lexicographically ascending by string representation of field.\r
+*/\r
+#define KCDB_CRED_COMP_INCREASING 0\r
+\r
+/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field\r
+\r
+ Sorts lexicographically descending by string representation of\r
+ field.\r
+ */\r
+#define KCDB_CRED_COMP_DECREASING 1\r
+\r
+/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field \r
+\r
+ Any credentials which have the ::KCDB_CRED_FLAG_INITIAL will be\r
+ grouped above any that don't.\r
+\r
+ If that does not apply, then credentials from the primary\r
+ credentials type will be sorted before others.\r
+*/\r
+#define KCDB_CRED_COMP_INITIAL_FIRST 2\r
+\r
+/*! \brief Defines the sort criteria for kcdb_cred_comp_generic()\r
+\r
+ \see kcdb_cred_comp_generic()\r
+*/\r
+typedef struct tag_kcdb_cred_comp_order {\r
+ khm_int32 nFields;\r
+ kcdb_cred_comp_field * fields;\r
+} kcdb_cred_comp_order;\r
+\r
+/*! \brief A generic compare function for comparing credentials.\r
+\r
+ This function can be passed as a parameter to kcdb_credset_sort().\r
+\r
+ The \a rock parameter to this function should be a pointer to a\r
+ ::kcdb_cred_comp_order object. The \a fields member of the\r
+ ::kcdb_cred_comp_order object should point to an array of\r
+ ::kcdb_cred_comp_field objects, each of which specifies the sort\r
+ order in decreasing order of priority. The number of\r
+ ::kcdb_cred_comp_field objects in the array should correspond to\r
+ the \a nFields member in the ::kcdb_cred_comp_order object.\r
+\r
+ The array of ::kcdb_cred_comp_field objects define the sort\r
+ criteria, in order. The \a attrib member should be a valid\r
+ attribute ID, while the \a order member determines whether the\r
+ sort order is increasing or decreasing. The exact meaning or\r
+ increasing or decreasing depends on the data type of the\r
+ attribute.\r
+\r
+ \param[in] rock a pointer to a ::kcdb_cred_comp_order object\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_comp_generic(khm_handle cred1, \r
+ khm_handle cred2, \r
+ void * rock);\r
+\r
+/*@}*/\r
+\r
+/*! \defgroup kcdb_cred Credentials */\r
+/*@{*/\r
+\r
+/*! \brief Maximum number of characters in a credential name */\r
+#define KCDB_CRED_MAXCCH_NAME 256\r
+\r
+/*! \brief Maximum number of bytes in a credential name */\r
+#define KCDB_CRED_MAXCB_NAME (sizeof(wchar_t) * KCDB_CRED_MAXCCH_NAME)\r
+\r
+/*! \brief Marked as deleted */\r
+#define KCDB_CRED_FLAG_DELETED 0x00000008\r
+\r
+/*! \brief Renewable */\r
+#define KCDB_CRED_FLAG_RENEWABLE 0x00000010\r
+\r
+/*! \brief Initial\r
+\r
+ Initial credentials form the basis of an identity. Some\r
+ properties of an initial credential, such as being renewable, are\r
+ directly inherited by the identity. An identity is also\r
+ automatically considered valid if it contains a valid initial\r
+ credential.\r
+ */\r
+#define KCDB_CRED_FLAG_INITIAL 0x00000020\r
+\r
+/*! \brief Expired\r
+\r
+ The credential's lifetime has ended.\r
+ */\r
+#define KCDB_CRED_FLAG_EXPIRED 0x00000040\r
+\r
+/*! \brief Invalid\r
+\r
+ The credential can no longer serve its intended function. This\r
+ may be because it is expired and is not renewable, or its\r
+ renewable time period has also expired, or for some other reason.\r
+ */\r
+#define KCDB_CRED_FLAG_INVALID 0x00000080\r
+\r
+/*! \brief Credential is selected\r
+\r
+ Indicates that the credential is selected. Note that using this\r
+ flag may be subject to race conditions.\r
+ */\r
+#define KCDB_CRED_FLAG_SELECTED 0x00000100\r
+\r
+/*! \brief Bitmask indicating all known credential flags\r
+ */\r
+#define KCDB_CRED_FLAGMASK_ALL 0x0000ffff\r
+\r
+/*! \brief Bitmask indicating dditive flags \r
+\r
+ Additive flags are special flags which are added to exiting\r
+ credentials based on new credentials when doing a collect\r
+ operation. See details on kcdb_credset_collect()\r
+\r
+ \see kcdb_credset_collect()\r
+*/\r
+#define KCDB_CRED_FLAGMASK_ADDITIVE KCDB_CRED_FLAG_SELECTED\r
+\r
+/*! \brief Generic credentials request\r
+\r
+ This data structure is used as the format for a generic\r
+ credentials reqeust for a ::KMSG_KCDB_REQUEST message. A plugin\r
+ typically publishes this message so that a credentials provider\r
+ may handle it and in response, obtain the specified credential.\r
+\r
+ While the \a identity, \a type and \a name members of the\r
+ structure are all optional, typically one would specify all three\r
+ or at least two for a credential provider to be able to provide\r
+ the credential unambigously.\r
+\r
+ Credential providers do not need to respond to ::KMSG_KCDB_REQUEST\r
+ messages. However, if they do, they should make sure that they\r
+ are the only credential provider that is responding by setting the\r
+ \a semaphore member to a non-zero value. The \a semaphore is set\r
+ to zero when a request is initially sent out. When incrementing\r
+ the semaphore, the plugin should use a thread safe mechanism to\r
+ ensure that there are no race conditions that would allow more\r
+ than one provider to respond to the message.\r
+ */\r
+typedef struct tag_kcdb_cred_request {\r
+ khm_handle identity; /*!< Identity of the credential. Set\r
+ to NULL if not specified. */\r
+ khm_int32 type; /*!< Type of the credential. Set to\r
+ KCDB_CREDTYPE_INVALID if not\r
+ specified. */\r
+ wchar_t * name; /*!< Name of the credential. Set to\r
+ NULL if not specified. */\r
+\r
+ khm_handle dest_credset; /*!< If non-NULL, instructs whoever is\r
+ handling the request that the\r
+ credential thus obtained be placed\r
+ in this credential set in addition\r
+ to whereever it may place newly\r
+ acquired credentials. Note that\r
+ while this can be NULL if the new\r
+ credential does not need to be\r
+ placed in a credential set, it can\r
+ not equal the root credential\r
+ set. */\r
+\r
+ void * vparam; /*!< An unspecified\r
+ parameter. Specific credential types\r
+ may specify how this field is to be\r
+ used. */\r
+\r
+ long semaphore; /*!< Incremented by one when this\r
+ request is answered. Only one\r
+ credential provider is allowed to\r
+ answer a ::KMSG_KCDB_REQUEST\r
+ message. Initially, when the\r
+ message is sent out, this member\r
+ should be set to zero. */\r
+} kcdb_cred_request;\r
+\r
+/*! \brief Create a new credential\r
+\r
+ \param[in] name Name of credential. \a name cannot be NULL and cannot\r
+ exceed \a KCDB_CRED_MAXCCH_NAME unicode characters including the \r
+ \a NULL terminator.\r
+ \param[in] identity A reference to an identity.\r
+ \param[in] cred_type A credentials type identifier for the credential.\r
+ \param[out] result Gets a held reference to the newly created credential.\r
+ Call kcdb_cred_release() or kcdb_cred_delete() to release the \r
+ reference.\r
+ \see kcdb_cred_release()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_create(wchar_t * name, \r
+ khm_handle identity,\r
+ khm_int32 cred_type,\r
+ khm_handle * result);\r
+\r
+/*! \brief Duplicate an existing credential.\r
+\r
+ \param[out] newcred A held reference to the new credential if the call\r
+ succeeds.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_dup(khm_handle cred,\r
+ khm_handle * newcred);\r
+\r
+/*! \brief Updates one credential using field values from another\r
+\r
+ All fields that exist in \a vsrc will get copied to \a vdest and will\r
+ overwrite any values that are already there in \a vdest. However any\r
+ values that exist in \a vdest taht do not exist in \a vsrc will not be\r
+ modified.\r
+\r
+ \retval KHM_ERROR_SUCCESS vdest was successfully updated\r
+ \retval KHM_ERROR_EQUIVALENT all fields in vsrc were present and equivalent in vdest\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_update(khm_handle vdest,\r
+ khm_handle vsrc);\r
+\r
+/*! \brief Set an attribute in a credential by name\r
+\r
+ \param[in] cbbuf Number of bytes of data in \a buffer. The\r
+ individual data type handlers may copy in less than this many\r
+ bytes in to the credential.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_set_attrib(khm_handle cred, \r
+ wchar_t * name, \r
+ void * buffer, \r
+ khm_size cbbuf);\r
+\r
+/*! \brief Set an attribute in a credential by attribute id\r
+\r
+ \param[in] buffer A pointer to a buffer containing the data to\r
+ assign to the attribute. Setting this to NULL has the effect\r
+ of removing any data that is already assigned to the\r
+ attribute. If \a buffer is non-NULL, then \a cbbuf should\r
+ specify the number of bytes in \a buffer.\r
+\r
+ \param[in] cbbuf Number of bytes of data in \a buffer. The\r
+ individual data type handlers may copy in less than this many\r
+ bytes in to the credential.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_set_attr(khm_handle cred, \r
+ khm_int32 attr_id, \r
+ void * buffer, \r
+ khm_size cbbuf);\r
+\r
+/*! \brief Get an attribute from a credential by name.\r
+\r
+ \param[in] buffer The buffer that is to receive the attribute\r
+ value. Set this to NULL if only the required buffer size is\r
+ to be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+\r
+ \note Set both \a buffer and \a cbbuf to NULL if only the\r
+ existence of the attribute is to be checked. If the attribute\r
+ exists in this credential then the function will return\r
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_attrib(khm_handle cred, \r
+ wchar_t * name, \r
+ khm_int32 * attr_type,\r
+ void * buffer, \r
+ khm_size * cbbuf);\r
+\r
+/*! \brief Get an attribute from a credential by attribute id.\r
+\r
+ \param[in] buffer The buffer that is to receive the attribute\r
+ value. Set this to NULL if only the required buffer size is\r
+ to be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+\r
+ \param[out] attr_type Receives the data type of the attribute.\r
+ Set this to NULL if the type is not required.\r
+\r
+ \note Set both \a buffer and \a cbbuf to NULL if only the\r
+ existence of the attribute is to be checked. If the attribute\r
+ exists in this credential then the function will return\r
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_attr(khm_handle cred, \r
+ khm_int32 attr_id,\r
+ khm_int32 * attr_type,\r
+ void * buffer, \r
+ khm_size * cbbuf);\r
+\r
+/*! \brief Get the name of a credential.\r
+\r
+ \param[in] buffer The buffer that is to receive the credential\r
+ name. Set this to NULL if only the required buffer size is to\r
+ be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_name(khm_handle cred, \r
+ wchar_t * buffer, \r
+ khm_size * cbbuf);\r
+\r
+/*! \brief Get the string representation of a credential attribute.\r
+\r
+ A shortcut function which generates the string representation of a\r
+ credential attribute directly.\r
+\r
+ \param[in] vcred A handle to a credential\r
+\r
+ \param[in] attr_id The attribute to retrieve\r
+\r
+ \param[out] buffer A pointer to a string buffer which receives the\r
+ string form of the attribute. Set this to NULL if you only\r
+ want to determine the size of the required buffer.\r
+\r
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,\r
+ holds the size of the buffer pointed to by \a buffer, and on\r
+ exit, receives the actual number of bytes that were copied.\r
+\r
+ \param[in] flags Flags for the string conversion. Can be set to\r
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is\r
+ KCDB_TS_LONG.\r
+\r
+ \retval KHM_ERROR_SUCCESS Success\r
+ \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid\r
+ or was not defined for this credential\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the\r
+ supplied buffer was insufficient\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_attr_string(khm_handle vcred, \r
+ khm_int32 attr_id,\r
+ wchar_t * buffer, \r
+ khm_size * pcbbuf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Get the string representation of a credential attribute by name.\r
+\r
+ A shortcut function which generates the string representation of a\r
+ credential attribute directly.\r
+\r
+ \param[in] vcred A handle to a credential\r
+\r
+ \param[in] attrib The name of the attribute to retrieve\r
+\r
+ \param[out] buffer A pointer to a string buffer which receives the\r
+ string form of the attribute. Set this to NULL if you only\r
+ want to determine the size of the required buffer.\r
+\r
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,\r
+ holds the size of the buffer pointed to by \a buffer, and on\r
+ exit, receives the actual number of bytes that were copied.\r
+\r
+ \param[in] flags Flags for the string conversion. Can be set to\r
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is\r
+ KCDB_TS_LONG.\r
+\r
+ \see kcdb_cred_get_attr_string()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_attrib_string(khm_handle cred, \r
+ wchar_t * name, \r
+ wchar_t * buffer, \r
+ khm_size * cbbuf,\r
+ khm_int32 flags) ;\r
+\r
+\r
+/*! \brief Get a held reference to the identity associated with a credential\r
+\r
+ Use kcdb_identity_release() to release the reference that is\r
+ returned.\r
+\r
+ \see kcdb_identity_relase()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_identity(khm_handle cred, \r
+ khm_handle * identity);\r
+\r
+/*! \brief Set the identity of a credential\r
+\r
+ While it is ill-advised to change the identity of a credential\r
+ that has been placed in one or more credential sets, there can be\r
+ legitimate reasons for doing so. Only change the identity of a\r
+ credential that is not placed in a credential set or placed in a\r
+ credential set that is only used by a single entity.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_set_identity(khm_handle vcred,\r
+ khm_handle id);\r
+\r
+/*! \brief Get the serial number for the credential.\r
+\r
+ Each credential gets assigned a serial number at the time it is\r
+ created. This will stay with the credential for its lifetime.\r
+\r
+ \param[out] pserial Receives the serial number. Cannot be NULL.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_serial(khm_handle cred,\r
+ khm_ui_8 * pserial);\r
+\r
+/*! \brief Get the type of the credential.\r
+\r
+ The returned type is a credential type. Doh.\r
+\r
+ \param[out] type Receives the type. Cannot be NULL.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_type(khm_handle cred,\r
+ khm_int32 * type);\r
+\r
+/*! \brief Retrieve flags from a credential\r
+\r
+ The flags returned will be place in the location pointed to by \a\r
+ flags. Note that the specified credential must be an active\r
+ credential for the operation to succeed. This means the\r
+ ::KCDB_CRED_FLAG_DELETED will never be retured by this function.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_get_flags(khm_handle cred,\r
+ khm_int32 * flags);\r
+\r
+/*! \brief Set the flags of a credential\r
+\r
+ The flags specified in the \a mask parameter will be set to the\r
+ values specified in the \a flags parameter. The flags that are\r
+ not included in \a mask will not be modified.\r
+\r
+ This function can not be used to set the ::KCDB_CRED_FLAG_DELETED\r
+ flag. If this bit is specified in either \a flags or \a mask, it\r
+ will be ignored.\r
+\r
+ \see ::KCDB_CRED_FLAGMASK_ALL\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_set_flags(khm_handle cred,\r
+ khm_int32 flags,\r
+ khm_int32 mask);\r
+\r
+/*! \brief Hold a reference to a credential.\r
+\r
+ Use kcdb_cred_release() to release the reference.\r
+\r
+ \see kcdb_cred_release()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_hold(khm_handle cred);\r
+\r
+/*! \brief Release a held reference to a credential.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_release(khm_handle cred);\r
+\r
+/*! \brief Delete a credential.\r
+\r
+ The credential will be marked for deletion and will continue to\r
+ exist until all held references are released. If the credential\r
+ is bound to a credential set or the root credential store, it will\r
+ be removed from the respective container.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_cred_delete(khm_handle cred);\r
+\r
+/*! \brief Compare an attribute of two credentials by name.\r
+\r
+ \return The return value is dependent on the type of the attribute\r
+ and indicate a weak ordering of the attribute values of the two\r
+ credentials. If one or both credentials do not contain the\r
+ attribute, the return value is 0, which signifies that no ordering\r
+ can be determined.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_creds_comp_attrib(khm_handle cred1, \r
+ khm_handle cred2, \r
+ wchar_t * name);\r
+\r
+/*! \brief Compare an attribute of two credentials by attribute id.\r
+\r
+ \return The return value is dependent on the type of the attribute\r
+ and indicate a weak ordering of the attribute values of the two\r
+ credentials. If one or both credentials do not contain the\r
+ attribute, the return value is 0, which signifies that no ordering\r
+ can be determined.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_creds_comp_attr(khm_handle cred1, \r
+ khm_handle cred2, \r
+ khm_int32 attr_id);\r
+\r
+/*! \brief Compare two credentials for equivalence\r
+\r
+ \return Non-zero if the two credentials are equal. Zero otherwise.\r
+ \note Two credentials are considered equal if all the following hold:\r
+ - Both refer to the same identity.\r
+ - Both have the same name.\r
+ - Both have the same type.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_creds_is_equal(khm_handle cred1,\r
+ khm_handle cred2);\r
+\r
+/*@}*/\r
+/*@}*/\r
+\r
+/********************************************************************/\r
+\r
+/*! \defgroup kcdb_type Credential attribute types */\r
+/*@{*/\r
+\r
+/*! \brief Convert a field to a string\r
+\r
+ Provides a string representation of a field in a credential. The\r
+ data buffer can be assumed to be valid.\r
+\r
+ On entry, \a s_buf can be NULL if only the required size of the\r
+ buffer is to be returned. \a pcb_s_buf should be non-NULL and\r
+ should point to a valid variable of type ::khm_size that will, on\r
+ entry, contain the size of the buffer pointed to by \a s_buf if \a\r
+ s_buf is not \a NULL, and on exit will contain the number of bytes\r
+ consumed in \a s_buf, or the required size of the buffer if \a\r
+ s_buf was NULL or the size of the buffer was insufficient.\r
+\r
+ The implementation should verify the parameters that are passed in\r
+ to the function.\r
+\r
+ The data pointed to by \a data should not be modified in any way.\r
+\r
+ \param[in] data Valid pointer to a block of data\r
+\r
+ \param[in] cb_data Number of bytes in data block pointed to by \a\r
+ data\r
+\r
+ \param[out] s_buf Buffer to receive the string representation of\r
+ data. If the data type flags has KCDB_TYPE_FLAG_CB_AUTO, then\r
+ this parameter could be set to KCDB_CBSIZE_AUTO. In this\r
+ case, the function should compute the size of the input buffer\r
+ assuming that the input buffer is valid.\r
+\r
+ \param[in,out] pcb_s_buf On entry, contains the size of the buffer\r
+ pointed to by \a s_buf, and on exit, contains the number of\r
+ bytes used by the string representation of the data including\r
+ the NULL terminator\r
+\r
+ \param[in] flags Flags for formatting the string\r
+\r
+ \retval KHM_ERROR_SUCCESS The string representation of the data\r
+ field was successfully copied to \a s_buf and the size of the\r
+ buffer used was copied to \a pcb_s_buf.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+\r
+ \retval KHM_ERROR_TOO_LONG Either \a s_buf was \a NULL or the size\r
+ indicated by \a pcb_s_buf was too small to contain the string\r
+ representation of the value. The required size of the buffer\r
+ is in \a pcb_s_buf.\r
+\r
+ \note This documents the expected behavior of this prototype function\r
+\r
+ \see ::kcdb_type\r
+ */\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_dtf_toString)(const void * data,\r
+ khm_size cb_data,\r
+ wchar_t * s_buf,\r
+ khm_size * pcb_s_buf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Verifies whetehr the given buffer contains valid data\r
+\r
+ The function should examine the buffer and the size of the buffer\r
+ and determine whether or not the buffer contains valid data for\r
+ this data type.\r
+\r
+ The data field pointed to by \a data should not be modified in any\r
+ way.\r
+\r
+ \param[in] data A pointer to a data buffer\r
+\r
+ \param[in] cb_data The number of bytes in the data buffer. If the\r
+ data type flags has KCDB_TYPE_FLAG_CB_AUTO, then this\r
+ parameter could be set to KCDB_CBSIZE_AUTO. In this case, the\r
+ function should compute the size of the input buffer assuming\r
+ that the input buffer is valid.\r
+\r
+ \return TRUE if the data is valid, FALSE otherwise.\r
+\r
+ \note This documents the expected behavior of this prototype function\r
+\r
+ \see ::kcdb_type\r
+*/\r
+typedef khm_boolean \r
+(KHMAPI *kcdb_dtf_isValid)(const void * data,\r
+ khm_size cb_data);\r
+\r
+/*! \brief Compare two fields\r
+\r
+ Compare the two data fields and return a value indicating their\r
+ relative ordering. The return value follows the same\r
+ specification as strcmp().\r
+\r
+ Both data buffers that are passed in can be assumed to be valid.\r
+\r
+ None of the data buffers should be modified in any way.\r
+\r
+ \param[in] data_l Valid pointer to first data buffer\r
+\r
+ \param[in] cb_data_l Number of bytes in \a data_l. If the data\r
+ type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter\r
+ could be set to KCDB_CBSIZE_AUTO. In this case, the function\r
+ should compute the size of the input buffer assuming that the\r
+ input buffer is valid.\r
+\r
+ \param[in] data_r Valid pointer to second data buffer\r
+\r
+ \param[in] cb_data_r Number of bytes in \a data_r. If the data\r
+ type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter\r
+ could be set to KCDB_CBSIZE_AUTO. In this case, the function\r
+ should compute the size of the input buffer assuming that the\r
+ input buffer is valid.\r
+\r
+ \return The return value should be\r
+ - Less than zero if \a data_l < \a data_r\r
+ - Equal to zero if \a data_l == \a data_r or if this data type can not be compared\r
+ - Greater than zero if \a data_l > \a data_r\r
+\r
+ \note This documents the expected behavior of this prototype function\r
+\r
+ \see ::kcdb_type\r
+*/\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_dtf_comp)(const void * data_l,\r
+ khm_size cb_data_l,\r
+ const void * data_r,\r
+ khm_size cb_data_r);\r
+\r
+/*! \brief Duplicate a data field\r
+\r
+ Duplicates a data field. The buffer pointed to by \a data_src\r
+ contains a valid field. The function should copy the field with\r
+ appropriate adjustments to \a data_dst.\r
+\r
+ The \a data_dst parameter can be NULL if only the required size of\r
+ the buffer is needed. In this case, teh function should set \a\r
+ pcb_data_dst to the number of bytes required and then return\r
+ KHM_ERROR_TOO_LONG.\r
+\r
+ \param[in] data_src Pointer to a valid data buffer\r
+\r
+ \param[in] cb_data_src Number of bytes in \a data_src. If the data\r
+ type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter\r
+ could be set to KCDB_CBSIZE_AUTO. In this case, the function\r
+ should compute the size of the input buffer assuming that the\r
+ input buffer is valid.\r
+\r
+ \param[out] data_dst Poitner to destination buffer. Could be NULL\r
+ if only the required size of the destination buffer is to be\r
+ returned.\r
+\r
+ \param[in,out] pcb_data_dst On entry specifies the number of bytes\r
+ in \a data_dst, and on exit should contain the number of bytes\r
+ copied.\r
+\r
+ \retval KHM_ERROR_SUCCESS The data was successfully copied. The\r
+ number of bytes copied is in \a pcb_data_dst\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters is incorrect.\r
+\r
+ \retval KHM_ERROR_TOO_LONG Either \a data_dst was NULL or the size\r
+ of the buffer was insufficient. The required size is in \a\r
+ pcb_data_dst\r
+\r
+ \note This documents the expected behavior of this prototype function\r
+\r
+ \see ::kcdb_type\r
+ */\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_dtf_dup)(const void * data_src,\r
+ khm_size cb_data_src,\r
+ void * data_dst,\r
+ khm_size * pcb_data_dst);\r
+\r
+/*! \brief A data type descriptor.\r
+\r
+ Handles basic operation for a specific data type.\r
+\r
+ \see \ref cred_data_types\r
+*/\r
+typedef struct tag_kcdb_type {\r
+ wchar_t * name;\r
+ khm_int32 id;\r
+ khm_int32 flags;\r
+\r
+ khm_size cb_min;\r
+ khm_size cb_max;\r
+\r
+ kcdb_dtf_toString toString;\r
+ /*!< Provides a string representation for a value. */\r
+\r
+ kcdb_dtf_isValid isValid;\r
+ /*!< Returns true of the value is valid for this data type */\r
+\r
+ kcdb_dtf_comp comp;\r
+ /*!< Compare two values and return \a strcmp style return value */\r
+\r
+ kcdb_dtf_dup dup;\r
+ /*!< Duplicate a value into a secondary buffer */\r
+} kcdb_type;\r
+\r
+/*! \name Flags for kcdb_type::toString\r
+@{*/\r
+/*! \brief Specify that the short form of the string representation should be returned. \r
+\r
+ Flags for #kcdb_type::toString. The flag specifies how long the\r
+ string representation should be. The specific length of a short\r
+ or long description is not restricted and it is up to the\r
+ implementation to choose how to interpret the flags.\r
+\r
+ Usually, KCDB_TS_SHORT is specified when the amount of space that\r
+ is available to display the string is very restricted. It may be\r
+ the case that the string is truncated to facilitate displaying in\r
+ a constrainted space. \r
+*/\r
+#define KCDB_TS_SHORT 1\r
+\r
+/*! \brief Specify that the long form of the string representation should be returned \r
+\r
+ Flags for #kcdb_type::toString. The flag specifies how long the\r
+ string representation should be. The specific length of a short\r
+ or long description is not restricted and it is up to the\r
+ implementation to choose how to interpret the flags.\r
+\r
+*/\r
+#define KCDB_TS_LONG 0\r
+/*@}*/\r
+\r
+/*! \brief The maximum number of bytes allowed for a value of any type */\r
+#define KCDB_TYPE_MAXCB 16384\r
+\r
+/*! \name Flags for kcdb_type\r
+@{*/\r
+\r
+/*! \brief The type supports KCDB_CBSIZE_AUTO.\r
+\r
+ Used for types where the size of the object can be determined\r
+ through context or by the object content. Such as for objects\r
+ that have a fixed size or unicode strings that have a terminator.\r
+\r
+ This implies that ALL the object manipulation callbacks that are\r
+ defined in this type definition support the KCDB_CBSIZE_AUTO\r
+ value.\r
+*/\r
+#define KCDB_TYPE_FLAG_CB_AUTO 16\r
+\r
+/*! \brief The \a cb_min member is valid.\r
+\r
+ The \a cb_min member defines the minimum number of bytes that an\r
+ object of this type will consume.\r
+\r
+ \note If this flag is used in conjunction with \a\r
+ KCDB_TYPE_FLAG_CB_MAX then, \a cb_min must be less than or equal\r
+ to \a cb_max. \r
+*/\r
+#define KCDB_TYPE_FLAG_CB_MIN 128\r
+\r
+/*! \brief The \a cb_max member is valid.\r
+\r
+ The \a cb_max member defines the maximum number of bytes that an\r
+ object of this type will consume.\r
+\r
+ \note If this flag is used in conjunction with \a\r
+ KCDB_TYPE_FLAG_CB_MIN then, \a cb_min must be less than or\r
+ equal to \a cb_max. */\r
+#define KCDB_TYPE_FLAG_CB_MAX 256\r
+\r
+/*! \brief Denotes that objects of this type have a fixed size.\r
+\r
+ If this flags is specified, then the type definition must also\r
+ specify cb_min and cb_max, which must both be the same value.\r
+\r
+ \note Implies \a KCDB_TYPE_FLAG_CB_AUTO, \a KCDB_TYPE_FLAG_CB_MIN\r
+ and \a KCDB_TYPE_FLAG_CB_MAX. Pay special attention to the\r
+ implication of \a KCDB_TYPE_FLAG_AUTO.\r
+*/\r
+#define KCDB_TYPE_FLAG_CB_FIXED (KCDB_TYPE_FLAG_CB_AUTO|KCDB_TYPE_FLAG_CB_MIN|KCDB_TYPE_FLAG_CB_MAX)\r
+\r
+/*@}*/\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_get_id(wchar_t *name, khm_int32 * id);\r
+\r
+/*! \brief Return the type descriptor for a given type id\r
+\r
+ \param[out] info Receives a held reference to a type descriptor.\r
+ Use kcdb_type_release_info() to release the handle. If the \a\r
+ info parameter is NULL, the function returns KHM_ERROR_SUCCESS\r
+ if \a id is a valid type id, and returns KHM_ERROR_NOT_FOUND\r
+ otherwise.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_get_info(khm_int32 id, kcdb_type ** info);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_release_info(kcdb_type * info);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_get_name(khm_int32 id, \r
+ wchar_t * buffer, \r
+ khm_size * cbbuf);\r
+\r
+/*! \brief Register a credentials attribute type\r
+\r
+ The credentials type record pointed to by \a type defines a new\r
+ credential attribute type. The \a id member of \a type may be set\r
+ to KCDB_TYPE_INVALID to indicate that an attribute ID is to be\r
+ generated automatically.\r
+\r
+ \param[in] type The type descriptor\r
+ \param[out] new_id Receives the identifier for the credential attribute type.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_register(kcdb_type * type, \r
+ khm_int32 * new_id);\r
+\r
+/*! \brief Unregister a credential attribute type\r
+\r
+ Removes the registration for the specified credentials attribute\r
+ type.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_unregister(khm_int32 id);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_type_get_next_free(khm_int32 * id);\r
+\r
+/*! \name Conversion functions\r
+@{*/\r
+/*! \brief Convert a time_t value to FILETIME\r
+*/\r
+KHMEXP void KHMAPI \r
+TimetToFileTime( time_t t, LPFILETIME pft );\r
+\r
+/*! \brief Convert a time_t interval to a FILETIME interval\r
+*/\r
+KHMEXP void KHMAPI \r
+TimetToFileTimeInterval(time_t t, LPFILETIME pft);\r
+\r
+/*! \brief Convert a FILETIME interval to seconds\r
+*/\r
+KHMEXP long KHMAPI \r
+FtIntervalToSeconds(LPFILETIME pft);\r
+\r
+/*! \brief Convert a FILETIME interval to milliseconds\r
+*/\r
+KHMEXP long KHMAPI \r
+FtIntervalToMilliseconds(LPFILETIME pft);\r
+\r
+/*! \brief Compare two FILETIME values\r
+\r
+ The return value is similar to the return value of strcmp(), based\r
+ on the comparison of the two FILETIME values.\r
+ */\r
+KHMEXP long KHMAPI \r
+FtCompare(LPFILETIME pft1, LPFILETIME pft2);\r
+\r
+/*! \brief Convert a FILETIME inverval to a string\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+FtIntervalToString(LPFILETIME data, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf);\r
+\r
+/*! \brief Parse a string representing an interval into a FILETIME interval\r
+\r
+ The string is a localized string which should look like the\r
+ following:\r
+\r
+ \code\r
+ [number unit] [number unit]...\r
+ \endcode\r
+\r
+ where \a number is an integer while \a unit is a localized\r
+ (possibly abbreviated) unit specification. The value of the\r
+ described interval is calculated as the sum of each \a number in\r
+ \a units. For example :\r
+\r
+ \code\r
+ 1 hour 36 minutes\r
+ \endcode\r
+\r
+ would result in an interval specification that's equivalent to 1\r
+ hour and 36 minutes. Of course there is no restriction on the\r
+ order in which the \a number \a unit specifications are given and\r
+ the same unit may be repeated multiple times.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM The given string was invalid or had\r
+ a token that could not be parsed. It can also mean that \a\r
+ pft was NULL or \a str was NULL.\r
+\r
+ \retval KHM_ERROR_SUCCESS The string was successfully parsed and\r
+ the result was placed in \a pft.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+IntervalStringToFt(FILETIME * pft, wchar_t * str);\r
+\r
+/*! \brief Return number of milliseconds till next representation change\r
+\r
+ Returns the number of milliseconds that must elapse away from the\r
+ interval specified in pft \a for the representation of pft to change\r
+ from whatever it is right now.\r
+\r
+ Returns 0 if the representation is not expected to change.\r
+*/\r
+KHMEXP long KHMAPI \r
+FtIntervalMsToRepChange(LPFILETIME pft);\r
+\r
+/*! \brief Convert a safe ANSI string to a Unicode string\r
+\r
+ The resulting string is guaranteed to be NULL terminated and\r
+ within the size limit set by \a cbwstr.\r
+\r
+ If the whole string cannot be converted, \a wstr is set to an\r
+ empty string.\r
+\r
+ \return the number of characters converted. This is always either\r
+ the length of the string \a astr or 0.\r
+*/\r
+KHMEXP int KHMAPI \r
+AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr);\r
+\r
+/*! \brief Convert a Unicode string to ANSI\r
+\r
+ The resulting string is guaranteed to be NULL terminated and\r
+ within the size limit set by \a cbdest.\r
+\r
+ \return the number of characters converted. This is always either\r
+ the length of the string \a src or 0.\r
+*/\r
+KHMEXP int KHMAPI \r
+UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src);\r
+/*@}*/\r
+\r
+/*! \name Standard type identifiers and names \r
+@{*/\r
+\r
+/*! Maximum identifier number */\r
+#define KCDB_TYPE_MAX_ID 255\r
+\r
+/*! \brief Invalid type\r
+\r
+ Used by functions that return a type identifier to indicate that\r
+ the returned type identifier is invalid. Also used to indicate\r
+ that a type identifier is not available */\r
+#define KCDB_TYPE_INVALID (-1)\r
+\r
+/*! \brief All types\r
+\r
+ Used by filters to indicate that all types are allowed.\r
+*/\r
+#define KCDB_TYPE_ALL KCDB_TYPE_INVALID\r
+\r
+#define KCDB_TYPE_VOID 0\r
+#define KCDB_TYPE_STRING 1\r
+#define KCDB_TYPE_DATE 2\r
+#define KCDB_TYPE_INTERVAL 3\r
+#define KCDB_TYPE_INT32 4\r
+#define KCDB_TYPE_INT64 5\r
+#define KCDB_TYPE_DATA 6\r
+\r
+#define KCDB_TYPENAME_VOID L"Void"\r
+#define KCDB_TYPENAME_STRING L"String"\r
+#define KCDB_TYPENAME_DATE L"Date"\r
+#define KCDB_TYPENAME_INTERVAL L"Interval"\r
+#define KCDB_TYPENAME_INT32 L"Int32"\r
+#define KCDB_TYPENAME_INT64 L"Int64"\r
+#define KCDB_TYPENAME_DATA L"Data"\r
+/*@}*/\r
+/*@}*/\r
+\r
+/********************************************************************/\r
+\r
+/*! \defgroup kcdb_credattr Credential attributes */\r
+/*@{*/\r
+\r
+/*! \brief Prototype callback function for computed data types.\r
+\r
+ If the flags for a particular attribute specifies that the value\r
+ is computed, then a callback function should be specified. The\r
+ callback function will be called with a handle to a credential\r
+ along with the attribute ID for the requested attribute. The\r
+ function should place the computed value in \a buffer. The size\r
+ of the buffer in bytes is specifed in \a cbsize. However, if \a\r
+ buffer is \a NULL, then the required buffer size should be placed\r
+ in \a cbsize.\r
+ */\r
+typedef khm_int32 \r
+(KHMAPI *kcdb_attrib_compute_cb)(khm_handle cred, \r
+ khm_int32 id,\r
+ void * buffer,\r
+ khm_size * cbsize);\r
+\r
+/*! \brief Credential attribute descriptor\r
+\r
+ \see kcdb_attrib_register()\r
+*/\r
+typedef struct tag_kcdb_attrib {\r
+ wchar_t * name; /*!< Name. (Not localized,\r
+ required) */\r
+ khm_int32 id; /*!< Identifier. When registering,\r
+ this can be set to\r
+ ::KCDB_ATTR_INVALID if a unique\r
+ identifier is to be generated. */\r
+ khm_int32 alt_id; /*!< Alternate identifier. If the \a\r
+ flags specify\r
+ ::KCDB_ATTR_FLAG_ALTVIEW, then this\r
+ field should specify the identifier\r
+ of the canonical attribute from\r
+ which this attribute is derived. */\r
+ khm_int32 flags; /*!< Flags. Combination of \ref\r
+ kcdb_credattr_flags "attribute\r
+ flags" */\r
+ khm_int32 type; /*!< Type of the attribute. Must be valid. */\r
+ wchar_t * short_desc; /*!< Short description. (Localized,\r
+ optional) */\r
+ wchar_t * long_desc; /*!< Long description. (Localized,\r
+ optional) */\r
+\r
+ kcdb_attrib_compute_cb compute_cb;\r
+ /*!< Callback. Required if \a flags\r
+ specify ::KCDB_ATTR_FLAG_COMPUTED. */\r
+ khm_size compute_min_cbsize;\r
+ /*!< Minimum number of bytes required\r
+ to store this attribute. Required\r
+ if ::KCDB_ATTR_FLAG_COMPUTED is\r
+ specified.*/\r
+ khm_size compute_max_cbsize;\r
+ /*!< Maximum number of bytes required\r
+ to store this attribute. Required\r
+ if ::KCDB_ATTR_FLAG_COMPUTED is\r
+ specified.*/\r
+} kcdb_attrib;\r
+\r
+/*! \brief Retrieve the ID of a named attribute */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_get_id(wchar_t *name, \r
+ khm_int32 * id);\r
+\r
+/*! \brief Register an attribute\r
+\r
+ \param[out] new_id Receives the ID of the newly registered\r
+ attribute. If the \a id member of the ::kcdb_attrib object is\r
+ set to KCDB_ATTR_INVALID, then a unique ID is generated. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_register(kcdb_attrib * attrib, \r
+ khm_int32 * new_id);\r
+\r
+/*! \brief Retrieve the attribute descriptor for an attribute \r
+\r
+ The descriptor that is returned must be released through a call to\r
+ kcdb_attrib_release_info()\r
+\r
+ If only the validity of the attribute identifier needs to be\r
+ checked, you can pass in NULL for \a attrib. In this case, if the\r
+ identifier is valid, then the funciton will return\r
+ KHM_ERROR_SUCCESS, otherwise it will return KHM_ERROR_NOT_FOUND.\r
+ \r
+ \see kcdb_attrib_release_info()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_get_info(khm_int32 id, \r
+ kcdb_attrib ** attrib);\r
+\r
+/*! \brief Release an attribute descriptor\r
+\r
+ \see kcdb_attrib_get_info()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_release_info(kcdb_attrib * attrib);\r
+\r
+/*! \brief Unregister an attribute \r
+\r
+ Once an attribute ID has been unregistered, it may be reclaimed by\r
+ a subsequent call to kcdb_attrib_register().\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_unregister(khm_int32 id);\r
+\r
+/*! \brief Retrieve the description of an attribute \r
+\r
+ \param[in] flags Specify \a KCDB_TS_SHORT to retrieve the short description. */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_describe(khm_int32 id, \r
+ wchar_t * buffer, \r
+ khm_size * cbsize, \r
+ khm_int32 flags);\r
+\r
+/*! \brief Count attributes\r
+\r
+ Counts the number of attributes that match the given criteria.\r
+ The criteria is specified against the flags of the attribute. An\r
+ attribute is a match if its flags satisfy the condition below:\r
+\r
+ \code\r
+ (attrib.flags & and_flags) == (eq_flags & and_flags)\r
+ \endcode\r
+\r
+ The number of attributes that match are returned in \a pcount.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_get_count(khm_int32 and_flags,\r
+ khm_int32 eq_flags,\r
+ khm_size * pcount);\r
+\r
+/*! \brief List attribute identifiers\r
+\r
+ Lists the identifiers of the attributes that match the given\r
+ criteria. The criteria is specified against the flags of the\r
+ attribute. An attribute is a match if the following condition is\r
+ satisfied:\r
+\r
+ \code\r
+ (attrib.flags & and_flags) == (eq_flags & and_flags)\r
+ \endcode\r
+\r
+ The list of attributes found are copied to the \a khm_int32 array\r
+ specified in \a plist. The number of elements available in the\r
+ buffer \a plist is specified in \a pcsize. On exit, \a pcsize\r
+ will hold the actual number of attribute identifiers copied to the\r
+ array.\r
+\r
+ \param[in] and_flags See above\r
+ \param[in] eq_flags See above\r
+ \param[in] plist A khm_int32 array\r
+ \param[in,out] pcsize On entry, holds the number of elements\r
+ available in the array pointed to by \a plist. On exit, holds\r
+ the number of elements copied to the array.\r
+\r
+ \retval KHM_ERROR_SUCCESS The list of attribute identifiers have\r
+ been copied.\r
+ \retval KHM_ERROR_TOO_LONG The list was too long to fit in the\r
+ supplied buffer. As many elements as possible have been\r
+ copied to the \a plist array and the required number of\r
+ elements has been written to \a pcsize.\r
+\r
+ \note The \a pcsize parameter specifies the number of khm_int32\r
+ elements in the array and not the number of bytes in the\r
+ array. This is different from the usual size parameters used\r
+ in the NetIDMgr API.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_attrib_get_ids(khm_int32 and_flags,\r
+ khm_int32 eq_flags,\r
+ khm_int32 * plist,\r
+ khm_size * pcsize);\r
+\r
+/*! \defgroup kcdb_credattr_flags Attribute flags */\r
+/*@{*/\r
+/*! \brief The attribute is required */\r
+#define KCDB_ATTR_FLAG_REQUIRED 0x00000008\r
+\r
+/*! \brief The attribute is computed.\r
+\r
+ If this flag is set, the \a compute_cb, \a compute_min_cbsize and\r
+ \a compute_max_cbsize members of the ::kcdb_attrib attribute\r
+ descriptor must be assigned valid values.\r
+*/\r
+#define KCDB_ATTR_FLAG_COMPUTED 0x00000010\r
+\r
+/*! \brief System attribute.\r
+\r
+ This cannot be specified for a custom attribute. Implies that the\r
+ value of the attribute is given by the credentials database\r
+ itself.\r
+*/\r
+#define KCDB_ATTR_FLAG_SYSTEM 0x00000020\r
+\r
+/*! \brief Hidden\r
+\r
+ The attribute is not meant to be displayed to the user. Setting\r
+ this flag prevents this attribute from being listed in the list of\r
+ available data fields in the UI.\r
+*/\r
+#define KCDB_ATTR_FLAG_HIDDEN 0x00000040\r
+\r
+/*! \brief Property\r
+\r
+ The attribute is a property. The main difference between regular\r
+ attributes and properties are that properties are not allocated\r
+ off the credentials record. Hence, a property can not be used as\r
+ a credentials field. Other objects such as identities can hold\r
+ property sets. A property set can hold both regular attributes as\r
+ well as properties.\r
+*/\r
+#define KCDB_ATTR_FLAG_PROPERTY 0x00000080\r
+\r
+/*! \brief Volatile\r
+\r
+ A volatile property is one whose value changes often, such as\r
+ ::KCDB_ATTR_TIMELEFT. Some controls will make use of additional\r
+ logic to deal with such values, or not display them at all.\r
+ */\r
+#define KCDB_ATTR_FLAG_VOLATILE 0x00000100\r
+\r
+/*! \brief Alternate view\r
+\r
+ The attribute is actually an alternate representation of another\r
+ attribute. The Canonical attribute name is specified in \a\r
+ alt_id.\r
+\r
+ Sometimes a certain attribute may need to be represented in\r
+ different ways. You can register multiple attributes for each\r
+ view. However, you should also provide a canonical attribute for\r
+ whenever the canonical set of attributes of the credential is\r
+ required.\r
+ */\r
+#define KCDB_ATTR_FLAG_ALTVIEW 0x00000200\r
+/*@}*/\r
+\r
+/*! \defgroup kcdb_credattr_idnames Standard attribute IDs and names */\r
+/*@{*/\r
+\r
+/*! \name Attribute related constants */\r
+/*@{*/\r
+/*! \brief Maximum valid attribute ID */\r
+#define KCDB_ATTR_MAX_ID 255\r
+\r
+/*! \brief Minimum valid property ID */\r
+#define KCDB_ATTR_MIN_PROP_ID 4096\r
+\r
+/*! \brief Maximum number of properties */\r
+#define KCDB_ATTR_MAX_PROPS 128\r
+\r
+/*! \brief Maximum valid property ID */\r
+#define KCDB_ATTR_MAX_PROP_ID (KCDB_ATTR_MIN_PROP_ID + KCDB_ATTR_MAX_PROPS - 1)\r
+\r
+/*! \brief Invalid ID */\r
+#define KCDB_ATTR_INVALID (-1)\r
+\r
+/*! \brief First custom attribute ID */\r
+#define KCDB_ATTRID_USER 20\r
+\r
+/*@}*/\r
+\r
+/*!\name Attribute identifiers */\r
+/*@{*/\r
+/*! \brief Name of the credential\r
+\r
+ - \b Type: STRING\r
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM\r
+ */\r
+#define KCDB_ATTR_NAME 0\r
+\r
+/*! \brief The identity handle for the credential\r
+\r
+ - \b Type: INT64\r
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN\r
+\r
+ \note The handle returned in by specifying this attribute to\r
+ kcdb_cred_get_attr() or kcdb_cred_get_attrib() is not held.\r
+ While the identity is implicitly held for the duration that\r
+ the credential is held, it is not recommended to obtain a\r
+ handle to the identity using this method. Use\r
+ kcdb_cred_get_identity() instead.\r
+*/\r
+#define KCDB_ATTR_ID 1\r
+\r
+/*! \brief The name of the identity \r
+\r
+ - \b Type: STRING\r
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM\r
+ */\r
+#define KCDB_ATTR_ID_NAME 2\r
+\r
+/*! \brief The type of the credential\r
+\r
+ - \b Type: INT32\r
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN\r
+*/\r
+#define KCDB_ATTR_TYPE 3\r
+\r
+/*! \brief Type name for the credential \r
+\r
+ - \b Type: STRING\r
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM\r
+*/\r
+#define KCDB_ATTR_TYPE_NAME 4\r
+\r
+/*! \brief Name of the parent credential \r
+\r
+ - \b Type: STRING\r
+ - \b Flags: SYSTEM\r
+*/\r
+#define KCDB_ATTR_PARENT_NAME 5\r
+\r
+/*! \brief Issed on \r
+\r
+ - \b Type: DATE\r
+ - \b Flags: SYSTEM\r
+*/\r
+#define KCDB_ATTR_ISSUE 6\r
+\r
+/*! \brief Expires on \r
+\r
+ - \b Type: DATE\r
+ - \b Flags: SYSTEM\r
+*/\r
+#define KCDB_ATTR_EXPIRE 7\r
+\r
+/*! \brief Renewable period expires on \r
+\r
+ - \b Type: DATE\r
+ - \b Flags: SYSTEM\r
+*/\r
+#define KCDB_ATTR_RENEW_EXPIRE 8\r
+\r
+/*! \brief Time left till expiration \r
+\r
+ - \b Type: INTERVAL\r
+ - \b Flags: SYSTEM, COMPUTED, VOLATILE\r
+*/\r
+#define KCDB_ATTR_TIMELEFT 9\r
+\r
+#define KCDB_ATTR_RENEW_TIMELEFT 10\r
+\r
+/*! \brief Location of the credential\r
+\r
+ - \b Type: STRING\r
+ - \b Flags: SYSTEM\r
+*/\r
+#define KCDB_ATTR_LOCATION 11\r
+\r
+/*! \brief Lifetime of the credential \r
+\r
+ - \b Type: INTERVAL\r
+ - \b Flags: SYSTEM\r
+*/\r
+#define KCDB_ATTR_LIFETIME 12\r
+\r
+#define KCDB_ATTR_RENEW_LIFETIME 13\r
+\r
+/*! \brief Flags for the credential\r
+\r
+ - \b Type: INT32\r
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN\r
+ */\r
+#define KCDB_ATTR_FLAGS 14\r
+\r
+/*@}*/\r
+\r
+/*!\name Attribute names */\r
+/*@{ */\r
+\r
+#define KCDB_ATTRNAME_NAME L"Name"\r
+#define KCDB_ATTRNAME_ID L"Identity"\r
+#define KCDB_ATTRNAME_ID_NAME L"IdentityName"\r
+#define KCDB_ATTRNAME_TYPE L"TypeId"\r
+#define KCDB_ATTRNAME_TYPE_NAME L"TypeName"\r
+#define KCDB_ATTRNAME_FLAGS L"Flags"\r
+\r
+#define KCDB_ATTRNAME_PARENT_NAME L"Parent"\r
+#define KCDB_ATTRNAME_ISSUE L"Issed"\r
+#define KCDB_ATTRNAME_EXPIRE L"Expires"\r
+#define KCDB_ATTRNAME_RENEW_EXPIRE L"RenewExpires"\r
+#define KCDB_ATTRNAME_TIMELEFT L"TimeLeft"\r
+#define KCDB_ATTRNAME_RENEW_TIMELEFT L"RenewTimeLeft"\r
+#define KCDB_ATTRNAME_LOCATION L"Location"\r
+#define KCDB_ATTRNAME_LIFETIME L"Lifetime"\r
+#define KCDB_ATTRNAME_RENEW_LIFETIME L"RenewLifetime"\r
+\r
+/*@}*/\r
+\r
+/*@}*/\r
+\r
+/*@}*/\r
+\r
+/*****************************************************************************/\r
+\r
+/*! \defgroup kcdb_credtype Credential types */\r
+/*@{*/\r
+\r
+/*! \brief Credential type descriptor */\r
+typedef struct tag_kcdb_credtype {\r
+ wchar_t * name; /*!< name (less than KCDB_MAXCB_NAME bytes) */\r
+ khm_int32 id;\r
+ wchar_t * short_desc; /*!< short localized description (less\r
+ than KCDB_MAXCB_SHORT_DESC\r
+ bytes) */\r
+ wchar_t * long_desc; /*!< long localized descriptionn (less\r
+ than KCDB_MAXCB_LONG_DESC\r
+ bytes) */\r
+ khm_handle sub; /*!< Subscription for credentials type\r
+ hander. This should be a valid\r
+ subscription constructed through\r
+ a call to\r
+ kmq_create_subscription() and\r
+ must handle KMSG_CRED messages\r
+ that are marked as being sent to\r
+ type specific subscriptions.\r
+\r
+ The subscription will be\r
+ automatically deleted with a call\r
+ to kmq_delete_subscription() when\r
+ the credentials type is\r
+ unregistered.*/\r
+\r
+#ifdef _WIN32\r
+ HICON icon;\r
+#endif\r
+} kcdb_credtype;\r
+\r
+/*! \brief Maximum value of a credential type identifier\r
+\r
+ Credential type identifiers are assigned serially unless the\r
+ process registering the credential type sets a specific identity.\r
+ The maximum identifier number places a hard limit to the number of\r
+ credential types that can be registered at one time, which is\r
+ KCDB_CREDTYPE_MAX_ID + 1.\r
+ */\r
+#define KCDB_CREDTYPE_MAX_ID 31\r
+\r
+/*! \brief Specify all credential types\r
+\r
+ This value is used by functions which filter credentials based on\r
+ credential types. Specifying this value tells the filter to\r
+ accept all credential types.\r
+ */\r
+#define KCDB_CREDTYPE_ALL (-1)\r
+\r
+/*! \brief Automatically determine a credential type identifier\r
+\r
+ Used with kcdb_credtype_register() to specify that the credential\r
+ type identifier should be automatically determined to avoid\r
+ collisions.\r
+ */\r
+#define KCDB_CREDTYPE_AUTO (-2)\r
+\r
+/*! \brief An invalid credential type\r
+\r
+ Even though any non positive credential type ID is invalid\r
+ anywhere where a specific credential type ID is required, this\r
+ value is provided for explicit indication that the credential type\r
+ is invalid. Also it makes code more readable to have a constant\r
+ that shouts out INVALID.\r
+\r
+*/\r
+#define KCDB_CREDTYPE_INVALID (-3)\r
+\r
+/*! \brief Macro predicate for testing whether a credtype is valid\r
+\r
+ Returns TRUE if the given credtype is valid. This is a safe\r
+ macro.\r
+*/\r
+#define KCDB_CREDTYPE_IS_VALID(t) ((t) >= 0)\r
+\r
+/*! \brief Register a credentials type.\r
+\r
+ The information given in the \a type parameter is used to register\r
+ a new credential type. Note that the \a name member of the \a\r
+ type should be unique among all credential types.\r
+\r
+ You can specify ::KCDB_CREDTYPE_AUTO as the \a id member of \a\r
+ type to let kcdb_credtype_register() determine a suitable\r
+ credential type identifier. You can subsequently call\r
+ kcdb_credtype_get_id() to retrieve the generated id or pass a\r
+ valid pointer to a khm_int32 type variable as \a new_id.\r
+\r
+ \param[in] type Credential type descriptor\r
+\r
+ \param[out] new_id The credential type identifier that this type\r
+ was registered as.\r
+\r
+ \retval KHM_ERROR_SUCCESS The credential type was successfully registered.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more of the parameters were invalid\r
+\r
+ \retval KHM_ERROR_TOO_LONG One or more of the string fields in \a\r
+ type exceeded the character limit for that field.\r
+\r
+ \retval KHM_ERROR_NO_RESOURCES When autogenerating credential type\r
+ identifiers, this value indicates that the maximum number of\r
+ credential types have been registered. No more registrations\r
+ can be accepted unless some credentials type is unregisred.\r
+\r
+ \retval KHM_ERROR_DUPLICATE The \a name or \a id that was\r
+ specified is already in use.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_register(kcdb_credtype * type, \r
+ khm_int32 * new_id);\r
+\r
+/*! \brief Return a held reference to a \a kcdb_credtype object describing the credential type.\r
+\r
+ The reference points to a static internal object of type \a\r
+ kcdb_credtype. Use the kcdb_credtype_release_info() function to\r
+ release the reference.\r
+\r
+ Also, the structure passed in as the \a type argument to\r
+ kcdb_credtype_register() is not valid as a credential type\r
+ descriptor. Use kcdb_credtype_get_info() to obtain the actual\r
+ credential type descriptor.\r
+\r
+ \param[in] id Credentials type identifier.\r
+\r
+ \param[out] type Receives the credentials descriptor handle. If\r
+ \a type is NULL, then no handle is returned. However, the\r
+ function will still return \a KHM_ERROR_SUCCESS if the \a id\r
+ parameter passed in is a valid credentials type identifier.\r
+\r
+ \see kcdb_credtype_release_info()\r
+ \see kcdb_credtype_register()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_get_info(khm_int32 id, \r
+ kcdb_credtype ** type);\r
+\r
+/*! \brief Release a reference to a \a kcdb_credtype object\r
+\r
+ Undoes the hold obtained on a \a kcdb_credtype object from a\r
+ previous call to kcdb_credtype_get_info().\r
+\r
+ \see kcdb_credtype_get_info()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_release_info(kcdb_credtype * type);\r
+\r
+/*! \brief Unregister a credentials type\r
+\r
+ Undoes the registration performed by kcdb_credtype_register().\r
+\r
+ This should only be done when the credentials provider is being\r
+ unloaded.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_unregister(khm_int32 id);\r
+\r
+/*! \brief Retrieve the name of a credentials type\r
+\r
+ Given a credentials type identifier, retrieves the name. The name\r
+ is not localized and serves as a persistent identifier of the\r
+ credentials type.\r
+\r
+ \param[out] buf The buffer to receive the name. Could be \a NULL\r
+ if only the length of the buffer is required.\r
+\r
+ \param[in,out] cbbuf On entry, specifies the size of the buffer\r
+ pointed to by \a buf if \a buf is not NULL. On exit, contains\r
+ the number of bytes copied to \a buf or the required size of\r
+ the buffer.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded.\r
+\r
+ \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied\r
+ buffer was not large enough. The required size is in \a cbbuf.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM Invalid parameter.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_get_name(khm_int32 id,\r
+ wchar_t * buf,\r
+ khm_size * cbbuf);\r
+\r
+/*! \brief Retrieve the type specific subscription for a type\r
+\r
+ Given a credentials type, this function returns the credentials\r
+ type specific subcription. It may return NULL if the subscription\r
+ is not available.\r
+ */\r
+KHMEXP khm_handle KHMAPI \r
+kcdb_credtype_get_sub(khm_int32 id);\r
+\r
+/*! \brief Get the description of a credentials type\r
+\r
+ Unlike the name of a credential type, the description is localized.\r
+\r
+ \param[in] id Credentials type identifier\r
+\r
+ \param[out] buf Receives the description. Can bet set to NULL if\r
+ only the size of the buffer is required.\r
+\r
+ \param[in,out] cbbuf On entry, specifies the size of the buffer\r
+ pointed to by \a buf. On exit, specifies the required size of\r
+ the buffer or the number of bytes copied, depending on whether\r
+ the call succeeded or not.\r
+\r
+ \param[in] flags Specify ::KCDB_TS_SHORT if the short version of\r
+ the description is desired if there is more than one.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded\r
+ \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied buffer was insufficient. The required size is specified in \a cbbuf.\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_describe(khm_int32 id,\r
+ wchar_t * buf,\r
+ khm_size * cbbuf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Look up the identifier of a credentials type by name\r
+\r
+ Given a name, looks up the identifier.\r
+\r
+ \param[in] name Name of the credentials type\r
+ \param[out] id Receives the identifier if the call succeeds\r
+\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_credtype_get_id(wchar_t * name, \r
+ khm_int32 * id);\r
+\r
+/*@}*/\r
+\r
+/*********************************************************************/\r
+\r
+/*! \defgroup kcdb_buf Generic access to buffer \r
+\r
+ Currently, credentials and identities both hold record data types.\r
+ This set of API's allow an application to access fields in the\r
+ records using a single interface. Note that credentials only\r
+ accept regular attributes while identities can hold both\r
+ attributes and properties.\r
+\r
+ Handles to credentials and identities are implicitly also handles\r
+ to records. Thus they can be directly used as such.\r
+*/\r
+/*@{*/\r
+\r
+/*! \brief Get an attribute from a record by attribute id.\r
+\r
+ \param[in] buffer The buffer that is to receive the attribute\r
+ value. Set this to NULL if only the required buffer size is\r
+ to be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+\r
+ \param[out] attr_type Receives the data type of the attribute.\r
+ Set this to NULL if the type is not required.\r
+\r
+ \note Set both \a buffer and \a cbbuf to NULL if only the\r
+ existence of the attribute is to be checked. If the attribute\r
+ exists in this record then the function will return\r
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_get_attr(khm_handle record, \r
+ khm_int32 attr_id, \r
+ khm_int32 * attr_type, \r
+ void * buffer, \r
+ khm_size * pcb_buf);\r
+\r
+/*! \brief Get an attribute from a record by name.\r
+\r
+ \param[in] buffer The buffer that is to receive the attribute\r
+ value. Set this to NULL if only the required buffer size is\r
+ to be returned.\r
+\r
+ \param[in,out] cbbuf The number of bytes available in \a buffer.\r
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and\r
+ sets this to the required buffer size.\r
+\r
+ \note Set both \a buffer and \a cbbuf to NULL if only the\r
+ existence of the attribute is to be checked. If the attribute\r
+ exists in this record then the function will return\r
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_get_attrib(khm_handle record,\r
+ wchar_t * attr_name,\r
+ khm_int32 * attr_type,\r
+ void * buffer,\r
+ khm_size * pcb_buf);\r
+\r
+/*! \brief Get the string representation of a record attribute.\r
+\r
+ A shortcut function which generates the string representation of a\r
+ record attribute directly.\r
+\r
+ \param[in] record A handle to a record\r
+\r
+ \param[in] attr_id The attribute to retrieve\r
+\r
+ \param[out] buffer A pointer to a string buffer which receives the\r
+ string form of the attribute. Set this to NULL if you only\r
+ want to determine the size of the required buffer.\r
+\r
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,\r
+ holds the size of the buffer pointed to by \a buffer, and on\r
+ exit, receives the actual number of bytes that were copied.\r
+\r
+ \param[in] flags Flags for the string conversion. Can be set to\r
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is\r
+ KCDB_TS_LONG.\r
+\r
+ \retval KHM_ERROR_SUCCESS Success\r
+ \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid\r
+ or was not defined for this record\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the\r
+ supplied buffer was insufficient\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_get_attr_string(khm_handle record,\r
+ khm_int32 attr_id,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Get the string representation of a record attribute by name.\r
+\r
+ A shortcut function which generates the string representation of a\r
+ record attribute directly.\r
+\r
+ \param[in] record A handle to a record\r
+\r
+ \param[in] attrib The name of the attribute to retrieve\r
+\r
+ \param[out] buffer A pointer to a string buffer which receives the\r
+ string form of the attribute. Set this to NULL if you only\r
+ want to determine the size of the required buffer.\r
+\r
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,\r
+ holds the size of the buffer pointed to by \a buffer, and on\r
+ exit, receives the actual number of bytes that were copied.\r
+\r
+ \param[in] flags Flags for the string conversion. Can be set to\r
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is\r
+ KCDB_TS_LONG.\r
+\r
+ \see kcdb_cred_get_attr_string()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_get_attrib_string(khm_handle record,\r
+ wchar_t * attr_name,\r
+ wchar_t * buffer,\r
+ khm_size * pcbbuf,\r
+ khm_int32 flags);\r
+\r
+/*! \brief Set an attribute in a record by attribute id\r
+\r
+ \param[in] cbbuf Number of bytes of data in \a buffer. The\r
+ individual data type handlers may copy in less than this many\r
+ bytes in to the record.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_set_attr(khm_handle record,\r
+ khm_int32 attr_id,\r
+ void * buffer,\r
+ khm_size cbbuf);\r
+\r
+/*! \brief Set an attribute in a record by name\r
+\r
+ \param[in] cbbuf Number of bytes of data in \a buffer. The\r
+ individual data type handlers may copy in less than this many\r
+ bytes in to the record.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_set_attrib(khm_handle record,\r
+ wchar_t * attr_name,\r
+ void * buffer,\r
+ khm_size cbbuf);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_hold(khm_handle record);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kcdb_buf_release(khm_handle record);\r
+\r
+/*@}*/\r
+\r
+/********************************************************************/\r
+\r
+/* Notification operation constants */\r
+\r
+#define KCDB_OP_INSERT 1\r
+#define KCDB_OP_DELETE 2\r
+#define KCDB_OP_MODIFY 3\r
+#define KCDB_OP_ACTIVATE 4\r
+#define KCDB_OP_DEACTIVATE 5\r
+#define KCDB_OP_HIDE 6\r
+#define KCDB_OP_UNHIDE 7\r
+#define KCDB_OP_SETSEARCH 8\r
+#define KCDB_OP_UNSETSEARCH 9\r
+#define KCDB_OP_NEW_DEFAULT 10\r
+\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCREDDBINTERNAL_H__\r
+#define __KHIMAIRA_KCREDDBINTERNAL_H__\r
+\r
+#include<windows.h>\r
+#include<kcreddb.h>\r
+#include<kmq.h>\r
+#include<khlist.h>\r
+#include<utils.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<kconfig.h>\r
+#include<strsafe.h>\r
+\r
+#include<langres.h>\r
+\r
+#include "buf.h"\r
+#include "identity.h"\r
+#include "attrib.h"\r
+#include "type.h"\r
+#include "credential.h"\r
+#include "credset.h"\r
+#include "credtype.h"\r
+\r
+/* globals */\r
+\r
+extern HINSTANCE hinst_kcreddb;\r
+\r
+kconf_schema schema_kcdbconfig[];\r
+\r
+void kcdb_init(void);\r
+void kcdb_exit(void);\r
+khm_handle kcdb_get_config(void);\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+\r
+HINSTANCE hinst_kcreddb;\r
+\r
+void\r
+kcdb_process_attach(HINSTANCE hinstDLL) {\r
+ hinst_kcreddb = hinstDLL;\r
+ kcdb_init();\r
+}\r
+\r
+void\r
+kcdb_process_detach(void) {\r
+ kcdb_exit();\r
+}\r
--- /dev/null
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "..\..\langres.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "..\\..\\langres.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "..\\..\\langres.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_CREDDB "Khimaira Credentials Database"\r
+ IDS_NAME "Name"\r
+ IDS_IDENTITY "Identity"\r
+ IDS_ISSUED "Issued on"\r
+ IDS_EXPIRES "Expires on"\r
+ IDS_TIMELEFT "Time left"\r
+ IDS_LOCATION "Location"\r
+ IDS_PARENT "Parent"\r
+ IDS_TYPE "Type"\r
+ IDS_IVL_EXPIRED "(Expired)"\r
+ IDS_IVL_D_H "%I64u days %I64u hours"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_IVL_H_M "%I64u hours %I64u mins"\r
+ IDS_IVL_M_S "%I64u mins %I64u secs"\r
+ IDS_IVL_S "%I64u seconds"\r
+ IDS_IVL_UNKNOWN "(Unknown)"\r
+ IDS_LIFETIME "Lifetime"\r
+ IDS_IVL_1D "1 day"\r
+ IDS_IVL_1H "1 hour"\r
+ IDS_IVL_1M "1 minute"\r
+ IDS_IVL_1S "1 second"\r
+ IDS_IVL_D "%I64u days"\r
+ IDS_IVL_H "%I64u hours"\r
+ IDS_IVL_M "%I64u minutes"\r
+ IDS_IVL_S_SPEC "s,sec,second,seconds,secs"\r
+ IDS_IVL_M_SPEC "m,min,mins,minutes"\r
+ IDS_IVL_H_SPEC "h,hrs,hours"\r
+ IDS_IVL_D_SPEC "d,day,days,ds"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_IVl_W_SPEC "w,wk,wks,weeks"\r
+ IDS_FLAGS "Flags"\r
+ IDS_RENEW_TIMELEFT "Renewable Time left"\r
+ IDS_RENEW_EXPIRES "Renewable time expires"\r
+ IDS_RENEW_LIFETIME "Renewable lifetime"\r
+END\r
+\r
+#endif // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
+\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by D:\work\khimaira\src\kcreddb\lang\en_us\kcredres.rc\r
+//\r
+#define IDS_CREDDB 101\r
+#define IDS_NAME 102\r
+#define IDS_IDENTITY 103\r
+#define IDS_ISSUED 104\r
+#define IDS_EXPIRES 105\r
+#define IDS_TIMELEFT 106\r
+#define IDS_LOCATION 107\r
+#define IDS_PARENT 108\r
+#define IDS_TYPE 109\r
+#define IDS_IVL_EXPIRED 110\r
+#define IDS_IVL_D_H 111\r
+#define IDS_IVL_H_M 112\r
+#define IDS_IVL_M_S 113\r
+#define IDS_IVL_S 114\r
+#define IDS_IVL_UNKNOWN 115\r
+#define IDS_LIFETIME 116\r
+#define IDS_IVL_1D 117\r
+#define IDS_IVL_1H 118\r
+#define IDS_IVL_1M 119\r
+#define IDS_IVL_1S 120\r
+#define IDS_IVL_D 121\r
+#define IDS_IVL_H 122\r
+#define IDS_IVL_M 123\r
+#define IDS_IVL_S_SPEC 124\r
+#define IDS_IVL_M_SPEC 125\r
+#define IDS_IVL_H_SPEC 126\r
+#define IDS_IVL_D_SPEC 127\r
+#define IDS_IVl_W_SPEC 128\r
+#define IDS_IVL_W_SPEC 128\r
+#define IDS_IVl_W_SPEC 128\r
+#define IDS_FLAGS 129\r
+#define IDS_RENEW_TIMELEFT 130\r
+#define IDS_RENEW_EXPIRES 131\r
+#define IDS_RENEW_LIFETIME 132\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 102\r
+#define _APS_NEXT_COMMAND_VALUE 40001\r
+#define _APS_NEXT_CONTROL_VALUE 1001\r
+#define _APS_NEXT_SYMED_VALUE 101\r
+#endif\r
+#endif\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by kcreddb.rc\r
+//\r
+#define IDS_PROJNAME 100\r
+#define IDR_WMDMLOGGER 101\r
+#define IDS_LOG_SEV_INFO 201\r
+#define IDS_LOG_SEV_WARN 202\r
+#define IDS_LOG_SEV_ERROR 203\r
+#define IDS_LOG_DATETIME 204\r
+#define IDS_LOG_SRCNAME 205\r
+#define IDS_DEF_LOGFILE 301\r
+#define IDS_DEF_MAXSIZE 302\r
+#define IDS_DEF_SHRINKTOSIZE 303\r
+#define IDS_DEF_LOGENABLED 304\r
+#define IDS_MUTEX_TIMEOUT 401\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 201\r
+#define _APS_NEXT_COMMAND_VALUE 32768\r
+#define _APS_NEXT_CONTROL_VALUE 201\r
+#define _APS_NEXT_SYMED_VALUE 101\r
+#endif\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kcreddbinternal.h>\r
+#include<limits.h>\r
+\r
+CRITICAL_SECTION cs_type;\r
+hashtable * kcdb_type_namemap;\r
+kcdb_type_i ** kcdb_type_tbl;\r
+kcdb_type_i * kcdb_types = NULL;\r
+\r
+/* Void */\r
+\r
+#define GENERIC_VOID_STR L"(Void)"\r
+\r
+khm_int32 KHMAPI kcdb_type_void_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ size_t cbsize;\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cbsize = sizeof(GENERIC_VOID_STR);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cb_buf, GENERIC_VOID_STR);\r
+\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_void_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ /* void is always valid, even if d is NULL */\r
+ return TRUE;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_void_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ /* voids can not be compared */\r
+ return 0;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_void_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ if(!cbd_dst)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ *cbd_dst = 0;\r
+\r
+ /* copying a void doesn't do much */\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+\r
+/* String */\r
+khm_int32 KHMAPI kcdb_type_string_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ size_t cbsize;\r
+ wchar_t * sd;\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ sd = (wchar_t *) d;\r
+\r
+ if(FAILED(StringCbLength(sd, KCDB_TYPE_MAXCB, &cbsize)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cb_buf, sd);\r
+\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_string_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ size_t cbsize;\r
+\r
+ if(cbd == KCDB_CBSIZE_AUTO)\r
+ cbd = KCDB_TYPE_MAXCB;\r
+\r
+ if(FAILED(StringCbLength((wchar_t *) d, cbd, &cbsize)))\r
+ return FALSE;\r
+ else\r
+ return TRUE;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_string_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ return wcscmp((const wchar_t *) d1, (const wchar_t *) d2);\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_string_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ size_t cbsize;\r
+\r
+ if(!cbd_dst)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(cbd_src == KCDB_CBSIZE_AUTO) {\r
+ cbd_src = KCDB_TYPE_MAXCB;\r
+ }\r
+\r
+ if(FAILED(StringCbLength((const wchar_t *) d_src, cbd_src, &cbsize))) {\r
+ return KHM_ERROR_UNKNOWN;\r
+ }\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!d_dst || *cbd_dst < cbsize) {\r
+ *cbd_dst = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy((wchar_t *) d_dst, *cbd_dst, (const wchar_t *) d_src);\r
+ *cbd_dst = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/* Date and time */\r
+\r
+\r
+khm_int32 KHMAPI kcdb_type_date_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ size_t cbsize;\r
+ size_t cchsize;\r
+ wchar_t * bufend;\r
+ SYSTEMTIME st_now;\r
+ SYSTEMTIME st_d;\r
+ SYSTEMTIME st_dl;\r
+ FILETIME *ft;\r
+ int today = 0;\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ ft = (FILETIME *) d;\r
+\r
+ GetLocalTime(&st_now);\r
+ FileTimeToSystemTime(ft, &st_d);\r
+ SystemTimeToTzSpecificLocalTime(NULL, &st_d, &st_dl);\r
+ if(st_now.wYear == st_dl.wYear &&\r
+ st_now.wMonth == st_dl.wMonth &&\r
+ st_now.wDay == st_dl.wDay)\r
+ today = 1;\r
+\r
+ if(today && (flags & KCDB_TS_SHORT)) {\r
+ cbsize = 0;\r
+ } else {\r
+ cbsize = GetDateFormat(\r
+ LOCALE_USER_DEFAULT,\r
+ DATE_SHORTDATE,\r
+ &st_dl,\r
+ NULL,\r
+ NULL,\r
+ 0) * sizeof(wchar_t);\r
+ cbsize += sizeof(wchar_t);\r
+ }\r
+\r
+ cbsize += GetTimeFormat(\r
+ LOCALE_USER_DEFAULT,\r
+ 0,\r
+ &st_dl,\r
+ NULL,\r
+ NULL,\r
+ 0) * sizeof(wchar_t);\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ cchsize = cbsize / sizeof(wchar_t);\r
+\r
+ if(!today || !(flags & KCDB_TS_SHORT)) {\r
+ size_t cch_buf_len;\r
+\r
+ GetDateFormat(\r
+ LOCALE_USER_DEFAULT,\r
+ DATE_SHORTDATE,\r
+ &st_dl,\r
+ NULL,\r
+ buffer,\r
+ (int) cchsize);\r
+\r
+ StringCchCat(buffer, cchsize, L" ");\r
+\r
+ StringCchLength(buffer, cchsize, &cch_buf_len);\r
+\r
+ bufend = buffer + cch_buf_len;\r
+ cchsize -= cch_buf_len;\r
+ } else {\r
+ bufend = buffer;\r
+ }\r
+\r
+ GetTimeFormat(\r
+ LOCALE_USER_DEFAULT,\r
+ 0,\r
+ &st_dl,\r
+ NULL,\r
+ bufend,\r
+ (int) cchsize);\r
+\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_date_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(FILETIME)));\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_date_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ return (khm_int32) CompareFileTime((CONST FILETIME *) d1, (CONST FILETIME *) d2);\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_date_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ if(d_dst && *cbd_dst >= sizeof(FILETIME)) {\r
+ *cbd_dst = sizeof(FILETIME);\r
+ *((FILETIME *) d_dst) = *((FILETIME *) d_src);\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *cbd_dst = sizeof(FILETIME);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+}\r
+\r
+/* Interval */\r
+\r
+/* returns the number of milliseconds that must elapse away from the\r
+ interval specified in pft for the representation of pft to change\r
+ from whatever it is right now */\r
+KHMEXP long KHMAPI FtIntervalMsToRepChange(LPFILETIME pft)\r
+{\r
+ __int64 ms,s,m,h,d;\r
+ long l;\r
+\r
+ ms = *((__int64 *) pft) / 10000i64;\r
+ \r
+ if(ms < 0 || *((__int64 *) pft) == _I64_MAX)\r
+ return -1;\r
+\r
+ s = ms / 1000i64;\r
+ m = s / 60;\r
+ h = s / 3600;\r
+ d = s / (3600*24);\r
+\r
+ if(d > 0) {\r
+ /* rep change at next hour change */\r
+ l = (long) (ms % (3600*1000i64));\r
+ } else if(h > 0) {\r
+ /* rep change at next minute change */\r
+ l = (long) (ms % (60*1000i64));\r
+ } else {\r
+ l = (long) (ms % 1000);\r
+ }\r
+\r
+ return l;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI FtIntervalToString(LPFILETIME data, wchar_t * buffer, khm_size * cb_buf)\r
+{\r
+ size_t cbsize;\r
+ __int64 s,m,h,d;\r
+ wchar_t ibuf[256];\r
+ wchar_t fbuf[256];\r
+ wchar_t * t;\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+ s = *((__int64 *) data) / 10000000i64;\r
+\r
+ m = s / 60;\r
+ h = s / 3600;\r
+ d = s / (3600*24);\r
+\r
+ if(*((__int64 *) data) == _I64_MAX) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_UNKNOWN, ibuf, sizeof(ibuf)/sizeof(wchar_t));\r
+ } else if(s < 0) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_EXPIRED, ibuf, sizeof(ibuf)/sizeof(wchar_t));\r
+ } else if(d > 0) {\r
+ h = (s - (d * 3600 * 24)) / 3600;\r
+ if(d == 1) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1D, ibuf, ARRAYLENGTH(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_D, fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, d);\r
+ }\r
+ if(h > 0) {\r
+ StringCbCat(ibuf, sizeof(ibuf), L" ");\r
+ t = ibuf + wcslen(ibuf);\r
+ if(h == 1)\r
+ {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1H, t, ARRAYLENGTH(ibuf) - wcslen(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, h);\r
+ }\r
+ }\r
+ } else if(h > 0) {\r
+ m = (s - (h * 3600)) / 60;\r
+ if(h == 1) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1H, ibuf, ARRAYLENGTH(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, h);\r
+ }\r
+ if(m > 0) {\r
+ StringCbCat(ibuf, sizeof(ibuf), L" ");\r
+ t = ibuf + wcslen(ibuf);\r
+ if(m == 1)\r
+ {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1M, t, ARRAYLENGTH(ibuf) - wcslen(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, m);\r
+ }\r
+ }\r
+ } else if(m > 0) {\r
+ s -= m * 60;\r
+ if(m == 1) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1M, ibuf, ARRAYLENGTH(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, m);\r
+ }\r
+ if(s > 0) {\r
+ StringCbCat(ibuf, sizeof(ibuf), L" ");\r
+ t = ibuf + wcslen(ibuf);\r
+ if(s == 1)\r
+ {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1S, t, ARRAYLENGTH(ibuf) - wcslen(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, s);\r
+ }\r
+ }\r
+ } else {\r
+ if(s == 1) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_1S, ibuf, ARRAYLENGTH(ibuf));\r
+ } else {\r
+ LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, sizeof(fbuf)/sizeof(wchar_t));\r
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, s);\r
+ }\r
+ }\r
+\r
+ StringCbLength(ibuf, sizeof(ibuf), &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cb_buf, ibuf);\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_interval_toString(\r
+ const void * data, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ return FtIntervalToString((LPFILETIME) data, buffer, cb_buf);\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_interval_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ return (d && (cbd == sizeof(FILETIME) || cbd == KCDB_CBSIZE_AUTO));\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_interval_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ __int64 i1, i2;\r
+\r
+ i1 = *((__int64 *) d1);\r
+ i2 = *((__int64 *) d2);\r
+\r
+ if(i1 < i2)\r
+ return -1;\r
+ else if(i1 > i2)\r
+ return 1;\r
+ else\r
+ return 0;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_interval_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ if(d_dst && *cbd_dst >= sizeof(__int64)) {\r
+ *cbd_dst = sizeof(__int64);\r
+ *((__int64 *) d_dst) = *((__int64 *) d_src);\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *cbd_dst = sizeof(__int64);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+}\r
+\r
+/* Int32 */\r
+\r
+khm_int32 KHMAPI kcdb_type_int32_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ size_t cbsize;\r
+ wchar_t ibuf[12];\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ StringCbPrintf(ibuf, sizeof(ibuf), L"%d", *((khm_int32 *) d));\r
+ StringCbLength(ibuf, sizeof(ibuf), &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf);\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_int32_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(khm_int32)));\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_int32_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ return *((khm_int32 *) d1) - *((khm_int32 *) d2);\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_int32_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ if(d_dst && (*cbd_dst >= sizeof(khm_int32))) {\r
+ *cbd_dst = sizeof(khm_int32);\r
+ *((khm_int32 *) d_dst) = *((khm_int32 *) d_src);\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *cbd_dst = sizeof(khm_int32);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+}\r
+\r
+/* Int64 */\r
+\r
+khm_int32 KHMAPI kcdb_type_int64_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ size_t cbsize;\r
+ wchar_t ibuf[22];\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ StringCbPrintf(ibuf, sizeof(ibuf), L"%I64d", *((__int64 *) d));\r
+ StringCbLength(ibuf, sizeof(ibuf), &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf);\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_int64_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(__int64)));\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_int64_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ __int64 r = *((__int64 *) d1) - *((__int64 *) d2);\r
+ return (r==0i64)?0:((r>0i64)?1:-1);\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_int64_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ if(d_dst && (*cbd_dst >= sizeof(__int64))) {\r
+ *cbd_dst = sizeof(__int64);\r
+ *((__int64 *) d_dst) = *((__int64 *) d_src);\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *cbd_dst = sizeof(__int64);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+}\r
+\r
+/* Data */\r
+#define GENERIC_DATA_STR L"(Data)"\r
+\r
+khm_int32 KHMAPI kcdb_type_data_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags)\r
+{\r
+ size_t cbsize;\r
+\r
+ if(!cb_buf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cbsize = sizeof(GENERIC_DATA_STR);\r
+\r
+ if(!buffer || *cb_buf < cbsize) {\r
+ *cb_buf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cb_buf, GENERIC_DATA_STR);\r
+\r
+ *cb_buf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_boolean KHMAPI kcdb_type_data_isValid(\r
+ const void * d,\r
+ khm_size cbd)\r
+{\r
+ /* data is always valid, even if d is NULL */\r
+ return TRUE;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_data_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2)\r
+{\r
+ /* datas can not be compared */\r
+ return 0;\r
+}\r
+\r
+khm_int32 KHMAPI kcdb_type_data_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst)\r
+{\r
+ if(!cbd_dst)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ *cbd_dst = cbd_src;\r
+\r
+ if(!d_dst || *cbd_dst < cbd_src) {\r
+ return KHM_ERROR_TOO_LONG;\r
+ } else {\r
+ memcpy(d_dst, d_src, cbd_src);\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+}\r
+\r
+\r
+void kcdb_type_msg_completion(kmq_message * m) \r
+{\r
+ kcdb_type_release((kcdb_type_i *) m->vparam);\r
+}\r
+\r
+void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t)\r
+{\r
+ kcdb_type_hold(t);\r
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_TYPE, op, (void *) t);\r
+}\r
+\r
+void kcdb_type_init(void)\r
+{\r
+ kcdb_type type;\r
+\r
+ InitializeCriticalSection(&cs_type);\r
+ kcdb_type_namemap = hash_new_hashtable(\r
+ KCDB_TYPE_HASH_SIZE,\r
+ hash_string,\r
+ hash_string_comp,\r
+ kcdb_type_add_ref,\r
+ kcdb_type_del_ref);\r
+ kcdb_type_tbl = malloc(sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1));\r
+ ZeroMemory(kcdb_type_tbl, sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1));\r
+ kcdb_types = NULL;\r
+\r
+ /*TODO: register standard data types */\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_void_comp;\r
+ type.dup = kcdb_type_void_dup;\r
+ type.isValid = kcdb_type_void_isValid;\r
+ type.toString = kcdb_type_void_toString;\r
+ type.name = KCDB_TYPENAME_VOID;\r
+ type.id = KCDB_TYPE_VOID;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_string_comp;\r
+ type.dup = kcdb_type_string_dup;\r
+ type.isValid = kcdb_type_string_isValid;\r
+ type.toString = kcdb_type_string_toString;\r
+ type.name = KCDB_TYPENAME_STRING;\r
+ type.id = KCDB_TYPE_STRING;\r
+ type.flags = KCDB_TYPE_FLAG_CB_AUTO;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_date_comp;\r
+ type.dup = kcdb_type_date_dup;\r
+ type.isValid = kcdb_type_date_isValid;\r
+ type.toString = kcdb_type_date_toString;\r
+ type.name = KCDB_TYPENAME_DATE;\r
+ type.id = KCDB_TYPE_DATE;\r
+ type.cb_max = sizeof(FILETIME);\r
+ type.cb_min = sizeof(FILETIME);\r
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_interval_comp;\r
+ type.dup = kcdb_type_interval_dup;\r
+ type.isValid = kcdb_type_interval_isValid;\r
+ type.toString = kcdb_type_interval_toString;\r
+ type.name = KCDB_TYPENAME_INTERVAL;\r
+ type.id = KCDB_TYPE_INTERVAL;\r
+ type.cb_max = sizeof(__int64);\r
+ type.cb_min = sizeof(__int64);\r
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_int32_comp;\r
+ type.dup = kcdb_type_int32_dup;\r
+ type.isValid = kcdb_type_int32_isValid;\r
+ type.toString = kcdb_type_int32_toString;\r
+ type.name = KCDB_TYPENAME_INT32;\r
+ type.id = KCDB_TYPE_INT32;\r
+ type.cb_max = sizeof(khm_int32);\r
+ type.cb_min = sizeof(khm_int32);\r
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_int64_comp;\r
+ type.dup = kcdb_type_int64_dup;\r
+ type.isValid = kcdb_type_int64_isValid;\r
+ type.toString = kcdb_type_int64_toString;\r
+ type.name = KCDB_TYPENAME_INT64;\r
+ type.id = KCDB_TYPE_INT64;\r
+ type.cb_max = sizeof(__int64);\r
+ type.cb_min = sizeof(__int64);\r
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+\r
+ ZeroMemory(&type, sizeof(type));\r
+ type.comp = kcdb_type_data_comp;\r
+ type.dup = kcdb_type_data_dup;\r
+ type.isValid = kcdb_type_data_isValid;\r
+ type.toString = kcdb_type_data_toString;\r
+ type.name = KCDB_TYPENAME_DATA;\r
+ type.id = KCDB_TYPE_DATA;\r
+\r
+ kcdb_type_register(&type, NULL);\r
+}\r
+\r
+void kcdb_type_add_ref(const void *key, void *vt)\r
+{\r
+ kcdb_type_hold((kcdb_type_i *) vt);\r
+}\r
+\r
+void kcdb_type_del_ref(const void *key, void *vt)\r
+{\r
+ kcdb_type_release((kcdb_type_i *) vt);\r
+}\r
+\r
+khm_int32 kcdb_type_hold(kcdb_type_i * t)\r
+{\r
+ if(!t)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ t->refcount++;\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 kcdb_type_release(kcdb_type_i * t)\r
+{\r
+ if(!t)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ t->refcount--;\r
+ kcdb_type_check_and_delete(t->type.id);\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+void kcdb_type_exit(void)\r
+{\r
+ EnterCriticalSection(&cs_type);\r
+ free(kcdb_type_tbl);\r
+ /*TODO: free up the individual types */\r
+ LeaveCriticalSection(&cs_type);\r
+ DeleteCriticalSection(&cs_type);\r
+}\r
+\r
+void kcdb_type_check_and_delete(khm_int32 id)\r
+{\r
+ kcdb_type_i * t;\r
+\r
+ if(id < 0 || id > KCDB_TYPE_MAX_ID)\r
+ return;\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ t = kcdb_type_tbl[id];\r
+ if(t && !t->refcount) {\r
+ kcdb_type_tbl[id] = NULL;\r
+ LDELETE(&kcdb_types, t);\r
+ /* must already be out of the hash-table, otherwise refcount should not\r
+ be zero */\r
+ free(t->type.name);\r
+ free(t);\r
+ }\r
+ LeaveCriticalSection(&cs_type);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_get_id(wchar_t *name, khm_int32 * id)\r
+{\r
+ kcdb_type_i * t;\r
+ size_t cbsize;\r
+\r
+ if(FAILED(StringCbLength(name, KCDB_MAXCB_NAME, &cbsize))) {\r
+ /* also fails of name is NULL */\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ t = hash_lookup(kcdb_type_namemap, (void*) name);\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ if(!t) {\r
+ *id = KCDB_TYPE_INVALID;\r
+ return KHM_ERROR_NOT_FOUND;\r
+ } else {\r
+ *id = t->type.id;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_get_info(khm_int32 id, kcdb_type ** info)\r
+{\r
+ kcdb_type_i * t;\r
+\r
+ if(id < 0 || id > KCDB_TYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ t = kcdb_type_tbl[id];\r
+\r
+ if (t)\r
+ kcdb_type_hold(t);\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ if(info)\r
+ *info = (kcdb_type *) t;\r
+ else if (t)\r
+ kcdb_type_release(t);\r
+\r
+ return (t)? KHM_ERROR_SUCCESS : KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_release_info(kcdb_type * info)\r
+{\r
+ return kcdb_type_release((kcdb_type_i *) info);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_get_name(khm_int32 id, wchar_t * buffer, khm_size * cbbuf)\r
+{\r
+ size_t cbsize;\r
+ kcdb_type_i * t;\r
+\r
+ if(id < 0 || id > KCDB_TYPE_MAX_ID || !cbbuf)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ t = kcdb_type_tbl[id];\r
+\r
+ if(!t)\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ if(FAILED(StringCbLength(t->type.name, KCDB_MAXCB_NAME, &cbsize)))\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ if(!buffer || *cbbuf < cbsize) {\r
+ *cbbuf = cbsize;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buffer, *cbbuf, t->type.name);\r
+ *cbbuf = cbsize;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_register(kcdb_type * type, khm_int32 * new_id)\r
+{\r
+ kcdb_type_i *t;\r
+ size_t cbsize;\r
+ khm_int32 type_id;\r
+\r
+ if(!type || \r
+ !type->comp || \r
+ !type->dup || \r
+ !type->isValid || \r
+ !type->toString || \r
+ !type->name)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if((type->flags & KCDB_TYPE_FLAG_CB_MIN) &&\r
+ (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB))\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if((type->flags & KCDB_TYPE_FLAG_CB_MAX) &&\r
+ (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB))\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if((type->flags & KCDB_TYPE_FLAG_CB_MIN) &&\r
+ (type->flags & KCDB_TYPE_FLAG_CB_MAX) &&\r
+ (type->cb_max < type->cb_min))\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cbsize)))\r
+ return KHM_ERROR_TOO_LONG;\r
+\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ if(type->id == KCDB_TYPE_INVALID) {\r
+ kcdb_type_get_next_free(&type_id);\r
+ } else if(type->id < 0 || type->id > KCDB_TYPE_MAX_ID) {\r
+ LeaveCriticalSection(&cs_type);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ } else if(kcdb_type_tbl[type->id]) {\r
+ LeaveCriticalSection(&cs_type);\r
+ return KHM_ERROR_DUPLICATE;\r
+ } else {\r
+ type_id = type->id;\r
+ }\r
+\r
+ if(type_id == KCDB_TYPE_INVALID) {\r
+ LeaveCriticalSection(&cs_type);\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+\r
+ t = malloc(sizeof(kcdb_type_i));\r
+ ZeroMemory(t, sizeof(kcdb_type_i));\r
+\r
+ t->type.name = malloc(cbsize);\r
+ StringCbCopy(t->type.name, cbsize, type->name);\r
+\r
+ t->type.comp = type->comp;\r
+ t->type.dup = type->dup;\r
+ t->type.flags = type->flags;\r
+ t->type.id = type_id;\r
+ t->type.isValid = type->isValid;\r
+ t->type.toString = type->toString;\r
+\r
+ LINIT(t);\r
+\r
+ kcdb_type_tbl[type_id] = t;\r
+ LPUSH(&kcdb_types, t);\r
+\r
+ hash_add(kcdb_type_namemap, (void *) t->type.name, (void *) t);\r
+\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ if(new_id)\r
+ *new_id = type_id;\r
+\r
+ kcdb_type_post_message(KCDB_OP_INSERT, t);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_unregister(khm_int32 id)\r
+{\r
+ kcdb_type_i * t;\r
+\r
+ if(id < 0 || id > KCDB_TYPE_MAX_ID)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_type);\r
+ t = kcdb_type_tbl[id];\r
+ if(t) {\r
+ kcdb_type_post_message(KCDB_OP_DELETE, t);\r
+ /* we are going to remove t from the hash table. If no one is holding\r
+ a reference to it, then we can free it (actually, the del_ref code\r
+ will take care of that anyway). If there is a hold, then it will\r
+ get freed when they release it. \r
+ \r
+ Actually, the post_message call above pretty much guarantees that\r
+ the type has a hold on it.*/\r
+ t->type.flags |= KCDB_TYPE_FLAG_DELETED;\r
+ hash_del(kcdb_type_namemap, t->type.name);\r
+ }\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ if(t)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kcdb_type_get_next_free(khm_int32 * id)\r
+{\r
+ int i;\r
+\r
+ if(!id)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ /* do a linear search because this function only gets called a few times */\r
+ EnterCriticalSection(&cs_type);\r
+ for(i=0; i <= KCDB_TYPE_MAX_ID; i++) {\r
+ if(!kcdb_type_tbl[i])\r
+ break;\r
+ }\r
+ LeaveCriticalSection(&cs_type);\r
+\r
+ if(i <= KCDB_TYPE_MAX_ID) {\r
+ *id = i;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *id = KCDB_TYPE_INVALID;\r
+ return KHM_ERROR_NO_RESOURCES;\r
+ }\r
+}\r
+\r
+/* Conversion functions */\r
+\r
+KHMEXP void KHMAPI TimetToFileTime( time_t t, LPFILETIME pft )\r
+{\r
+ LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000i64;\r
+ pft->dwLowDateTime = (DWORD) ll;\r
+ pft->dwHighDateTime = (DWORD) (ll >> 32);\r
+}\r
+\r
+KHMEXP void KHMAPI TimetToFileTimeInterval(time_t t, LPFILETIME pft)\r
+{\r
+ LONGLONG ll = Int32x32To64(t, 10000000);\r
+ pft->dwLowDateTime = (DWORD) ll;\r
+ pft->dwHighDateTime = (DWORD) (ll >> 32);\r
+}\r
+\r
+KHMEXP long KHMAPI FtIntervalToSeconds(LPFILETIME pft)\r
+{\r
+ __int64 i = *((__int64 *) pft);\r
+ return (long) (i / 10000000i64);\r
+}\r
+\r
+KHMEXP long KHMAPI FtIntervalToMilliseconds(LPFILETIME pft)\r
+{\r
+ __int64 i = *((__int64 *) pft);\r
+ return (long) (i / 10000i64);\r
+}\r
+\r
+KHMEXP long KHMAPI FtCompare(LPFILETIME pft1, LPFILETIME pft2) {\r
+ __int64 i1 = *((__int64 *) pft1);\r
+ __int64 i2 = *((__int64 *) pft2);\r
+\r
+ if (i1 < i2)\r
+ return -1;\r
+ if (i1 == i2)\r
+ return 0;\r
+ return 1;\r
+}\r
+\r
+KHMEXP int KHMAPI AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr)\r
+{\r
+ size_t nc;\r
+\r
+ if(cbwstr == 0)\r
+ return 0;\r
+\r
+ nc = strlen(astr);\r
+ if(nc == MultiByteToWideChar(\r
+ CP_ACP, \r
+ 0, \r
+ astr, \r
+ (int) nc, \r
+ wstr, \r
+ (int)(cbwstr / sizeof(wchar_t) - 1))) {\r
+ wstr[nc] = L'\0';\r
+ } else {\r
+ wstr[0] = L'\0';\r
+ nc = 0;\r
+ }\r
+\r
+ return (int) nc;\r
+}\r
+\r
+KHMEXP int KHMAPI UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src)\r
+{\r
+ size_t nc;\r
+\r
+ if(cbdest == 0)\r
+ return 0;\r
+\r
+ dest[0] = 0;\r
+\r
+ if(FAILED(StringCchLength(src, cbdest, &nc)) || nc*sizeof(char) >= cbdest)\r
+ // note that cbdest counts the terminating NULL, while nc doesn't\r
+ return 0;\r
+\r
+ nc = WideCharToMultiByte(\r
+ CP_ACP, \r
+ WC_NO_BEST_FIT_CHARS, \r
+ src, \r
+ (int) nc, \r
+ dest, \r
+ (int) cbdest, \r
+ NULL, \r
+ NULL);\r
+\r
+ dest[nc] = 0;\r
+\r
+ return (int) nc;\r
+}\r
+\r
+#define MAX_IVL_SPECLIST_LEN 256\r
+#define MAX_IVL_UNITS 5\r
+\r
+enum _ivl_indices {\r
+ IVL_SECONDS = 0,\r
+ IVL_MINUTES,\r
+ IVL_HOURS,\r
+ IVL_DAYS,\r
+ IVL_WEEKS\r
+};\r
+\r
+typedef struct ivspec_t {\r
+ wchar_t str[MAX_IVL_SPECLIST_LEN];\r
+ __int64 mul;\r
+} ivspec;\r
+\r
+static ivspec ivspecs[MAX_IVL_UNITS];\r
+static BOOL ivspecs_loaded = FALSE;\r
+\r
+int _iv_is_in_spec(wchar_t *s, int n, wchar_t * spec)\r
+{\r
+ /* spec strigns are comma separated */\r
+ wchar_t *b, *e;\r
+\r
+ b = spec;\r
+ while(*b) {\r
+ e = wcschr(b, L',');\r
+ if(!e)\r
+ e = b + wcslen(b);\r
+ \r
+ if((e - b) == n && !wcsnicmp(b, s, n)) {\r
+ return TRUE;\r
+ }\r
+\r
+ if(*e)\r
+ b = e+1;\r
+ else\r
+ break;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI IntervalStringToFt(FILETIME * pft, wchar_t * str)\r
+{\r
+ size_t cb;\r
+ wchar_t * b;\r
+ __int64 *pr, t;\r
+\r
+ pr = (__int64 *) pft;\r
+ *pr = 0;\r
+\r
+ /* ideally we should synchronize this, but it doesn't hurt if two\r
+ threads do this at the same time, because we only set the ivspecs_loaded\r
+ flag when we are done */\r
+ if(!ivspecs_loaded) {\r
+ LoadString(hinst_kcreddb, IDS_IVL_S_SPEC, ivspecs[IVL_SECONDS].str, MAX_IVL_SPECLIST_LEN);\r
+ ivspecs[IVL_SECONDS].mul = 10000000i64;\r
+ LoadString(hinst_kcreddb, IDS_IVL_M_SPEC, ivspecs[IVL_MINUTES].str, MAX_IVL_SPECLIST_LEN);\r
+ ivspecs[IVL_MINUTES].mul = ivspecs[IVL_SECONDS].mul * 60;\r
+ LoadString(hinst_kcreddb, IDS_IVL_H_SPEC, ivspecs[2].str, MAX_IVL_SPECLIST_LEN);\r
+ ivspecs[IVL_HOURS].mul = ivspecs[IVL_MINUTES].mul * 60;\r
+ LoadString(hinst_kcreddb, IDS_IVL_D_SPEC, ivspecs[3].str, MAX_IVL_SPECLIST_LEN);\r
+ ivspecs[IVL_DAYS].mul = ivspecs[IVL_HOURS].mul * 24;\r
+ LoadString(hinst_kcreddb, IDS_IVL_W_SPEC, ivspecs[4].str, MAX_IVL_SPECLIST_LEN);\r
+ ivspecs[IVL_WEEKS].mul = ivspecs[IVL_DAYS].mul * 7;\r
+\r
+ ivspecs_loaded = TRUE;\r
+ }\r
+\r
+ if(!str || FAILED(StringCbLength(str, MAX_IVL_SPECLIST_LEN, &cb)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ b = str;\r
+ t = 0;\r
+ while(*b) {\r
+ __int64 f = 1;\r
+ wchar_t *e;\r
+ int i;\r
+\r
+ while(*b && iswspace(*b))\r
+ b++;\r
+\r
+ if(*b && iswdigit(*b)) {\r
+ f = _wtoi64(b);\r
+\r
+ while(*b && iswdigit(*b))\r
+ b++;\r
+ }\r
+\r
+ while(*b && iswspace(*b))\r
+ b++;\r
+\r
+ if(!*b) /* no unit specified */\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ e = b;\r
+\r
+ while(*e && !iswspace(*e))\r
+ e++;\r
+\r
+ for(i=0; i < MAX_IVL_UNITS; i++) {\r
+ if(_iv_is_in_spec(b, (int)(e-b), ivspecs[i].str))\r
+ break;\r
+ }\r
+\r
+ if(i==MAX_IVL_UNITS)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ t += f * ivspecs[i].mul;\r
+\r
+ b = e;\r
+ }\r
+\r
+ *pr = t;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KCDB_TYPE_H\r
+#define __KHIMAIRA_KCDB_TYPE_H\r
+\r
+/* Types */\r
+\r
+typedef struct kcdb_type_i_t {\r
+ kcdb_type type;\r
+\r
+ khm_int32 refcount;\r
+\r
+ struct kcdb_type_i_t * next;\r
+ struct kcdb_type_i_t * prev;\r
+} kcdb_type_i;\r
+\r
+#define KCDB_TYPE_HASH_SIZE 31\r
+\r
+#define KCDB_TYPE_FLAG_DELETED 8\r
+\r
+void kcdb_type_init(void);\r
+void kcdb_type_exit(void);\r
+void kcdb_type_add_ref(const void *key, void *vt);\r
+void kcdb_type_del_ref(const void *key, void *vt);\r
+void kcdb_type_msg_completion(kmq_message * m);\r
+khm_int32 kcdb_type_hold(kcdb_type_i * t);\r
+khm_int32 kcdb_type_release(kcdb_type_i * t);\r
+void kcdb_type_check_and_delete(khm_int32 id);\r
+void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t);\r
+\r
+khm_int32 KHMAPI kcdb_type_void_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_void_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_void_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_void_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+khm_int32 KHMAPI kcdb_type_string_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_string_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_string_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_string_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+khm_int32 KHMAPI kcdb_type_date_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_date_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_date_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_date_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+khm_int32 KHMAPI kcdb_type_interval_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_interval_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_interval_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_interval_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+khm_int32 KHMAPI kcdb_type_int32_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_int32_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_int32_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_int32_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+khm_int32 KHMAPI kcdb_type_int64_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_int64_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_int64_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_int64_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+khm_int32 KHMAPI kcdb_type_data_toString(\r
+ const void * d, \r
+ khm_size cbd, \r
+ wchar_t * buffer, \r
+ khm_size * cb_buf, \r
+ khm_int32 flags);\r
+\r
+khm_boolean KHMAPI kcdb_type_data_isValid(\r
+ const void * d,\r
+ khm_size cbd);\r
+\r
+khm_int32 KHMAPI kcdb_type_data_comp(\r
+ const void * d1,\r
+ khm_size cbd1,\r
+ const void * d2,\r
+ khm_size cbd2);\r
+\r
+khm_int32 KHMAPI kcdb_type_data_dup(\r
+ const void * d_src,\r
+ khm_size cbd_src,\r
+ void * d_dst,\r
+ khm_size * cbd_dst);\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=kherr\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\kherr.h\r
+\r
+OBJFILES= \\r
+ $(OBJ)\kherrmain.obj \\r
+ $(OBJ)\kherr.obj\r
+\r
+LIBFILES=\r
+\r
+SDKLIBFILES= \\r
+ strsafe.lib\r
+\r
+all: mkdirs $(INCFILES) $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kherrinternal.h>\r
+#include<assert.h>\r
+#ifdef Debug\r
+#include<stdarg.h>\r
+#endif\r
+\r
+CRITICAL_SECTION cs_error;\r
+DWORD tls_error = 0;\r
+kherr_context * ctx_free_list = NULL;\r
+kherr_context * ctx_root_list = NULL;\r
+kherr_context * ctx_error_list = NULL;\r
+kherr_event * evt_free_list = NULL;\r
+\r
+kherr_handler_node * ctx_handlers = NULL;\r
+khm_size n_ctx_handlers;\r
+khm_size nc_ctx_handlers;\r
+\r
+khm_ui_4 ctx_serial = 0;\r
+\r
+#ifdef DEBUG\r
+static void DebugPrintf(wchar_t * fmt, ...) {\r
+ va_list vl;\r
+ wchar_t buf[1024];\r
+\r
+ va_start(vl, fmt);\r
+ StringCbVPrintf(buf, sizeof(buf), fmt, vl);\r
+ OutputDebugString(buf);\r
+ va_end(vl);\r
+}\r
+#endif\r
+\r
+KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h,\r
+ khm_int32 filter) {\r
+\r
+ assert(h);\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ if( ctx_handlers == NULL) {\r
+ nc_ctx_handlers = CTX_ALLOC_INCR;\r
+ n_ctx_handlers = 0;\r
+ ctx_handlers = malloc(sizeof(*ctx_handlers) * nc_ctx_handlers);\r
+ /* No need to initialize */\r
+ } else if (n_ctx_handlers == nc_ctx_handlers) {\r
+ khm_size new_nc;\r
+ kherr_handler_node * new_ctxs;\r
+\r
+ new_nc = nc_ctx_handlers + CTX_ALLOC_INCR;\r
+ new_ctxs = malloc(sizeof(*new_ctxs) * new_nc);\r
+ memmove(new_ctxs, ctx_handlers, n_ctx_handlers);\r
+\r
+ free(ctx_handlers);\r
+ ctx_handlers = new_ctxs;\r
+ nc_ctx_handlers = new_nc;\r
+ }\r
+\r
+ if (filter == 0)\r
+ filter = KHERR_CTX_BEGIN |\r
+ KHERR_CTX_DESCRIBE |\r
+ KHERR_CTX_END |\r
+ KHERR_CTX_ERROR;\r
+\r
+ ctx_handlers[n_ctx_handlers].h = h;\r
+ ctx_handlers[n_ctx_handlers].filter = filter;\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h) {\r
+ khm_size i;\r
+ EnterCriticalSection(&cs_error);\r
+\r
+ for (i=0 ; i < n_ctx_handlers; i++) {\r
+ if (ctx_handlers[i].h == h) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if ( i < n_ctx_handlers ) {\r
+ n_ctx_handlers --;\r
+ for (; i < n_ctx_handlers; i++) {\r
+ ctx_handlers[i] = ctx_handlers[i + 1];\r
+ }\r
+ }\r
+ \r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+/* Called with cs_error held */\r
+void notify_ctx_event(enum kherr_ctx_event e, kherr_context * c) {\r
+ khm_size i;\r
+\r
+ for (i=0; i<n_ctx_handlers; i++) {\r
+ if (ctx_handlers[i].filter & e)\r
+ ctx_handlers[i].h(e,c);\r
+ }\r
+}\r
+\r
+void attach_this_thread(void) {\r
+ kherr_thread * t;\r
+\r
+ t = (kherr_thread *) TlsGetValue(tls_error);\r
+ if (t)\r
+ return;\r
+\r
+ t = malloc(sizeof(kherr_thread) + \r
+ sizeof(kherr_context *) * THREAD_STACK_SIZE);\r
+ t->nc_ctx = THREAD_STACK_SIZE;\r
+ t->n_ctx = 0;\r
+ t->ctx = (kherr_context **) &t[1];\r
+\r
+ TlsSetValue(tls_error, t);\r
+}\r
+\r
+void detach_this_thread(void) {\r
+ kherr_thread * t;\r
+ khm_size i;\r
+\r
+ t = (kherr_thread *) TlsGetValue(tls_error);\r
+ if (t) {\r
+ for(i=0; i < t->n_ctx; i++) {\r
+ kherr_release_context(t->ctx[i]);\r
+ }\r
+ free(t);\r
+ TlsSetValue(tls_error, 0);\r
+ }\r
+}\r
+\r
+kherr_context * peek_context(void) {\r
+ kherr_thread * t;\r
+\r
+ t = (kherr_thread *) TlsGetValue(tls_error);\r
+ if (t) {\r
+ if (t->n_ctx > 0)\r
+ return t->ctx[t->n_ctx - 1];\r
+ else\r
+ return NULL;\r
+ } else\r
+ return NULL;\r
+}\r
+\r
+void push_context(kherr_context * c) {\r
+ kherr_thread * t;\r
+\r
+ t = (kherr_thread *) TlsGetValue(tls_error);\r
+ if (!t) {\r
+ attach_this_thread();\r
+ t = (kherr_thread *) TlsGetValue(tls_error);\r
+ assert(t);\r
+ }\r
+\r
+ if (t->n_ctx == t->nc_ctx) {\r
+ khm_size nc_new;\r
+ khm_size cb_new;\r
+ kherr_thread * nt;\r
+\r
+ nc_new = t->nc_ctx + THREAD_STACK_SIZE;\r
+ cb_new = sizeof(kherr_thread) + \r
+ sizeof(kherr_context *) * nc_new;\r
+\r
+ nt = malloc(cb_new);\r
+ memcpy(nt, t, sizeof(kherr_thread) +\r
+ sizeof(kherr_context *) * t->n_ctx);\r
+ nt->ctx = (kherr_context **) &nt[1];\r
+ nt->nc_ctx = nc_new;\r
+\r
+ free(t);\r
+ t = nt;\r
+ TlsSetValue(tls_error, t);\r
+ }\r
+\r
+ assert(t->n_ctx < t->nc_ctx);\r
+ t->ctx[t->n_ctx++] = c;\r
+\r
+ kherr_hold_context(c);\r
+}\r
+\r
+/* returned pointer is still held */\r
+kherr_context * pop_context(void) {\r
+ kherr_thread * t;\r
+ kherr_context * c;\r
+\r
+ t = (kherr_thread *) TlsGetValue(tls_error);\r
+ if (t) {\r
+ if (t->n_ctx > 0) {\r
+ c = t->ctx[--(t->n_ctx)];\r
+ return c;\r
+ } else\r
+ return NULL;\r
+ } else {\r
+ return NULL;\r
+ }\r
+}\r
+\r
+kherr_event * get_empty_event(void) {\r
+ kherr_event * e;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ if(evt_free_list)\r
+ LPOP(&evt_free_list, &e);\r
+ else\r
+ e = malloc(sizeof(*e));\r
+ LeaveCriticalSection(&cs_error);\r
+ ZeroMemory(e, sizeof(*e));\r
+ e->severity = KHERR_NONE;\r
+ e->magic = KHERR_EVENT_MAGIC;\r
+\r
+ return e;\r
+}\r
+\r
+void free_event_params(kherr_event * e) {\r
+ if(parm_type(e->p1) == KEPT_STRINGT) {\r
+ assert((void *) parm_data(e->p1));\r
+ free((void*) parm_data(e->p1));\r
+ e->p1 = (kherr_param) 0;\r
+ }\r
+ if(parm_type(e->p2) == KEPT_STRINGT) {\r
+ assert((void *) parm_data(e->p2));\r
+ free((void*) parm_data(e->p2));\r
+ e->p2 = (kherr_param) 0;\r
+ }\r
+ if(parm_type(e->p3) == KEPT_STRINGT) {\r
+ assert((void *) parm_data(e->p3));\r
+ free((void*) parm_data(e->p3));\r
+ e->p3 = (kherr_param) 0;\r
+ }\r
+ if(parm_type(e->p4) == KEPT_STRINGT) {\r
+ assert((void *) parm_data(e->p4));\r
+ free((void*) parm_data(e->p4));\r
+ e->p4 = (kherr_param) 0;\r
+ }\r
+}\r
+\r
+void free_event(kherr_event * e) {\r
+ assert(e->magic == KHERR_EVENT_MAGIC);\r
+\r
+#ifdef DEBUG\r
+ DebugPrintf(L"Freeing event 0x%x\n", e);\r
+ if (!(e->flags & KHERR_RF_STR_RESOLVED))\r
+ resolve_event_strings(e);\r
+ if (e->short_desc)\r
+ DebugPrintf(L" Desc(S):[%s]\n", e->short_desc);\r
+ if (e->long_desc)\r
+ DebugPrintf(L" Desc(L):[%s]\n", e->long_desc);\r
+ if (e->suggestion)\r
+ DebugPrintf(L" Suggest:[%s]\n", e->suggestion);\r
+ if (e->facility)\r
+ DebugPrintf(L" Facility:[%s]\n", e->facility);\r
+#endif\r
+\r
+ if(e->flags & KHERR_RF_FREE_SHORT_DESC) {\r
+ assert(e->short_desc);\r
+ free((void *) e->short_desc);\r
+ }\r
+ if(e->flags & KHERR_RF_FREE_LONG_DESC) {\r
+ assert(e->long_desc);\r
+ free((void *) e->long_desc);\r
+ }\r
+ if(e->flags & KHERR_RF_FREE_SUGGEST) {\r
+ assert(e->suggestion);\r
+ free((void *) e->suggestion);\r
+ }\r
+\r
+ free_event_params(e);\r
+\r
+ ZeroMemory(e, sizeof(e));\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ LPUSH(&evt_free_list, e);\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+kherr_context * get_empty_context(void) {\r
+ kherr_context * c;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ if(ctx_free_list)\r
+ LPOP(&ctx_free_list, &c);\r
+ else {\r
+ c = malloc(sizeof(kherr_context));\r
+ }\r
+ \r
+ ZeroMemory(c,sizeof(*c));\r
+ c->severity = KHERR_NONE;\r
+ c->flags = KHERR_CF_UNBOUND;\r
+ c->magic = KHERR_CONTEXT_MAGIC;\r
+ c->serial = ++ctx_serial;\r
+\r
+ LPUSH(&ctx_root_list, c);\r
+\r
+ LeaveCriticalSection(&cs_error);\r
+ \r
+ return c;\r
+}\r
+\r
+\r
+/* Assumes that the context has been deleted from all relevant\r
+ lists */\r
+void free_context(kherr_context * c) {\r
+ kherr_context * ch;\r
+ kherr_event * e;\r
+\r
+ assert(c->magic == KHERR_CONTEXT_MAGIC);\r
+#ifdef DEBUG\r
+ DebugPrintf(L"Freeing context 0x%x\n", c);\r
+#endif\r
+\r
+ EnterCriticalSection(&cs_error);\r
+\r
+ if (c->desc_event)\r
+ free_event(c->desc_event);\r
+ c->desc_event = NULL;\r
+\r
+ TPOPCHILD(c, &ch);\r
+ while(ch) {\r
+ free_context(ch);\r
+ TPOPCHILD(c, &ch);\r
+ }\r
+ QGET(c, &e);\r
+ while(e) {\r
+ free_event(e);\r
+ QGET(c, &e);\r
+ }\r
+\r
+ c->serial = 0;\r
+\r
+ LPUSH(&ctx_free_list,c);\r
+ LeaveCriticalSection(&cs_error);\r
+\r
+#ifdef DEBUG\r
+ DebugPrintf(L"Done with context 0x%x\n", c);\r
+#endif\r
+}\r
+\r
+\r
+void add_event(kherr_context * c, kherr_event * e)\r
+{\r
+ EnterCriticalSection(&cs_error);\r
+ QPUT(c,e);\r
+ if(c->severity >= e->severity) {\r
+ if (e->severity <= KHERR_ERROR)\r
+ notify_ctx_event(KHERR_CTX_ERROR, c);\r
+\r
+ c->severity = e->severity;\r
+ c->err_event = e;\r
+ c->flags &= ~KHERR_CF_DIRTY;\r
+ }\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+void pick_err_event(kherr_context * c)\r
+{\r
+ kherr_event * e;\r
+ kherr_event * ce = NULL;\r
+ enum kherr_severity s;\r
+\r
+ s = KHERR_RESERVED_BANK;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = QTOP(c);\r
+ while(e) {\r
+ if(!(e->flags & KHERR_RF_INERT) && \r
+ s >= e->severity) {\r
+ ce = e;\r
+ s = e->severity;\r
+ }\r
+ e = QNEXT(e);\r
+ }\r
+\r
+ if(ce) {\r
+ c->err_event = ce;\r
+ c->severity = ce->severity;\r
+ } else {\r
+ c->err_event = NULL;\r
+ c->severity = KHERR_NONE;\r
+ }\r
+\r
+ c->flags &= ~KHERR_CF_DIRTY;\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+static void arg_from_param(DWORD_PTR ** parm, kherr_param p) {\r
+ int t;\r
+\r
+ if (p != 0) {\r
+ t = parm_type(p);\r
+ if (t == KEPT_INT32 ||\r
+ t == KEPT_UINT32 ||\r
+ t == KEPT_STRINGC ||\r
+ t == KEPT_STRINGT) {\r
+\r
+ *(*parm)++ = (DWORD_PTR) parm_data(p);\r
+\r
+ } else if (t == KEPT_INT64 ||\r
+ t == KEPT_UINT64) {\r
+ *(*parm)++ = (DWORD_PTR) parm_data(p) & 0xffffffff;\r
+ *(*parm)++ = (DWORD_PTR) (parm_data(p) >> 32) & 0xffffffff;\r
+ } else\r
+ *(*parm)++ = 0;\r
+ }\r
+}\r
+\r
+/* The 'buf' parameter MUST point to a DWORD_PTR[8] array */\r
+static void args_from_event(DWORD_PTR * buf, kherr_event * e) {\r
+ arg_from_param(&buf, e->p1);\r
+ arg_from_param(&buf, e->p2);\r
+ arg_from_param(&buf, e->p3);\r
+ arg_from_param(&buf, e->p4);\r
+}\r
+\r
+static void resolve_string_resource(kherr_event * e,\r
+ const wchar_t ** str,\r
+ khm_int32 if_flag,\r
+ khm_int32 or_flag) {\r
+ wchar_t tfmt[KHERR_MAXCCH_STRING];\r
+ wchar_t tbuf[KHERR_MAXCCH_STRING];\r
+ size_t chars;\r
+ size_t bytes;\r
+\r
+ if(e->flags & if_flag) {\r
+ if(e->h_module != NULL)\r
+ chars = LoadString(e->h_module, (UINT)(INT_PTR) *str, \r
+ tfmt, ARRAYLENGTH(tbuf));\r
+ if(e->h_module == NULL || chars == 0)\r
+ *str = NULL;\r
+ else {\r
+ wchar_t * s;\r
+ DWORD_PTR args[8];\r
+\r
+ args_from_event(args, e);\r
+\r
+ chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING |\r
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,\r
+ tfmt,\r
+ 0,\r
+ 0,\r
+ tbuf,\r
+ ARRAYLENGTH(tbuf),\r
+ (va_list *) args);\r
+\r
+ if (chars == 0) {\r
+ *str = NULL;\r
+ } else {\r
+ bytes = (chars + 1) * sizeof(wchar_t);\r
+ s = malloc(bytes);\r
+ assert(s);\r
+ StringCbCopy(s, bytes, tbuf);\r
+ *str = s;\r
+ e->flags |= or_flag;\r
+ }\r
+ }\r
+ e->flags &= ~if_flag;\r
+ }\r
+}\r
+\r
+static void resolve_msg_resource(kherr_event * e,\r
+ const wchar_t ** str,\r
+ khm_int32 if_flag,\r
+ khm_int32 or_flag) {\r
+ wchar_t tbuf[KHERR_MAXCCH_STRING];\r
+ size_t chars;\r
+ size_t bytes;\r
+ DWORD_PTR args[8];\r
+\r
+ if(e->flags & if_flag) {\r
+ if(e->h_module != NULL) {\r
+ args_from_event(args, e);\r
+\r
+ chars = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |\r
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,\r
+ (LPCVOID) e->h_module,\r
+ (DWORD)(DWORD_PTR) *str,\r
+ 0,\r
+ tbuf,\r
+ ARRAYLENGTH(tbuf),\r
+ (va_list *) args);\r
+ }\r
+\r
+ if(e->h_module == NULL || chars == 0) {\r
+ *str = NULL;\r
+ } else {\r
+ wchar_t * s;\r
+\r
+ /* MC inserts trailing \r\n to each message unless the\r
+ message is terminated with a %0. We remove the last\r
+ line break since it is irrelevant to our handling of\r
+ the string in the UI. */\r
+ if (tbuf[chars-1] == L'\n')\r
+ tbuf[--chars] = L'\0';\r
+ if (tbuf[chars-1] == L'\r')\r
+ tbuf[--chars] = L'\0';\r
+\r
+ bytes = (chars + 1) * sizeof(wchar_t);\r
+ s = malloc(bytes);\r
+ assert(s);\r
+ StringCbCopy(s, bytes, tbuf);\r
+ *str = s;\r
+ e->flags |= or_flag;\r
+ }\r
+ e->flags &= ~if_flag;\r
+ }\r
+}\r
+\r
+static void resolve_string(kherr_event * e,\r
+ const wchar_t ** str,\r
+ khm_int32 mask,\r
+ khm_int32 free_if,\r
+ khm_int32 or_flag) {\r
+\r
+ wchar_t tbuf[KHERR_MAXCCH_STRING];\r
+ size_t chars;\r
+ size_t bytes;\r
+ DWORD_PTR args[8];\r
+\r
+ if (((e->flags & mask) == 0 ||\r
+ (e->flags & mask) == free_if) &&\r
+ *str != NULL) {\r
+\r
+ args_from_event(args, e);\r
+ chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING |\r
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,\r
+ (LPCVOID) *str,\r
+ 0,\r
+ 0,\r
+ tbuf,\r
+ ARRAYLENGTH(tbuf),\r
+ (va_list *) args);\r
+\r
+ if ((e->flags & mask) == free_if) {\r
+ free((void *) *str);\r
+ }\r
+\r
+ e->flags &= ~mask;\r
+\r
+ if (chars == 0) {\r
+ *str = 0;\r
+ } else {\r
+ wchar_t * s;\r
+\r
+ bytes = (chars + 1) * sizeof(wchar_t);\r
+ s = malloc(bytes);\r
+ assert(s);\r
+ StringCbCopy(s, bytes, tbuf);\r
+ *str = s;\r
+ e->flags |= or_flag;\r
+ }\r
+ }\r
+\r
+}\r
+\r
+void resolve_event_strings(kherr_event * e)\r
+{\r
+ resolve_string(e, &e->short_desc,\r
+ KHERR_RFMASK_SHORT_DESC,\r
+ KHERR_RF_FREE_SHORT_DESC,\r
+ KHERR_RF_FREE_SHORT_DESC);\r
+\r
+ resolve_string(e, &e->long_desc,\r
+ KHERR_RFMASK_LONG_DESC,\r
+ KHERR_RF_FREE_LONG_DESC,\r
+ KHERR_RF_FREE_LONG_DESC);\r
+\r
+ resolve_string(e, &e->suggestion,\r
+ KHERR_RFMASK_SUGGEST,\r
+ KHERR_RF_FREE_SUGGEST,\r
+ KHERR_RF_FREE_SUGGEST);\r
+\r
+ resolve_string_resource(e, &e->short_desc,\r
+ KHERR_RF_RES_SHORT_DESC,\r
+ KHERR_RF_FREE_SHORT_DESC);\r
+\r
+ resolve_string_resource(e, &e->long_desc,\r
+ KHERR_RF_RES_LONG_DESC, \r
+ KHERR_RF_FREE_LONG_DESC);\r
+\r
+ resolve_string_resource(e, &e->suggestion,\r
+ KHERR_RF_RES_SUGGEST, \r
+ KHERR_RF_FREE_SUGGEST);\r
+\r
+ resolve_msg_resource(e, &e->short_desc,\r
+ KHERR_RF_MSG_SHORT_DESC, \r
+ KHERR_RF_FREE_SHORT_DESC);\r
+ resolve_msg_resource(e, &e->long_desc,\r
+ KHERR_RF_MSG_LONG_DESC, \r
+ KHERR_RF_FREE_LONG_DESC);\r
+ resolve_msg_resource(e, &e->suggestion,\r
+ KHERR_RF_MSG_SUGGEST, \r
+ KHERR_RF_FREE_SUGGEST);\r
+\r
+ /* get rid of dangling reference now that we have done everything\r
+ we can with it. Since we have already dealt with all the\r
+ parameter inserts, we don't need the parameters anymore\r
+ either. */\r
+ free_event_params(e);\r
+\r
+ e->h_module = NULL;\r
+ e->flags |= KHERR_RF_STR_RESOLVED;\r
+}\r
+\r
+\r
+KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e) {\r
+ EnterCriticalSection(&cs_error);\r
+ resolve_event_strings(e);\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_evaluate_last_event(void) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+ DWORD tid;\r
+\r
+ c = peek_context();\r
+ if(!c)\r
+ return;\r
+ tid = GetCurrentThreadId();\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = QBOTTOM(c);\r
+ while (e != NULL && e->thread_id != tid)\r
+ e = QPREV(e);\r
+\r
+ if(!e)\r
+ goto _exit;\r
+\r
+ resolve_event_strings(e);\r
+\r
+_exit:\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP kherr_event * KHMAPI \r
+kherr_report(enum kherr_severity severity,\r
+ const wchar_t * short_desc,\r
+ const wchar_t * facility,\r
+ const wchar_t * location,\r
+ const wchar_t * long_desc,\r
+ const wchar_t * suggestion,\r
+ khm_int32 facility_id,\r
+ enum kherr_suggestion suggestion_id,\r
+ kherr_param p1,\r
+ kherr_param p2,\r
+ kherr_param p3,\r
+ kherr_param p4,\r
+ khm_int32 flags\r
+#ifdef _WIN32\r
+ ,HMODULE h_module\r
+#endif\r
+ ) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+\r
+ /*TODO: sanity check flags (ISPOW2) */\r
+\r
+ e = get_empty_event();\r
+\r
+ e->thread_id = GetCurrentThreadId();\r
+ e->time_ticks = GetTickCount();\r
+ GetSystemTimeAsFileTime(&e->time_ft);\r
+\r
+ e->severity = severity;\r
+ e->short_desc = short_desc;\r
+ e->facility = facility;\r
+ e->location = location;\r
+ e->long_desc = long_desc;\r
+ e->suggestion = suggestion;\r
+ e->facility_id = facility_id;\r
+ e->suggestion_id = suggestion_id;\r
+ e->p1 = p1;\r
+ e->p2 = p2;\r
+ e->p3 = p3;\r
+ e->p4 = p4;\r
+ e->flags = flags;\r
+#ifdef _WIN32\r
+ e->h_module = h_module;\r
+#endif\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ c = peek_context();\r
+\r
+ if(!c) {\r
+ /* the reason why we are doing it this way is because p1..p4,\r
+ the descriptions and the suggestion may contain allocations\r
+ that has to be freed. In terms of performance we are\r
+ assuming that this case doesn't happen that much. Har\r
+ har */\r
+ free_event(e);\r
+ e = NULL;\r
+ } else {\r
+ add_event(c,e);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_error);\r
+\r
+ return e;\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, \r
+ enum kherr_suggestion suggestion_id,\r
+ khm_int32 flags) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+ DWORD tid;\r
+\r
+ if (flags != KHERR_RF_CSTR_SUGGEST &&\r
+ flags != KHERR_RF_RES_SUGGEST &&\r
+ flags != KHERR_RF_MSG_SUGGEST &&\r
+ flags != KHERR_RF_FREE_SUGGEST)\r
+ return;\r
+\r
+ c = peek_context();\r
+ if(!c)\r
+ return;\r
+\r
+ tid = GetCurrentThreadId();\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = QBOTTOM(c);\r
+ while (e != NULL && e->thread_id != tid)\r
+ e = QPREV(e);\r
+\r
+ if(!e)\r
+ goto _exit;\r
+\r
+ /* if strings have already been resolved in this event, we cant\r
+ add any more unresolved strings. */\r
+ if ((flags == KHERR_RF_RES_SUGGEST ||\r
+ flags == KHERR_RF_MSG_SUGGEST) &&\r
+ (e->flags & KHERR_RF_STR_RESOLVED))\r
+ goto _exit;\r
+\r
+ e->suggestion = suggestion;\r
+ e->suggestion_id = suggestion_id;\r
+ e->flags |= flags;\r
+_exit:\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_location(wchar_t * location) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+ DWORD tid;\r
+\r
+ c = peek_context();\r
+ if(!c)\r
+ return;\r
+ tid = GetCurrentThreadId();\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = QBOTTOM(c);\r
+ while (e != NULL && e->thread_id != tid)\r
+ e = QPREV(e);\r
+\r
+ if(!e)\r
+ goto _exit;\r
+ e->location = location;\r
+_exit:\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_facility(wchar_t * facility, \r
+ khm_int32 facility_id) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+ DWORD tid;\r
+\r
+ c = peek_context();\r
+ if(!c)\r
+ return;\r
+ tid = GetCurrentThreadId();\r
+ EnterCriticalSection(&cs_error);\r
+ e = QBOTTOM(c);\r
+ while (e != NULL && e->thread_id != tid)\r
+ e = QPREV(e);\r
+\r
+ if(!e)\r
+ goto _exit;\r
+ e->facility = facility;\r
+ e->facility_id = facility_id;\r
+_exit:\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_set_desc_event(void) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+ DWORD tid;\r
+\r
+ c = peek_context();\r
+ if(!c)\r
+ return;\r
+ tid = GetCurrentThreadId();\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = QBOTTOM(c);\r
+ while (e != NULL && e->thread_id != tid)\r
+ e = QPREV(e);\r
+\r
+ if(!e || c->desc_event)\r
+ goto _exit;\r
+\r
+ QDEL(c,e);\r
+ c->desc_event = e;\r
+ e->severity = KHERR_NONE;\r
+ resolve_event_strings(e);\r
+\r
+ notify_ctx_event(KHERR_CTX_DESCRIBE, c);\r
+\r
+_exit:\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_del_last_event(void) {\r
+ kherr_context * c;\r
+ kherr_event * e;\r
+ DWORD tid;\r
+\r
+ c = peek_context();\r
+\r
+ if(!c)\r
+ return;\r
+\r
+ tid = GetCurrentThreadId();\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = QBOTTOM(c);\r
+ while (e != NULL && e->thread_id != tid)\r
+ e = QPREV(e);\r
+\r
+ if(e) {\r
+ QDEL(c, e);\r
+ if(c->err_event == e) {\r
+ pick_err_event(c);\r
+ }\r
+ free_event(e);\r
+ }\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_push_context(kherr_context * c)\r
+{\r
+ kherr_context * p;\r
+ int new_context = FALSE;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ p = peek_context();\r
+ if(p && (c->flags & KHERR_CF_UNBOUND)) {\r
+ LDELETE(&ctx_root_list, c);\r
+ TADDCHILD(p,c);\r
+ c->flags &= ~KHERR_CF_UNBOUND;\r
+ kherr_hold_context(p);\r
+ new_context = TRUE;\r
+ }\r
+ push_context(c);\r
+\r
+ if (new_context)\r
+ notify_ctx_event(KHERR_CTX_BEGIN, c);\r
+\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags) \r
+{\r
+ kherr_context * p;\r
+ kherr_context * c;\r
+\r
+ flags &= KHERR_CFMASK_INITIAL;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ p = peek_context();\r
+ c = get_empty_context();\r
+ if(p) {\r
+ LDELETE(&ctx_root_list, c);\r
+ TADDCHILD(p,c);\r
+ c->flags &= ~KHERR_CF_UNBOUND;\r
+ kherr_hold_context(p);\r
+ }\r
+ c->flags |= flags;\r
+ push_context(c);\r
+\r
+ notify_ctx_event(KHERR_CTX_BEGIN, c);\r
+\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+kherr_param dup_parm(kherr_param p) {\r
+ if(parm_type(p) == KEPT_STRINGT) {\r
+ wchar_t * d = wcsdup((wchar_t *)parm_data(p));\r
+ return kherr_val(KEPT_STRINGT, d);\r
+ } else\r
+ return p;\r
+}\r
+\r
+kherr_event * fold_context(kherr_context * c) {\r
+ kherr_event * e;\r
+ kherr_event * g;\r
+\r
+ if (!c)\r
+ return NULL;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ if(!c->err_event || (c->flags & KHERR_CF_DIRTY)) {\r
+ pick_err_event(c);\r
+ }\r
+ if(c->err_event) {\r
+ g = c->err_event;\r
+ e = get_empty_event();\r
+ *e = *g;\r
+ g->short_desc = NULL;\r
+ g->long_desc = NULL;\r
+ g->suggestion = NULL;\r
+ g->flags &=\r
+ ~(KHERR_RF_FREE_SHORT_DESC |\r
+ KHERR_RF_FREE_LONG_DESC |\r
+ KHERR_RF_FREE_SUGGEST);\r
+ LINIT(e);\r
+ e->p1 = dup_parm(g->p1);\r
+ e->p2 = dup_parm(g->p2);\r
+ e->p3 = dup_parm(g->p3);\r
+ e->p4 = dup_parm(g->p4);\r
+ } else {\r
+ e = c->desc_event;\r
+ c->desc_event = NULL;\r
+ }\r
+\r
+ if (e)\r
+ e->flags |= KHERR_RF_CONTEXT_FOLD;\r
+\r
+ LeaveCriticalSection(&cs_error);\r
+\r
+ return e;\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_hold_context(kherr_context * c) {\r
+ assert(c && c->magic == KHERR_CONTEXT_MAGIC);\r
+ EnterCriticalSection(&cs_error);\r
+ c->refcount++;\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_release_context(kherr_context * c) {\r
+ assert(c && c->magic == KHERR_CONTEXT_MAGIC);\r
+ EnterCriticalSection(&cs_error);\r
+ c->refcount--;\r
+ if (c->refcount == 0) {\r
+ kherr_event * e;\r
+ kherr_context * p;\r
+\r
+ notify_ctx_event(KHERR_CTX_END, c);\r
+\r
+ p = TPARENT(c);\r
+ if (p) {\r
+ e = fold_context(c);\r
+ if (e)\r
+ add_event(p, e);\r
+\r
+ TDELCHILD(p, c);\r
+ kherr_release_context(p);\r
+ } else {\r
+ LDELETE(&ctx_root_list, c);\r
+ }\r
+ free_context(c);\r
+ }\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_pop_context(void) {\r
+ kherr_context * c;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ c = pop_context();\r
+ if(c) {\r
+ kherr_release_context(c);\r
+ }\r
+ LeaveCriticalSection(&cs_error);\r
+}\r
+\r
+KHMEXP kherr_context * KHMAPI kherr_peek_context(void) {\r
+ kherr_context * c;\r
+\r
+ c = peek_context();\r
+ if (c)\r
+ kherr_hold_context(c);\r
+\r
+ return c;\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI kherr_is_error(void) {\r
+ kherr_context * c = peek_context();\r
+ return kherr_is_error_i(c);\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c) {\r
+ if(c && c->severity <= KHERR_ERROR)\r
+ return TRUE;\r
+ else\r
+ return FALSE;\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_clear_error(void) {\r
+ kherr_context * c = peek_context();\r
+ if (c)\r
+ kherr_clear_error_i(c);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c) {\r
+ kherr_event * e;\r
+ if (c) {\r
+ EnterCriticalSection(&cs_error);\r
+ e = QTOP(c);\r
+ while(e) {\r
+ e->flags |= KHERR_RF_INERT;\r
+ e = QNEXT(e);\r
+ }\r
+ c->severity = KHERR_NONE;\r
+ c->err_event = NULL;\r
+ c->flags &= ~KHERR_CF_DIRTY;\r
+ LeaveCriticalSection(&cs_error);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom) {\r
+ kherr_context * c = peek_context();\r
+ if(c) {\r
+ EnterCriticalSection(&cs_error);\r
+ c->progress_denom = denom;\r
+ c->progress_num = num;\r
+ LeaveCriticalSection(&cs_error);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom) {\r
+ kherr_context * c = peek_context();\r
+ kherr_get_progress_i(c,num,denom);\r
+}\r
+\r
+KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, \r
+ khm_ui_4 * num, \r
+ khm_ui_4 * denom) {\r
+ if(c) {\r
+ EnterCriticalSection(&cs_error);\r
+ *num = c->progress_num;\r
+ *denom = c->progress_denom;\r
+ LeaveCriticalSection(&cs_error);\r
+ } else {\r
+ *num = 0;\r
+ *denom = 0;\r
+ }\r
+}\r
+\r
+KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c)\r
+{\r
+ kherr_event * e;\r
+ EnterCriticalSection(&cs_error);\r
+ e = QTOP(c);\r
+ LeaveCriticalSection(&cs_error);\r
+ return e;\r
+}\r
+\r
+KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e)\r
+{\r
+ kherr_event * ee;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ ee = QNEXT(e);\r
+ LeaveCriticalSection(&cs_error);\r
+ return ee;\r
+}\r
+\r
+KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c)\r
+{\r
+ kherr_context * cc;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ if (c) {\r
+ cc = TFIRSTCHILD(c);\r
+ if (cc)\r
+ kherr_hold_context(cc);\r
+ } else {\r
+ cc = ctx_root_list;\r
+ if (cc)\r
+ kherr_hold_context(cc);\r
+ }\r
+ LeaveCriticalSection(&cs_error);\r
+ return cc;\r
+}\r
+\r
+KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c)\r
+{\r
+ kherr_context * cc;\r
+ EnterCriticalSection(&cs_error);\r
+ cc = LNEXT(c);\r
+ if (cc)\r
+ kherr_hold_context(cc);\r
+ LeaveCriticalSection(&cs_error);\r
+ return cc;\r
+}\r
+\r
+KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c)\r
+{\r
+ kherr_event * e;\r
+ EnterCriticalSection(&cs_error);\r
+ if(!c->err_event) {\r
+ pick_err_event(c);\r
+ }\r
+ e = c->err_event;\r
+ LeaveCriticalSection(&cs_error);\r
+ return e;\r
+}\r
+\r
+KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c)\r
+{\r
+ kherr_event * e;\r
+\r
+ EnterCriticalSection(&cs_error);\r
+ e = c->desc_event;\r
+ LeaveCriticalSection(&cs_error);\r
+ return e;\r
+}\r
+\r
+KHMEXP kherr_param kherr_dup_string(const wchar_t * s)\r
+{\r
+ wchar_t * dest;\r
+ size_t cb_s;\r
+\r
+ if (s == NULL)\r
+ return (kherr_param) 0;\r
+\r
+ if (FAILED(StringCbLength(s, KHERR_MAXCB_STRING, &cb_s)))\r
+ cb_s = KHERR_MAXCB_STRING;\r
+ else\r
+ cb_s += sizeof(wchar_t);\r
+\r
+ dest = malloc(cb_s);\r
+ assert(dest != NULL);\r
+ dest[0] = L'\0';\r
+\r
+ StringCbCopy(dest, cb_s, s);\r
+\r
+ return _tstr(dest);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHERR_H\r
+#define __KHIMAIRA_KHERR_H\r
+\r
+/*! \defgroup kherr NetIDMgr Error Reporting\r
+\r
+ Error reporting functions provide a mechanism to construct\r
+ meaningful and user friendly error reports for the user.\r
+\r
+ Unlike most of the other NetIDMgr API's, the error reporting APIs\r
+ are lightweight and usually do not return an error value. This is\r
+ mostly because, these functions are called \b after an error\r
+ occurs.\r
+\r
+ @{*/\r
+#include<khdefs.h>\r
+#include<khlist.h>\r
+\r
+/*! \name Customizable macros\r
+@{ */\r
+#ifndef KHERR_FACILITY\r
+/*! \brief The default facility when reporting errors\r
+\r
+ When including this header file, if the KHERR_FACILITY macro is\r
+ defined to be a wide character string, then it will be used as the\r
+ default facility when for the convenience macros. All of the\r
+ calls to the convenience macros in the source file would then have\r
+ that facility.\r
+\r
+ If left undefined, the convenience macros will leave the facility\r
+ value undefined.\r
+ */ \r
+#define KHERR_FACILITY NULL\r
+#endif\r
+\r
+#ifndef KHERR_FACILITY_ID\r
+/*! \brief The default facility ID when reporting errors\r
+\r
+ When including this header file, if the KHERR_FACILITY_ID macro is\r
+ defined to be non-zero, then it will be used as the default\r
+ facility identifier for the convenience macros. All of the calls\r
+ to the convenience macros in the source file would then have that\r
+ facility identifier.\r
+\r
+ The default value of 0 means that the facility is undefined.\r
+ */\r
+#define KHERR_FACILITY_ID 0\r
+#endif\r
+\r
+/*! \define KHERR_HMODULE (undefined)\r
+ \brief The default module handle\r
+\r
+ When including this header file, if the KHERR_HMODULE macro is\r
+ defined to be an identifier that holds the module handle, then the\r
+ convenience macros that specify a module handle will use it.\r
+\r
+ A default value is not defined for KHERR_HMODULE. Any attempt to\r
+ invoke any of the convenience macros that use it should generate a\r
+ compile time error.\r
+ */\r
+#ifdef _WIN32\r
+#ifndef KHERR_HMODULE\r
+#endif\r
+#endif\r
+/*@}*/\r
+\r
+/*! \brief Parameter types\r
+ */\r
+enum kherr_parm_types {\r
+ KEPT_INT32 = 1,\r
+ KEPT_UINT32,\r
+ KEPT_INT64,\r
+ KEPT_UINT64,\r
+ KEPT_STRINGC, /*!< String constant */\r
+ KEPT_STRINGT /*!< String. Will be freed using\r
+ free() when the event is freed */\r
+};\r
+\r
+#ifdef _WIN32\r
+typedef khm_ui_8 kherr_param;\r
+#else\r
+#error kherr_param undefined\r
+#endif\r
+\r
+/*! \brief Severity levels\r
+\r
+ Larger the value, the less severe it is.\r
+*/\r
+enum tag_kherr_severity {\r
+ KHERR_FATAL = 0, /*!< Fatal error.*/\r
+ KHERR_ERROR, /*!< Non-fatal error. We'll probably\r
+ survive. See the suggested action. */\r
+ KHERR_WARNING, /*!< Warning. Something almost broke\r
+ or soon will. See the suggested\r
+ action. */\r
+ KHERR_INFO, /*!< Informational. Something happened\r
+ that we would like you to know\r
+ about. */\r
+ KHERR_DEBUG_3 = 64, /*!< Verbose debug level 3 (high) */\r
+ KHERR_DEBUG_2 = 65, /*!< Verbose debug level 2 (medium) */\r
+ KHERR_DEBUG_1 = 66, /*!< Verbose debug level 1 (low) */\r
+ KHERR_RESERVED_BANK = 127, /*!< Internal use */\r
+ KHERR_NONE = 128 /*!< Nothing interesting has happened\r
+ so far */\r
+};\r
+\r
+typedef enum tag_kherr_severity kherr_severity;\r
+\r
+/*! \brief Suggestions */\r
+enum tag_kherr_suggestion {\r
+ KHERR_SUGGEST_NONE = 0, /*!< No suggestions. */\r
+ KHERR_SUGGEST_ABORT, /*!< Abort whatever it was you were\r
+ trying. It's not gonna work. */\r
+ KHERR_SUGGEST_RETRY, /*!< Retry. It might work the second\r
+ or third time over */\r
+ KHERR_SUGGEST_IGNORE, /*!< Ignore. It might go away. */\r
+ KHERR_SUGGEST_INTERACT, /*!< Further user interaction is\r
+ necessary to resolve the situation.\r
+ The suggest string in the event\r
+ should be prompted to the user. */\r
+ KHERR_SUGGEST_OTHER, /*!< Something else. */\r
+};\r
+\r
+typedef enum tag_kherr_suggestion kherr_suggestion;\r
+\r
+/*! \brief An event */\r
+typedef struct tag_kherr_event {\r
+ khm_int32 magic; /*!< Magic number. Always set to\r
+ KHERR_EVENT_MAGIC */\r
+ DWORD thread_id; /*!< The thread which reported this\r
+ event. */\r
+ const wchar_t * short_desc; /*!< Short description or title\r
+ (localized) */\r
+ const wchar_t * facility; /*!< Facility name of the reporter\r
+ (not localized) */\r
+ const wchar_t * location; /*!< Location. Usually the function\r
+ name or such of where the event\r
+ occured (not localized) */\r
+ const wchar_t * long_desc; /*!< A long description of what went\r
+ wrong (localized, formatted) */\r
+ const wchar_t * suggestion; /*!< A suggested way to fix it\r
+ (localized,formatted) */\r
+\r
+ kherr_severity severity; \r
+ /*!< Severity level. One of the\r
+ severity levels listed in\r
+ enumeration ::kherr_severity */\r
+ khm_int32 facility_id; /*!< Left to the application to\r
+ interpret */\r
+ kherr_suggestion suggestion_id; \r
+ /*!< One of the suggestion ID's from\r
+ the enumeration\r
+ ::kherr_suggestion */\r
+\r
+ int flags; /*!< Flags. */\r
+\r
+ kherr_param p1; /*!< Parameter 1 for formatting */\r
+ kherr_param p2; /*!< Parameter 2 for formatting */\r
+ kherr_param p3; /*!< Parameter 3 for formatting */\r
+ kherr_param p4; /*!< Parameter 4 for formatting */\r
+\r
+ DWORD time_ticks; /*!< Time at which event was reported\r
+ (as returned by GetTickCount(). */\r
+ FILETIME time_ft; /*!< Time at which event was reported.\r
+ Current system time as FILETIME. */\r
+\r
+#ifdef _WIN32\r
+ HMODULE h_module; /*!< Handle to the module which should\r
+ resolve any unresolved resources\r
+ references above. */\r
+#endif\r
+\r
+ LDCL(struct tag_kherr_event);\r
+} kherr_event;\r
+\r
+#define KHERR_EVENT_MAGIC 0x0423e84f\r
+\r
+/*! \brief Flags for kherr_event\r
+\r
+ Each set of flags that define the type of resource for one value\r
+ is mutually exclusive.\r
+ */\r
+enum kherr_event_flags {\r
+ KHERR_RF_CSTR_SHORT_DESC= 0x00000000, \r
+ /*!< Short description is a constant\r
+ string */\r
+ KHERR_RF_RES_SHORT_DESC = 0x00000001, \r
+ /*!< Short description is a string\r
+ resource */\r
+ KHERR_RF_MSG_SHORT_DESC = 0x00000002, \r
+ /*!< Short description is a message\r
+ resource */\r
+ KHERR_RF_FREE_SHORT_DESC= 0x00000004, \r
+ /*!< Short description is an allocated\r
+ string */\r
+ KHERR_RFMASK_SHORT_DESC = 0x00000007,\r
+\r
+ KHERR_RF_CSTR_LONG_DESC = 0x00000000, \r
+ /*!< Long description is a constant\r
+ string */\r
+ KHERR_RF_RES_LONG_DESC = 0x00000008, \r
+ /*!< Long description is a string\r
+ resource */\r
+ KHERR_RF_MSG_LONG_DESC = 0x00000010, \r
+ /*!< Long description is a message\r
+ resouce */\r
+ KHERR_RF_FREE_LONG_DESC = 0x00000020, \r
+ /*!< Long description is an allocated\r
+ string */\r
+ KHERR_RFMASK_LONG_DESC = 0x00000038,\r
+\r
+ KHERR_RF_CSTR_SUGGEST = 0x00000000, \r
+ /*!< Suggestion is a constant\r
+ string */\r
+ KHERR_RF_RES_SUGGEST = 0x00000040, \r
+ /*!< Suggestion is a string\r
+ resource */\r
+ KHERR_RF_MSG_SUGGEST = 0x00000080, \r
+ /*!< Suggestion is a message\r
+ resource */\r
+ KHERR_RF_FREE_SUGGEST = 0x00000100, \r
+ /*!< Suggestion is an allocated\r
+ string */\r
+ KHERR_RFMASK_SUGGEST = 0x000001C0,\r
+\r
+ KHERR_RF_STR_RESOLVED = 0x00010000,\r
+ /*!< The string resources in the event\r
+ have been resolved. */\r
+ KHERR_RF_CONTEXT_FOLD = 0x00020000,\r
+ /*!< The event is a representation of\r
+ a folded context. */\r
+\r
+ KHERR_RF_INERT = 0x00040000\r
+ /*!< Inert event. The event has\r
+ already been dealt with and is no\r
+ longer considered significant. */\r
+};\r
+\r
+/*! \brief An error context\r
+*/\r
+typedef struct tag_kherr_context {\r
+ khm_int32 magic; /*!< Magic number. Always set to\r
+ KHERR_CONTEXT_MAGIC */\r
+\r
+ khm_ui_4 serial; /*!< Context instance serial number.\r
+ Context objects themselves may be\r
+ reused for different contexts as\r
+ they are freed and reallocated.\r
+ However every instance of a context\r
+ is guaranteed to have a unique\r
+ serial number as specified in this\r
+ field. If an external entity wants\r
+ to keep track of the context, it\r
+ should keep track of the serial\r
+ number as well as the pointer to the\r
+ context object. */\r
+\r
+ kherr_severity severity; \r
+ /*!< Severity level. One of the\r
+ severity levels listed below. This\r
+ is the severity level of the context\r
+ and is the maximum severity level of\r
+ all the events in the queue of\r
+ events. */\r
+\r
+ khm_int32 flags; /*!< Flags. Used internally. */\r
+ khm_ui_4 refcount; /*!< Reference count. Used\r
+ internally */\r
+\r
+ kherr_event *desc_event; /*!< Description event. The event that\r
+ describes the error context. This\r
+ points to an event that is not in\r
+ the event queue. */\r
+\r
+ kherr_event *err_event; /*!< Significant event. The last one\r
+ that caused the severity level to be\r
+ what it is right now. This points\r
+ to an event that is listed in the\r
+ event queue for this context.*/\r
+\r
+ khm_ui_4 progress_num; /*!< Progress numerator */\r
+ khm_ui_4 progress_denom; /*!< Progress denominator */\r
+\r
+ TDCL(struct tag_kherr_context);\r
+ QDCL(struct tag_kherr_event);\r
+} kherr_context;\r
+\r
+#define KHERR_CONTEXT_MAGIC 0x34f3238c\r
+\r
+enum kherr_context_flags {\r
+ KHERR_CF_NONE = 0x00000000,\r
+ /*!< None. */\r
+\r
+ KHERR_CF_DIRTY = 0x00000001,\r
+ /*!< Used Internally. Denotes that\r
+ the err_event and severity may need\r
+ to be recalculated. Cannot be set\r
+ as an initial flag. */\r
+\r
+ KHERR_CF_OWN_PROGRESS = 0x00000002,\r
+ /*!< The context maintains its own\r
+ progress meter as opposed to one\r
+ that is derived from child\r
+ contexts. */\r
+\r
+ KHERR_CF_UNBOUND = 0x00000004,\r
+ /*!< Unbound context. The context\r
+ can't be used to log events. Call\r
+ kherr_push_context() to associate\r
+ the context with the global context\r
+ hierarchy. Cannot be set as an\r
+ initial flag. */\r
+\r
+ KHERR_CF_TRANSITIVE = 0x00000008,\r
+ /*!< Transitive. The context is\r
+ automatically made the current\r
+ context for all other threads that\r
+ handle messages sent or posted by\r
+ threads whose current error context\r
+ is this one. */\r
+\r
+ KHERR_CFMASK_INITIAL = 0x0000000a,\r
+ /*!< Allowed initial flags */\r
+};\r
+\r
+/*! \brief Maximum length of a string field in characters including terminating NULL\r
+ */\r
+#define KHERR_MAXCCH_STRING 1024\r
+\r
+/*! \brief Maximum length of a string field in bytes including terminating NULL\r
+ */\r
+#define KHERR_MAXCB_STRING (KHERR_MAXCCH_STRING * sizeof(wchar_t))\r
+\r
+/*! \brief Context event\r
+\r
+ \see kherr_add_ctx_handler()\r
+*/\r
+enum kherr_ctx_event {\r
+ KHERR_CTX_BEGIN = 0x0001, /*!< A new context was created */\r
+ KHERR_CTX_DESCRIBE=0x0002, /*!< A context was described */\r
+ KHERR_CTX_END = 0x0004, /*!< A context was closed */\r
+ KHERR_CTX_ERROR = 0x0008 /*!< A context switched to an error\r
+ state */\r
+};\r
+\r
+/*! \brief Context event handler\r
+\r
+ Context event handlers are invoked when specific events occur with\r
+ respect to an error context. The ::kherr_ctx_event parameter\r
+ specifies which event occurred using one of the event values\r
+ described in the enumeration. The error context in which this\r
+ event occurred is specified by the ::kherr_context pointer.\r
+\r
+ Note that if the handler needs to keep track of the error context\r
+ for later processing, it also needs to keep track of the \a serial\r
+ field of the error context. The same context object may be\r
+ reused, but the serial number is guaranteed to be unique.\r
+\r
+ \see kherr_add_ctx_handler()\r
+ */\r
+typedef void (*kherr_ctx_handler)(enum kherr_ctx_event, kherr_context *);\r
+\r
+/*! \brief Add a context event handler\r
+\r
+ An application can register an event handler that gets notified of\r
+ events that pertain to error contexts. More than one handler can\r
+ be registered. The order in which the handlers are called is\r
+ undefined for any specific event.\r
+\r
+ These event occur in the context of individual application\r
+ threads. The handler will be called from within the thread that\r
+ caused the event. Therefore it is important that the handler is\r
+ both reentrant and returns quickly.\r
+\r
+ The events that the handler will be notified of are explained\r
+ below:\r
+\r
+ <b>KHERR_CTX_BEGIN</b>: Notification that a new context was\r
+ created. A pointer to the context will be supplied to the\r
+ handler. The supplied pointer should not be used to obtain a hold\r
+ on the context, as it will prevent the context from being closed.\r
+\r
+ <b>KHERR_CTX_DESCRIBE</b>: The thread called\r
+ kherr_set_desc_event() to set the description of a context. Once\r
+ again, the pointer should not be used to obtain a hold on the\r
+ context.\r
+\r
+ <b>KHERR_CTX_ERROR</b>: The last event that was reported for the\r
+ context was an error event (the severity was was equal or higher\r
+ than KHERR_ERROR). The pointer may be used to obtain a hold on\r
+ the context. However, it is the application's resonsibility to\r
+ make sure that the hold is released later. Otherwise the event\r
+ will never be closed.\r
+\r
+ <b>KHERR_CTX_END</b>: Closure. This event is signalled when the\r
+ last open handle to the context is closed and there is no thread\r
+ that is currently active which has this context in its error\r
+ context stack. At the time the handler is invoked, the context is\r
+ still intact. The pointer that is supplied should not be used to\r
+ obtain a handle on the context.\r
+\r
+ \param[in] h Context event handler, of type ::kherr_ctx_handler\r
+\r
+ \param[in] filter A combination of ::kherr_ctx_event values\r
+ indication which notifications should be sent to the handler.\r
+ If a \a filter value of zero is provided, all of the events\r
+ will be sent to the handler.\r
+ */\r
+KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, \r
+ khm_int32 filter);\r
+\r
+/*! \brief Remove a context event handler\r
+\r
+ Undoes what was done with kherr_add_ctx_handler()\r
+\r
+ \see kherr_add_ctx_handler()\r
+ */\r
+KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h);\r
+\r
+\r
+/*! \brief Report an error\r
+\r
+ Creates an event, fills in the details specified in the arguments,\r
+ and adds it to the current error context.\r
+\r
+ If the current thread does not have an error context, no reporting\r
+ happens. However, if any of the supplied strings or parameters\r
+ are marked as allocated, they will be freed before the function\r
+ returns.\r
+\r
+ Certain parameters that expect strings can instead be given string\r
+ resources, message resources or allocated strings in addition to\r
+ constant string. By default, the parameters are expected to be\r
+ constant strings.\r
+\r
+ <b>Allocated strings</b>: The application can allocate memory for\r
+ a string. Since the application is not notified when the event is\r
+ no longer used and freed, it \b must indicate that the string is\r
+ an allocated string by setting the appropriate flag in the \a\r
+ flags parameter. When the event is no longer used, the memory\r
+ pointed to by the relevant pointer will be freed through a call to\r
+ free(). Not all string parameters take allocated strings. See\r
+ individual parameter documentation for details.\r
+\r
+ <b>String resources</b>: On WIN32, string resources can be passed\r
+ in to kherr_report() using the MAKEINTRESOURCE macro. However,\r
+ the application \b must specify that the parameter is a string\r
+ resource using the appropriate flag in the \a flags parameter.\r
+ The error reporting engine will expand the string against the\r
+ module handle passed in the \a h_module parameter when the value\r
+ of the string is required. Not all string parameters take string\r
+ resources. See individual parameter documentation for details.\r
+ Strings loaded through string resources cannot be longer than\r
+ ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL.\r
+\r
+ <b>Message resources</b>: On WIN32, message resources can be\r
+ passed in to kherr_report() by specifying the message ID where it\r
+ ordinarily expects a pointer to a constant string. The\r
+ application \b must indicate that the string is a message resource\r
+ by using the appropriate flag in the \a flags parameter. When the\r
+ value of the string is needed, it is expanded against the module\r
+ handle passed in the \a h_module parameter using the message ID.\r
+ Not all string parameters take message resources. See individual\r
+ parameter documentation for details. Note that the facility and\r
+ severity values associated with a message resource are ignored.\r
+ Strings loaded through message resources cannot be longer than\r
+ ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL.\r
+\r
+ <b>Formatted fields</b>: Parameters that are formatted can have\r
+ can have parameter inserts like in printf(). However, specifying\r
+ inserts is different from printf() and follows the conventions\r
+ used in WIN32 API FormatMessage(). This is because for localized\r
+ strings, the order of the parameters in the string may be\r
+ different. See the documentation for FormatMessage() for details\r
+ on the format string. The same set of parameters (i.e. \a p1, \a\r
+ p2, \a p3, \a p4) is used for all formatted strings with\r
+ appropriate marshalling for 64 bit types. The size of the string\r
+ after expansion must not exceed 65536 bytes inclusive of\r
+ terminating NULL.\r
+\r
+ \param[in] severity One of ::kherr_severity_level\r
+ \param[in] short_desc Short description or title (localized). Can\r
+ be a string resource, message resource, allocated string or\r
+ constant string. The \a flags parameter should indicate the\r
+ type of string used.\r
+ \param[in] facility Facility name of the reporter (not localized)\r
+ \param[in] location Usually the function name or such of where the\r
+ event occured (not localized)\r
+ \param[in] long_desc Long description of event (localized,\r
+ formatted). Can be a string resource, message resource,\r
+ allocated string or constant string. The \a flags parameter\r
+ should indicate the type of string used.\r
+ \param[in] suggestion Suggested action to correct situation, if\r
+ applicable (localized). Can be a string resource, message\r
+ resource, allocated string or constant string. The \a flags\r
+ parameter should indicate the type of string used.\r
+ \param[in] facility_id Identifier of facility. Application\r
+ defined.\r
+ \param[in] suggestion_id One of the suggestion identifiers from\r
+ ::kherr_suggestion_ids\r
+ \param[in] p1 First parameter. Used for formatting.\r
+ \param[in] p2 Second parameter. Used for formatting.\r
+ \param[in] p3 Third parameter. Used for formatting.\r
+ \param[in] p4 Fourth parameter. Used for formatting.\r
+ \param[in] flags Flags. See ::kherr_report_flags\r
+ \param[in] h_module Handle to a module that resolves any string or\r
+ message resources used for the \a short_description , \a\r
+ long_desc or \a suggestion parameters. This parameter is only\r
+ available on WIN32.\r
+\r
+ \note With the exception of parameters of type KEPT_STRINGT and\r
+ parameters which are flagged for freeing using the \a flags\r
+ parameter, all other string parameters are assumed to be\r
+ pointers to constant strings. The strings are not copied and\r
+ the pointers are used as is. Also, no clean-up is performed\r
+ when the event is freed other than that implied by \a flags.\r
+ */\r
+KHMEXP kherr_event * KHMAPI kherr_report(\r
+ enum kherr_severity severity,\r
+ const wchar_t * short_desc,\r
+ const wchar_t * facility,\r
+ const wchar_t * location,\r
+ const wchar_t * long_desC,\r
+ const wchar_t * suggestion,\r
+ khm_int32 facility_id,\r
+ enum kherr_suggestion suggestion_id,\r
+ kherr_param p1,\r
+ kherr_param p2,\r
+ kherr_param p3,\r
+ kherr_param p4,\r
+ khm_int32 flags\r
+#ifdef _WIN32\r
+ ,HMODULE h_module\r
+#endif\r
+);\r
+\r
+/*! \brief Create a parameter out of a transient string\r
+\r
+ A parameter is created by duplicating the string that is passed\r
+ into the function. If the string exceeds KHERR_MAXCCH_STRING,\r
+ then only the first part of the string that fits within the limit\r
+ is duplicated.\r
+\r
+ The resulign ::kherr_param must be passed in to kherr_report().\r
+ The event logging framework will free the duplicated string once\r
+ the data is no longer required.\r
+ */\r
+KHMEXP kherr_param kherr_dup_string(const wchar_t * s);\r
+\r
+/* convenience macros for specifying parameters for kherr_report */\r
+#define kherr_val(type,val) \\r
+ ((((kherr_param)(type)) << ((sizeof(kherr_param)-1)*8)) | (kherr_param) (val))\r
+\r
+#define _int32(i) kherr_val(KEPT_INT32, i)\r
+#define _uint32(ui) kherr_val(KEPT_UINT32, ui)\r
+#define _int64(i) kherr_val(KEPT_INT64, i)\r
+#define _uint64(ui) kherr_val(KEPT_UINT64, ui)\r
+#define _cstr(cs) kherr_val(KEPT_STRINGC, cs)\r
+#define _tstr(ts) kherr_val(KEPT_STRINGT, ts)\r
+#define _dupstr(s) kherr_dup_string(s)\r
+\r
+/* convenience macros for calling kherr_report */\r
+#ifdef KHERR_HMODULE\r
+\r
+#define _report_cs0(severity, long_description) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, 0, KHERR_HMODULE)\r
+\r
+#define _report_cs1(severity, long_description, p1) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, 0, KHERR_HMODULE)\r
+\r
+#define _report_cs2(severity, long_description, p1, p2) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, 0, KHERR_HMODULE)\r
+\r
+#define _report_cs3(severity, long_description, p1, p2, p3) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, 0, KHERR_HMODULE)\r
+\r
+#define _report_cs4(severity, long_description, p1, p2, p3, p4) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, KHERR_HMODULE)\r
+\r
+#else\r
+\r
+#define _report_cs0(severity, long_description) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, 0, NULL)\r
+\r
+#define _report_cs1(severity, long_description, p1) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, 0, NULL)\r
+\r
+#define _report_cs2(severity, long_description, p1, p2) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, 0, NULL)\r
+\r
+#define _report_cs3(severity, long_description, p1, p2, p3) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, 0, NULL)\r
+\r
+#define _report_cs4(severity, long_description, p1, p2, p3, p4) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, NULL)\r
+#endif /* !defined(KHERR_HMODULE) */\r
+\r
+#ifdef _WIN32\r
+#define _report_sr0(severity, long_desc_id) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_sr1(severity, long_desc_id, p1) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_sr2(severity, long_desc_id, p1, p2) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_sr3(severity, long_desc_id, p1, p2, p3) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_sr4(severity, long_desc_id, p1, p2, p3, p4) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE)\r
+#endif\r
+\r
+#ifdef _WIN32\r
+#define _report_mr0(severity, long_desc_msg_id) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_mr1(severity, long_desc_msg_id, p1) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_mr2(severity, long_desc_msg_id, p1, p2) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_mr3(severity, long_desc_msg_id, p1, p2, p3) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE)\r
+\r
+#define _report_mr4(severity, long_desc_msg_id, p1, p2, p3, p4) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE)\r
+#endif\r
+\r
+#define _report_ts0(severity, long_desc_ptr) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, KHERR_RF_FREE_LONG_DESC, NULL)\r
+\r
+#define _report_ts1(severity, long_desc_ptr, p1) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, KHERR_RF_FREE_LONG_DESC, NULL)\r
+\r
+#define _report_ts2(severity, long_desc_ptr, p1, p2) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, KHERR_RF_FREE_LONG_DESC, NULL)\r
+\r
+#define _report_ts3(severity, long_desc_ptr, p1, p2, p3) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, KHERR_RF_FREE_LONG_DESC, NULL)\r
+\r
+#define _report_ts4(severity, long_desc_ptr, p1, p2, p3, p4) \\r
+ kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_FREE_LONG_DESC, NULL)\r
+\r
+/*! \brief Set the suggestion and suggestion identifier for the last event\r
+\r
+ The event that will be modified is the last event reported by the\r
+ calling thread.\r
+ */\r
+KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, khm_int32 suggestion_id, khm_int32 flags);\r
+#define _suggest_cs(cs,sid) kherr_suggest((cs), (sid), KHERR_RF_CSTR_SUGGEST)\r
+#define _suggest_ts(ts,sid) kherr_suggest((ts), (sid), KHERR_RF_FREE_SUGGEST)\r
+#define _suggest_sr(sr,sid) kherr_suggest(MAKEINTRESOURCE(sr), (sid), KHERR_RF_RES_SUGGEST)\r
+#define _suggest_mr(mr,sid) kherr_suggest((wchar_t *)(DWORD_PTR)(mr), (sid), KHERR_RF_MSG_SUGGEST)\r
+\r
+/*! \brief Set the location string for the last event\r
+\r
+ The event that will be modified is the last event reported by the\r
+ calling thread.\r
+ */\r
+KHMEXP void KHMAPI kherr_location(wchar_t * location);\r
+#define _location(l) kherr_location(l)\r
+\r
+/*! \brief Set the facility string and identifier for the last event\r
+\r
+ The event that will be modified is the last event reported by the\r
+ calling thread.\r
+ */\r
+KHMEXP void KHMAPI kherr_facility(wchar_t * facility, khm_int32 facility_id);\r
+#define _facility(f,fid) kherr_facility((f),(fid))\r
+\r
+/*! \brief Marks the last event as the descriptor event for the current error context\r
+\r
+ Note that marking an event as the descriptor event has the effect\r
+ of removing the event from event queue. The event will henceforth\r
+ be used as the descriptor for the context. The only effective\r
+ fields of a descriptor event are \a short_desc, \a long_desc, \a\r
+ facility, \a facility_id and the parameters which are used for\r
+ resolving formatted strings in the aforementioned fields.\r
+\r
+ Upon calling kherr_set_desc_event(), the event will be\r
+ automatically evaluated as if kherr_evaluate_event() was called.\r
+\r
+ The event that will be referenced is the last event reported by\r
+ the calling thread.\r
+ */\r
+KHMEXP void KHMAPI kherr_set_desc_event(void);\r
+#define _describe kherr_set_desc_event\r
+\r
+/*! \brief Delete the last event\r
+\r
+ The event that will be deleted is the last event reported by the\r
+ calling thread.\r
+ */\r
+KHMEXP void KHMAPI kherr_del_last_event(void);\r
+#define _del_event kherr_del_last_event\r
+\r
+/*! \brief Create a new context\r
+\r
+ The created context is not bound to any thread or any context\r
+ hierarchy. Hence it cannot be used to capture any events until it\r
+ is used in a call to kherr_push_context().\r
+\r
+ Release the returned context pointer with a call to\r
+ kherr_release_context().\r
+\r
+ \param[in] flags Initial flags for the context. Combination of\r
+ ::kherr_context_flags\r
+\r
+ \note This function is for internal use only.\r
+ */\r
+KHMEXP kherr_context * KHMAPI kherr_create_new_context(khm_int32 flags);\r
+\r
+/*! \brief Obtain a hold on a context */\r
+KHMEXP void KHMAPI kherr_hold_context(kherr_context * c);\r
+\r
+/*! \brief Release a context */\r
+KHMEXP void KHMAPI kherr_release_context(kherr_context * c);\r
+\r
+/*! \brief Push an empty context\r
+\r
+ Creates an empty context, adds it as a child of the current\r
+ thread's error context. If the current thread does not have an\r
+ error context, then the created error context will be a root level\r
+ context.\r
+\r
+ The new context will be the current error context for the calling\r
+ thread.\r
+\r
+ \param[in] flags Initial flags for the context. Combination of\r
+ ::kherr_context_flags\r
+\r
+ \see kherr_push_new_context() for more information about thread\r
+ specific context stacks.\r
+\r
+ */\r
+KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags);\r
+#define _begin_task kherr_push_new_context\r
+\r
+/*! \brief Push a context\r
+\r
+ Each thread has a stack of error contexts. The topmost one is\r
+ current. The thread can push or pop contexts on to the stack\r
+ independently of the hierarchy of contexts (the only exception, as\r
+ explained below is when the context that is being pushed is\r
+ unbound).\r
+\r
+ If the context being pushed by kherr_push_context() is unbound,\r
+ then it will be attached to the current context of the thread as a\r
+ child. Once the new context is pushed to the top of the stack, it\r
+ will become the current context for the thread.\r
+\r
+ The calling thread must call kherr_pop_context() to remove the\r
+ context from the top of the stack. Each call to\r
+ kherr_push_new_context() or kher_push_context() must have a\r
+ corresponding kherr_pop_context() call.\r
+\r
+ When the thread terminates, all of the contexts in the thread's\r
+ context stack will be automatically removed.\r
+\r
+ \see kherr_pop_context()\r
+ */\r
+KHMEXP void KHMAPI kherr_push_context(kherr_context * c);\r
+\r
+/*! \brief Pop a context\r
+\r
+ Remove the current error context from the thread's context stack.\r
+ If no other open handles exist to the error context, this causes\r
+ the error context to collapse into it's parent context or vanish\r
+ entirely unless the context contains an error.\r
+\r
+ \see kherr_push_context() for more information about thread\r
+ specific context stacks.\r
+ */\r
+KHMEXP void KHMAPI kherr_pop_context(void);\r
+#define _end_task kherr_pop_context\r
+\r
+/*! \brief Retrieve the current error context\r
+\r
+ The returned pointer must be released with a call to\r
+ kherr_release_context().\r
+*/\r
+KHMEXP kherr_context * KHMAPI kherr_peek_context(void);\r
+\r
+/*! \brief Check if the current error context indicates an error\r
+\r
+ \return TRUE if there is an error. FALSE otherwise.\r
+ \see kherr_analyze()\r
+ */\r
+KHMEXP khm_boolean KHMAPI kherr_is_error(void);\r
+\r
+/*! \brief Check if an error context indicates an error\r
+\r
+ \return TRUE if there is an error. FALSE otherwise.\r
+ \see kherr_analyze()\r
+ */\r
+KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c);\r
+\r
+/*! \brief Clear the error state of the current context */\r
+KHMEXP void KHMAPI kherr_clear_error(void);\r
+\r
+/*! \brief Clear the error state of an error context */\r
+KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c);\r
+\r
+/*! \brief Set the progress meter of the current error context\r
+\r
+ Setting \a denom to zero removes the progress meter.\r
+ */\r
+KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom);\r
+#define _progress(num,denom) kherr_set_progress((num),(denom))\r
+\r
+/*! \brief Get the progress meter of the current error context\r
+ */\r
+KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom);\r
+\r
+/*! \brief Get the progress meter of an error context\r
+ */\r
+KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, khm_ui_4 * num, khm_ui_4 * denom);\r
+\r
+/*! \brief Get the first event in a context\r
+\r
+ The returned pointer is only valid as long as there is a hold on\r
+ \a c. Once the context is released with a call to\r
+ kherr_release_context() all pointers to events in the context\r
+ becomes invalid.\r
+\r
+ Use kherr_get_next_event() to obtain the other events.\r
+ */\r
+KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c);\r
+\r
+/*! \brief Get the next event\r
+\r
+ Call kherr_get_first_event() to obtain the first event in a\r
+ context. Subsequent calls to kherr_get_next_event() will yield\r
+ other events in the order in which they were reported. The list\r
+ ends when kherr_get_next_event() returns NULL.\r
+\r
+ The returned pointer is only valid as long as there is a hold on\r
+ \a c. Once the context is released with a call to\r
+ kherr_release_context() all pointers to events in the context\r
+ becomes invalid.\r
+ */\r
+KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e);\r
+\r
+/*! \brief Get the first child context of a context\r
+\r
+ Contexts are arranged in a hiearchy. This function returns the\r
+ first child of an error context. Use kherr_get_next_context() to\r
+ obtain the other contexts. If \a c is \a NULL, this returns the\r
+ first root level context.\r
+\r
+ The returned pointer must be released with a call to\r
+ kherr_release_context()\r
+ */\r
+KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c);\r
+\r
+/*! \brief Get the next sibling context of a context\r
+\r
+ The returned pointer must be released with a call to\r
+ kherr_release_context()\r
+\r
+ \see kherr_get_first_context()\r
+ */\r
+KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c);\r
+\r
+/*! \brief Get the desciption event for the context\r
+\r
+ The description event is the event that was denoted using\r
+ kherr_set_desc_event() as the event which describes the context.\r
+\r
+ The returned pointer is only valid as long as there is a hold on\r
+ \a c. Once the context is released with a call to\r
+ kherr_release_context() all pointers to events in the context\r
+ becomes invalid.\r
+ */\r
+KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c);\r
+\r
+/*! \brief Get the error event for the context\r
+\r
+ The error event for a context is the last event that had the\r
+ highest severity level.\r
+\r
+ The returned pointer is only valid as long as there is a hold on\r
+ \a c. Once the context is released with a call to\r
+ kherr_release_context() all pointers to events in the context\r
+ becomes invalid.\r
+ */\r
+KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c);\r
+\r
+/*! \brief Evaluate an event\r
+\r
+ When an event is reported, all the parameters and resource\r
+ references that were passed to kherr_report() are kept as-is until\r
+ the actual string values are required by the error reporting\r
+ library. However, if the string fields are required before then,\r
+ an application can call kherr_evaluate_event() to get them.\r
+\r
+ This function does the following:\r
+\r
+ - Load any referenced string or message resources that are\r
+ referenced in the event's short description, long description or\r
+ suggestion.\r
+\r
+ - Expand any inserts using the parameters that were passed in.\r
+\r
+ - Free up allocated strings in for the descriptions or suggestion\r
+ fields and any parameters.\r
+\r
+ - Update the string fields in the event to contain the newly\r
+ generated strings.\r
+\r
+ */\r
+KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e);\r
+\r
+/*! \brief Evaluate the last event\r
+\r
+ Same as kherr_evaluate_event(), but operates on the last event\r
+ logged by the current thread.\r
+\r
+ \see kherr_evaluate_event()\r
+ */\r
+KHMEXP void KHMAPI kherr_evaluate_last_event(void);\r
+#define _resolve kherr_evaluate_last_event\r
+\r
+/*! \defgroup kherr_fids Standard Facility IDs\r
+@{*/\r
+#define KHM_FACILITY_KMM 1\r
+#define KHM_FACILITY_KCDB 2\r
+#define KHM_FACILITY_UI 3\r
+#define KHM_FACILITY_KRB5 64\r
+#define KHM_FACILITY_KRB4 65\r
+#define KHM_FACILITY_AFS 66\r
+#define KHM_FACILITY_USER 128\r
+/*@}*/\r
+\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHERRORINTERNAL_H\r
+#define __KHIMAIRA_KHERRORINTERNAL_H\r
+\r
+#include<windows.h>\r
+#include<kherr.h>\r
+#include<strsafe.h>\r
+\r
+typedef struct tag_kherr_thread {\r
+ khm_size nc_ctx;\r
+ khm_size n_ctx;\r
+ kherr_context ** ctx;\r
+} kherr_thread;\r
+\r
+#define THREAD_STACK_SIZE 8\r
+\r
+typedef struct tag_kherr_handler_node {\r
+ khm_int32 filter;\r
+ kherr_ctx_handler h;\r
+} kherr_handler_node;\r
+\r
+#define CTX_ALLOC_INCR 4\r
+\r
+#define EVENT_MASK_UNRESOLVED \\r
+ (KHERR_RF_RES_SHORT_DESC|KHERR_RF_MSG_SHORT_DESC| \\r
+ KHERR_RF_RES_LONG_DESC|KHERR_RF_MSG_LONG_DESC| \\r
+ KHERR_RF_RES_SUGGEST|KHERR_RF_MSG_SUGGEST)\r
+\r
+extern CRITICAL_SECTION cs_error;\r
+extern DWORD tls_error;\r
+extern kherr_context * ctx_free_list;\r
+extern kherr_event * evt_free_list;\r
+extern kherr_handler_node * ctx_handlers;\r
+extern khm_size n_ctx_handlers;\r
+\r
+#define parm_type(p) ((int) (((p)>>((sizeof(kherr_param) - 1) * 8)) & 0xff))\r
+#define parm_data(p) ((p) & ~(((kherr_param)0xff)<<((sizeof(kherr_param) - 1) * 8)))\r
+\r
+void resolve_event_strings(kherr_event *);\r
+void attach_this_thread(void);\r
+void detach_this_thread(void);\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kherrinternal.h>\r
+\r
+void\r
+kherr_process_attach(void) {\r
+ InitializeCriticalSection(&cs_error);\r
+ tls_error = TlsAlloc();\r
+}\r
+\r
+void\r
+kherr_process_detach(void) {\r
+ TlsFree(tls_error);\r
+ DeleteCriticalSection(&cs_error);\r
+}\r
+\r
+void\r
+kherr_thread_attach(void) {\r
+ /* We don't call attach_this_thread() here since we only\r
+ want to create a context stack for this thread if\r
+ someone wants one. */\r
+ /* attach_this_thread(); */\r
+}\r
+\r
+void\r
+kherr_thread_detach(void) {\r
+ detach_this_thread();\r
+}\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=kmm\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\kmm.h \\r
+ $(INCDIR)\kplugin.h\r
+\r
+OBJFILES= \\r
+ $(OBJ)\kmmmain.obj \\r
+ $(OBJ)\kmm.obj \\r
+ $(OBJ)\kmm_plugin.obj \\r
+ $(OBJ)\kmm_module.obj \\r
+ $(OBJ)\kmm_reg.obj \\r
+ $(OBJ)\kmm_registrar.obj \\r
+ $(OBJ)\kmmconfig.obj\r
+\r
+MSGRESFILE=$(OBJ)\kmm_msgs.res\r
+\r
+$(OBJ)\kmmconfig.c: kmmconfig.csv $(CONFDIR)\csvschema.cfg\r
+ $(CCSV) $** $@\r
+\r
+$(MSGRESFILE): $(OBJ)\kmm_msgs.rc\r
+\r
+$(OBJ)\kmm_msgs.rc: lang\kmm_msgs.mc\r
+ $(MC2RC)\r
+\r
+all: mkdirs $(INCFILES) $(MSGRESFILE) $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmminternal.h>\r
+\r
+khm_boolean kmm_load_locale_lib(kmm_module_i * m, kmm_module_locale * l)\r
+{\r
+ HMODULE h;\r
+\r
+ if(l->filename != NULL) {\r
+ h = LoadLibrary(l->filename);\r
+ if(!h)\r
+ return FALSE;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ m->h_resource = h;\r
+ m->lcid_resource = l->language;\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return TRUE;\r
+ } else {\r
+ /* in this case, the language resources are assumed to be in the\r
+ main module library itself. */\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ m->h_resource = m->h_module;\r
+ m->lcid_resource = l->language;\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_set_locale_info(kmm_module module, kmm_module_locale * locales, khm_int32 n_locales)\r
+{\r
+ kmm_module_i * m;\r
+ LANGID lcid;\r
+ int i;\r
+ int * f;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ m = kmm_module_from_handle(module);\r
+\r
+ if(!m || m->state != KMM_MODULE_STATE_INIT)\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(!locales || n_locales < 0)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ f = malloc(n_locales * sizeof(int));\r
+ if(!f)\r
+ return KHM_ERROR_UNKNOWN;\r
+ ZeroMemory(f, sizeof(int) * n_locales);\r
+\r
+ lcid = GetUserDefaultLangID();\r
+\r
+ /* first search for an exact match */\r
+ for(i=0; i<n_locales; i++) {\r
+ if(locales[i].language == lcid) {\r
+ f[i] = TRUE;\r
+ if(kmm_load_locale_lib(m, &locales[i]))\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(i<n_locales)\r
+ goto _exit;\r
+\r
+ /* ok, that didn't work. Try an inexact match. */\r
+ for(i=0; i<n_locales; i++) {\r
+ if(!f[i] && (PRIMARYLANGID(locales[i].language) == PRIMARYLANGID(lcid))) {\r
+ f[i] = TRUE;\r
+ if(kmm_load_locale_lib(m,&locales[i]))\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(i < n_locales)\r
+ goto _exit;\r
+\r
+ /* hmm. no matches yet. just try to locate the default locale */\r
+ for(i=0; i<n_locales; i++) {\r
+ if(!f[i] && (locales[i].flags & KMM_MLOC_FLAG_DEFAULT)) {\r
+ f[i] = TRUE;\r
+ if(kmm_load_locale_lib(m,&locales[i]))\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(i < n_locales)\r
+ goto _exit;\r
+\r
+ /* give up */\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+\r
+_exit:\r
+ free(f);\r
+ return rv;\r
+}\r
+\r
+#ifdef _WIN32\r
+KHMEXP HMODULE KHMAPI kmm_get_resource_hmodule(kmm_module vm)\r
+{\r
+ if(!kmm_is_module(vm))\r
+ return NULL;\r
+ else\r
+ return (kmm_module_from_handle(vm))->h_resource;\r
+}\r
+#endif\r
+\r
+KHMEXP kmm_module KHMAPI\r
+kmm_this_module(void) {\r
+ kmm_plugin_i * p;\r
+ kmm_module_i * m;\r
+ kmm_module vm;\r
+\r
+ p = TlsGetValue(tls_kmm);\r
+ if (!kmm_is_plugin(p))\r
+ return NULL;\r
+\r
+ m = p->module;\r
+ vm = kmm_handle_from_module(m);\r
+\r
+ kmm_hold_module(vm);\r
+\r
+ return vm;\r
+}\r
+\r
+KHMEXP kmm_plugin KHMAPI\r
+kmm_this_plugin(void) {\r
+ kmm_plugin_i * p;\r
+ kmm_plugin vp;\r
+\r
+ p = TlsGetValue(tls_kmm);\r
+ if (!kmm_is_plugin(p))\r
+ return NULL;\r
+\r
+ vp = kmm_handle_from_plugin(p);\r
+\r
+ kmm_hold_plugin(vp);\r
+\r
+ return vp;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KMM_H\r
+#define __KHIMAIRA_KMM_H\r
+\r
+#include<khdefs.h>\r
+#include<kmq.h>\r
+\r
+/*! \defgroup kmm NetIDMgr Module Manager\r
+@{*/\r
+\r
+/*! \brief A handle to a module.\r
+*/\r
+typedef khm_handle kmm_module;\r
+\r
+/*! \brief A handle to a plugin.\r
+ */\r
+typedef khm_handle kmm_plugin;\r
+\r
+/*! \name Limits\r
+ @{*/\r
+\r
+/*! \brief Maximum number of characters in a name in KMM including the terminating NULL */\r
+#define KMM_MAXCCH_NAME 256\r
+\r
+/*! \brief Maximum number of bytes in a name in KMM including the terminating NULL */\r
+#define KMM_MAXCB_NAME (sizeof(wchar_t) * KMM_MAXCCH_NAME)\r
+\r
+/*! \brief Maximum number of characters in a description in KMM including the terminating NULL */\r
+#define KMM_MAXCCH_DESC 512\r
+\r
+/*! \brief Maximum number of bytes in a description in KMM including the terminating NULL */\r
+#define KMM_MAXCB_DESC (sizeof(wchar_t) * KMM_MAXCB_NAME)\r
+\r
+/*! \brief Maximum number of dependencies per plugin\r
+*/\r
+#define KMM_MAX_DEPENDENCIES 8\r
+\r
+/*! \brief Maximum number of dependants per plugin\r
+ */\r
+#define KMM_MAX_DEPENDANTS 16\r
+\r
+/*! \brief Maximum number of characters a dependency string including trailing double NULL */\r
+#define KMM_MAXCCH_DEPS (KMM_MAXCCH_NAME * KMM_MAX_DEPENDENCIES + 1)\r
+\r
+/*! \brief Maximum number of bytes in a dependency string including trailing double NULL */\r
+#define KMM_MAXCB_DEPS (sizeof(wchar_t) * KMM_MAXCCH_DEPS)\r
+/*@}*/ /* Limits */\r
+\r
+/*! \brief Plugin registration\r
+\r
+ \see ::khm_cred_provider\r
+*/\r
+typedef struct tag_kmm_plugin_reg {\r
+ wchar_t * name; /*!< Name of the plugin. Maximum of\r
+ KMM_MAXCCH_NAME characters\r
+ including the terminating\r
+ NULL. Required. */\r
+\r
+ wchar_t * module; /*!< Name of module that owns the\r
+ plugin. Maximum of\r
+ KMM_MAXCCH_NAME characters\r
+ including terminating NULL.\r
+ Required. */\r
+\r
+ khm_int32 type; /*!< Type plugin type. One of\r
+ KHM_PITYPE_*. Required. */\r
+ khm_int32 flags; /*!< Unused. Set to 0 */\r
+ kmq_callback_t msg_proc; /*!< Message processor. Required. */\r
+ wchar_t * dependencies; /*!< Dependencies. Note that this is\r
+ a multi string. (you can use the\r
+ KHC multi string functions to\r
+ manipulate multi strings or to\r
+ convert a comma separated list of\r
+ dependencies to a multi string).\r
+ Each string in the multi string\r
+ is a name of a plugin that this\r
+ plugin depends on. Optional (set\r
+ to NULL if this plugin has no\r
+ dependencies). Maximum of\r
+ KMM_MAXCCH_DEPS characters\r
+ including terminating double\r
+ NULL.*/\r
+\r
+ wchar_t * description; /*!< Description of the plugin.\r
+ Maximum of KMM_MAXCCH_DESC\r
+ characters including the\r
+ terminating\r
+ NULL. Localized. Optional (set to\r
+ NULL if not provided) */\r
+#ifdef _WIN32\r
+ HICON icon; /*!< Icon used to represent the\r
+ plugin. Optional. (set to NULL if\r
+ not provided) */\r
+#endif\r
+} kmm_plugin_reg;\r
+\r
+/*! \brief Plugin information\r
+*/\r
+typedef struct tag_kmm_plugin_info {\r
+ kmm_plugin_reg reg; /*!< Registration info */\r
+\r
+ khm_int32 state; /*!< Current status of the plugin.\r
+ One of ::_kmm_plugin_states */\r
+\r
+ khm_int32 failure_count; /*!< Number of recorded failures in\r
+ the plugin */\r
+ FILETIME failure_time; /*!< Time of first recorded failure */\r
+ khm_int32 failure_reason; /*!< The reason for the first recorded\r
+ failure */\r
+\r
+ kmm_plugin h_plugin; /*!< Handle to plugin */\r
+} kmm_plugin_info;\r
+\r
+/*! \name Plugin types\r
+@{*/\r
+/*! \brief A credentials provider\r
+\r
+ \see \ref pi_pt_cred for more information.\r
+*/\r
+#define KHM_PITYPE_CRED 1\r
+\r
+/*! \brief A configuration provider\r
+\r
+ \see \ref pi_pt_conf for more information.\r
+*/\r
+#define KHM_PITYPE_CONFIG 2\r
+\r
+/*@}*/\r
+\r
+/*! \name Plugin flags\r
+@{*/\r
+\r
+/*! \brief The plugin is an identity provider\r
+*/\r
+#define KHM_PIFLAG_IDENTITY_PROVIDER 1\r
+/*@}*/\r
+\r
+/*! \brief Plugin states */\r
+enum _kmm_plugin_states {\r
+ KMM_PLUGIN_STATE_FAIL_UNKNOWN = -5, /*!< Failed due to unknown\r
+ reasons */\r
+ KMM_PLUGIN_STATE_FAIL_MAX_FAILURE = -4, /*!< The plugin has\r
+ reached the maximum number\r
+ of failures and cannot be\r
+ initialized until the\r
+ failure count is reset */\r
+ KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED = -3, /*!< Failed because the\r
+ plugin was not registered\r
+ and automatic registration\r
+ failed. */\r
+ KMM_PLUGIN_STATE_FAIL_DISABLED = -2,/*!< Failed because plugin was\r
+ disabled by the user. */\r
+ KMM_PLUGIN_STATE_FAIL_LOAD = -1, /*!< The plugin failed to load\r
+ due to some unknown\r
+ reason. */\r
+ KMM_PLUGIN_STATE_NONE = 0, /*!< Unknown state */\r
+ KMM_PLUGIN_STATE_PLACEHOLDER, /*!< Placeholder. The plugin\r
+ hasn't been provided by\r
+ anyone yet, but the plugin\r
+ record has been created to\r
+ keep track of\r
+ dependencies. */\r
+ KMM_PLUGIN_STATE_REG, /*!< The plugin is registered\r
+ but not initialized */\r
+ KMM_PLUGIN_STATE_PREINIT, /*!< The plugin is in the\r
+ process of being\r
+ initialized */\r
+ KMM_PLUGIN_STATE_HOLD, /*!< On hold. One or more\r
+ dependencies of this plugin\r
+ has not been resolved */\r
+ KMM_PLUGIN_STATE_INIT, /*!< The plugin was initialized */\r
+ KMM_PLUGIN_STATE_RUNNING, /*!< The plugin is running */\r
+ KMM_PLUGIN_STATE_EXITED /*!< The plugin has been stopped. */\r
+};\r
+\r
+/*! \brief Module registration */\r
+typedef struct tag_kmm_module_reg {\r
+ wchar_t * name; /*!< Identifier for the module */\r
+ wchar_t * path; /*!< Full pathname to module\r
+ binary */\r
+\r
+ wchar_t * description; /*!< Description of module */\r
+\r
+ wchar_t * vendor; /*!< Vendor/copyright string */\r
+\r
+ khm_int32 n_plugins; /*!< Number of plugins that are\r
+ active */\r
+ kmm_plugin_reg * plugin_reg_info; /*!< Array of kmm_plugin_reg\r
+ records for each active\r
+ plugin */\r
+} kmm_module_reg;\r
+\r
+/*! \brief Module information record */\r
+typedef struct tag_kmm_module_info {\r
+ kmm_module_reg reg; /*!< Registration info */\r
+\r
+ khm_ui_4 language; /*!< Currently loaded langugage */\r
+\r
+ khm_int32 state; /*!< Current status of the\r
+ module */\r
+\r
+ khm_version file_version; /*!< File version for the\r
+ module */\r
+ khm_version product_version; /*!< Product version for the\r
+ module */\r
+\r
+ khm_int32 failure_count; /*!< Number of times the module\r
+ has failed to load */\r
+ FILETIME failure_time; /*!< Time of first recorded\r
+ failure */\r
+ khm_int32 failure_reason; /*!< Reason for first failure.\r
+ One of the module status\r
+ values */\r
+\r
+ kmm_module h_module; /*!< Handle to the module. */\r
+} kmm_module_info;\r
+\r
+/*! \brief Module states\r
+*/\r
+enum KMM_MODULE_STATES {\r
+ KMM_MODULE_STATE_FAIL_UNKNOWN=-10, /*!< Module could not be\r
+ loaded due to unknown\r
+ reasons. */\r
+ KMM_MODULE_STATE_FAIL_MAX_FAILURE=-9,/*!< The module has failed\r
+ too many times already. Not\r
+ attempting to restart it\r
+ again */\r
+ KMM_MODULE_STATE_FAIL_DUPLICATE=-8, /*!< An attempt was made to\r
+ load the same module\r
+ twice. */\r
+ KMM_MODULE_STATE_FAIL_NOT_REGISTERED=-7, /*!< The module is not\r
+ found among the registered\r
+ module list */\r
+ KMM_MODULE_STATE_FAIL_NO_PLUGINS=-6,/*!< The module provided no\r
+ plugins, or all the plugins\r
+ that are provided are\r
+ disabled */\r
+ KMM_MODULE_STATE_FAIL_DISABLED=-5, /*!< Module is disabled and\r
+ cannot be loaded */\r
+ KMM_MODULE_STATE_FAIL_LOAD=-4, /*!< The module failed to\r
+ initialize */\r
+ KMM_MODULE_STATE_FAIL_INVALID=-3, /*!< The module was invalid.\r
+ Typically caused by the\r
+ required entrypoints not\r
+ being present */\r
+ KMM_MODULE_STATE_FAIL_SIGNATURE=-2, /*!< The module failed to load\r
+ due to an unverifiable\r
+ signature */\r
+ KMM_MODULE_STATE_FAIL_NOT_FOUND=-1, /*!< The module was not\r
+ found */\r
+ KMM_MODULE_STATE_NONE=0, /*!< Unknown state. The handle\r
+ is possibly invalid */\r
+ KMM_MODULE_STATE_PREINIT, /*!< The module is being\r
+ loaded. init_module() hasn't\r
+ been called yet */\r
+ KMM_MODULE_STATE_INIT, /*!< In init_module() */\r
+ KMM_MODULE_STATE_INITPLUG, /*!< Initializing plugins */\r
+ KMM_MODULE_STATE_RUNNING, /*!< Running */\r
+ KMM_MODULE_STATE_EXITPLUG, /*!< Currently exiting plugins */\r
+ KMM_MODULE_STATE_EXIT, /*!< Currently exiting */\r
+ KMM_MODULE_STATE_EXITED /*!< Exited */\r
+};\r
+\r
+/*! \brief Start the Module Manager\r
+\r
+ \note Only called by the NetIDMgr core.\r
+*/\r
+KHMEXP void KHMAPI \r
+kmm_init(void);\r
+\r
+/*! \brief Stop the Module Manager\r
+\r
+ \note Only called by the NetIDMgr core.\r
+*/\r
+KHMEXP void KHMAPI \r
+kmm_exit(void);\r
+\r
+/*! \brief Return the plugin handle for the current plugin\r
+\r
+ The returned handle represents the plugin which owns the current\r
+ thread. The returned handle must be released by calling\r
+ kmm_release_plugin(). Returns NULL if the current thread is not\r
+ owned by any plugin.\r
+ */\r
+KHMEXP kmm_plugin KHMAPI \r
+kmm_this_plugin(void);\r
+\r
+/*! \brief Return the module handle for the current module\r
+\r
+ The returned handle represents the module which owns the current\r
+ thread. The returned handle must be released by calling\r
+ kmm_release_module()\r
+*/\r
+KHMEXP kmm_module KHMAPI \r
+kmm_this_module(void);\r
+\r
+/*! \name Flags for kmm_load_module()\r
+@{*/\r
+/*!\brief Load synchronously\r
+\r
+ If this flag is set, then the function waits for the module to be\r
+ loaded. The default is to load the module asynchronously.\r
+\r
+ When loading a module asynchronously, the kmm_load_module()\r
+ function returns KHM_ERROR_SUCCESS and exits without waiting for\r
+ the module to load. If \a result is not NULL, it will receive a\r
+ valid handle to the module.\r
+\r
+ When loading a module synchronously, kmm_load_module() will wait\r
+ for the module to completely load. If it fails to load properly,\r
+ it will return an error code and set \a result to NULL.\r
+*/\r
+#define KMM_LM_FLAG_SYNC 1\r
+\r
+/*! \brief Do not load\r
+\r
+ Indicates that the module shouldn't actually be loaded. If the\r
+ specified module name identifies a module that has already been\r
+ loaded, then the function returns a held handle to the existing\r
+ module (use kmm_release_module() to free the handle). Otherwise,\r
+ the function returns KHM_ERROR_NOT_FOUND.\r
+*/\r
+#define KMM_LM_FLAG_NOLOAD 2\r
+/*@}*/\r
+\r
+/*! \brief Load a module\r
+\r
+ The \a modulename parameter specifies a module to load. Depending\r
+ on the configuration, not all of the plugins that are provided by\r
+ the module may be loaded. If no plugins are successfully loaded,\r
+ the module will be immediately unloaded.\r
+\r
+ If the module is currently loaded or is being loaded, then a valid\r
+ handle to the existing module is returned.\r
+\r
+ When called with KMM_LM_FLAG_SYNC, the function does not return\r
+ until the module and the associated plugins are all initialized,\r
+ or an error occurs.\r
+\r
+ If the KMM_LM_FLAG_NOLOAD flag is set, then a handle to an\r
+ existing instance of the module will be returned. If the module\r
+ hasn't been loaded yet, then no handle is returned and the\r
+ function returns KHM_ERROR_NOT_FOUND.\r
+\r
+ See the associated NetIDMgr Module Manager documentation on the\r
+ sequence of events associated with loading a module.\r
+\r
+ \param[in] modulename Name of the module. The module should have\r
+ been registered under this name prior to the call.\r
+ \param[in] flags Combination of KMM_LM_FLAG_*\r
+ \param[out] result Receives a handle to the loaded module. If the\r
+ result is not required, set this to NULL. If \a result is not\r
+ NULL, and km_load_module() returns KHM_ERROR_SUCCESS, then\r
+ kmm_release_module() must be called to release the handle to\r
+ the module. Otherwise, \a result receives NULL. If a handle\r
+ is returned, it will be valid regardless of whether the module\r
+ fails to load or not. You can use kmm_get_module_state() to\r
+ query the progress of the loading process. See\r
+ ::KMM_LM_FLAG_SYNC.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded. If \a\r
+ KMM_LM_FLAG_SYNC was specified, this means that the module was\r
+ successfully loaded. Otherwise, it only means that the module\r
+ has been queued up for loading. Use kmm_get_module_state() to\r
+ determine if it was successfully loaded. If \a result is not\r
+ NULL, a valid handle is returned.\r
+ \retval KHM_ERROR_EXISTS The module is already loaded or has been\r
+ already queued for loading. If \a result is not NULL, a valid\r
+ handle to the existing module instance is returned.\r
+ \retval KHM_ERROR_NOT_FOUND If called with KMM_LM_FLAG_NOLOAD,\r
+ indicates that the module has not been loaded. Otherwise only\r
+ returned when called with KMM_LM_FLAG_SYNC. The module image\r
+ was not found. No handle is returned.\r
+ \retval KHM_ERROR_INVALID_SIGNATURE Only returned when called with\r
+ KMM_LM_FLAG_SYNC. The module was signed with an invalid\r
+ certificate. No handle is returned.\r
+ \retval KHM_ERROR_UNKNOWN Only returned when called with\r
+ KMM_LM_FLAG_SYNC. Some other error has occured. No handle is\r
+ returned.\r
+\r
+ \see \ref pi_fw_pm_load\r
+ \see ::KMM_LM_FLAG_SYNC, ::KMM_LM_FLAG_NOLOAD\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_load_module(wchar_t * modname, khm_int32 flags, kmm_module * result);\r
+\r
+/*! \brief Hold a handle to a module\r
+\r
+ Use kmm_release_module() to release the hold.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_hold_module(kmm_module module);\r
+\r
+/*! \brief Release a handle to a module\r
+\r
+ Release a held referece to a module that was returned in a call to \r
+ kmm_load_module().\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_release_module(kmm_module m);\r
+\r
+/*! \brief Query the state of a module\r
+\r
+ When loading a module asynchronously you can query the state of\r
+ the loading process using this. The return value is a status\r
+ indicator.\r
+\r
+ \return The return value is one of the ::KMM_MODULE_STATES\r
+ enumerations.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_module_state(kmm_module m);\r
+\r
+/*! \brief Unload a module\r
+\r
+ See the associated NetIDMgr Module Manager documentation on the\r
+ sequence of events associated with unloading a module.\r
+\r
+ \see \ref pi_fw_pm_unload\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_unload_module(kmm_module module);\r
+\r
+/*! \brief Loads the default modules as specified in the configuration\r
+\r
+ The configuration can specify the default set of modules to load.\r
+ This function dispatches the necessary message for loading these\r
+ modules and reutnrs.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_load_default_modules(void);\r
+\r
+/*! \brief Checks whether there are any pending loads\r
+\r
+ Returns TRUE if there are modules still waiting to be loaded.\r
+*/\r
+KHMEXP khm_boolean KHMAPI\r
+kmm_load_pending(void);\r
+\r
+#ifdef _WIN32\r
+/*! \brief Returns the Windows module handle from a handle to a NetIDMgr module.\r
+\r
+ Although it is possible to obtain the Windows module handle and\r
+ use it to call Windows API functions, it is not recommended to do\r
+ so. This is because that might cause the state of the module to\r
+ change in ways which are inconsistent from the internal data\r
+ structures that kmm maintains.\r
+*/\r
+KHMEXP HMODULE KHMAPI \r
+kmm_get_hmodule(kmm_module m);\r
+#endif\r
+\r
+/*! \brief Hold a plugin\r
+\r
+ Obtains a hold on a plugin. The plugin handle will remain valid\r
+ until the hold is released with a call to kmm_release_plugin().\r
+ No guarantees are made on the handle once the handle is released.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_hold_plugin(kmm_plugin p);\r
+\r
+/*! \brief Release a plugin\r
+\r
+ Releases a hold on a plugin obtained through a call to\r
+ kmm_hold_plugin(). The plugin handle should no longer be\r
+ considered valied once this is called.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_release_plugin(kmm_plugin p);\r
+\r
+/*! \brief Provide a plugin\r
+\r
+ This function must be called for each plugin that the module\r
+ provides.\r
+\r
+ Note that this function returns immediately and does not\r
+ initialize the plugin. All plugins that are provided by a\r
+ module will be initialized once the init_module() function\r
+ returns. If the plugin has dependencies, it will be kept in a\r
+ held state until the plugins that it depends on are successfully\r
+ initialized. If the dependencies are not resolved (the dependent\r
+ plugins are not loaded), then plugin will not be initialized.\r
+\r
+ If the plugin is not registered and \a plugin contains enough\r
+ information to perform the registration, then it will be\r
+ automatically registered. However, if the plugin is not\r
+ registered and cannot be registered using the provided\r
+ information, the plugin will not be initialized properly. Note\r
+ that automatic registration will always register the plugin in the\r
+ user configuration store.\r
+\r
+ The \a name and \a msg_proc members of \a plugin are required to\r
+ have valid values. The \a icon member may optionally be\r
+ specified. The other fields can be specified if the plugin should\r
+ be automatically registered, however, the \a module field will be\r
+ ignored and will be determined by the \a module handle.\r
+\r
+ \param[in] module Handle to this module that is providing the plugin.\r
+ \param[in] plugin A plugin descriptor.\r
+\r
+ \retval KHM_ERROR_SUCCESS Succeeded.\r
+ \retval KHM_ERROR_INVALID_OPERATION The function was not called\r
+ during init_module()\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_DUPLICATE The plugin was already provided\r
+\r
+ \note This can only be called when handing init_module()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin);\r
+\r
+/*! \brief Query the state of a plugin.\r
+\r
+ \return One of ::_kmm_plugin_states\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugin_state(wchar_t * plugin);\r
+\r
+/*! \defgroup kmm_reg Registration\r
+\r
+ The functions for managing plugin and module registration. These\r
+ functions are also available as static linked libraries for use by\r
+ external applications which must register or unregister plugins or\r
+ modules.\r
+@{*/\r
+\r
+/*! \brief Obtain the configuration space for a named plugin\r
+\r
+ Note that the named plugin does not have to actually exist.\r
+ Configuration spaces for plugins are based solely on the plugin\r
+ name and hence can be accessed regardless of whether the specific\r
+ plugin is loaded or not.\r
+\r
+ \param[in] flags Controls the options for opening the\r
+ configuration space. If KHM_FLAG_CREATE is specified, then\r
+ the configuration space for the plugin named \a plugin wil be\r
+ created if it doesn't already exist. The \a flags parameter\r
+ is directly passed into a call to khc_open_space().\r
+\r
+ \param[in] plugin Name of the plugin. The name can not contain\r
+ slashes.\r
+\r
+ \param[out] result Receives a configuration space handle. The\r
+ calling application should free the handle using\r
+ khc_close_space().\r
+\r
+ \see khc_open_space()\r
+ \see khc_close_space()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result);\r
+\r
+/*! \brief Obtain the configuration space or a named module\r
+\r
+ The named module does not have to actually exist. Configuration\r
+ spaces for modules are based on the basename of the module\r
+ (including the extension).\r
+\r
+ \param[in] module Name of the module.\r
+\r
+ \param[in] flags The flags used to call khc_open_space(). You can\r
+ use this to specify a particular configuration store if\r
+ needed.\r
+\r
+ \param[out] result Receives the handle to a configuration space if\r
+ successful. Call khc_close_space() to close the handle.\r
+\r
+ \see khc_open_space()\r
+ \see khc_close_space()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result);\r
+\r
+/*! \brief Retrieve a handle to the configuration space for plugins\r
+\r
+ The configuration space for plugins is a container which holds the\r
+ configuration subspaces for all the plugins. This is the config\r
+ space which must be used to load a configuration space for a\r
+ plugin.\r
+\r
+ \param[in] flags The flags to pass in to the call to\r
+ khc_open_space(). The flags can be used to select a specific\r
+ configuration store if needed.\r
+\r
+ \param[out] result Receives a handle to the configuration\r
+ space. Call khc_close_space() to close the handle\r
+\r
+ \see khc_open_space()\r
+ \see khc_close_space()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugins_config(khm_int32 flags, khm_handle * result);\r
+\r
+/*! \brief Retrieve the handle to the configuration space for modules\r
+\r
+ The configuration space for modules is a container which hold the\r
+ configuration subspaces for all the modules. Each module\r
+ registration ends up in this subspace.\r
+\r
+ \param[in] flags The flags to pass in to the call to\r
+ khc_open_space(). The flags can be used to select a specific\r
+ configuration store if needed.\r
+\r
+ \param[out] result Receives a handle to the configuration space.\r
+ Call khc_close_space() to close the handle.\r
+\r
+ \see khc_open_space()\r
+ \see khc_close_space()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_modules_config(khm_int32 flags, khm_handle * result);\r
+\r
+/*! \brief Return information about a loaded module\r
+\r
+ The retrieves a block of information about a module. Refer to\r
+ ::kmm_module_info for information about the format of the returned\r
+ data.\r
+\r
+ Note that the size of the required buffer is actually greater than\r
+ the size of the ::kmm_module_info structure and accomodates the\r
+ ::kmm_plugin_info structures and strings required to complete the\r
+ information block.\r
+\r
+ Call the function with \a buffer set to NULL and \a cb_buffer\r
+ pointing at a khm_size variable to obtain the required size of the\r
+ buffer.\r
+\r
+ \param[in] module_name Name of a module\r
+ \param[in] flags Flags indicating which types of information to\r
+ return\r
+ \param[out] buffer Points to a buffer that recieves information.\r
+ Set this to NULL if only the size of the buffer is required.\r
+ \param[in,out] On entry, contains the size of the buffer pointed\r
+ to by \a buffer if \a buffer is not NULL. On exit, contains\r
+ the required size of the buffer or the number of actual bytes\r
+ copied.\r
+\r
+ \retval KHM_ERROR_SUCCESS The requested information was copied\r
+ \retval KHM_ERROR_INVALID_PARM One of the parameters was invalid\r
+ \retval KHM_ERROR_TOO_LONG The buffer was not large enough or was\r
+ NULL. The number of bytes requied is in \a cb_buffer.\r
+ \retval KHM_ERROR_NOT_FOUND The specified module is not a\r
+ registered module.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_module_info(wchar_t * module_name, khm_int32 flags, \r
+ kmm_module_info * buffer, khm_size * cb_buffer);\r
+\r
+/*! \brief Get information about a module\r
+\r
+ Similar to kmm_get_module_info(), but uses a module handle instead\r
+ of a name, and uses internal buffers for providing string fields.\r
+\r
+ The information that is returned should be freed using a call to\r
+ kmm_release_module_info_i().\r
+\r
+ \see kmm_release_module_info_i()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_get_module_info_i(kmm_module module, kmm_module_info * info);\r
+\r
+/*! \brief Release module information\r
+\r
+ Releases the information returned by a previous call to\r
+ kmm_get_module_info_i(). The contents of the ::kmm_module_info\r
+ structure should not have been modified in any way between calling\r
+ kmm_get_module_info_i() and kmm_release_module_info_i().\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_release_module_info_i(kmm_module_info * info);\r
+\r
+/*! \brief Obtain information about a plugin\r
+\r
+ Retrieve a block of information about a plugin. See\r
+ ::kmm_plugin_info for details about what information can be\r
+ returned. Note that some fields may not be available if the\r
+ module is not loaded.\r
+\r
+ Note that the size of the required buffer is greater than the size\r
+ of the ::kmm_plugin_info structure and accounts for strings as\r
+ well. Call kmm_get_plugin_info() with \a buffer set to NULL and\r
+ \a cb_buffer set to point to a variable of type \a khm_size to\r
+ obtain the required size of the structure.\r
+\r
+ \param[in] plugin_name Name of the plugin\r
+ \param[out] buffer The buffer to receive the plugin information.\r
+ Set to \a NULL if only the size of the buffer is required.\r
+ \param[in,out] cb_buffer On entry, points to variable that\r
+ specifies the size of the buffer pointed to by \a buffer is \a\r
+ buffer is not \a NULL. On exit, holds the number of bytes\r
+ copied or the required size of the buffer.\r
+\r
+ \retval KHM_ERROR_SUCCESS The requested information was\r
+ successfully copied to the \a buffer\r
+ \retval KHM_ERROR_TOO_LONG The buffer was either \a NULL or\r
+ insufficient to hold the requested information. The required\r
+ size of the buffer was stored in \a cb_buffer\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were\r
+ invlaid.\r
+ \retval KHM_ERROR_NOT_FOUND The specified plugin was not found\r
+ among the registered plugins.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugin_info(wchar_t * plugin_name, \r
+ kmm_plugin_info * buffer, \r
+ khm_size * cb_buffer);\r
+\r
+/*! \brief Obtain information about a plugin using a plugin handle\r
+\r
+ Similar to kmm_get_plugin_info() but uses a plugin handle instead\r
+ of a plugin name. If the call is successful, the \a info\r
+ structure will be filled with information about the plugin. The\r
+ returned info should not be modified in any way and may contain\r
+ pointers to internal buffers.\r
+\r
+ The returned information must be released with a call to\r
+ kmm_release_plugin_info_i().\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info);\r
+\r
+/*! \brief Release plugin information returned by kmm_get_plugin_info_i\r
+\r
+ The information returned by kmm_get_plugin_info_i() should not be\r
+ modified in any way before calling kmm_release_plugin_info_i().\r
+ Once the call completes, the contents of \a info will be\r
+ initialized to zero.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_release_plugin_info_i(kmm_plugin_info * info);\r
+\r
+/*! \brief Enumerates plugins\r
+\r
+ Enumerates through known plugins. This list may not include\r
+ plugins which were not loaded by NetIDMgr in this session.\r
+\r
+ If the call is successful, a handle to the next plugin in the list\r
+ will be placed in \a p_next. The returned handle must be freed\r
+ with a call to kmm_release_plugin().\r
+\r
+ If the \a p parameter is set to NULL, then the first plugin handle\r
+ will be placed in \a p_next. The handles will not be returned in\r
+ any specific order. In addition, the enumeration may not include\r
+ all known plugins if the list of plugins changes during\r
+ enumeration.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next);\r
+\r
+/*! \brief Register a plugin\r
+\r
+ The \a plugin member defines the plugin to be registered. The \a\r
+ msg_proc and \a icon members of the structure are ignored.\r
+\r
+ At the time kmm_register_plugin() is called, the module specified\r
+ by \a module member of the \a plugin parameter must have been already\r
+ registered. Otherwise the function call fails.\r
+\r
+ If the plugin has already been registered, then all the fields in\r
+ the plugin registration will be updated to be in sync with the\r
+ information provided in the \a plugin parameter. The failure\r
+ counts and associated statistics will not be reset when the\r
+ configuration information is updated.\r
+\r
+ If the plugin has not been registered, the a new registration\r
+ entry is created in the configuration space indicated by the \a\r
+ config_flags parameter. In addition, the plugin will be added to\r
+ the list of plugins associated with the owning module.\r
+\r
+ Note that the module that owns the plugin must be registered in\r
+ the same configuration store as the plugin.\r
+\r
+ \param[in] plugin Registration info for the plugin. The \a\r
+ msg_proc and \a icon members are ignored. All other fields\r
+ are required. The \a description member should be localized\r
+ to the system locale when registering a plugin in the machine\r
+ configuration store and should be localized to the user locale\r
+ when registering a plugin in the user configuration store.\r
+ \param[in] config_flags Flags for the configuration provider.\r
+ These flags are used verbatim to call khc_open_space(), hence\r
+ they may be used to pick whether or not the registration is\r
+ per machine or per user.\r
+\r
+ \see kmm_register_module()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags);\r
+\r
+/*! \brief Register a module\r
+\r
+ The \a module parameter specifies the parameters for the module\r
+ registration.\r
+\r
+ The \a plugin_info member should point to an array of\r
+ ::kmm_plugin_info structures unless the \a n_plugins member is\r
+ zero, in which case \a plugin_info can be \a NULL. Plugins can be\r
+ registered separately using kmm_register_plugin().\r
+\r
+ \param[in] module Information about the module. All members are\r
+ required, however \a plugin_info can be \a NULL if \a\r
+ n_plugins is zero.\r
+\r
+ \param[in] config_flags Flags used to call khc_open_space(). This\r
+ can be used to choose the configuration store in which the\r
+ module registration will be performed.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_register_module(kmm_module_reg * module, khm_int32 config_flags);\r
+\r
+/*! \brief Unregister a plugin\r
+\r
+ Registration information associated with the plugin will be\r
+ removed. In addtion, the plugin will be removed from the list of\r
+ plugins provided by the owner module.\r
+\r
+ \param[in] plugin Names the plugin to be removed\r
+ \param[in] config_flags Flags used to call khc_open_space(). Can\r
+ be used to choose the configuraiton store that is affected by\r
+ the call.\r
+\r
+ \note kmm_unregister_plugin() has no effect on whether the plugin\r
+ is loaded or not. The caller must make sure that the plugin\r
+ is unloaded and the associated module is either also unloaded\r
+ or in a state where the plugin can be unregistered.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags);\r
+\r
+/*! \brief Unregister a module\r
+\r
+ Registration information associated with the module as well as all\r
+ the plugins provided by the module will be removed from the\r
+ configuration store.\r
+\r
+ \param[in] module Names the module to be removed\r
+\r
+ \param[in] config_flags Flags used to call khc_open_space(). Can\r
+ be used to choose the configuration store affected by the\r
+ call.\r
+\r
+ \note kmm_unregister_module() has no effect on the loaded state of\r
+ the module. The caller should make sure that the module is\r
+ unloaded and in a state where it can be unregistered.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_unregister_module(wchar_t * module, khm_int32 config_flags);\r
+\r
+/*@}*/ /* kmm_reg */\r
+\r
+/*! \defgroup kmm_loc Internationalization support\r
+\r
+ See \ref pi_localization for more information about\r
+ internationalization.\r
+\r
+@{*/\r
+\r
+/*! \brief Locale descriptor record\r
+\r
+ See kmm_set_locale()\r
+*/\r
+typedef struct tag_kmm_module_locale {\r
+ khm_ui_4 language; /*!< A language ID. On Windows, you can use the\r
+ MAKELANGID macro to generate this value. */\r
+ wchar_t * filename; /*!< The filename corresponding to this language.\r
+ Use NULL to indicate that resources for this\r
+ language are to be found in the main module. */\r
+ khm_int32 flags; /*!< Flags. Combination of KMM_MLOC_FLAG_* */\r
+} kmm_module_locale;\r
+\r
+#define LOCALE_DEF(language_id, filename, flags) {language_id, filename, flags}\r
+\r
+/*! \brief Default (fallback) locale\r
+*/\r
+#define KMM_MLOC_FLAG_DEFAULT 1\r
+\r
+\r
+/*! \brief Sets the locale for a loaded module.\r
+\r
+ The given locale records are searched in the given order until a\r
+ locale that matches the current user locale is found. If no\r
+ locales match, then the first locale with the\r
+ ::KMM_MLOC_FLAG_DEFAULT flag set will be loaded. If no locales\r
+ have that flag set, then the first locale is loaded.\r
+\r
+ You can obtain a handle to the loaded library using\r
+ kmm_get_resource_hmodule(). This function does not return until a\r
+ matched library is loaded.\r
+\r
+ \param[in] module The module handle\r
+ \param[in] locales An array of ::kmm_module_locale objects\r
+ \param[in] n_locales The number of objects in the array pointed to by \a locales\r
+\r
+ \retval KHM_ERROR_SUCCESS Succeeded.\r
+ \retval KHM_ERROR_NOT_FOUND A matching locale resource library was not found.\r
+ \retval KHM_ERROR_INVALID_OPERATION The function was called on a module which is currently not being initalized.\r
+\r
+ \see \ref pi_localization\r
+ \see kmm_get_resource_hmodule()\r
+\r
+ \note This can only be called when handing init_module()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_set_locale_info(kmm_module module, \r
+ kmm_module_locale * locales, \r
+ khm_int32 n_locales);\r
+\r
+#ifdef _WIN32\r
+\r
+/*! \brief Return the Windows module handle of the resource library of a NetIDMgr module.\r
+\r
+ NetIDMgr allows the specification of an alternate resource library\r
+ that will be used to load localized resources from. This function\r
+ returns a handle to this library.\r
+ \r
+ While you can use the convenience macros to access resources in a\r
+ localization library using the module handle, it is recommended,\r
+ for performance reasons, to use this function to obtain the handle\r
+ to the resource library and then use that handle in calls to\r
+ LoadString, LoadImage etc. directly.\r
+*/\r
+KHMEXP HMODULE KHMAPI \r
+kmm_get_resource_hmodule(kmm_module m);\r
+\r
+/*! \name Convenience Macros\r
+@{*/\r
+/*! \brief Convenience macro for using calling LoadAccelerators using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadAccelerators(module, lpTableName) \\r
+ (LoadAccelerators(kmm_get_resource_hmodule(module), lpTableName))\r
+\r
+/*! \brief Convenience macro for using calling LoadBitmap using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadBitmap(module, lpBitmapName) \\r
+ (LoadBitmap(kmm_get_resource_hmodule(module), lpBitmapName))\r
+\r
+/*! \brief Convenience macro for using calling LoadImage using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadImage(module, lpszName, uType, cxDesired, cyDesired, fuLoad) \\r
+ (LoadImage(kmm_get_resource_hmodule(module), lpszName, uType, cxDesired, cyDesired, fuLoad))\r
+\r
+/*! \brief Convenience macro for using calling LoadCursor using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadCursor(module, lpCursorName) \\r
+ (LoadCursor(kmm_get_resource_hmodule(module), lpCursorName))\r
+\r
+/*! \brief Convenience macro for using calling LoadIcon using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadIcon(module, lpIconName) \\r
+ (LoadIcon(kmm_get_resource_hmodule(module), lpIconName))\r
+\r
+/*! \brief Convenience macro for using calling LoadMenu using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadMenu(module, lpMenuName) \\r
+ (LoadMenu(kmm_get_resource_hmodule(module), lpMenuName))\r
+\r
+/*! \brief Convenience macro for using calling LoadString using a module handle\r
+\r
+ \param[in] module A handle to a loaded module. The corresponding resource \r
+ module will be located through a call to kmm_get_resource_hmodule()\r
+*/\r
+#define kmm_LoadString(module, uID, lpBuffer, nBufferMax) \\r
+ (LoadString(kmm_get_resource_hmodule(module), uID, lpBuffer, nBufferMax))\r
+/*@}*/ /* Convenience Macros */\r
+#endif\r
+/*@}*/ /* group kmm_loc */\r
+/*@}*/ /* group kmm */\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmminternal.h>\r
+\r
+kmm_module_i * kmm_get_module_i(wchar_t * name)\r
+{\r
+ kmm_module_i * m;\r
+ size_t sz;\r
+\r
+ if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &sz)))\r
+ return NULL;\r
+ sz += sizeof(wchar_t);\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name);\r
+\r
+ if(m == NULL) {\r
+ m = malloc(sizeof(kmm_module_i));\r
+ ZeroMemory(m, sizeof(kmm_module_i));\r
+\r
+ m->magic = KMM_MODULE_MAGIC;\r
+ m->name = malloc(sz);\r
+ StringCbCopy(m->name, sz, name);\r
+ m->state = KMM_MODULE_STATE_NONE;\r
+\r
+ hash_add(hash_modules, (void *) m->name, (void *) m);\r
+ LPUSH(&kmm_all_modules, m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return m;\r
+}\r
+\r
+kmm_module_i * kmm_find_module_i(wchar_t * name)\r
+{\r
+ kmm_module_i * m;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name);\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return m;\r
+}\r
+\r
+/* called with cs_kmm held */\r
+void kmm_free_module(kmm_module_i * m)\r
+{\r
+ m->magic = 0;\r
+\r
+ hash_del(hash_modules, m->name);\r
+ LDELETE(&kmm_all_modules, m);\r
+\r
+ if (m->name)\r
+ free(m->name);\r
+ if (m->path)\r
+ free(m->path);\r
+ if (m->vendor)\r
+ free(m->vendor);\r
+ if (m->version_info)\r
+ free(m->version_info);\r
+ free(m);\r
+\r
+ if (kmm_all_modules == NULL)\r
+ SetEvent(evt_exit);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module)\r
+{\r
+ if(!kmm_is_module(module))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ EnterCriticalSection(&cs_kmm);\r
+ kmm_module_from_handle(module)->refcount++;\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_release_module(kmm_module vm)\r
+{\r
+ kmm_module_i * m;\r
+ if(!kmm_is_module(vm))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ m = kmm_module_from_handle(vm);\r
+ if(! --(m->refcount)) \r
+ {\r
+ /* note that a 0 ref count means that there are no active\r
+ plugins */\r
+ kmm_free_module(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_load_module(wchar_t * modname, \r
+ khm_int32 flags, \r
+ kmm_module * result)\r
+{\r
+ kmm_module_i * m = NULL;\r
+ kmm_module_i * mi;\r
+ size_t cbsize;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(FAILED(StringCbLength(modname, KMM_MAXCB_NAME, &cbsize)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ mi = kmm_find_module_i(modname);\r
+\r
+ if(mi != NULL) {\r
+ kmm_hold_module(kmm_handle_from_module(mi));\r
+ /* check if the module has either failed to load either or if\r
+ it has been terminated. If so, we try once again to load the\r
+ module. */\r
+ if(!(flags & KMM_LM_FLAG_NOLOAD) && \r
+ (mi->state < 0 || mi->state == KMM_MODULE_STATE_EXITED)) \r
+ {\r
+ mi->state = KMM_MODULE_STATE_PREINIT;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ if(flags & KMM_LM_FLAG_NOLOAD) {\r
+ if(result)\r
+ *result = mi;\r
+ else if(mi)\r
+ kmm_release_module(kmm_handle_from_module(mi));\r
+\r
+ return (mi)? KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ if(mi) {\r
+ m = mi;\r
+ } else {\r
+ m = kmm_get_module_i(modname);\r
+ m->state = KMM_MODULE_STATE_PREINIT;\r
+ kmm_hold_module(kmm_handle_from_module(m));\r
+ }\r
+\r
+ /* the module is already running or is already being\r
+ worked on by the registrar */\r
+ if(m->state != KMM_MODULE_STATE_PREINIT) {\r
+ if(result)\r
+ *result = kmm_handle_from_module(m);\r
+ else\r
+ kmm_release_module(kmm_handle_from_module(m));\r
+\r
+ return KHM_ERROR_EXISTS;\r
+ }\r
+\r
+ kmmint_add_to_module_queue();\r
+\r
+ if(flags & KMM_LM_FLAG_SYNC) {\r
+ kmm_hold_module(kmm_handle_from_module(m));\r
+ kmq_send_message(KMSG_KMM, \r
+ KMSG_KMM_I_REG, \r
+ KMM_REG_INIT_MODULE, \r
+ (void*) m);\r
+ if(m->state <= 0) {\r
+ /* failed to load ? */\r
+ if(m->state == KMM_MODULE_STATE_FAIL_NOT_FOUND)\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ else if(m->state == KMM_MODULE_STATE_FAIL_SIGNATURE)\r
+ rv = KHM_ERROR_INVALID_SIGNATURE;\r
+ else\r
+ rv = KHM_ERROR_UNKNOWN;\r
+\r
+ kmm_release_module(kmm_handle_from_module(m));\r
+ if(result)\r
+ *result = NULL;\r
+ } else {\r
+ if(result)\r
+ *result = kmm_handle_from_module(m);\r
+ else\r
+ kmm_release_module(kmm_handle_from_module(m));\r
+ }\r
+ } else {\r
+ kmm_hold_module(kmm_handle_from_module(m));\r
+ kmq_post_message(KMSG_KMM, \r
+ KMSG_KMM_I_REG, \r
+ KMM_REG_INIT_MODULE, \r
+ (void*) m);\r
+ if(result)\r
+ *result = kmm_handle_from_module(m);\r
+ else\r
+ kmm_release_module(kmm_handle_from_module(m));\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_get_module_state(kmm_module m)\r
+{\r
+ if(!kmm_is_module(m))\r
+ return KMM_MODULE_STATE_NONE;\r
+ else\r
+ return kmm_module_from_handle(m)->state;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_get_module_info_i(kmm_module vm, kmm_module_info * info) {\r
+ kmm_module_i * m;\r
+ khm_int32 rv;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ if (!kmm_is_module(vm) || !info)\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ else {\r
+ m = kmm_module_from_handle(vm);\r
+\r
+ ZeroMemory(info, sizeof(*info));\r
+\r
+ info->reg.name = m->name;\r
+ info->reg.path = m->path;\r
+ info->reg.vendor = m->vendor;\r
+\r
+ info->reg.n_plugins = m->plugin_count;\r
+\r
+ info->state = m->state;\r
+\r
+ info->h_module = vm;\r
+ kmm_hold_module(vm);\r
+\r
+ rv = KHM_ERROR_SUCCESS;\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_release_module_info_i(kmm_module_info * info) {\r
+ if (info->h_module)\r
+ kmm_release_module(info->h_module);\r
+\r
+ ZeroMemory(info, sizeof(*info));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_unload_module(kmm_module module)\r
+{\r
+ if(!kmm_is_module(module))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ kmm_hold_module(module);\r
+ kmq_post_message(KMSG_KMM, \r
+ KMSG_KMM_I_REG, \r
+ KMM_REG_EXIT_MODULE, \r
+ (void *) kmm_module_from_handle(module));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmm_load_default_modules(void) {\r
+ khm_handle csm = NULL;\r
+ khm_int32 rv;\r
+ wchar_t * ll = NULL;\r
+ wchar_t *str;\r
+ wchar_t buf[KMM_MAXCCH_NAME];\r
+ khm_size s;\r
+\r
+ rv = kmm_get_modules_config(0, &csm);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_mr0(KHERR_NONE, MSG_LOAD_DEFAULT);\r
+ _describe();\r
+\r
+ rv = khc_read_multi_string(csm, KMM_VALNAME_LOADLIST, NULL, &s);\r
+ if(rv != KHM_ERROR_TOO_LONG)\r
+ goto _exit;\r
+\r
+ ll = malloc(s);\r
+ rv = khc_read_multi_string(csm, KMM_VALNAME_LOADLIST, ll, &s);\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ kmmint_add_to_module_queue();\r
+\r
+ str = ll;\r
+ while(str && *str) {\r
+ if(SUCCEEDED(StringCbCopy(buf, sizeof(buf), str))) {\r
+ kmm_load_module(buf, 0, NULL);\r
+ }\r
+ str = multi_string_next(str);\r
+ }\r
+\r
+ kmmint_remove_from_module_queue();\r
+\r
+_exit:\r
+ if(ll)\r
+ free(ll);\r
+ if(csm)\r
+ khc_close_space(csm);\r
+\r
+ _end_task();\r
+\r
+ return rv;\r
+}\r
+\r
+#ifdef _WIN32\r
+KHMEXP HMODULE KHMAPI kmm_get_hmodule(kmm_module m)\r
+{\r
+ if(!kmm_is_module(m))\r
+ return NULL;\r
+ else\r
+ return kmm_module_from_handle(m)->h_module;\r
+}\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmminternal.h>\r
+\r
+/* Called with no locks held to get a kmm_plugin_i structure\r
+ that matches the name. First we look in the hash table, and\r
+ if one isn't found, we create an empty one.\r
+*/\r
+\r
+kmm_plugin_i * \r
+kmm_get_plugin_i(wchar_t * name)\r
+{\r
+ kmm_plugin_i * p;\r
+ size_t cb;\r
+\r
+ if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb)))\r
+ return NULL;\r
+ cb += sizeof(wchar_t);\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name);\r
+\r
+ if(p == NULL) {\r
+ p = malloc(sizeof(kmm_plugin_i));\r
+ ZeroMemory(p, sizeof(kmm_plugin_i));\r
+ p->magic = KMM_PLUGIN_MAGIC;\r
+ p->p.name = malloc(cb);\r
+ StringCbCopy(p->p.name, cb, name);\r
+ p->state = KMM_PLUGIN_STATE_NONE;\r
+\r
+ hash_add(hash_plugins, (void *) p->p.name, (void *) p);\r
+ kmm_list_plugin(p);\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return p;\r
+}\r
+\r
+kmm_plugin_i * \r
+kmm_find_plugin_i(wchar_t * name)\r
+{\r
+ kmm_plugin_i * p;\r
+ size_t cb;\r
+\r
+ if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb)))\r
+ return NULL;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name);\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return p;\r
+}\r
+\r
+/* the plugin must be delisted before calling this */\r
+void \r
+kmm_list_plugin(kmm_plugin_i * p)\r
+{\r
+ EnterCriticalSection(&cs_kmm);\r
+ if((p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) ||\r
+ (p->flags & KMM_PLUGIN_FLAG_IN_LIST)) \r
+ {\r
+ RaiseException(2, EXCEPTION_NONCONTINUABLE, 0, NULL);\r
+ }\r
+ p->flags |= KMM_PLUGIN_FLAG_IN_LIST;\r
+ LPUSH(&kmm_listed_plugins, p);\r
+ LeaveCriticalSection(&cs_kmm);\r
+}\r
+\r
+void \r
+kmm_delist_plugin(kmm_plugin_i * p)\r
+{\r
+ EnterCriticalSection(&cs_kmm);\r
+ if(p->flags & KMM_PLUGIN_FLAG_IN_LIST) {\r
+ p->flags &= ~KMM_PLUGIN_FLAG_IN_LIST;\r
+ LDELETE(&kmm_listed_plugins, p);\r
+ }\r
+ if(p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) {\r
+ p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST;\r
+ LDELETE(&(p->module->plugins), p);\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_hold_plugin(kmm_plugin p)\r
+{\r
+ kmm_plugin_i * pi;\r
+\r
+ if(!kmm_is_plugin(p))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ pi = kmm_plugin_from_handle(p);\r
+ pi->refcount++;\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/* called with cs_kmm held */\r
+void \r
+kmm_free_plugin(kmm_plugin_i * pi)\r
+{\r
+ int i;\r
+ pi->magic = 0;\r
+\r
+ hash_del(hash_plugins, (void *) pi->p.name);\r
+\r
+ kmm_delist_plugin(pi);\r
+\r
+ for(i=0; i<pi->n_dependants; i++) {\r
+ kmm_release_plugin(kmm_handle_from_plugin(pi->dependants[i]));\r
+ pi->dependants[i] = NULL;\r
+ }\r
+\r
+ if(pi->module) {\r
+ kmm_release_module(kmm_handle_from_module(pi->module));\r
+ }\r
+\r
+ pi->module = NULL;\r
+ pi->p.module = NULL;\r
+\r
+ if(pi->p.name)\r
+ free(pi->p.name);\r
+ pi->p.name = NULL;\r
+\r
+ if(pi->p.description)\r
+ free(pi->p.description);\r
+ pi->p.description = NULL;\r
+\r
+ if(pi->p.dependencies)\r
+ free(pi->p.dependencies);\r
+ pi->p.dependencies = NULL;\r
+\r
+ free(pi);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ kmm_plugin_i * pi;\r
+ khm_handle csp_plugin;\r
+\r
+ if (!info)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ if (!kmm_is_plugin(p)) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _cleanup;\r
+ }\r
+\r
+ pi = kmm_plugin_from_handle(p);\r
+\r
+ ZeroMemory(info, sizeof(*info));\r
+\r
+ info->reg = pi->p;\r
+ info->reg.msg_proc = NULL;\r
+\r
+ if (KHM_FAILED(kmm_get_plugin_config(pi->p.name, KHM_PERM_READ,\r
+ &csp_plugin))) {\r
+ info->failure_count = 0;\r
+ *((khm_int64 *)&info->failure_time) = 0;\r
+ info->failure_reason = 0;\r
+ } else {\r
+ if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureCount",\r
+ &info->failure_count)))\r
+ info->failure_count = 0;\r
+ if (KHM_FAILED(khc_read_int64(csp_plugin, L"FailureTime",\r
+ (khm_int64 *) &info->failure_time)))\r
+ *((khm_int64 *) &info->failure_time) = 0;\r
+ if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureReason",\r
+ &info->failure_reason)))\r
+ info->failure_reason = 0;\r
+\r
+ khc_close_space(csp_plugin);\r
+ }\r
+\r
+ info->state = pi->state;\r
+\r
+ info->h_plugin = p;\r
+ kmm_hold_plugin(p);\r
+\r
+ _cleanup:\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_release_plugin_info_i(kmm_plugin_info * info) {\r
+ khm_int32 rv;\r
+\r
+ if (!info || !info->h_plugin)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ rv = kmm_release_plugin(info->h_plugin);\r
+\r
+ ZeroMemory(info, sizeof(info));\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ kmm_plugin_i * pi;\r
+ kmm_plugin_i * pi_next = NULL;\r
+ kmm_module_i * m;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ if (p == NULL) {\r
+ if (kmm_listed_plugins)\r
+ pi_next = kmm_listed_plugins;\r
+ else {\r
+ for (m = kmm_all_modules; m; m = LNEXT(m)) {\r
+ if (m->plugins) {\r
+ pi_next = m->plugins;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ } else if (kmm_is_plugin(p)) {\r
+ pi = kmm_plugin_from_handle(p);\r
+ pi_next = LNEXT(pi);\r
+\r
+ if (!pi_next) {\r
+ /* we have either exhausted the listed plugins or we are\r
+ at the end of the module's plugin list */\r
+ if (pi->module) {\r
+ m = LNEXT(pi->module);\r
+ } else {\r
+ m = kmm_all_modules;\r
+ }\r
+\r
+ for(; m; m = LNEXT(m)) {\r
+ if (m->plugins) {\r
+ pi_next = m->plugins;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (pi_next) {\r
+ *p_next = kmm_handle_from_plugin(pi_next);\r
+ kmm_hold_plugin(*p_next);\r
+ } else {\r
+ *p_next = NULL;\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_kmm);\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_release_plugin(kmm_plugin p)\r
+{\r
+ kmm_plugin_i * pi;\r
+\r
+ if(!kmm_is_plugin(p))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ pi = kmm_plugin_from_handle(p);\r
+ pi->refcount--;\r
+ if(pi->refcount == 0) {\r
+ kmm_free_plugin(pi);\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin)\r
+{\r
+ kmm_module_i * m;\r
+ kmm_plugin_i * p;\r
+ size_t cb_name = 0;\r
+ size_t cb_desc = 0;\r
+ size_t cb_dep = 0;\r
+\r
+ m = kmm_module_from_handle(module);\r
+\r
+ /* can only called when handing init_module() */\r
+ if(m->state != KMM_MODULE_STATE_INIT)\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+ if(!plugin || \r
+ FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t), &cb_name)) ||\r
+ (plugin->description && \r
+ FAILED(StringCbLength(plugin->description, KMM_MAXCB_DESC - sizeof(wchar_t), &cb_desc))) ||\r
+ (plugin->dependencies && \r
+ KHM_FAILED(multi_string_length_cb(plugin->dependencies, KMM_MAXCB_DEPS, &cb_dep)))\r
+ )\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ cb_name += sizeof(wchar_t);\r
+ cb_desc += sizeof(wchar_t);\r
+\r
+ p = kmm_get_plugin_i(plugin->name);\r
+\r
+ /* released below or in kmm_init_module() */\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+\r
+ if(p->state != KMM_PLUGIN_STATE_NONE &&\r
+ p->state != KMM_PLUGIN_STATE_PLACEHOLDER)\r
+ {\r
+ kmm_release_plugin(kmm_handle_from_plugin(p));\r
+ return KHM_ERROR_DUPLICATE;\r
+ }\r
+\r
+ /* released when the plugin quits */\r
+ kmm_hold_module(module);\r
+\r
+ p->module = m;\r
+ p->p.flags = plugin->flags;\r
+ p->p.msg_proc = plugin->msg_proc;\r
+ p->p.type = plugin->type;\r
+\r
+ if(plugin->description) {\r
+ p->p.description = malloc(cb_desc);\r
+ StringCbCopy(p->p.description, cb_desc, plugin->description);\r
+ } else\r
+ p->p.description = NULL;\r
+\r
+ if(plugin->dependencies) {\r
+ p->p.dependencies = malloc(cb_dep);\r
+ multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies);\r
+ } else\r
+ p->p.dependencies = NULL;\r
+\r
+ p->p.module = p->module->name;\r
+\r
+ p->p.icon = plugin->icon;\r
+\r
+ p->state = KMM_PLUGIN_STATE_REG;\r
+\r
+ kmm_delist_plugin(p);\r
+ EnterCriticalSection(&cs_kmm);\r
+ LPUSH(&(m->plugins), p);\r
+ p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST;\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ /* leave the plugin held because it is in the module's plugin list */\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmminternal.h>\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_module_info(wchar_t * module_name, khm_int32 flags, \r
+ kmm_module_info * buffer, khm_size * cb_buffer)\r
+{\r
+ /*TODO:Implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugin_info(wchar_t * plugin_name, \r
+ kmm_plugin_info * buffer, khm_size * cb_buffer)\r
+{\r
+ /*TODO:Implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugins_config(khm_int32 flags, khm_handle * result) {\r
+ khm_handle csp_root;\r
+ khm_handle csp_plugins;\r
+ khm_int32 rv;\r
+\r
+ rv = khc_open_space(KHM_INVALID_HANDLE, KMM_CSNAME_ROOT, flags, &csp_root);\r
+\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = khc_open_space(csp_root, KMM_CSNAME_PLUGINS, flags, &csp_plugins);\r
+ khc_close_space(csp_root);\r
+\r
+ if(KHM_SUCCEEDED(rv))\r
+ *result = csp_plugins;\r
+ else\r
+ *result = NULL;\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_modules_config(khm_int32 flags, khm_handle * result) {\r
+ khm_handle croot;\r
+ khm_handle kmm_all_modules;\r
+ khm_int32 rv;\r
+\r
+ rv = khc_open_space(NULL, KMM_CSNAME_ROOT, flags, &croot);\r
+\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = khc_open_space(croot, KMM_CSNAME_MODULES, flags, &kmm_all_modules);\r
+ khc_close_space(croot);\r
+\r
+ if(KHM_SUCCEEDED(rv))\r
+ *result = kmm_all_modules;\r
+ else\r
+ *result = NULL;\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result)\r
+{\r
+ khm_handle csplugins;\r
+ khm_handle csplugin;\r
+ khm_int32 rv;\r
+\r
+ if(!plugin || wcschr(plugin, L'/') || wcschr(plugin, L'\\'))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(KHM_FAILED(kmm_get_plugins_config(flags, &csplugins)))\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ rv = khc_open_space(csplugins, plugin, flags, &csplugin);\r
+ *result = csplugin;\r
+\r
+ khc_close_space(csplugins);\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result)\r
+{\r
+ khm_handle csmodules;\r
+ khm_handle csmodule;\r
+ khm_int32 rv;\r
+\r
+ if(!module || wcschr(module, L'/') || wcschr(module, L'\\'))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(KHM_FAILED(kmm_get_modules_config(flags, &csmodules)))\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ rv = khc_open_space(csmodules, module, flags, &csmodule);\r
+ *result = csmodule;\r
+\r
+ khc_close_space(csmodules);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle csp_plugin = NULL;\r
+ khm_handle csp_module = NULL;\r
+ size_t cch;\r
+\r
+ /* avoid accidently creating the module key if it doesn't exist */\r
+ config_flags &= ~KHM_FLAG_CREATE;\r
+\r
+ if((plugin == NULL) ||\r
+ (plugin->dependencies && \r
+ KHM_FAILED(multi_string_length_cch(plugin->dependencies, KMM_MAXCCH_DEPS, &cch))) ||\r
+ FAILED(StringCchLength(plugin->module, KMM_MAXCCH_NAME - 1, &cch)) ||\r
+ (plugin->description && \r
+ FAILED(StringCchLength(plugin->description, KMM_MAXCCH_DESC - 1, &cch))) ||\r
+ FAILED(StringCchLength(plugin->name, KMM_MAXCCH_NAME - 1, &cch)))\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ /* note that we are retaining the length of the plugin name in\r
+ chars in cch */\r
+ cch ++;\r
+\r
+#define CKRV if(KHM_FAILED(rv)) goto _exit\r
+\r
+ rv = kmm_get_plugin_config(plugin->name, \r
+ config_flags | KHM_FLAG_CREATE, &csp_plugin);\r
+ CKRV;\r
+\r
+ /* should fail if the module key doesn't exist */\r
+ rv = kmm_get_module_config(plugin->module, config_flags, &csp_module);\r
+ CKRV;\r
+\r
+ /*TODO: Make sure that the module registration is in the same\r
+ config store as the one in which the plugin is going to be\r
+ registered */\r
+\r
+ rv = khc_write_string(csp_plugin, L"Module", plugin->module);\r
+ CKRV;\r
+ if(plugin->description) {\r
+ rv = khc_write_string(csp_plugin, L"Description", plugin->description);\r
+ CKRV;\r
+ }\r
+ if(plugin->dependencies) {\r
+ rv = khc_write_multi_string(csp_plugin, L"Dependencies", plugin->dependencies);\r
+ CKRV;\r
+ }\r
+ rv = khc_write_int32(csp_plugin, L"Type", plugin->type);\r
+ CKRV;\r
+ rv = khc_write_int32(csp_plugin, L"Flags", plugin->flags);\r
+ CKRV;\r
+\r
+ {\r
+ khm_size cb = 0;\r
+ wchar_t * pl = NULL;\r
+ size_t scb = 0;\r
+\r
+ rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb);\r
+ if(rv != KHM_ERROR_TOO_LONG)\r
+ goto _exit;\r
+\r
+ cb += cch * sizeof(wchar_t);\r
+ scb = cb;\r
+\r
+ pl = malloc(cb);\r
+\r
+ rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb);\r
+ if(KHM_FAILED(rv)) {\r
+ if(pl)\r
+ free(pl);\r
+ goto _exit;\r
+ }\r
+\r
+ if(!multi_string_find(pl, plugin->name, 0)) {\r
+ multi_string_append(pl, &scb, plugin->name);\r
+ rv = khc_write_multi_string(csp_module, L"PluginList", pl);\r
+ }\r
+\r
+ free(pl);\r
+ CKRV;\r
+ }\r
+\r
+#undef CKRV\r
+\r
+_exit:\r
+ if(csp_plugin)\r
+ khc_close_space(csp_plugin);\r
+ if(csp_module)\r
+ khc_close_space(csp_module);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_register_module(kmm_module_reg * module, khm_int32 config_flags)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle csp_module = NULL;\r
+ size_t cch;\r
+ int i;\r
+\r
+ if((module == NULL) ||\r
+ FAILED(StringCchLength(module->name, KMM_MAXCCH_NAME - 1, &cch)) ||\r
+ (module->description && \r
+ FAILED(StringCchLength(module->description, KMM_MAXCCH_DESC - 1, &cch))) ||\r
+ FAILED(StringCchLength(module->path, MAX_PATH, &cch)) ||\r
+ (module->n_plugins > 0 && module->plugin_reg_info == NULL))\r
+ {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+#define CKRV if(KHM_FAILED(rv)) goto _exit\r
+\r
+ rv = kmm_get_module_config(module->name, config_flags | KHM_FLAG_CREATE, &csp_module);\r
+ CKRV;\r
+\r
+ if(module->description) {\r
+ rv = khc_write_string(csp_module, L"Description", module->description);\r
+ CKRV;\r
+ }\r
+ rv = khc_write_string(csp_module, L"ImagePath", module->path);\r
+ CKRV;\r
+\r
+ rv = khc_write_int32(csp_module, L"Flags", 0);\r
+ CKRV;\r
+\r
+ /* FileVersion and ProductVersion will be set when the module\r
+ is loaded for the first time */\r
+\r
+ for(i=0; i<module->n_plugins; i++) {\r
+ rv = kmm_register_plugin(module->plugin_reg_info + i, config_flags);\r
+ CKRV;\r
+ }\r
+\r
+#undef CKRV\r
+_exit:\r
+ if(csp_module)\r
+ khc_close_space(csp_module);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags)\r
+{\r
+ /*TODO: implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+kmm_unregister_module(wchar_t * module, khm_int32 config_flags)\r
+{\r
+ /*TODO: implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmminternal.h>\r
+\r
+static LONG pending_modules = 0;\r
+static LONG pending_plugins = 0;\r
+static LONG startup_signal = 0;\r
+static BOOL load_done = FALSE;\r
+\r
+void\r
+kmmint_check_completion(void) {\r
+ if (pending_modules == 0 &&\r
+ pending_plugins == 0 &&\r
+ InterlockedIncrement(&startup_signal) == 1) {\r
+\r
+ load_done = TRUE;\r
+ kmq_post_message(KMSG_KMM, KMSG_KMM_I_DONE, 0, 0);\r
+ }\r
+}\r
+\r
+void\r
+kmmint_add_to_module_queue(void) {\r
+ InterlockedIncrement(&pending_modules);\r
+}\r
+\r
+void\r
+kmmint_remove_from_module_queue(void) {\r
+\r
+ InterlockedDecrement(&pending_modules);\r
+\r
+ kmmint_check_completion();\r
+}\r
+\r
+void\r
+kmmint_add_to_plugin_queue(void) {\r
+ InterlockedIncrement(&pending_plugins);\r
+}\r
+\r
+void\r
+kmmint_remove_from_plugin_queue(void) {\r
+ InterlockedDecrement(&pending_plugins);\r
+\r
+ kmmint_check_completion();\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI\r
+kmm_load_pending(void) {\r
+ return !load_done;\r
+}\r
+\r
+/*! \internal\r
+ \brief Message handler for the registrar thread. */\r
+khm_boolean KHMAPI kmm_reg_cb(\r
+ khm_int32 msg_type, \r
+ khm_int32 msg_sub_type, \r
+ khm_ui_4 uparam,\r
+ void *vparam)\r
+{\r
+ /* we should only be getting <KMSG_KMM,KMSG_KMM_I_REG> anyway */\r
+ if(msg_type != KMSG_KMM || msg_sub_type != KMSG_KMM_I_REG)\r
+ return FALSE;\r
+\r
+ switch(uparam) {\r
+ case KMM_REG_INIT_MODULE:\r
+ kmm_init_module((kmm_module_i *) vparam);\r
+ kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam));\r
+ break;\r
+\r
+ case KMM_REG_EXIT_MODULE:\r
+ kmm_exit_module((kmm_module_i *) vparam);\r
+ kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam));\r
+ break;\r
+\r
+ case KMM_REG_INIT_PLUGIN:\r
+ kmm_init_plugin((kmm_plugin_i *) vparam);\r
+ kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam));\r
+ break;\r
+\r
+ case KMM_REG_EXIT_PLUGIN:\r
+ kmm_exit_plugin((kmm_plugin_i *) vparam);\r
+ kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam));\r
+ break;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/*! \internal\r
+ \brief The registrar thread.\r
+\r
+ The only thing this function does is to dispatch messages to the\r
+ callback routine ( kmm_reg_cb() ) */\r
+DWORD WINAPI kmm_registrar(\r
+ LPVOID lpParameter\r
+)\r
+{\r
+ tid_registrar = GetCurrentThreadId();\r
+\r
+ kmq_subscribe(KMSG_KMM, kmm_reg_cb);\r
+ kmq_subscribe(KMSG_SYSTEM, kmm_reg_cb);\r
+\r
+ SetEvent(evt_startup);\r
+\r
+ while(KHM_SUCCEEDED(kmq_dispatch(INFINITE)));\r
+\r
+ ExitThread(0);\r
+ /* not reached */\r
+ return 0;\r
+}\r
+\r
+/*! \internal\r
+ \brief Manages a plugin message thread.\r
+\r
+ Each plugin gets its own plugin thread which is used to dispatch\r
+ messages to the plugin. This acts as the thread function for the\r
+ plugin thread.*/\r
+DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter)\r
+{\r
+ DWORD rv = 0;\r
+ kmm_plugin_i * p = (kmm_plugin_i *) lpParameter;\r
+\r
+ TlsSetValue(tls_kmm, (LPVOID) p);\r
+\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+\r
+ p->tid_thread = GetCurrentThreadId();\r
+\r
+ rv = (p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_INIT, 0, (void *) &(p->p)));\r
+\r
+ /* if it fails to initialize, we exit the plugin */\r
+ if(KHM_FAILED(rv)) {\r
+ kmmint_remove_from_plugin_queue();\r
+ rv = 1;\r
+ goto _exit;\r
+ }\r
+\r
+ /* subscribe to default message classes by plugin type */\r
+ if(p->p.type & KHM_PITYPE_CRED) {\r
+ kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc);\r
+ kmq_subscribe(KMSG_KCDB, p->p.msg_proc);\r
+ kmq_subscribe(KMSG_CRED, p->p.msg_proc);\r
+ }\r
+\r
+ if(p->p.flags & KHM_PIFLAG_IDENTITY_PROVIDER) {\r
+ khm_handle h = NULL;\r
+\r
+ kmq_create_subscription(p->p.msg_proc, &h);\r
+ kcdb_identity_set_provider(h);\r
+ /* kcdb deletes the subscription when it's done with it */\r
+ }\r
+\r
+ if(p->p.type == KHM_PITYPE_CONFIG) {\r
+ /*TODO: subscribe to configuration provider messages here */\r
+ }\r
+\r
+ p->state = KMM_PLUGIN_STATE_RUNNING;\r
+\r
+ /* if there were any plugins that were waiting for this one to\r
+ start, we should start them too */\r
+ EnterCriticalSection(&cs_kmm);\r
+ do {\r
+ kmm_plugin_i * pd;\r
+ int i;\r
+\r
+ for(i=0; i < p->n_dependants; i++) {\r
+ pd = p->dependants[i];\r
+\r
+ pd->n_unresolved--;\r
+\r
+ if(pd->n_unresolved == 0) {\r
+ kmm_hold_plugin(kmm_handle_from_plugin(pd));\r
+ kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_INIT_PLUGIN, (void *) pd);\r
+ }\r
+ }\r
+ } while(FALSE);\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ kmmint_remove_from_plugin_queue();\r
+\r
+ /* main message loop */\r
+ while(KHM_SUCCEEDED(kmq_dispatch(INFINITE)));\r
+\r
+ /* unsubscribe from default message classes by plugin type */\r
+ if(p->p.type & KHM_PITYPE_CRED) {\r
+ kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc);\r
+ kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc);\r
+ kmq_unsubscribe(KMSG_CRED, p->p.msg_proc);\r
+ }\r
+\r
+ if(p->p.flags & KHM_PIFLAG_IDENTITY_PROVIDER) {\r
+ kcdb_identity_set_provider(NULL);\r
+ }\r
+\r
+ if(p->p.type == KHM_PITYPE_CONFIG) {\r
+ /*TODO: unsubscribe from configuration provider messages here */\r
+ }\r
+\r
+ p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p));\r
+\r
+_exit:\r
+ p->state = KMM_PLUGIN_STATE_EXITED;\r
+\r
+ /* the following call will automatically release the plugin */\r
+ kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p);\r
+\r
+ TlsSetValue(tls_kmm, (LPVOID) 0);\r
+\r
+ ExitThread(rv);\r
+\r
+ /* not reached */\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+ \brief Initialize a plugin\r
+\r
+ \note If kmm_init_plugin() is called on a plugin, then kmm_exit_plugin()\r
+ \b must be called for the plugin.\r
+\r
+ \note Should only be called from the context of the registrar thread */\r
+void kmm_init_plugin(kmm_plugin_i * p) {\r
+ DWORD dummy;\r
+ khm_handle csp_plugin = NULL;\r
+ khm_handle csp_plugins = NULL;\r
+ khm_int32 t;\r
+\r
+ /* the following will be undone in kmm_exit_plugin() */\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ if(p->state != KMM_PLUGIN_STATE_REG &&\r
+ p->state != KMM_PLUGIN_STATE_HOLD)\r
+ {\r
+ LeaveCriticalSection(&cs_kmm);\r
+ goto _exit;\r
+ }\r
+\r
+ _begin_task(0);\r
+ _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name));\r
+ _describe();\r
+\r
+ if(p->state == KMM_PLUGIN_STATE_HOLD) {\r
+ /* if this plugin was held, then we already had a hold\r
+ from the initial attempt to start the plugin. Undo\r
+ the hold we did a few lines earlier. */\r
+ kmm_release_plugin(kmm_handle_from_plugin(p));\r
+ /* same for the plugin count for the module. */\r
+ p->module->plugin_count--;\r
+ }\r
+\r
+ p->state = KMM_PLUGIN_STATE_PREINIT;\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) {\r
+ _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG);\r
+\r
+ p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin)) ||\r
+ KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t)))\r
+ {\r
+ if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) {\r
+ _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);\r
+\r
+ p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;\r
+ goto _exit;\r
+ }\r
+ \r
+ if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) {\r
+ _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);\r
+\r
+ p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) {\r
+ _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);\r
+\r
+ p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;\r
+ goto _exit;\r
+ }\r
+ }\r
+\r
+ if(t & KMM_PLUGIN_FLAG_DISABLED) {\r
+ _report_mr0(KHERR_ERROR, MSG_IP_DISABLED);\r
+\r
+ p->state = KMM_PLUGIN_STATE_FAIL_DISABLED;\r
+ goto _exit;\r
+ }\r
+\r
+#if 0\r
+ /*TODO: check the failure count and act accordingly */\r
+ if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) {\r
+ }\r
+#endif\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+\r
+ p->n_depends = 0;\r
+ p->n_unresolved = 0;\r
+ \r
+ do {\r
+ wchar_t * deps = NULL;\r
+ wchar_t * d;\r
+ khm_size sz = 0;\r
+\r
+ if(khc_read_multi_string(csp_plugin, L"Dependencies", NULL, &sz) != KHM_ERROR_TOO_LONG)\r
+ break;\r
+\r
+ deps = malloc(sz);\r
+ if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", deps, &sz))) {\r
+ if(deps)\r
+ free(deps);\r
+ break;\r
+ }\r
+\r
+ for(d = deps; d && *d; d = multi_string_next(d)) {\r
+ kmm_plugin_i * pd;\r
+ int i;\r
+\r
+ pd = kmm_get_plugin_i(d);\r
+\r
+ if(pd->state == KMM_PLUGIN_STATE_NONE) {\r
+ /* the dependant was not previously known */\r
+ pd->state = KMM_PLUGIN_STATE_PLACEHOLDER;\r
+ }\r
+\r
+ for(i=0; i<pd->n_dependants; i++) {\r
+ if(pd->dependants[i] == p)\r
+ break;\r
+ }\r
+\r
+ if(i >= pd->n_dependants) {\r
+ if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) {\r
+ /*TODO: handle this gracefully */\r
+ RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL);\r
+ }\r
+\r
+ /* released in kmm_free_plugin() */\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+ pd->dependants[pd->n_dependants] = p;\r
+ pd->n_dependants++;\r
+ }\r
+\r
+ p->n_depends++;\r
+\r
+ if(pd->state != KMM_PLUGIN_STATE_RUNNING) {\r
+ p->n_unresolved++;\r
+ }\r
+ }\r
+\r
+ if(p->n_unresolved > 0) {\r
+ p->state = KMM_PLUGIN_STATE_HOLD;\r
+ }\r
+\r
+ free(deps);\r
+\r
+ } while(FALSE);\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ p->module->plugin_count++;\r
+ kmm_delist_plugin(p);\r
+ kmm_list_plugin(p);\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ if(p->state == KMM_PLUGIN_STATE_HOLD) {\r
+ _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name));\r
+\r
+ goto _exit_post;\r
+ }\r
+\r
+ kmmint_add_to_plugin_queue();\r
+\r
+ p->ht_thread = CreateThread(\r
+ NULL,\r
+ 0,\r
+ kmm_plugin_broker,\r
+ (LPVOID) p,\r
+ CREATE_SUSPENDED,\r
+ &dummy);\r
+\r
+ p->state = KMM_PLUGIN_STATE_INIT;\r
+\r
+ ResumeThread(p->ht_thread);\r
+\r
+_exit_post:\r
+ if(csp_plugin != NULL)\r
+ khc_close_space(csp_plugin);\r
+\r
+ if(csp_plugins != NULL)\r
+ khc_close_space(csp_plugins);\r
+\r
+ _report_mr2(KHERR_INFO, MSG_IP_STATE, \r
+ _dupstr(p->p.name), _int32(p->state));\r
+\r
+ _end_task();\r
+ \r
+ return;\r
+\r
+ /* jump here if an error condition happens before the plugin\r
+ broker thread starts and the plugin should be unloaded */\r
+\r
+_exit:\r
+ if(csp_plugin != NULL)\r
+ khc_close_space(csp_plugin);\r
+ if(csp_plugins != NULL)\r
+ khc_close_space(csp_plugins);\r
+\r
+ _report_mr2(KHERR_WARNING, MSG_IP_EXITING, \r
+ _dupstr(p->p.name), _int32(p->state));\r
+ _end_task();\r
+\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+\r
+ kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p);\r
+}\r
+\r
+/*! \internal\r
+ \brief Uninitialize a plugin\r
+\r
+ In addition to terminating the thread, and removing p from the\r
+ linked list and hashtable, it also frees up p.\r
+ \r
+ \note Should only be called from the context of the registrar thread. */\r
+void kmm_exit_plugin(kmm_plugin_i * p) {\r
+ int np;\r
+\r
+ if(p->state == KMM_PLUGIN_STATE_RUNNING ||\r
+ p->state == KMM_PLUGIN_STATE_INIT)\r
+ {\r
+ kmq_post_thread_quit_message(p->tid_thread, 0, NULL);\r
+ /* when we post the quit message to the plugin thread, the plugin\r
+ broker terminates the plugin and posts a EXIT_PLUGIN message,\r
+ which calls this function again. We just exit here because\r
+ the EXIT_PLUGIN message will end up calling us again momentarily */\r
+ return;\r
+ }\r
+\r
+ if(p->ht_thread) {\r
+ /* wait for the thread to terminate */\r
+ WaitForSingleObject(p->ht_thread, INFINITE);\r
+ p->ht_thread = NULL;\r
+ }\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+\r
+ /* undo reference count done in kmm_init_plugin() */\r
+ if(p->state == KMM_PLUGIN_STATE_EXITED ||\r
+ p->state == KMM_PLUGIN_STATE_HOLD) \r
+ {\r
+ np = --(p->module->plugin_count);\r
+ } else {\r
+ /* the plugin was never active. We can't base a module unload\r
+ decision on np */\r
+ np = TRUE;\r
+ }\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ if(!np) {\r
+ /* if this is the last plugin to exit, then notify the\r
+ registrar that the module should be removed as well */\r
+ kmm_hold_module(kmm_handle_from_module(p->module));\r
+ kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module);\r
+ }\r
+\r
+ /* release the hold obtained in kmm_init_plugin() */\r
+ kmm_release_plugin(kmm_handle_from_plugin(p));\r
+}\r
+\r
+/*! \internal\r
+ \brief Initialize a module\r
+\r
+ \a m is not in the linked list yet.\r
+\r
+ \note Should only be called from the context of the registrar thread. */\r
+void kmm_init_module(kmm_module_i * m) {\r
+ HMODULE hm;\r
+ init_module_t p_init_module;\r
+ kmm_plugin_i * pi;\r
+ khm_int32 rv;\r
+ khm_handle csp_mod = NULL;\r
+ khm_handle csp_mods = NULL;\r
+ khm_size sz;\r
+ khm_int32 i;\r
+\r
+ /* error condition handling */\r
+ BOOL exit_module = FALSE;\r
+ BOOL release_module = TRUE;\r
+ BOOL record_failure = FALSE;\r
+\r
+ /* failure handling */\r
+ khm_int32 max_fail_count = 0;\r
+ khm_int64 fail_reset_time = 0;\r
+\r
+ _begin_task(0);\r
+ _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name));\r
+ _describe();\r
+\r
+ kmm_hold_module(kmm_handle_from_module(m));\r
+\r
+ if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG);\r
+ _location(L"kmm_get_modules_config()");\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_UNKNOWN;\r
+ goto _exit;\r
+ }\r
+\r
+ khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count);\r
+ khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time);\r
+\r
+ /* If the module is not in the pre-init state, we can't\r
+ initialize it. */\r
+ if(m->state != KMM_MODULE_STATE_PREINIT) {\r
+ _report_mr1(KHERR_WARNING, MSG_IM_NOT_PREINIT, _int32(m->state));\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED);\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED;\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Flags", &i))) {\r
+ if(i & KMM_MODULE_FLAG_DISABLED) {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_DISABLED);\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_DISABLED;\r
+ goto _exit;\r
+ }\r
+ }\r
+\r
+ if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) {\r
+ khm_int64 tm;\r
+ khm_int64 ct;\r
+\r
+ /* reset the failure count if the failure count reset time\r
+ period has elapsed */\r
+ tm = 0;\r
+ khc_read_int64(csp_mod, L"FailureTime", &tm);\r
+ GetSystemTimeAsFileTime((LPFILETIME) &ct);\r
+ ct -= tm;\r
+\r
+ if(tm > 0 && \r
+ FtIntervalToSeconds((LPFILETIME) &ct) > fail_reset_time) {\r
+\r
+ i = 0;\r
+ khc_write_int32(csp_mod, L"FailureCount", 0);\r
+ khc_write_int64(csp_mod, L"FailureTime", 0);\r
+\r
+ }\r
+\r
+ if(i > max_fail_count) {\r
+ /* failed too many times */\r
+ _report_mr0(KHERR_ERROR, MSG_IM_MAX_FAIL);\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE;\r
+ goto _exit;\r
+ }\r
+ }\r
+\r
+ if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) == KHM_ERROR_TOO_LONG) {\r
+ if(m->path)\r
+ free(m->path);\r
+ m->path = malloc(sz);\r
+ khc_read_string(csp_mod, L"ImagePath", m->path, &sz);\r
+ } else {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED);\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED;\r
+ goto _exit;\r
+ }\r
+\r
+ if (khc_read_string(csp_mod, L"Vendor", NULL, &sz) == KHM_ERROR_TOO_LONG) {\r
+ if (m->vendor)\r
+ free(m->vendor);\r
+ m->vendor = malloc(sz);\r
+ khc_read_string(csp_mod, L"Vendor", m->vendor, &sz);\r
+ }\r
+\r
+ /* check again */\r
+ if(m->state != KMM_MODULE_STATE_PREINIT) {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT);\r
+\r
+ goto _exit;\r
+ }\r
+\r
+ hm = LoadLibrary(m->path);\r
+ if(!hm) {\r
+ m->h_module = NULL;\r
+ m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND;\r
+ record_failure = TRUE;\r
+\r
+ _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path));\r
+\r
+ goto _exit;\r
+ }\r
+\r
+ /* from this point on, we need to discard the module through\r
+ exit_module */\r
+ release_module = FALSE;\r
+ exit_module = TRUE;\r
+ record_failure = TRUE;\r
+\r
+ m->flags |= KMM_MODULE_FLAG_LOADED;\r
+ m->h_module = hm;\r
+\r
+ /*TODO: check signatures */\r
+\r
+ p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE);\r
+\r
+ if(!p_init_module) {\r
+ _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE));\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_INVALID;\r
+ goto _exit;\r
+ }\r
+\r
+ m->state = KMM_MODULE_STATE_INIT;\r
+\r
+\r
+ /* call init_module() */\r
+ rv = (*p_init_module)(kmm_handle_from_module(m));\r
+\r
+ m->flags |= KMM_MODULE_FLAG_INITP;\r
+\r
+ if(KHM_FAILED(rv)) {\r
+ _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv));\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_LOAD;\r
+ goto _exit;\r
+ }\r
+\r
+ if(!m->plugins) {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS);\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS;\r
+ record_failure = FALSE;\r
+ goto _exit;\r
+ }\r
+\r
+ m->state = KMM_MODULE_STATE_INITPLUG;\r
+\r
+ do {\r
+ LPOP(&(m->plugins), &pi);\r
+ if(pi) {\r
+ pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST;\r
+ kmm_init_plugin(pi);\r
+\r
+ /* release the hold obtained in kmm_provide_plugin() */\r
+ kmm_release_plugin(kmm_handle_from_plugin(pi));\r
+ }\r
+ } while(pi);\r
+\r
+ if(!m->plugin_count) {\r
+ _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS);\r
+\r
+ m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS;\r
+ record_failure = FALSE;\r
+ goto _exit;\r
+ }\r
+\r
+ m->state = KMM_MODULE_STATE_RUNNING;\r
+\r
+ exit_module = FALSE;\r
+ record_failure = FALSE;\r
+\r
+ ResetEvent(evt_exit);\r
+\r
+_exit:\r
+ if(csp_mod) {\r
+ if(record_failure) {\r
+ khm_int64 ct;\r
+\r
+ i = 0;\r
+ khc_read_int32(csp_mod, L"FailureCount", &i);\r
+ i++;\r
+ khc_write_int32(csp_mod, L"FailureCount", i);\r
+\r
+ if(i==1) { /* first fault */\r
+ GetSystemTimeAsFileTime((LPFILETIME) &ct);\r
+ khc_write_int64(csp_mod, L"FailureTime", ct);\r
+ }\r
+ }\r
+ khc_close_space(csp_mod);\r
+ }\r
+ if(csp_mods)\r
+ khc_close_space(csp_mods);\r
+\r
+ _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE, \r
+ _dupstr(m->name), _int32(m->state));\r
+\r
+ if(release_module)\r
+ kmm_release_module(kmm_handle_from_module(m));\r
+\r
+ kmmint_remove_from_module_queue();\r
+\r
+ /* if something went wrong after init_module was called on the\r
+ module code, we need to call exit_module */\r
+ if(exit_module)\r
+ kmm_exit_module(m);\r
+\r
+ _end_task();\r
+}\r
+\r
+\r
+/*! \internal\r
+ \brief Uninitializes a module\r
+\r
+ \note Should only be called from the context of the registrar\r
+ thread */\r
+void kmm_exit_module(kmm_module_i * m) {\r
+ kmm_plugin_i * p;\r
+\r
+ /* exiting a module happens in two stages. \r
+ \r
+ If the module state is running (there are active plugins) then\r
+ those plugins must be exited. This has to be done from the\r
+ plugin threads. The signal for the plugins to exit must be\r
+ issued from the registrar. Therefore, we post messages to the\r
+ registrar for each plugin we want to remove and exit\r
+ kmm_exit_module().\r
+\r
+ When the last plugin is exited, the plugin management code\r
+ automatically signalls the registrar to remove the module.\r
+ kmm_exit_module() gets called again. This is the second\r
+ stage, where we call exit_module() for the module and start\r
+ unloading everything.\r
+ */\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+\r
+ /* get rid of any dangling uninitialized plugins */\r
+ LPOP(&(m->plugins), &p);\r
+ while(p) {\r
+ p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST;\r
+ kmm_exit_plugin(p);\r
+\r
+ /* release hold from kmm_provide_plugin() */\r
+ kmm_release_plugin(kmm_handle_from_plugin(p));\r
+\r
+ LPOP(&(m->plugins), &p);\r
+ }\r
+\r
+ if(m->state == KMM_MODULE_STATE_RUNNING) {\r
+ int np = 0;\r
+\r
+ m->state = KMM_MODULE_STATE_EXITPLUG;\r
+\r
+ p = kmm_listed_plugins;\r
+\r
+ while(p) {\r
+ if(p->module == m) {\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+ kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p);\r
+ np++;\r
+ }\r
+\r
+ p = LNEXT(p);\r
+ }\r
+\r
+ if(np > 0) {\r
+ /* we have to go back and wait for the plugins to exit.\r
+ when the last plugin exits, it automatically posts\r
+ EXIT_MODULE. We can pick up from there when this\r
+ happens. */\r
+ LeaveCriticalSection(&cs_kmm);\r
+ return;\r
+ }\r
+ }\r
+\r
+ if(m->flags & KMM_MODULE_FLAG_INITP)\r
+ {\r
+ exit_module_t p_exit_module;\r
+\r
+ if(m->state > 0)\r
+ m->state = KMM_MODULE_STATE_EXIT;\r
+\r
+ p_exit_module = \r
+ (exit_module_t) GetProcAddress(m->h_module, \r
+ EXP_EXIT_MODULE);\r
+ if(p_exit_module) {\r
+ LeaveCriticalSection(&cs_kmm);\r
+ p_exit_module(kmm_handle_from_module(m));\r
+ EnterCriticalSection(&cs_kmm);\r
+ }\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ if(m->state > 0)\r
+ m->state = KMM_MODULE_STATE_EXITED;\r
+\r
+ if(m->h_module) {\r
+ FreeLibrary(m->h_module);\r
+ }\r
+\r
+ if(m->h_resource && (m->h_resource != m->h_module)) {\r
+ FreeLibrary(m->h_resource);\r
+ }\r
+\r
+ m->h_module = NULL;\r
+ m->h_resource = NULL;\r
+ m->flags = 0;\r
+\r
+ /* release the hold obtained in kmm_init_module() */\r
+ kmm_release_module(kmm_handle_from_module(m));\r
+}\r
--- /dev/null
+Name,Type,Value,Description\r
+PluginManager,KC_SPACE,0,Plugin Manager Configuration\r
+ Plugins,KC_SPACE,0,Plugin Specific configuration\r
+ PluginMaxFailureCount,KC_INT32,3,Maximum number of failure counts before plugin is disabled\r
+ PluginFailureCountResetTime,KC_INT64,36000,Time after first failure at which the failure count is reset\r
+ LoadList,KC_STRING,AfsCred,List of plugins that are active\r
+ _Schema,KC_SPACE,0,Plugin schema\r
+ Module,KC_STRING,<module name>,The name of the module that registered this plugin\r
+ Description,KC_STRING,<Description>,Description of the plugin\r
+ Dependencies,KC_STRING,<Dependencies>,Multi string of plugin names of plugins that this plugin depends on\r
+ Type,KC_INT32,0,The type of the plugin\r
+ Flags,KC_INT32,0,Flags. Currently unused\r
+ FailureCount,KC_INT32,0,Number of failed loads\r
+ FailureTime,KC_INT64,0,FILETIME of first failure\r
+ FailureReason,KC_INT32,0,Reason for first failure. One of the plugin status values.\r
+ Parameters,KC_SPACE,0,Plugin parameters. The schema beyond this is plugin dependent.\r
+ Parameters,KC_ENDSPACE,0,\r
+ _Schema,KC_ENDSPACE,0,\r
+ Plugins,KC_ENDSPACE,0,\r
+ Modules,KC_SPACE,0,Module Specific configuration\r
+ LoadList,KC_STRING,"OpenAFS,MITKrb5,MITKrb4",List of modules to load at startup\r
+ ModuleMaxFailureCount,KC_INT32,3,Maximum number of failure counts before module is disabled\r
+ ModuleFailureCountResetTime,KC_INT64,72000,Time after first failure at which the failure count is reset\r
+ _Schema,KC_SPACE,0,Module schema\r
+ ImagePath,KC_STRING,<Path to the library binary>,Path to the DLL\r
+ Description,KC_STRING,<Description>,Description of the module\r
+ Vendor,KC_STRING,<Vendor string>,Vendor or copyright string\r
+ Flags,KC_INT32,0,Flags. Currently unused.\r
+ FailureCount,KC_INT32,0,Number of failed loads\r
+ FailureTime,KC_INT64,0,FILETIME of first failure\r
+ FailureReason,KC_INT32,0,Reason for first failure. One of the module status values.\r
+ FileVersion,KC_INT64,0,khm_version of file\r
+ ProductVersion,KC_INT64,0,khm_version of product\r
+ PluginList,KC_STRING,<plugins>,List of plugins implemented in the module\r
+ _Schema,KC_ENDSPACE,0,\r
+ OpenAFS,KC_SPACE,0,OpenAFS Module\r
+ ImagePath,KC_STRING,afscred.dll,\r
+ PluginList,KC_STRING,AfsCred,\r
+ Vendor,KC_STRING,OpenAFS.org,\r
+ OpenAFS,KC_ENDSPACE,0,\r
+ MITKrb5,KC_SPACE,0,MIT Kerberos V\r
+ ImagePath,KC_STRING,krb5cred.dll,\r
+ PluginList,KC_STRING,Krb5Cred,\r
+ Vendor,KC_STRING,Massachusetts Institute of Technology,\r
+ MITKrb5,KC_ENDSPACE,0,\r
+ MITKrb4,KC_SPACE,0,MIT Kerberos IV\r
+ ImagePath,KC_STRING,krb4cred.dll,\r
+ PluginList,KC_STRING,Krb4Cred,\r
+ Vendor,KC_STRING,Massachusetts Institute of Technology,\r
+ MITKrb4,KC_ENDSPACE,0,\r
+ Modules,KC_ENDSPACE,0,\r
+PluginManager,KC_ENDSPACE,0,\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KMMINTERNAL_H\r
+#define __KHIMAIRA_KMMINTERNAL_H\r
+\r
+#include<windows.h>\r
+#include<strsafe.h>\r
+\r
+#define KHERR_FACILITY kmm_facility\r
+#define KHERR_FACILITY_ID KHM_FACILITY_KMM\r
+#define KHERR_HMODULE ((HMODULE) kmm_hInstance)\r
+#include<kherr.h>\r
+\r
+#include<kmm.h>\r
+#include<khmsgtypes.h>\r
+#include<kherror.h>\r
+#include<kplugin.h>\r
+#include<utils.h>\r
+#include<kconfig.h>\r
+#include<kcreddb.h>\r
+#include<kmm_msgs.h>\r
+\r
+\r
+struct kmm_plugin_i_t; /* forward dcl */\r
+\r
+typedef struct kmm_module_i_t {\r
+ khm_int32 magic;\r
+\r
+ wchar_t * name;\r
+ wchar_t * path;\r
+\r
+ wchar_t * vendor;\r
+\r
+ HMODULE h_module;\r
+\r
+ HMODULE h_resource;\r
+ WORD lcid_resource;\r
+\r
+ khm_int32 flags;\r
+ khm_int32 state;\r
+ khm_int32 plugin_count; /* number of active plugins */\r
+\r
+ void * version_info;\r
+\r
+ khm_int32 refcount;\r
+\r
+ struct kmm_plugin_i_t * plugins; /* only used for registration */\r
+\r
+ LDCL(struct kmm_module_i_t);\r
+} kmm_module_i;\r
+\r
+#define KMM_MODULE_MAGIC 0x482f4e88\r
+\r
+#define kmm_is_module(m) ((m) && ((kmm_module_i *)m)->magic == KMM_MODULE_MAGIC)\r
+\r
+#define kmm_module_from_handle(m) ((kmm_module_i *) m)\r
+#define kmm_handle_from_module(m) ((kmm_module) m)\r
+\r
+/* the resources have been loaded */\r
+#define KMM_MODULE_FLAG_RES_LOADED 8\r
+\r
+/* the signature has been verified */\r
+#define KMM_MODULE_FLAG_SIG 16\r
+\r
+/* LoadLibrary succeeded for module */\r
+#define KMM_MODULE_FLAG_LOADED 1\r
+\r
+/* init_module entry called */\r
+#define KMM_MODULE_FLAG_INITP 2\r
+\r
+/* the module is disabled by the user\r
+ (option specifed in configuration) */\r
+#define KMM_MODULE_FLAG_DISABLED 1024\r
+\r
+typedef struct kmm_plugin_i_t {\r
+ kmm_plugin_reg p;\r
+\r
+ khm_int32 magic;\r
+\r
+ kmm_module_i * module;\r
+ HANDLE ht_thread;\r
+ DWORD tid_thread;\r
+\r
+ khm_int32 state;\r
+ khm_int32 flags;\r
+ \r
+ int refcount;\r
+\r
+ int n_depends;\r
+ int n_unresolved;\r
+ struct kmm_plugin_i_t * dependants[KMM_MAX_DEPENDANTS];\r
+ int n_dependants;\r
+\r
+ LDCL(struct kmm_plugin_i_t);\r
+} kmm_plugin_i;\r
+\r
+#define KMM_PLUGIN_MAGIC 0x320e8fb4\r
+\r
+#define kmm_is_plugin(p) ((p) && ((kmm_plugin_i *) (p))->magic == KMM_PLUGIN_MAGIC)\r
+\r
+#define kmm_handle_from_plugin(p) ((kmm_plugin) p)\r
+#define kmm_plugin_from_handle(ph) ((kmm_plugin_i *) ph)\r
+\r
+/* the plugin has already been marked for unload */\r
+#define KMM_PLUGIN_FLAG_UNLOAD 1\r
+\r
+/* the plugin is disabled by the user\r
+ (option specified in configuration) */\r
+#define KMM_PLUGIN_FLAG_DISABLED 1024\r
+\r
+/* the plugin is in the kmm_listed_plugins list */\r
+#define KMM_PLUGIN_FLAG_IN_LIST 2\r
+\r
+/* the plugin is in the module's plugin list */\r
+#define KMM_PLUGIN_FLAG_IN_MODLIST 4\r
+\r
+enum kmm_registrar_uparam_t {\r
+ KMM_REG_INIT_MODULE,\r
+ KMM_REG_EXIT_MODULE,\r
+ KMM_REG_INIT_PLUGIN,\r
+ KMM_REG_EXIT_PLUGIN\r
+};\r
+\r
+extern kmm_module_i * kmm_all_modules;\r
+extern kmm_plugin_i * kmm_listed_plugins;\r
+extern HANDLE ht_registrar;\r
+extern DWORD tid_registrar;\r
+extern DWORD tls_kmm;\r
+\r
+extern hashtable * hash_plugins;\r
+extern hashtable * hash_modules;\r
+\r
+extern CRITICAL_SECTION cs_kmm;\r
+extern int ready;\r
+extern HANDLE evt_startup;\r
+extern HANDLE evt_exit;\r
+extern const wchar_t * kmm_facility;\r
+\r
+extern HINSTANCE kmm_hInstance;\r
+\r
+extern kconf_schema schema_kmmconfig[];\r
+\r
+/* Registrar */\r
+\r
+khm_boolean KHMAPI \r
+kmm_reg_cb(khm_int32 msg_type, \r
+ khm_int32 msg_sub_type, \r
+ khm_ui_4 uparam,\r
+ void *vparam);\r
+\r
+DWORD WINAPI kmm_registrar(LPVOID lpParameter);\r
+\r
+DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter);\r
+\r
+void kmm_init_plugin(kmm_plugin_i * p);\r
+void kmm_exit_plugin(kmm_plugin_i * p);\r
+void kmm_init_module(kmm_module_i * m);\r
+void kmm_exit_module(kmm_module_i * m);\r
+\r
+/* Modules */\r
+kmm_module_i * kmm_get_module_i(wchar_t * name);\r
+kmm_module_i * kmm_find_module_i(wchar_t * name);\r
+void kmm_free_module(kmm_module_i * m);\r
+\r
+/* Plugins */\r
+kmm_plugin_i * kmm_get_plugin_i(wchar_t * name);\r
+kmm_plugin_i * kmm_find_plugin_i(wchar_t * name);\r
+void kmm_free_plugin(kmm_plugin_i * pi);\r
+void kmm_list_plugin(kmm_plugin_i * p);\r
+void kmm_delist_plugin(kmm_plugin_i * p);\r
+\r
+khm_boolean kmm_load_locale_lib(kmm_module_i * m, kmm_module_locale * l);\r
+\r
+#define KMM_CSNAME_ROOT L"PluginManager"\r
+#define KMM_CSNAME_PLUGINS L"Plugins"\r
+#define KMM_CSNAME_MODULES L"Modules"\r
+#define KMM_VALNAME_LOADLIST L"LoadList"\r
+\r
+void\r
+kmmint_add_to_module_queue(void);\r
+\r
+void\r
+kmmint_remove_from_module_queue(void);\r
+\r
+#define _WAIT_FOR_START \\r
+ do { \\r
+ if(ready) break; \\r
+ WaitForSingleObject(evt_startup, INFINITE); \\r
+ } while(0)\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmminternal.h>\r
+\r
+kmm_module_i * kmm_all_modules = NULL;\r
+kmm_plugin_i * kmm_listed_plugins = NULL;\r
+\r
+HANDLE ht_registrar = NULL;\r
+DWORD tid_registrar = 0;\r
+DWORD tls_kmm = 0;\r
+\r
+#define KMM_HASH_SIZE 31\r
+hashtable * hash_plugins = NULL;\r
+hashtable * hash_modules = NULL;\r
+\r
+CRITICAL_SECTION cs_kmm;\r
+HANDLE evt_startup = NULL;\r
+HANDLE evt_exit = NULL;\r
+int ready = 0;\r
+\r
+HINSTANCE kmm_hInstance;\r
+const wchar_t * kmm_facility = L"KMM";\r
+\r
+KHMEXP void KHMAPI kmm_init(void)\r
+{\r
+ DWORD dummy;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+ kmm_all_modules = NULL;\r
+ kmm_listed_plugins = NULL;\r
+\r
+ tls_kmm = TlsAlloc();\r
+\r
+ hash_plugins = hash_new_hashtable(\r
+ KMM_HASH_SIZE, \r
+ hash_string, \r
+ hash_string_comp, \r
+ NULL, \r
+ NULL);\r
+\r
+ hash_modules = hash_new_hashtable(\r
+ KMM_HASH_SIZE,\r
+ hash_string,\r
+ hash_string_comp,\r
+ NULL,\r
+ NULL);\r
+\r
+ ht_registrar = CreateThread(\r
+ NULL,\r
+ 0,\r
+ kmm_registrar,\r
+ NULL,\r
+ 0,\r
+ &dummy);\r
+\r
+ _WAIT_FOR_START;\r
+\r
+ khc_load_schema(NULL, schema_kmmconfig);\r
+\r
+ LeaveCriticalSection(&cs_kmm);\r
+}\r
+\r
+KHMEXP void KHMAPI kmm_exit(void)\r
+{\r
+ kmm_module_i * m;\r
+ kmm_plugin_i * p;\r
+\r
+ EnterCriticalSection(&cs_kmm);\r
+\r
+ p = kmm_listed_plugins;\r
+ while(p) {\r
+ kmm_plugin_i * pn;\r
+\r
+ pn = LNEXT(p);\r
+ /* plugins that were never resolved should be kicked off\r
+ the list. Flipping the refcount will do that if no\r
+ other references exist for the plugin */\r
+ if(p->state == KMM_PLUGIN_STATE_PLACEHOLDER) {\r
+ kmm_hold_plugin(kmm_handle_from_plugin(p));\r
+ kmm_release_plugin(kmm_handle_from_plugin(p));\r
+ }\r
+\r
+ p = pn;\r
+ }\r
+\r
+ m = kmm_all_modules;\r
+ while(m) {\r
+ kmm_unload_module(kmm_handle_from_module(m));\r
+ m = LNEXT(m);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_kmm);\r
+ WaitForSingleObject(evt_exit, INFINITE);\r
+ EnterCriticalSection(&cs_kmm);\r
+\r
+ kmq_post_thread_quit_message(tid_registrar, 0, NULL);\r
+\r
+ hash_del_hashtable(hash_plugins);\r
+ hash_del_hashtable(hash_modules);\r
+\r
+ LeaveCriticalSection(&cs_kmm);\r
+\r
+ TlsFree(tls_kmm);\r
+\r
+ tls_kmm = 0;\r
+}\r
+\r
+void kmm_dll_init(void)\r
+{\r
+ InitializeCriticalSection(&cs_kmm);\r
+ evt_startup = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+ evt_exit = CreateEvent(NULL, TRUE, TRUE, NULL);\r
+}\r
+\r
+void kmm_dll_exit(void)\r
+{\r
+ DeleteCriticalSection(&cs_kmm);\r
+ if(evt_startup)\r
+ CloseHandle(evt_startup);\r
+ evt_startup = NULL;\r
+}\r
+\r
+void \r
+kmm_process_attach(HINSTANCE hinstDLL) {\r
+ kmm_hInstance = hinstDLL;\r
+ kmm_dll_init();\r
+}\r
+\r
+void\r
+kmm_process_detach(void) {\r
+ kmm_dll_exit();\r
+}\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KPLUGIN_H\r
+#define __KHIMAIRA_KPLUGIN_H\r
+\r
+#include<kmm.h>\r
+#include<kherror.h>\r
+\r
+/*! \addtogroup kmm\r
+@{*/\r
+/*! \defgroup kplugin NetIDMgr Plugin Callbacks\r
+\r
+See the following related documentation pages for more information \r
+about NetIDMgr plugins.\r
+\r
+These are prototypes of functions that must be implemented by a NetIDMgr\r
+plugin.\r
+\r
+- \ref plugins\r
+@{*/\r
+\r
+/*! \brief Initialize the module\r
+\r
+ This is the first callback function to be called in a module.\r
+ Perform all the required intialization when this is called. As\r
+ mentioned in \ref plugins, you should not attempt to call any\r
+ NetIDMgr API function from DLLMain or other initialization code\r
+ other than this one.\r
+\r
+ You should use this call back to register the plugins that will be\r
+ implemented in this module and to notify the plugin manager of any\r
+ resource libraries that this module will use.\r
+\r
+ Call:\r
+ - kmm_set_locale() : to set the notify the plugin manager of the\r
+ locale specifc resource libraries that are used by this module.\r
+ - kmm_provide_plugin() : to register each plugin that is\r
+ implemented in this module.\r
+\r
+ This function is called in the context of the current user, from\r
+ the plug-in manager thread. This same thread is used by the\r
+ plug-in manager to load and initialize all the modules for a\r
+ session.\r
+\r
+ The name of the callback must be init_module(). The calling\r
+ convention is KHMAPI, which is currently __stdcall.\r
+\r
+ If this function does not register any plugins, the plugin manager\r
+ will immediately call exit_module() and unload the module even if\r
+ the init_module() function completes successfully.\r
+\r
+ \return Return the following values to indicate whether the module\r
+ successfully initialized or not.\r
+ - KHM_ERROR_SUCCESS : Succeeded. The module manager will call\r
+ init_plugin() for each of the registered plugins for the\r
+ module.\r
+ - any other error code: Signals that the module did not\r
+ successfully initialize. The plugin manager will\r
+ immediately call exit_module() and then unload the module.\r
+\r
+ \note This callback is required.\r
+*/\r
+KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module);\r
+\r
+/*! \brief Type for init_module() */\r
+typedef khm_int32 (KHMAPI *init_module_t)(kmm_module);\r
+\r
+#if defined(_WIN64)\r
+#define EXP_INIT_MODULE "_init_module@8"\r
+#elif defined(_WIN32)\r
+#define EXP_INIT_MODULE "_init_module@4"\r
+#else\r
+#error EXP_INIT_MODULE not defined for platform\r
+#endif\r
+\r
+/*! \brief Plugin procedure\r
+\r
+ This is the message processor for a plugin. See \ref pi_fw_pnm_p\r
+ for more information.\r
+\r
+ Essentially, this is a message subscriber for KMQ messages.\r
+*/\r
+KHMEXP khm_int32 KHMAPI _plugin_proc(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);\r
+\r
+/*! \brief Type for init_plugin() */\r
+typedef kmq_callback_t _plugin_proc_t;\r
+\r
+/*! \brief Exit a module\r
+\r
+ This is the last callback function that the NetIDMgr module\r
+ manager calls before unloading the module. When this function is\r
+ called, all of the plugins for the module have already been\r
+ stopped. However, any localization libraries that were loaded as\r
+ a result of init_module() calling kmm_set_locale_info() will still\r
+ be loaded. These localization libraries will be unloaded\r
+ immediately after this callback returns.\r
+\r
+ Use this callback to perform any required cleanup tasks. However,\r
+ it is advisable that each plugin perform its own cleanup tasks,\r
+ since each plugin may be stopped independently of others.\r
+\r
+ \return The return value of this function is ignored.\r
+\r
+ \note This callback is not required.\r
+*/\r
+KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module);\r
+\r
+/*! \brief Type for exit_module() */\r
+typedef khm_int32 (KHMAPI *exit_module_t)(kmm_module);\r
+\r
+#if defined(_WIN64)\r
+#define EXP_EXIT_MODULE "_exit_module@8"\r
+#elif defined(_WIN32)\r
+#define EXP_EXIT_MODULE "_exit_module@4"\r
+#else\r
+#error EXP_EXIT_MODULE not defined for platform\r
+#endif\r
+\r
+/*@}*/\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+; // ** kmm_msgs.mc \r
+\r
+; /* Since .mc files can contain strings from any language, we define\r
+; all our messages in one file in the /lang/ directory instead of\r
+; language specific subdirectories. */\r
+\r
+; /* The type is set to (wchar_t *) because that's what we will be\r
+; feeding kherr_report() function. */\r
+\r
+MessageIdTypedef=LPWSTR\r
+\r
+; /* Severity values as defined in the message definition file are\r
+; currently ignored. */\r
+\r
+SeverityNames=(\r
+ Success=0x0\r
+)\r
+\r
+LanguageNames=(\r
+ English=0x409:MSG_ENU\r
+)\r
+\r
+OutputBase=16\r
+\r
+; /* Actual messages start here */\r
+\r
+MessageId=1\r
+Severity=Success\r
+SymbolicName=MSG_INITIAL\r
+Language=English\r
+Initial placeholder message\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_LOAD_DEFAULT\r
+Language=English\r
+Load default modules\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_INIT_MODULE\r
+Language=English\r
+Initializing module [%1]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_GET_CONFIG\r
+Language=English\r
+Can't get configuration for modules\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_NOT_PREINIT\r
+Language=English\r
+Module is not in PREINIT state. Current state=[%1!d!]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_NOT_REGISTERED\r
+Language=English\r
+Module is not registered\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_DISABLED\r
+Language=English\r
+Module is disabled\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_MAX_FAIL\r
+Language=English\r
+Module has failed too many times\r
+.\r
+\r
+Messageid=\r
+SymbolicName=MSG_IM_NOT_FOUND\r
+Language=English\r
+Module binary was not found. Checked path [%1]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_NO_ENTRY\r
+Language=English\r
+Entry point not found. Checked entry point [%1]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_INIT_FAIL\r
+Language=English\r
+Module initialization entry point returned failure code [%1!d!]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_NO_PLUGINS\r
+Language=English\r
+No plugins were registerd by the module\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IM_MOD_STATE\r
+Language=English\r
+Module [%1] is in state [%2!d!]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_TASK_DESC\r
+Language=English\r
+Initializing plugin [%1]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_GET_CONFIG\r
+Language=English\r
+Can't get configuration for plugins\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_NOT_REGISTERED\r
+Language=English\r
+The plugin is not registered\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_DISABLED\r
+Language=English\r
+The plugin is disabled\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_HOLD\r
+Language=English\r
+Placing plugin [%1] on hold\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_STATE\r
+Language=English\r
+Leaving plugin [%1] in state [%2!d!]\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_IP_EXITING\r
+Language=English\r
+The plugin [%1] is in error state [%2!d!]. Exiting plugin.\r
+.\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=kmq\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\kmq.h\r
+\r
+OBJFILES= \\r
+ $(OBJ)\kmqmain.obj \\r
+ $(OBJ)\init.obj \\r
+ $(OBJ)\msgtype.obj \\r
+ $(OBJ)\consumer.obj \\r
+ $(OBJ)\publisher.obj \\r
+ $(OBJ)\kmqconfig.obj\r
+\r
+SDKLIBFILES=\\r
+ strsafe.lib\r
+\r
+$(OBJ)\kmqconfig.c: kmqconfig.csv $(CONFDIR)\csvschema.cfg\r
+ $(CCSV) $** $@\r
+\r
+all: mkdirs $(INCFILES) $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmqinternal.h>\r
+#include<assert.h>\r
+\r
+DWORD kmq_tls_queue;\r
+\r
+CRITICAL_SECTION cs_kmq_msg_ref;\r
+\r
+kmq_message_ref * kmq_msg_ref_free = NULL;\r
+\r
+/* ad-hoc subscriptions */\r
+kmq_msg_subscription * kmq_adhoc_subs = NULL;\r
+\r
+/*! \internal\r
+ \brief Get a message ref object\r
+ \note called with cs_kmq_msg_ref held */\r
+kmq_message_ref * kmqint_get_message_ref(void) {\r
+ kmq_message_ref * r;\r
+\r
+ LPOP(&kmq_msg_ref_free, &r);\r
+ if(!r) {\r
+ r = malloc(sizeof(kmq_message_ref));\r
+ }\r
+ ZeroMemory(r, sizeof(kmq_message_ref));\r
+\r
+ r->msg = NULL;\r
+ r->recipient = NULL;\r
+\r
+ return r;\r
+}\r
+\r
+/*! \internal\r
+ \brief Free a message ref object\r
+ \note called with cs_kmq_msg_ref and cs_kmq_msg held */\r
+void kmqint_put_message_ref(kmq_message_ref * r) {\r
+ if(!r)\r
+ return;\r
+ if(r->msg) {\r
+ r->msg->refcount--;\r
+ r->msg = NULL;\r
+ }\r
+ LPUSH(&kmq_msg_ref_free, r);\r
+}\r
+\r
+/*! \internal\r
+ \brief Get the queue associated with the current thread\r
+ \note Obtains ::cs_kmq_global\r
+ */\r
+kmq_queue * kmqint_get_thread_queue(void) {\r
+ kmq_queue * q;\r
+\r
+ q = (kmq_queue *) TlsGetValue(kmq_tls_queue);\r
+ if(!q) {\r
+ kmqint_attach_this_thread();\r
+ q = (kmq_queue *) TlsGetValue(kmq_tls_queue);\r
+ }\r
+\r
+ return q;\r
+}\r
+\r
+/*! \internal\r
+ \brief Get the topmost message ref for a queue\r
+ \note Obtains kmq_queue::cs\r
+ */\r
+void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r) {\r
+ EnterCriticalSection(&q->cs);\r
+ QGET(q,r);\r
+ if(QTOP(q))\r
+ SetEvent(q->wait_o);\r
+ LeaveCriticalSection(&q->cs);\r
+}\r
+\r
+/*! \internal\r
+ \brief Post a message to a queue\r
+ \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs\r
+ */\r
+void kmqint_post_queue(kmq_queue * q, kmq_message *m) {\r
+ kmq_message_ref *r;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg_ref);\r
+ r = kmqint_get_message_ref();\r
+ LeaveCriticalSection(&cs_kmq_msg_ref);\r
+\r
+ r->msg = m;\r
+ r->recipient = NULL;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m->refcount++;\r
+ m->nSent++;\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ EnterCriticalSection(&q->cs);\r
+ QPUT(q,r);\r
+ SetEvent(q->wait_o);\r
+ LeaveCriticalSection(&q->cs);\r
+}\r
+\r
+/*! \internal\r
+ \brief Post a message to a subscriber\r
+ \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs\r
+ \note Should be called with ::cs_kmq_msg held\r
+ */\r
+void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send) {\r
+ if(s->rcpt_type == KMQ_RCPTTYPE_CB) {\r
+ kmq_queue *q;\r
+ kmq_message_ref *r;\r
+\r
+ q = s->queue;\r
+\r
+ if(try_send && q->thread == GetCurrentThreadId()) {\r
+ khm_int32 rv;\r
+ /* we are sending a message from this thread to this thread.\r
+ just call the recipient directly, bypassing the message queue. */\r
+ m->refcount++;\r
+ m->nSent++;\r
+ rv = s->recipient.cb(m->type, m->subtype, m->uparam, m->vparam);\r
+ m->refcount--;\r
+ if(KHM_SUCCEEDED(rv))\r
+ m->nCompleted++;\r
+ else\r
+ m->nFailed++;\r
+ } else {\r
+ EnterCriticalSection(&cs_kmq_msg_ref);\r
+ r = kmqint_get_message_ref();\r
+ LeaveCriticalSection(&cs_kmq_msg_ref);\r
+\r
+ r->msg = m;\r
+ r->recipient = s->recipient.cb;\r
+\r
+ m->refcount++;\r
+ m->nSent++;\r
+\r
+ EnterCriticalSection(&q->cs);\r
+ QPUT(q,r);\r
+ SetEvent(q->wait_o);\r
+ LeaveCriticalSection(&q->cs);\r
+ }\r
+ }\r
+\r
+#ifdef _WIN32\r
+ else if(s->rcpt_type == KMQ_RCPTTYPE_HWND) {\r
+ m->refcount++;\r
+\r
+ if(try_send && GetCurrentThreadId() == GetWindowThreadProcessId(s->recipient.hwnd, NULL)) {\r
+ /* kmqint_post does not know whether there are any other messages\r
+ waiting to be posted at this point. Hence, simply sending the\r
+ message is not the right thing to do as the recipient may\r
+ incorrectly assume that the message has completed when\r
+ (m->nCompleted + m->nFailed == m->nSent). Therefore, we only\r
+ increment nSent after the message is sent. */\r
+ SendMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, m->type, (LPARAM) m);\r
+ m->nSent++;\r
+ } else {\r
+ m->nSent++;\r
+ PostMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, m->type, (LPARAM) m);\r
+ }\r
+ } \r
+#endif\r
+\r
+ else {\r
+ /* This could either be because we were passed in an invalid subscription\r
+ or because we lost a race to a thread that deleted an ad-hoc\r
+ subscription. */\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return;\r
+#endif\r
+ }\r
+}\r
+\r
+/*! \internal\r
+ \brief Subscribes a window to a message type\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd) {\r
+ kmq_msg_subscription * s;\r
+\r
+ s = malloc(sizeof(kmq_msg_subscription));\r
+ LINIT(s);\r
+ s->queue = NULL;\r
+ s->rcpt_type = KMQ_RCPTTYPE_HWND;\r
+ s->recipient.hwnd = hwnd;\r
+ kmqint_msg_type_add_sub(type, s);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_types, ::cs_kmq_global\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb) {\r
+ kmq_msg_subscription * s;\r
+\r
+ s = malloc(sizeof(kmq_msg_subscription));\r
+ LINIT(s);\r
+ s->queue = kmqint_get_thread_queue();\r
+ s->rcpt_type = KMQ_RCPTTYPE_CB;\r
+ s->recipient.cb = cb;\r
+ kmqint_msg_type_add_sub(type, s);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_global\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_create_subscription(kmq_callback_t cb, khm_handle * result)\r
+{\r
+ kmq_msg_subscription * s;\r
+\r
+ s = malloc(sizeof(kmq_msg_subscription));\r
+ LINIT(s);\r
+ s->queue = kmqint_get_thread_queue();\r
+ s->rcpt_type = KMQ_RCPTTYPE_CB;\r
+ s->recipient.cb = cb;\r
+\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ LPUSH(&kmq_adhoc_subs, s);\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+\r
+ *result = (khm_handle) s;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub)\r
+{\r
+ kmq_msg_subscription * s;\r
+\r
+ s = (kmq_msg_subscription *) sub;\r
+\r
+ s->type = 0;\r
+\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ LDELETE(&kmq_adhoc_subs, s);\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+\r
+ free(s);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/*! \internal\r
+ \brief Unsubscribes a window from a message type\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd) {\r
+ kmq_msg_subscription * s;\r
+\r
+ s = kmqint_msg_type_del_sub_hwnd(type, hwnd);\r
+ if(s)\r
+ free(s);\r
+ return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+/*! \internal\r
+ \brief Unsubscribe a callback from a message type\r
+ \note Obtains ::cs_kmq_types, ::cs_kmq_global\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb) {\r
+ kmq_msg_subscription * s;\r
+\r
+ s = kmqint_msg_type_del_sub_cb(type,cb);\r
+ if(s)\r
+ free(s);\r
+\r
+ return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m) {\r
+ *m = (kmq_message *) lparm;\r
+ if ((*m)->err_ctx) {\r
+ kherr_push_context((*m)->err_ctx);\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_msg\r
+ */\r
+KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv) {\r
+ if (m->err_ctx)\r
+ kherr_pop_context();\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m->refcount--;\r
+ if(KHM_SUCCEEDED(rv))\r
+ m->nCompleted++;\r
+ else\r
+ m->nFailed++;\r
+\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_msg\r
+ */\r
+KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb) {\r
+ kmq_message *m;\r
+ khm_int32 rv;\r
+\r
+ m = (kmq_message *) lparm;\r
+\r
+ if (m->err_ctx)\r
+ kherr_push_context(m->err_ctx);\r
+\r
+ rv = cb(m->type, m->subtype, m->uparam, m->vparam);\r
+\r
+ if (m->err_ctx)\r
+ kherr_pop_context();\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+\r
+ m->refcount--;\r
+ if(KHM_SUCCEEDED(rv))\r
+ m->nCompleted++;\r
+ else\r
+ m->nFailed++;\r
+\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_global, kmq_queue::cs, ::cs_kmq_msg_ref, ::cs_kmq_msg, \r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout) {\r
+ kmq_queue * q;\r
+ kmq_message_ref * r;\r
+ kmq_message *m;\r
+ DWORD hr;\r
+\r
+ q = kmqint_get_thread_queue();\r
+\r
+ hr = WaitForSingleObject(q->wait_o, timeout);\r
+ if(hr == WAIT_OBJECT_0) {\r
+ /* signalled */\r
+ kmqint_get_queue_message_ref(q, &r);\r
+\r
+ m = r->msg;\r
+\r
+ if(m->type != KMSG_SYSTEM || m->subtype != KMSG_SYSTEM_EXIT) {\r
+ khm_boolean rv;\r
+\r
+ if (m->err_ctx)\r
+ kherr_push_context(m->err_ctx);\r
+\r
+ /* dispatch */\r
+ rv = r->recipient(m->type, m->subtype, m->uparam, m->vparam);\r
+\r
+ if (m->err_ctx)\r
+ kherr_pop_context();\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ EnterCriticalSection(&cs_kmq_msg_ref);\r
+ kmqint_put_message_ref(r);\r
+ LeaveCriticalSection(&cs_kmq_msg_ref);\r
+\r
+ if(KHM_SUCCEEDED(rv))\r
+ m->nCompleted++;\r
+ else\r
+ m->nFailed++;\r
+\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ EnterCriticalSection(&cs_kmq_msg_ref);\r
+ kmqint_put_message_ref(r);\r
+ LeaveCriticalSection(&cs_kmq_msg_ref);\r
+ m->nCompleted++;\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return KHM_ERROR_EXIT;\r
+ }\r
+ } else {\r
+ return KHM_ERROR_TIMEOUT;\r
+ }\r
+}\r
+\r
+/* TODO: rename this file to subscriber.c */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmqinternal.h>\r
+#include<kconfig.h>\r
+#include<assert.h>\r
+\r
+CRITICAL_SECTION cs_kmq_global;\r
+kmq_timer kmq_queue_dead_timeout;\r
+kmq_timer kmq_call_dead_timeout;\r
+\r
+kmq_queue * queues;\r
+\r
+LONG kmq_init_once = 0;\r
+\r
+void kmqint_init(void) {\r
+ khm_handle hconfig = NULL;\r
+\r
+ queues = NULL;\r
+\r
+ InitializeCriticalSection(&cs_kmq_global);\r
+ InitializeCriticalSection(&cs_kmq_msg);\r
+ InitializeCriticalSection(&cs_kmq_msg_ref);\r
+\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ khc_load_schema(NULL, schema_kmqconfig);\r
+ khc_open_space(NULL, KMQ_CONF_SPACE_NAME, KHM_PERM_READ, &hconfig);\r
+ if(hconfig) {\r
+ khc_read_int32(hconfig, KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME, &kmq_queue_dead_timeout);\r
+ khc_read_int32(hconfig, KMQ_CONF_CALL_DEAD_TIMEOUT_NAME, &kmq_call_dead_timeout);\r
+ khc_close_space(hconfig);\r
+ }\r
+ kmqint_init_msg_types();\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+\r
+ kmq_tls_queue = TlsAlloc();\r
+}\r
+\r
+void kmqint_exit(void) {\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ kmqint_exit_msg_types();\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+ DeleteCriticalSection(&cs_kmq_msg);\r
+ DeleteCriticalSection(&cs_kmq_msg_ref);\r
+ DeleteCriticalSection(&cs_kmq_global);\r
+\r
+ TlsFree(kmq_tls_queue);\r
+}\r
+\r
+/*! \internal\r
+ \brief Preps a thread for use with kmq\r
+ \note Obtains ::cs_kmq_global\r
+ */\r
+void kmqint_attach_this_thread(void) {\r
+ kmq_queue * q;\r
+\r
+ q = (kmq_queue *) TlsGetValue(kmq_tls_queue);\r
+ if(!q) {\r
+ EnterCriticalSection(&cs_kmq_global);\r
+\r
+ q = malloc(sizeof(kmq_queue));\r
+\r
+ InitializeCriticalSection(&q->cs);\r
+ q->thread = GetCurrentThreadId();\r
+ QINIT(q);\r
+ LINIT(q);\r
+ q->wait_o = CreateEvent(NULL, FALSE, FALSE, NULL);\r
+ q->load = 0;\r
+ q->last_post = 0;\r
+\r
+ LPUSH(&queues, q);\r
+\r
+ TlsSetValue(kmq_tls_queue, (LPVOID) q);\r
+\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+ }\r
+}\r
+\r
+/*! \internal\r
+ \brief Detaches the current thread from kmq\r
+ \note Obtains ::cs_kmq_global\r
+ */\r
+void kmqint_detach_this_thread(void) {\r
+ kmq_queue * q;\r
+\r
+ q = (kmq_queue *) TlsGetValue(kmq_tls_queue);\r
+ if(q) {\r
+ EnterCriticalSection(&cs_kmq_global);\r
+\r
+ LDELETE(&queues, q);\r
+ \r
+ DeleteCriticalSection(&q->cs);\r
+ CloseHandle(q->wait_o);\r
+\r
+ /* TODO: free up the queued messages */\r
+\r
+ TlsSetValue(kmq_tls_queue, (LPVOID) 0);\r
+\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+ }\r
+}\r
+\r
+HANDLE kmq_h_compl = NULL;\r
+kmq_thread_id kmq_tid_compl;\r
+\r
+/* Message transfer */\r
+struct tag_kmq_msg_xfer {\r
+ QDCL(kmq_message);\r
+} kmq_completion_xfer;\r
+\r
+HANDLE compl_wx;\r
+BOOL compl_continue;\r
+CRITICAL_SECTION cs_compl;\r
+\r
+DWORD WINAPI kmqint_completion_thread_proc(LPVOID p) {\r
+ kmq_message * m;\r
+ kherr_context * ctx;\r
+\r
+ EnterCriticalSection(&cs_compl);\r
+ do {\r
+ \r
+ if (QTOP(&kmq_completion_xfer) == NULL) {\r
+ LeaveCriticalSection(&cs_compl);\r
+ WaitForSingleObject(compl_wx, INFINITE);\r
+ EnterCriticalSection(&cs_compl);\r
+ /* go through the loop again before checking the queue */\r
+ } else {\r
+ QGET(&kmq_completion_xfer, &m);\r
+ LeaveCriticalSection(&cs_compl);\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+\r
+ ctx = m->err_ctx;\r
+\r
+ if (ctx)\r
+ kherr_push_context(ctx);\r
+\r
+ kmqint_put_message(m);\r
+\r
+ if (ctx)\r
+ kherr_pop_context();\r
+\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+ EnterCriticalSection(&cs_compl);\r
+ }\r
+\r
+ } while(compl_continue);\r
+\r
+ LeaveCriticalSection(&cs_compl);\r
+\r
+ ExitThread(0);\r
+\r
+ /* not reached */\r
+ return 0;\r
+}\r
+\r
+int kmqint_call_completion_handler(kmq_msg_completion_handler h,\r
+ kmq_message * m) {\r
+ if (h == NULL)\r
+ return 0;\r
+\r
+ /* We only dispatch to the completion thread if we are not the\r
+ completion thread. If calling the completion handler results\r
+ in more messages completing, then we just call the completion\r
+ handler directly. We also make an exception for completions\r
+ that happen before the message queue is properly intiailized. */\r
+\r
+ if (kmq_tid_compl != GetCurrentThreadId() &&\r
+ kmq_h_compl != NULL) {\r
+\r
+ EnterCriticalSection(&cs_compl);\r
+ QPUT(&kmq_completion_xfer, m);\r
+ SetEvent(compl_wx);\r
+ LeaveCriticalSection(&cs_compl);\r
+\r
+ return 1;\r
+\r
+ } else {\r
+ h(m);\r
+\r
+ return 0;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_init(void) {\r
+ if (InterlockedIncrement(&kmq_init_once) == 1) {\r
+ EnterCriticalSection(&cs_kmq_global);\r
+\r
+ InitializeCriticalSection(&cs_compl);\r
+ compl_wx = CreateEvent(NULL, FALSE, FALSE, NULL);\r
+ compl_continue = TRUE;\r
+ QINIT(&kmq_completion_xfer);\r
+\r
+ kmq_h_compl = CreateThread(NULL,\r
+ 0,\r
+ kmqint_completion_thread_proc,\r
+ NULL,\r
+ 0,\r
+ &kmq_tid_compl);\r
+\r
+ assert(kmq_h_compl != NULL);\r
+\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_exit(void) {\r
+ if (InterlockedDecrement(&kmq_init_once) == 0) {\r
+\r
+ EnterCriticalSection(&cs_compl);\r
+ compl_continue = FALSE;\r
+ SetEvent(compl_wx);\r
+ LeaveCriticalSection(&cs_compl);\r
+\r
+ WaitForSingleObject(kmq_h_compl, INFINITE);\r
+\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ CloseHandle(kmq_h_compl);\r
+ kmq_h_compl = NULL;\r
+ kmq_tid_compl = 0;\r
+ CloseHandle(compl_wx);\r
+ DeleteCriticalSection(&cs_compl);\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KMQ_H__\r
+#define __KHIMAIRA_KMQ_H__\r
+\r
+/*! \defgroup kmq NetIDMgr Message Queue */\r
+/*@{*/\r
+\r
+#include<khdefs.h>\r
+#include<khlist.h>\r
+#include<kherr.h>\r
+\r
+/* general */\r
+#ifdef _WIN32\r
+typedef DWORD kmq_thread_id;\r
+typedef DWORD kmq_timer;\r
+#endif\r
+\r
+#ifdef _WIN32\r
+/*! \brief Window message for kmq\r
+\r
+ This message is sent to the window procedure of a window if that\r
+ window is a subscriber to KMQ messages.\r
+\r
+ \see kmq_subscribe_hwnd() for more information about handling this\r
+ window message\r
+ */\r
+#define KMQ_WM_DISPATCH (WM_APP+0x100)\r
+#endif\r
+\r
+/* callback */\r
+\r
+/*! \brief A message callback\r
+\r
+ Should return TRUE if the message is properly handled. Otherwise\r
+ return FALSE */\r
+typedef khm_int32 (KHMAPI *kmq_callback_t)(khm_int32 msg_type, \r
+ khm_int32 msg_sub_type, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+/* message */\r
+\r
+/*! \brief A single response.\r
+\r
+ Certain broadcast messages may user scatter-gather type\r
+ notification and result gathering. Individual subscribers to a\r
+ message attach their individual responses to a ::kmq_response\r
+ object and attach that to the message which can later be read by\r
+ the sender of the message.\r
+ */\r
+typedef struct tag_kmq_response {\r
+ kmq_thread_id thread;\r
+ void * response;\r
+\r
+ LDCL(struct tag_kmq_response);\r
+} kmq_response;\r
+\r
+/*! \brief A single message\r
+ */\r
+typedef struct tag_kmq_message {\r
+ khm_int32 type; /*!< Type of message */\r
+ khm_int32 subtype; /*!< Subtype of message */\r
+\r
+ khm_ui_4 uparam; /*!< Integer parameter */\r
+ void * vparam; /*!< Pointer to parameter blob */\r
+ \r
+ khm_int32 nSent; /*!< Number of instances of message\r
+ sent (for broadcast messages) */\r
+\r
+ khm_int32 nCompleted; /*!< Number of instances that have\r
+ completed processing (for broadcast\r
+ messages) */\r
+\r
+ khm_int32 nFailed; /*!< Number of instances that failed\r
+ to process (for broadcast\r
+ messages) */\r
+\r
+ kmq_response * responses; /*!< List of responses */\r
+ HANDLE wait_o; /*!< Event to wait on (only valid if\r
+ the publisher of the message\r
+ requested a handle to the call) */\r
+\r
+ kmq_timer timeSent; /*!< Time at which the message was\r
+ sent */\r
+ kmq_timer timeExpire; /*!< Time at which the message\r
+ expires */\r
+\r
+ kherr_context * err_ctx; /*!< Error context for the message */\r
+\r
+ khm_int32 refcount;\r
+\r
+ LDCL(struct tag_kmq_message);\r
+} kmq_message;\r
+\r
+/*! \brief A handle to a call\r
+ */\r
+typedef kmq_message *kmq_call;\r
+\r
+/*! \brief Message reference */\r
+typedef struct tag_kmq_message_ref {\r
+ kmq_message * msg; /*!< Message that we are referring\r
+ to */\r
+ kmq_callback_t recipient; /*!< The recipient of the message */\r
+\r
+ LDCL(struct tag_kmq_message_ref);\r
+} kmq_message_ref;\r
+\r
+/*! \brief Message queue\r
+\r
+ Each thread gets its own message queue. When a message is\r
+ broadcast to which there is a subscriber in a particular thread, a\r
+ reference to the message is placed in the message queue of the\r
+ thread. The dispatch procedure then dispatches the message as\r
+ described in the message reference.\r
+*/\r
+typedef struct tag_kmq_queue {\r
+ kmq_thread_id thread; /*!< The thread id */\r
+\r
+ CRITICAL_SECTION cs;\r
+ HANDLE wait_o;\r
+\r
+ khm_int32 load; /*!< Number of messages waiting to be\r
+ processed on this message queue. */\r
+ kmq_timer last_post; /*!< Time the last message was\r
+ received */\r
+\r
+ /*Q*/\r
+ QDCL(kmq_message_ref); /*!< Queue of message references */\r
+\r
+ /*Lnode*/\r
+ LDCL(struct tag_kmq_queue);\r
+} kmq_queue;\r
+\r
+/*! \brief Message subscription\r
+\r
+ A subscription binds a recipient with a message type. These are\r
+ specific to a thread. I.e. a subscription that was made in one\r
+ thread will not receive messages in the context of another thread.\r
+*/\r
+typedef struct tag_kmq_msg_subscription {\r
+ khm_int32 type; /*!< Type of message */\r
+ khm_int32 rcpt_type; /*!< Type of recipient. One of\r
+ ::KMQ_RCPTTYPE_CB or\r
+ ::KMQ_RCPTTYPE_HWND */\r
+ union {\r
+ kmq_callback_t cb; /*!< Callback if the subscription is\r
+ of callback type */\r
+ HWND hwnd; /*!< Window handle if the subscription\r
+ is a windows message type */\r
+ } recipient;\r
+\r
+ kmq_queue * queue; /*!< Associated queue */\r
+\r
+ /*lnode*/\r
+ LDCL(struct tag_kmq_msg_subscription);\r
+} kmq_msg_subscription;\r
+\r
+/*! \brief Callback recipient type\r
+\r
+ The recipient is a callback function */\r
+#define KMQ_RCPTTYPE_CB 1\r
+\r
+/*! \brief Windows recipient type\r
+\r
+ The recipient is a window */\r
+#define KMQ_RCPTTYPE_HWND 2\r
+\r
+/* publishers */\r
+\r
+/*! \brief A completion handler for a message\r
+\r
+ Each message type can have a completion handler. Once a message\r
+ of this a specific type has been broadcast and handled by all the\r
+ subscripbers, the message will be passed down to the completion\r
+ handler before the associated data structures are freed. This\r
+ allows applications that define message type to also define clean\r
+ up for each message. For example, the completion handler can\r
+ initiate another message if the messages form a sequence or free\r
+ up blocks of memory that was passed as the parameter to the\r
+ message.\r
+ */\r
+typedef void (KHMAPI *kmq_msg_completion_handler)(kmq_message *);\r
+\r
+/*! \brief A message type\r
+ */\r
+typedef struct tag_kmq_msg_type {\r
+ khm_int32 id; /*!< Identifier for the message\r
+ type. */\r
+ kmq_msg_subscription * subs; /*!< The list of subscriptions */\r
+ kmq_msg_completion_handler completion_handler; /*!< Completion\r
+ handler for the message type */\r
+\r
+ wchar_t * name; /*!< Name of the message type for\r
+ named types. Message type names are\r
+ language independant. */\r
+\r
+ /*Lnode*/\r
+ LDCL(struct tag_kmq_msg_type);\r
+} kmq_msg_type;\r
+\r
+/*! \brief The maximum number of message types\r
+ */\r
+#define KMQ_MSG_TYPE_MAX 255\r
+\r
+/*! \brief Maximum number of characters in a message type name\r
+\r
+ The count includes the terminating NULL\r
+ */\r
+#define KMQ_MAXCCH_TYPE_NAME 256\r
+\r
+/*! \brief Maximum number of bytes in a message type name\r
+\r
+ Type count includes the terminating NULL\r
+ */\r
+#define KMQ_MAXCB_TYPE_NAME (KMQ_MAXCCH_TYPE_NAME * sizeof(wchar_t))\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_init(void);\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_exit(void);\r
+\r
+/*! \brief Register a message type\r
+\r
+ Registers a custom message type. The \a name parameter specifies\r
+ a language independent name for the message type and must be\r
+ unique and must be less than ::KMQ_MAXCCH_TYPE_NAME characters.\r
+\r
+ \param[in] name Name of the message type. Upto\r
+ ::KMQ_MAXCCH_TYPE_NAME characters including terminating NULL.\r
+ The \a name cannot be a zero length string.\r
+\r
+ \param[out] new_id Receives the new message type ID. Specify NULL\r
+ if the new message type is not required.\r
+\r
+ \see kmq_find_type() and kmq_unregister_type()\r
+\r
+ \retval KHM_ERROR_INVALID_PARM The \a name parameter was invalid.\r
+ \retval KHM_ERROR_EXISTS A message type with that name already exists.\r
+ \retval KHM_ERROR_NO_RESOURCES Can't register any more message types.\r
+ \retval KHM_ERROR_SUCCESS The operation succeeded.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, khm_int32 * new_id);\r
+\r
+/*! \brief Find a message type\r
+\r
+ Find the message type with the given name. If found, the type ID\r
+ is returned in \a id.\r
+\r
+ \retval KHM_ERROR_SUCCESS A message type with the given name was\r
+ found.\r
+ \retval KHM_ERROR_NOT_FOUND A message type with the given name was\r
+ not found.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id);\r
+\r
+/*! \brief Unregister a message type\r
+\r
+ Unregisters a message type that was registered using\r
+ kmq_register_type().\r
+\r
+ \retval KHM_ERROR_SUCCESS The specified message type was\r
+ successfully unregistered.\r
+\r
+ \retval KHM_ERROR_NOT_FOUND The message type was not found.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id);\r
+\r
+/*! \brief Subscribte to a message type.\r
+\r
+ Adds a subscription to messages of type \a type. Subscriptions\r
+ are managed per thread. Therefore the subscription is actually\r
+ added to the subscription list for the current thread (the thread\r
+ which calls kmq_subscribe()).\r
+\r
+ When a message of type \a type is received by the thread, it is\r
+ dispatched to the callback function identified by \a cb within the\r
+ context of this thread.\r
+\r
+ \note Calling kmq_subscribe() from within multiple threads with\r
+ the same \a type and \a cb will result in multiple\r
+ subscriptions.\r
+\r
+ \see kmq_unsubscribe()\r
+ \see kmq_dispatch()\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb);\r
+\r
+/*! \brief Subscribe a window to a message type\r
+\r
+ Adds the window specified by \a hwnd to the subscription list for\r
+ the message type \a type. When a message of this type is posted,\r
+ then the window procedure of the window \a hwnd receives a message\r
+ ::KMQ_WM_DISPATCH.\r
+\r
+ When a window receives a ::KMQ_WM_DISPATCH message, it means that\r
+ a message has been posted which is of a type that the window has\r
+ subscribed for. Because of the way Windows handles window\r
+ messages and the way NetIDMgr message queues work, a thread which\r
+ has a window (or thread) procedure can not call kmq_dispatch() to\r
+ handle these messages. For threads that have window or thread\r
+ message loops, they must call kmq_subscribe_hwnd() to subscribe a\r
+ particular window (for thread message loops, this would be the\r
+ HWND of the message window for the thread) to NetIDMgr messages.\r
+\r
+ There are two supported ways of handling the ::KMQ_WM_DISPATCH\r
+ message. Examples of both are provided below.\r
+\r
+ Handling the message inline:\r
+\r
+ \code\r
+ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
+ kmq_message * m;\r
+ khm_int32 rv;\r
+ ...\r
+ switch(uMsg) {\r
+ case WM_CREATE:\r
+ ...\r
+ kmq_subscribe_hwnd(KMSG_CRED, hwnd);\r
+ ...\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ ...\r
+ kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);\r
+ ...\r
+ break;\r
+\r
+ ...\r
+ case KMQ_WM_DISPATCH:\r
+ kmq_wm_begin(lParam,&m);\r
+\r
+ if(m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) {\r
+ // do something\r
+ rv = KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ return kmq_wm_end(m, rv);\r
+ ...\r
+ };\r
+ ...\r
+ }\r
+ \endcode\r
+\r
+ The other method is to dispatch the ::KMQ_WM_DISPATCH message to a\r
+ secondary callback function:\r
+\r
+ \code\r
+ khm_int32 msg_handler(khm_int32 t, khm_int32 st, khm_ui_4 up, void * pb) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ //handle message\r
+\r
+ return rv;\r
+ }\r
+\r
+ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
+ kmq_message * m;\r
+ khm_int32 rv;\r
+ ...\r
+ switch(uMsg) {\r
+ ...\r
+\r
+ case WM_CREATE:\r
+ ...\r
+ kmq_subscribe_hwnd(KMSG_CRED, hwnd);\r
+ ...\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ ...\r
+ kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);\r
+ ...\r
+ break;\r
+\r
+ ...\r
+ case KMQ_WM_DISPATCH:\r
+ return kmq_wm_dispatch(lParam, msg_handler);\r
+ ...\r
+ };\r
+ ...\r
+ }\r
+ \endcode\r
+\r
+ \note Make sure you unsubscribe from the message type when the\r
+ window is destroyed.\r
+\r
+ \see kmq_unsubscribe_hwnd()\r
+ \see kmq_wm_begin()\r
+ \see kmq_wm_end()\r
+ \see kmq_wm_dispatch()\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd);\r
+\r
+#ifdef _WIN32\r
+/*! \brief Begins handling a KMQ_WM_DISPATCH message\r
+\r
+ \return The return value of this function should be ignored.\r
+\r
+ \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH\r
+ */\r
+KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m);\r
+\r
+/*! \brief Ends handling a KMQ_WM_DISPATCH message\r
+\r
+ \return The return value of this function should be the return\r
+ value of the window procedure. See kmq_subscribe_hwnd()\r
+ documentation for example\r
+\r
+ \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH\r
+ */\r
+KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv);\r
+\r
+/*! \brief Dispatches a KMQ_WM_DISPATCH message to a callback\r
+\r
+ \return The return value of this function should be the return\r
+ value of the window procedure. See kmq_subscribe_hwnd()\r
+ documentation for example.\r
+\r
+ \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH\r
+ */\r
+KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb);\r
+#endif\r
+\r
+/*! \brief Unsubscribe a callback from a message type\r
+\r
+ Removes the subscription for message type \a type for callback\r
+ function \a cb from the subscription list for the current thread\r
+ (the thread that calls kmq_unsubscribe()).\r
+\r
+ \note kmq_unsubscribe() can only remove subscriptions for the subscription\r
+ list for the current thread.\r
+\r
+ \see kmq_subscribe()\r
+ \see kmq_dispatch()\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb);\r
+\r
+/*! \brief Unsubscribe a window from a message type\r
+\r
+ Removes the specific window from the subsription list for message\r
+ type \a type.\r
+\r
+ \see kmq_subscribe_hwnd()\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd);\r
+\r
+/*! \brief Create an ad-hoc subscription\r
+\r
+ An ad-hoc subscription describes a callback point in a thread that\r
+ can be dispatched messages to individually without broadcasting.\r
+\r
+ \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(),\r
+ kmq_send_sub_msg(), kmq_post_subs_msg(),\r
+ kmq_post_subs_msg_ex(), kmq_send_subs_msg(),\r
+ kmq_delete_subscription()\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_create_subscription(\r
+ kmq_callback_t cb, \r
+ khm_handle * result);\r
+\r
+/*! \brief Delete an ad-hoc subscription\r
+\r
+ Deletes a subscriptoin that was created using\r
+ kmq_create_subscription()\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub);\r
+\r
+/*! \brief Post a message to a subscription\r
+\r
+ Equivalent of kmq_post_msg() but only posts the message to the\r
+ specified subscription.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_post_sub_msg(\r
+ khm_handle sub, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+/*! \brief Post a message to a subscription and acquire a handle to the call\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex(\r
+ khm_handle sub, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam, \r
+ kmq_call * call);\r
+\r
+/*! \brief Send a synchronous message to a subscription\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors\r
+ \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_send_sub_msg(\r
+ khm_handle sub, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+/*! \brief Post a message to a group of subscriptions\r
+\r
+ The block of memory pointed to by \a subs should be an array of\r
+ subscriptions. The number of elements in that array should be \a\r
+ n_subs. A message as specified by the remaining parameters will\r
+ be dispatched to all of the subscription points in the array.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_post_subs_msg(\r
+ khm_handle * subs, \r
+ khm_size n_subs, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+/*! \brief Post a message to a group of subscriptions and acquire a handle to the call\r
+\r
+ The block of memory pointed to by \a subs should be an array of\r
+ subscriptions. The number of elements in that array should be \a\r
+ n_subs. A message as specified by the remaining parameters will\r
+ be dispatched to all of the subscription points in the array, and\r
+ a handle to the call will be returned in \a call.\r
+\r
+ The returned \a call will reference all of the dispatches that\r
+ were made.\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex(\r
+ khm_handle * subs, \r
+ khm_int32 n_subs, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam, \r
+ kmq_call * call);\r
+\r
+/*! \brief Send a synchronous message to a group of subscriptions\r
+\r
+ The block of memory pointed to by \a subs should be an array of\r
+ subscriptions. The number of elements in that array should be \a\r
+ n_subs. A message as specified by the remaining parameters will\r
+ be dispatched to all of the subscription points in the array. The\r
+ function will not return until all of the calls have succeeded.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors\r
+ \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_send_subs_msg(\r
+ khm_handle *subs, \r
+ khm_int32 n_subs,\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+/*! \brief Dispatch a message for the current thread.\r
+\r
+ This function opens the message list for the current thread and\r
+ dispatches the first message instance that is found. Note that if\r
+ multiple callbacks subscribe to the same message type in the same\r
+ thread, then when a message of that type is received, multiple\r
+ message instances are added to the message queue corresponding to\r
+ each subscription.\r
+\r
+ If no message instances are waiting in the queue, kmq_dispatch()\r
+ waits for the \a timeout period for a message.\r
+\r
+ \param[in] timeout The timeout period in milliseconds. Specify INFINITE for\r
+ kmq_dispatch() to wait indefinitely.\r
+\r
+ \retval KHM_ERROR_SUCCESS A message instance was dispatched\r
+ \retval KHM_ERROR_TIMEOUT The timeout period elapsed\r
+ \retval KHM_ERROR_EXIT The message found on the queue was <KMSG_SYSTEM,KMSG_SYSTEM_EXIT>\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout);\r
+\r
+/*! \brief Send a message\r
+\r
+ The specified message will be posted to all the subscribers of the\r
+ message type. Then the function will wait for all the subscribers\r
+ to finish processing the message before returning.\r
+ \r
+ \param[in] type The type of the message\r
+ \param[in] subtype The subtype\r
+ \param[in] uparam The khm_ui_4 parameter for the message\r
+ \param[in] blob The parameter blob for the message\r
+\r
+ \note The internal timeout for this function is INFINITE. If you\r
+ it is desirable to use a different timeout, use\r
+ kmq_post_message_ex() and kmq_wait() functions.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call succeeded and no subscribers returned errors\r
+ \retval KHM_ERROR_PARTIAL The call succeeded but at least one subscriber returned an error\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_send_message(\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * blob);\r
+\r
+/*! \brief Post a message\r
+\r
+ The specified message will be posted to all the subscribers of the\r
+ message type. The function returns immediately.\r
+ \r
+ If you want to be able to wait for all the subscribers to finish\r
+ processing the message, you should use kmq_post_message_ex()\r
+ instead.\r
+\r
+ \param[in] type The type of the message\r
+ \param[in] subtype The subtype\r
+ \param[in] uparam The khm_ui_4 parameter for the message\r
+ \param[in] blob The parameter blob for the message\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_post_message(\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * blob);\r
+\r
+/*! \brief Post a message and acquire a handle to the call.\r
+\r
+ The specified message is posted to all the subscribers. In\r
+ addition, a handle is obtained for the call which can be used in\r
+ subsequent call to kmq_free_call() or kmq_wait().\r
+\r
+ Call kmq_free_call() to free the handle.\r
+\r
+ \param[in] type The type of the message\r
+ \param[in] subtype The subtype\r
+ \param[in] uparam The khm_ui_4 parameter for the message\r
+ \param[in] blob The parameter blob for the message\r
+ \param[out] call Receives the call handle. Set to NULL if the call handle is not required.\r
+\r
+ \see kmq_free_call()\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_post_message_ex(\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * blob, \r
+ kmq_call * call);\r
+\r
+/*! \brief Free a handle to a call obtained through kmq_post_message_ex()\r
+\r
+ All call handles obtained through kmq_post_message_ex() must be\r
+ freed via a call to kmq_free_call().\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call);\r
+\r
+/*! \brief Sends a <KMSG_SYSTEM,KMSG_SYSTEM_EXIT> message to the specified thread.\r
+\r
+ The message itself will not be received by any callback function,\r
+ however, any kmq_dispatch() function that is currently active of\r
+ becomes active will exit with a KHM_ERROR_EXIT code.\r
+ kmq_send_thread_quit_message() will wait for this to happen before\r
+ returning.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message(\r
+ kmq_thread_id thread, \r
+ khm_ui_4 uparam);\r
+\r
+/*! \brief Post a <KMSG_SYSTEM,KMSG_SYSTEM_EXIT> message to the specified thread.\r
+\r
+ The message itself will not be received by any callback function,\r
+ however, any kmq_dispatch() function that is currently active of\r
+ becomes active will exit with a KHM_ERROR_EXIT code.\r
+ kmq_post_thread_quit_message() will return immediately.\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message(\r
+ kmq_thread_id thread, \r
+ khm_ui_4 uparam, \r
+ kmq_call * call);\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp);\r
+\r
+/*! \brief Check if a specific call has completed\r
+\r
+ \return TRUE if the call has completed. FALSE otherwise.\r
+*/\r
+KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call);\r
+\r
+/*! \brief Wait for a call to complete.\r
+\r
+ Waits for the specified call to complete. If the call dispatched\r
+ to multiple recipients, the function waits for all dispatches to\r
+ complete.\r
+\r
+ If the call has already completed, then the function returns\r
+ immediately.\r
+\r
+ If more than one thread is waiting for a single message to\r
+ complete, then only one of them will be released when the message\r
+ compeltes. Each subsequent thread will be released as each\r
+ released thread calls kmq_free_call().\r
+\r
+ \param[in] call A handle to a call.\r
+ \param[in] timeout Specifies, in milliseconds, the amount of time\r
+ to wait for the call to complete. Specify INFINITE to wait\r
+ indefinitely.\r
+\r
+ \retval KHM_ERROR_SUCCESS The call completed\r
+ \retval KHM_ERROR_TIMEOUT The timeout period expired\r
+ \retval KHM_ERROR_INVALID_PARM One of the parameters were invalid.\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout);\r
+\r
+/*! \brief Sets the completion handler for a specified message type.\r
+\r
+ \note Only one completion handler can exist for one message type.\r
+ Calling this function overwrites the previous completion\r
+ handler.\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_set_completion_handler(\r
+ khm_int32 type, \r
+ kmq_msg_completion_handler hander);\r
+\r
+/*@}*/\r
+#endif\r
--- /dev/null
+Name,Type,Value,Description\r
+KMQ,KC_SPACE,0,Options for the credentials window\r
+ QueueDeadTimeout,KC_INT32,12000,\r
+ CallDeadTimeout,KC_INT32,8000,\r
+KMQ,KC_ENDSPACE,0,\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KMQINTERNAL_H\r
+#define __KHIMAIRA_KMQINTERNAL_H\r
+\r
+#include<windows.h>\r
+#include<kmq.h>\r
+#include<khlist.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<kconfig.h>\r
+#include<strsafe.h>\r
+\r
+#define KMQ_CONF_SPACE_NAME L"KMQ"\r
+#define KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME L"QueueDeadTimeout"\r
+#define KMQ_CONF_CALL_DEAD_TIMEOUT_NAME L"CallDeadTimeout"\r
+\r
+extern CRITICAL_SECTION cs_kmq_global;\r
+extern kmq_timer kmq_queue_dead_timeout;\r
+extern kmq_timer kmq_call_dead_timeout;\r
+\r
+extern kmq_queue * queues;\r
+\r
+/* message type */\r
+extern CRITICAL_SECTION cs_kmq_types;\r
+extern kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX+1];\r
+\r
+void kmqint_init_msg_types(void);\r
+void kmqint_exit_msg_types(void);\r
+void kmqint_free_msg_type(int t);\r
+void kmqint_msg_type_create(int t);\r
+void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s);\r
+void kmqint_msg_type_del_sub(kmq_msg_subscription *s);\r
+kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd);\r
+kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb);\r
+khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send);\r
+khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler);\r
+int kmqint_notify_msg_completion(kmq_message * m);\r
+\r
+/* consumer */\r
+extern DWORD kmq_tls_queue;\r
+\r
+void kmqint_post_queue(kmq_queue * q, kmq_message *m);\r
+void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send);\r
+kmq_queue * kmqint_get_thread_queue(void);\r
+void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r);\r
+\r
+/* publisher */\r
+extern CRITICAL_SECTION cs_kmq_msg;\r
+extern CRITICAL_SECTION cs_kmq_msg_ref;\r
+\r
+kmq_message * kmqint_get_message(void);\r
+void kmqint_put_message(kmq_message *m);\r
+\r
+void kmqint_init(void);\r
+void kmqint_exit(void);\r
+void kmqint_attach_this_thread(void);\r
+void kmqint_detach_this_thread(void);\r
+\r
+khm_int32 kmqint_post_message_ex(\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * blob, \r
+ kmq_call * call,\r
+ khm_boolean try_send);\r
+\r
+int kmqint_call_completion_handler(kmq_msg_completion_handler h,\r
+ kmq_message * m);\r
+\r
+/* global */\r
+extern kconf_schema schema_kmqconfig[];\r
+\r
+/* Lock hiearchy :\r
+\r
+ cs_kmq_types\r
+ cs_kmq_msg\r
+ cs_kmq_msg_ref\r
+ cs_compl\r
+ cs_kmq_global\r
+ kmq_queue::cs\r
+\r
+ If you have a level 'x' lock, you can obtain a level 'x+n' lock.\r
+ You can't obtain a 'x-n' lock if you already have a level 'x' lock.\r
+ If you don't have any locks, you can obtain any lock.\r
+ */\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmqinternal.h>\r
+\r
+void\r
+kmq_process_attach(void) {\r
+ kmqint_init();\r
+}\r
+\r
+void\r
+kmq_process_detach(void) {\r
+ kmqint_exit();\r
+}\r
+\r
+void\r
+kmq_thread_attach(void) {\r
+ kmqint_attach_this_thread();\r
+}\r
+\r
+void\r
+kmq_thread_detach(void) {\r
+ kmqint_detach_this_thread();\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmqinternal.h>\r
+\r
+CRITICAL_SECTION cs_kmq_types;\r
+\r
+kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX + 1];\r
+kmq_msg_type *all_msg_types = NULL;\r
+\r
+/*! \internal\r
+ \brief Initializes the message type data structures\r
+ \note called with cs_mkq_global held */\r
+void kmqint_init_msg_types(void) {\r
+ ZeroMemory(msg_types, sizeof(kmq_msg_type *) * (KMQ_MSG_TYPE_MAX + 1));\r
+ InitializeCriticalSection(&cs_kmq_types);\r
+}\r
+\r
+/*! \internal\r
+ \brief Frees up the message type data structures\r
+ \note called with cs_mkq_global held */\r
+void kmqint_exit_msg_types(void) {\r
+ int i;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ for(i=0;i<KMQ_MSG_TYPE_MAX;i++) {\r
+ if(msg_types[i])\r
+ kmqint_free_msg_type(i);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+ DeleteCriticalSection(&cs_kmq_types);\r
+}\r
+\r
+/*! \internal\r
+ \brief Notifies that the message has completed\r
+\r
+ \return Zero if the completion handling is done. Nonzero if the\r
+ handling is queued.\r
+ */\r
+int kmqint_notify_msg_completion(kmq_message * m) {\r
+ kmq_msg_type * mt;\r
+ kmq_msg_completion_handler h;\r
+\r
+ /* doing it this way to elude race conditions without\r
+ obtaining a lock */\r
+\r
+ mt = msg_types[m->type];\r
+ if(mt == NULL)\r
+ return 0;\r
+ h = mt->completion_handler;\r
+\r
+ /* handler is set to NULL before freeing type */\r
+ if(h == NULL || msg_types[m->type] == NULL)\r
+ return 0;\r
+\r
+ return kmqint_call_completion_handler(h,m);\r
+}\r
+\r
+/* called with cs_mkq_global && cs_kmq_types held */\r
+void kmqint_free_msg_type(int t) {\r
+ /*TODO: free the message type*/\r
+ /* must set handler to NULL before freeing type */\r
+ /* must set msg_type[t] = NULL before starting to free type */\r
+}\r
+\r
+/*! \internal\r
+ \brief Create a message type\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+void kmqint_msg_type_create(int t) {\r
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)\r
+ return;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ if(!msg_types[t]) {\r
+ kmq_msg_type * mt;\r
+ mt = malloc(sizeof(kmq_msg_type));\r
+ ZeroMemory(mt, sizeof(kmq_msg_type));\r
+ mt->id = t;\r
+ LINIT(mt);\r
+ mt->subs = NULL;\r
+ msg_types[t] = mt;\r
+\r
+ LPUSH(&all_msg_types, mt);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, \r
+ khm_int32 * new_id)\r
+{\r
+ int i;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ BOOL registered = FALSE;\r
+ int first_free = 0;\r
+ size_t sz;\r
+\r
+ if(FAILED(StringCbLength(name, KMQ_MAXCB_TYPE_NAME, &sz)) ||\r
+ sz == 0)\r
+ return KHM_ERROR_INVALID_PARM;\r
+ sz += sizeof(wchar_t);\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) {\r
+ if(msg_types[i] == NULL) {\r
+ if(first_free == 0)\r
+ first_free = i;\r
+ } else {\r
+ if(msg_types[i]->name != NULL && \r
+ !wcscmp(msg_types[i]->name, name))\r
+ registered = TRUE;\r
+ }\r
+ }\r
+\r
+ if(registered) {\r
+ rv = KHM_ERROR_EXISTS;\r
+ } else if(first_free == 0) {\r
+ rv = KHM_ERROR_NO_RESOURCES;\r
+ } else {\r
+ kmqint_msg_type_create(first_free);\r
+ msg_types[first_free]->name = malloc(sz);\r
+ StringCbCopy(msg_types[first_free]->name, sz, name);\r
+\r
+ if(new_id != NULL)\r
+ *new_id = first_free;\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id)\r
+{\r
+ int i;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) {\r
+ if(msg_types[i] != NULL && msg_types[i]->name != NULL) {\r
+ if(!wcscmp(msg_types[i]->name, name))\r
+ break;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ if(i <= KMQ_MSG_TYPE_MAX) {\r
+ if(id != NULL)\r
+ *id = i;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(id < KMSGBASE_USER || id > KMQ_MSG_TYPE_MAX)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ if(msg_types[id] != NULL) {\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ kmqint_free_msg_type(id);\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+ } else {\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+ \brief Adds a subscription to a message type\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s) {\r
+ kmq_msg_subscription * ts;\r
+\r
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)\r
+ return;\r
+\r
+ if(!msg_types[t])\r
+ kmqint_msg_type_create(t);\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ s->type = t;\r
+ /* check if we already have this subscription */\r
+ ts = msg_types[t]->subs;\r
+ while(ts) {\r
+ if((ts->rcpt_type == s->rcpt_type) &&\r
+ (((ts->rcpt_type == KMQ_RCPTTYPE_CB) && (ts->recipient.cb == s->recipient.cb)) ||\r
+ ((ts->rcpt_type == KMQ_RCPTTYPE_HWND) && (ts->recipient.hwnd == s->recipient.hwnd))))\r
+ break;\r
+ ts = LNEXT(ts);\r
+ }\r
+ /* add it if we didn't find it */\r
+ if(!ts) {\r
+ LPUSH(&msg_types[t]->subs, s);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+}\r
+\r
+/*! \internal\r
+ \brief Delete a subscription\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+void kmqint_msg_type_del_sub(kmq_msg_subscription *s) {\r
+ int t = s->type;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ if(msg_types[t]) {\r
+ LDELETE(&msg_types[t]->subs,s);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+}\r
+\r
+/*! \internal\r
+ \brief Deletes a window subscription from a message type\r
+ \note Obtains ::cs_kmq_types\r
+*/\r
+kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd) {\r
+ kmq_msg_subscription *s;\r
+\r
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)\r
+ return NULL;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ if(msg_types[t]) {\r
+ s = msg_types[t]->subs;\r
+ while(s) {\r
+ kmq_msg_subscription * n = LNEXT(s);\r
+ if(s->rcpt_type == KMQ_RCPTTYPE_HWND && s->recipient.hwnd == hwnd) {\r
+ /*TODO: do more here? */\r
+ LDELETE(&msg_types[t]->subs, s);\r
+ break;\r
+ }\r
+ s = n;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ return s;\r
+}\r
+\r
+/*! \internal\r
+ \brief Delete a callback from a message type\r
+ \note Obtains ::cs_kmq_types, ::cs_kmq_global\r
+ */\r
+kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb) {\r
+ kmq_msg_subscription *s;\r
+ kmq_queue *q;\r
+\r
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)\r
+ return NULL;\r
+\r
+ if(!msg_types[t])\r
+ return NULL;\r
+\r
+ q = kmqint_get_thread_queue();\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ s = msg_types[t]->subs;\r
+ while(s) {\r
+ kmq_msg_subscription * n = LNEXT(s);\r
+ if(s->rcpt_type == KMQ_RCPTTYPE_CB && s->recipient.cb == cb && s->queue == q) {\r
+ /*TODO: do more here? */\r
+ LDELETE(&msg_types[t]->subs, s);\r
+ break;\r
+ }\r
+ s = n;\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ return s;\r
+}\r
+\r
+/*! \internal\r
+ \brief Publish a message\r
+ \note Obtains ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs, ::cs_kmq_msg\r
+ */\r
+khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ if(msg_types[m->type]) {\r
+ kmq_msg_type *t;\r
+ kmq_msg_subscription * s;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ t = msg_types[m->type];\r
+ s = t->subs;\r
+ while(s) {\r
+ kmqint_post(s, m, try_send);\r
+ s = LNEXT(s);\r
+ }\r
+\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ } else {\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ kmqint_put_message(m);\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+ }\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+ \brief Sets the completion handler for a message type\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler) {\r
+\r
+ if (type == KMSG_SYSTEM)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(!msg_types[type])\r
+ kmqint_msg_type_create(type);\r
+\r
+ if(!msg_types[type])\r
+ return KHM_ERROR_NO_RESOURCES;\r
+\r
+ EnterCriticalSection(&cs_kmq_types);\r
+ msg_types[type]->completion_handler = handler;\r
+ LeaveCriticalSection(&cs_kmq_types);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<kmqinternal.h>\r
+\r
+CRITICAL_SECTION cs_kmq_msg;\r
+kmq_message * msg_free = NULL;\r
+kmq_message * msg_active = NULL;\r
+\r
+/*! \internal\r
+ \brief Get a message object\r
+ \note called with ::cs_kmq_msg held */\r
+kmq_message * kmqint_get_message(void) {\r
+ kmq_message * m;\r
+\r
+ LPOP(&msg_free,&m);\r
+ if(!m) {\r
+ /* allocate one */\r
+ m = malloc(sizeof(kmq_message));\r
+ }\r
+ ZeroMemory((void*)m, sizeof(kmq_message));\r
+\r
+ LPUSH(&msg_active, m);\r
+\r
+ return m;\r
+}\r
+\r
+/*! \internal\r
+ \brief Frees a message object\r
+ \note called with ::cs_kmq_msg held\r
+ */\r
+void kmqint_put_message(kmq_message *m) {\r
+ int queued;\r
+ /* we can only free a message if the refcount is zero.\r
+ Otherwise we have to wait until the call is freed. */\r
+ if(m->refcount == 0) {\r
+ LDELETE(&msg_active, m);\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+ queued = kmqint_notify_msg_completion(m);\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ if (!queued) {\r
+ if(m->err_ctx) {\r
+ kherr_release_context(m->err_ctx);\r
+ m->err_ctx = NULL;\r
+ }\r
+ if(m->wait_o) {\r
+ CloseHandle(m->wait_o);\r
+ m->wait_o = NULL;\r
+ }\r
+ LPUSH(&msg_free,m);\r
+ }\r
+ } else if(m->wait_o) {\r
+ SetEvent(m->wait_o);\r
+ }\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_send_message(khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, void * blob) {\r
+ kmq_call c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ rv = kmqint_post_message_ex(type, subtype, uparam, blob, &c, TRUE);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = kmq_wait(c, INFINITE);\r
+ if(KHM_SUCCEEDED(rv) && c->nFailed > 0)\r
+ rv = KHM_ERROR_PARTIAL;\r
+\r
+ kmq_free_call(c);\r
+\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_post_message(khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, void * blob) {\r
+ return kmqint_post_message_ex(type, subtype, uparam, blob, NULL, FALSE);\r
+}\r
+\r
+/*! \internal\r
+ \brief Frees a call\r
+ \note Obtains ::cs_kmq_msg\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call) {\r
+ kmq_message * m;\r
+\r
+ m = call;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m->refcount--;\r
+ if(!m->refcount) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs \r
+ */\r
+khm_int32 kmqint_post_message_ex(\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * blob, \r
+ kmq_call * call,\r
+ khm_boolean try_send) {\r
+ kmq_message * m;\r
+ kherr_context * ctx;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m = kmqint_get_message();\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ m->type = type;\r
+ m->subtype = subtype;\r
+ m->uparam = uparam;\r
+ m->vparam = blob;\r
+\r
+ m->timeSent = GetTickCount();\r
+ m->timeExpire = m->timeSent + kmq_call_dead_timeout;\r
+\r
+ ctx = kherr_peek_context();\r
+ if (ctx) {\r
+ if (ctx->flags & KHERR_CF_TRANSITIVE) {\r
+ m->err_ctx = ctx;\r
+ /* leave it held */\r
+ } else {\r
+ kherr_release_context(ctx);\r
+ }\r
+ }\r
+\r
+ if(call) {\r
+ m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL);\r
+ *call = m;\r
+ m->refcount++;\r
+ } else\r
+ m->wait_o = NULL;\r
+\r
+ kmqint_msg_publish(m, try_send);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_post_message_ex(khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, void * blob, kmq_call * call)\r
+{\r
+ return kmqint_post_message_ex(type, subtype, uparam, blob, call, FALSE);\r
+}\r
+\r
+\r
+/*! \internal\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_post_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, void * vparam)\r
+{\r
+ return kmq_post_sub_msg_ex(sub, type, subtype, uparam, vparam, NULL);\r
+}\r
+\r
+/*! \internal\r
+*/\r
+khm_int32 kmqint_post_sub_msg_ex(\r
+ khm_handle sub, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam, \r
+ kmq_call * call,\r
+ khm_boolean try_send)\r
+{\r
+ kmq_message * m;\r
+ kherr_context * ctx;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m = kmqint_get_message();\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ m->type = type;\r
+ m->subtype = subtype;\r
+ m->uparam = uparam;\r
+ m->vparam = vparam;\r
+\r
+ m->timeSent = GetTickCount();\r
+ m->timeExpire = m->timeSent + kmq_call_dead_timeout;\r
+\r
+ ctx = kherr_peek_context();\r
+ if (ctx) {\r
+ if (ctx->flags & KHERR_CF_TRANSITIVE) {\r
+ m->err_ctx = ctx;\r
+ /* leave it held */\r
+ } else {\r
+ kherr_release_context(ctx);\r
+ }\r
+ }\r
+\r
+ if(call) {\r
+ m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL);\r
+ *call = m;\r
+ m->refcount++;\r
+ } else\r
+ m->wait_o = NULL;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ kmqint_post((kmq_msg_subscription *) sub, m, try_send);\r
+\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, void * vparam, kmq_call * call)\r
+{\r
+ return kmqint_post_sub_msg_ex(sub, type, subtype, uparam, vparam, call, FALSE);\r
+}\r
+\r
+khm_int32 kmqint_post_subs_msg_ex(\r
+ khm_handle * subs, \r
+ khm_size n_subs, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam, \r
+ kmq_call * call,\r
+ khm_boolean try_send)\r
+{\r
+ kmq_message * m;\r
+ kherr_context * ctx;\r
+ khm_size i;\r
+\r
+ if(n_subs == 0)\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m = kmqint_get_message();\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ m->type = type;\r
+ m->subtype = subtype;\r
+ m->uparam = uparam;\r
+ m->vparam = vparam;\r
+\r
+ m->timeSent = GetTickCount();\r
+ m->timeExpire = m->timeSent + kmq_call_dead_timeout;\r
+\r
+ ctx = kherr_peek_context();\r
+ if (ctx) {\r
+ if (ctx->flags & KHERR_CF_TRANSITIVE) {\r
+ m->err_ctx = ctx;\r
+ /* leave it held */\r
+ } else {\r
+ kherr_release_context(ctx);\r
+ }\r
+ }\r
+\r
+ if(call) {\r
+ m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL);\r
+ *call = m;\r
+ m->refcount++;\r
+ } else\r
+ m->wait_o = NULL;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ for(i=0;i<n_subs;i++) {\r
+ kmqint_post((kmq_msg_subscription *) subs[i], m, try_send);\r
+ }\r
+\r
+ if(m->nCompleted + m->nFailed == m->nSent) {\r
+ kmqint_put_message(m);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_post_subs_msg(\r
+ khm_handle * subs, \r
+ khm_size n_subs, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam)\r
+{\r
+ return kmqint_post_subs_msg_ex(\r
+ subs,\r
+ n_subs,\r
+ type,\r
+ subtype,\r
+ uparam,\r
+ vparam,\r
+ NULL,\r
+ FALSE);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex(\r
+ khm_handle * subs, \r
+ khm_int32 n_subs, \r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam, \r
+ kmq_call * call)\r
+{\r
+ return kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, uparam, vparam, call, FALSE);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_send_subs_msg(\r
+ khm_handle *subs, \r
+ khm_int32 n_subs,\r
+ khm_int32 type, \r
+ khm_int32 subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam)\r
+{\r
+ kmq_call c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ rv = kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, uparam, vparam, &c, TRUE);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = kmq_wait(c, INFINITE);\r
+ if(KHM_SUCCEEDED(rv) && c->nFailed > 0)\r
+ rv = KHM_ERROR_PARTIAL;\r
+\r
+ kmq_free_call(c);\r
+\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+*/\r
+KHMEXP khm_int32 KHMAPI kmq_send_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, void * vparam)\r
+{\r
+ kmq_call c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ rv = kmqint_post_sub_msg_ex(sub, type, subtype, uparam, vparam, &c, TRUE);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = kmq_wait(c, INFINITE);\r
+ if(KHM_SUCCEEDED(rv) && c->nFailed > 0)\r
+ rv = KHM_ERROR_PARTIAL;\r
+\r
+ kmq_free_call(c);\r
+\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message(kmq_thread_id thread, khm_ui_4 uparam) {\r
+ kmq_call c;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ rv = kmq_post_thread_quit_message(thread, uparam, &c);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = kmq_wait(c, INFINITE);\r
+\r
+ kmq_free_call(c);\r
+\r
+ return rv;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs\r
+ */ \r
+KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message(kmq_thread_id thread, khm_ui_4 uparam, kmq_call * call) {\r
+ kmq_message * m;\r
+ kmq_queue * q;\r
+\r
+ EnterCriticalSection(&cs_kmq_global);\r
+ q = queues;\r
+ while(q) {\r
+ if(q->thread == thread)\r
+ break;\r
+ q = LNEXT(q);\r
+ }\r
+ LeaveCriticalSection(&cs_kmq_global);\r
+\r
+ if(!q)\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ EnterCriticalSection(&cs_kmq_msg);\r
+ m = kmqint_get_message();\r
+ LeaveCriticalSection(&cs_kmq_msg);\r
+\r
+ m->type = KMSG_SYSTEM;\r
+ m->subtype = KMSG_SYSTEM_EXIT;\r
+ m->uparam = uparam;\r
+ m->vparam = NULL;\r
+\r
+ m->timeSent = GetTickCount();\r
+ m->timeExpire = m->timeSent + kmq_call_dead_timeout;\r
+\r
+ if(call) {\r
+ m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL);\r
+ *call = m;\r
+ m->refcount++;\r
+ } else\r
+ m->wait_o = NULL;\r
+\r
+ kmqint_post_queue(q, m);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/* TODO:Implement these */\r
+KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp) {\r
+ return 0;\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call) {\r
+ return (call->nCompleted + call->nFailed == call->nSent);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout) {\r
+ kmq_message * m = call;\r
+ DWORD rv;\r
+ /*TODO: check for call free */\r
+\r
+ if(m && m->wait_o) {\r
+ rv = WaitForSingleObject(m->wait_o, timeout);\r
+ if(rv == WAIT_OBJECT_0)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_TIMEOUT;\r
+ } else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+/*! \internal\r
+ \note Obtains ::cs_kmq_types\r
+ */\r
+KHMEXP khm_int32 KHMAPI kmq_set_completion_handler(khm_int32 type, kmq_msg_completion_handler handler) {\r
+ return kmqint_msg_type_set_handler(type, handler);\r
+}\r
+\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=nidmgrdll\r
+!include <../config/Makefile.w32>\r
+\r
+DLLFILE=$(BINDIR)\nidmgr32.dll\r
+\r
+LIBFILE=$(LIBDIR)\nidmgr32.lib\r
+\r
+UTILDIR=$(OBJDIR)\util\r
+\r
+KHERRDIR=$(OBJDIR)\kherr\r
+\r
+KCONFIGDIR=$(OBJDIR)\kconfig\r
+\r
+KMQDIR=$(OBJDIR)\kmq\r
+\r
+KCDBDIR=$(OBJDIR)\kcreddb\r
+\r
+KMMDIR=$(OBJDIR)\kmm\r
+\r
+UIDIR=$(OBJDIR)\uilib\r
+\r
+OBJFILES= \\r
+ $(OBJ)\dllmain.obj \\r
+ $(UTILDIR)\hashtable.obj \\r
+ $(UTILDIR)\sync.obj \\r
+ $(UTILDIR)\mstring.obj \\r
+ $(KHERRDIR)\kherrmain.obj \\r
+ $(KHERRDIR)\kherr.obj \\r
+ $(KCONFIGDIR)\kconfigmain.obj \\r
+ $(KCONFIGDIR)\api.obj \\r
+ $(KMQDIR)\kmqmain.obj \\r
+ $(KMQDIR)\init.obj \\r
+ $(KMQDIR)\msgtype.obj \\r
+ $(KMQDIR)\consumer.obj \\r
+ $(KMQDIR)\publisher.obj \\r
+ $(KMQDIR)\kmqconfig.obj \\r
+ $(KCDBDIR)\buf.obj \\r
+ $(KCDBDIR)\attrib.obj \\r
+ $(KCDBDIR)\credential.obj \\r
+ $(KCDBDIR)\credset.obj \\r
+ $(KCDBDIR)\credtype.obj \\r
+ $(KCDBDIR)\identity.obj \\r
+ $(KCDBDIR)\init.obj \\r
+ $(KCDBDIR)\kcreddbmain.obj \\r
+ $(KCDBDIR)\type.obj \\r
+ $(KCDBDIR)\kcdbconfig.obj \\r
+ $(KMMDIR)\kmmmain.obj \\r
+ $(KMMDIR)\kmm.obj \\r
+ $(KMMDIR)\kmm_plugin.obj \\r
+ $(KMMDIR)\kmm_module.obj \\r
+ $(KMMDIR)\kmm_reg.obj \\r
+ $(KMMDIR)\kmm_registrar.obj \\r
+ $(KMMDIR)\kmmconfig.obj \\r
+ $(UIDIR)\rescache.obj \\r
+ $(UIDIR)\action.obj \\r
+ $(UIDIR)\creddlg.obj \\r
+ $(UIDIR)\alert.obj \\r
+ $(UIDIR)\propsheet.obj \\r
+ $(UIDIR)\propwnd.obj \\r
+ $(UIDIR)\uilibmain.obj \\r
+ $(UIDIR)\actiondef.obj \\r
+ $(UIDIR)\acceldef.obj \\r
+ $(UIDIR)\configui.obj \\r
+ $(UIDIR)\trackerwnd.obj\r
+\r
+RESFILES= \\r
+ $(OBJ)\nidmgrdll.res \\r
+ $(KCDBDIR)\kcredres.res \\r
+ $(KMMDIR)\kmm_msgs.res \\r
+\r
+SDKLIBFILES= \\r
+ advapi32.lib \\r
+ strsafe.lib \\r
+ comctl32.lib\r
+\r
+$(DLLFILE): $(OBJFILES) $(RESFILES)\r
+ $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES)\r
+\r
+all: mkdirs $(DLLFILE)\r
+\r
+clean::\r
+ $(RM) $(DLLFILE)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<windows.h>\r
+\r
+/* forward dcls */\r
+void\r
+kherr_process_attach(void);\r
+\r
+void\r
+kherr_process_detach(void);\r
+\r
+void\r
+kherr_thread_attach(void);\r
+\r
+void\r
+kherr_thread_detach(void);\r
+\r
+void\r
+kconfig_process_attach(void);\r
+\r
+void\r
+kconfig_process_detach(void);\r
+\r
+void\r
+kmq_process_attach(void);\r
+\r
+void\r
+kmq_process_detach(void);\r
+\r
+void\r
+kmq_thread_attach(void);\r
+\r
+void\r
+kmq_thread_detach(void);\r
+\r
+void\r
+kcdb_process_attach(HINSTANCE);\r
+\r
+void\r
+kcdb_process_detach(void);\r
+\r
+void \r
+kmm_process_attach(HINSTANCE);\r
+\r
+void\r
+kmm_process_detach(void);\r
+\r
+void\r
+uilib_process_attach(void);\r
+\r
+void\r
+uilib_process_detach(void);\r
+\r
+\r
+BOOL WINAPI DllMain(\r
+ HINSTANCE hinstDLL, // handle to DLL module\r
+ DWORD fdwReason, // reason for calling function\r
+ LPVOID lpReserved ) // reserved\r
+{\r
+ switch(fdwReason) {\r
+ case DLL_PROCESS_ATTACH:\r
+ kherr_process_attach();\r
+ kconfig_process_attach();\r
+ kmq_process_attach();\r
+ kcdb_process_attach(hinstDLL);\r
+ kmm_process_attach(hinstDLL);\r
+ uilib_process_attach();\r
+ break;\r
+\r
+ case DLL_PROCESS_DETACH:\r
+ kherr_process_detach();\r
+ kconfig_process_detach();\r
+ kmq_process_detach();\r
+ kcdb_process_detach();\r
+ kmm_process_detach();\r
+ uilib_process_detach();\r
+ break;\r
+\r
+ case DLL_THREAD_ATTACH:\r
+ kherr_thread_attach();\r
+ kmq_thread_attach();\r
+ break;\r
+\r
+ case DLL_THREAD_DETACH:\r
+ kherr_thread_detach();\r
+ kmq_thread_detach();\r
+ break;\r
+ }\r
+ return TRUE;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<afxres.h>\r
+#include<khimaira_version.h>\r
+\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif\r
+\r
+1 VERSIONINFO\r
+ FILEVERSION KH_VERSION_LIST\r
+ PRODUCTVERSION KH_VERSION_LIST\r
+ FILEFLAGSMASK 0x17L\r
+ FILEFLAGS KH_VER_FILEFLAGS\r
+ FILEOS KH_VER_FILEOS\r
+ FILETYPE KH_VER_FILETYPEDLL\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+ BLOCK "StringFileInfo"\r
+ BEGIN\r
+ BLOCK "040904b0"\r
+ BEGIN\r
+ VALUE "CompanyName", KH_VERSTR_COMPANY_1033\r
+ VALUE "FileDescription", "NetIDMgr API"\r
+ VALUE "FileVersion", KH_VERSION_STRING\r
+ VALUE "InternalName", "nidmgr32"\r
+ VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033\r
+ VALUE "OriginalFilename", "nidmgr32.dll"\r
+ VALUE "ProductName", KH_VERSTR_PRODUCT_1033\r
+ VALUE "ProductVersion", KH_VERSTR_VERSION_1033\r
+#ifdef KH_VERSTR_COMMENT_1033\r
+ VALUE "Comments", KH_VERSTR_COMMENT_1033\r
+#endif\r
+#ifdef KH_VERSTR_PRIVATE_1033\r
+ VALUE "PrivateBuild", KH_VERSTR_PRIVATE_1033\r
+#endif\r
+#ifdef KH_VERSTR_SPECIAL_1033\r
+ VALUE "SpecialBuild", KH_VERSTR_SPECIAL_1033\r
+#endif\r
+ END\r
+ END\r
+\r
+/* Language independent */\r
+ BLOCK "VarFileInfo"\r
+ BEGIN\r
+ VALUE "Translation", 0x409, 1200\r
+ END\r
+\r
+END\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=plugins\common\r
+!include <../../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\krb5common.h \\r
+ $(INCDIR)\dynimport.h\r
+\r
+OBJFILES= \\r
+ $(LIBDIR)\krb5common.obj \\r
+ $(LIBDIR)\dynimport.obj\r
+\r
+all: mkdirs $(INCFILES) $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
+\r
+{}.c{$(LIBDIR)}.obj:\r
+ $(C2OBJ)\r
--- /dev/null
+/*\r
+* Copyright (c) 2004 Massachusetts Institute of Technology\r
+*\r
+* Permission is hereby granted, free of charge, to any person\r
+* obtaining a copy of this software and associated documentation\r
+* files (the "Software"), to deal in the Software without\r
+* restriction, including without limitation the rights to use, copy,\r
+* modify, merge, publish, distribute, sublicense, and/or sell copies\r
+* of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be\r
+* included in all copies or substantial portions of the Software.\r
+*\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+* SOFTWARE.\r
+*/\r
+\r
+/* $Id$ */\r
+\r
+#include<windows.h>\r
+#include<khdefs.h>\r
+#include<kherror.h>\r
+#include<dynimport.h>\r
+\r
+HINSTANCE hKrb4 = 0;\r
+HINSTANCE hKrb5 = 0;\r
+HINSTANCE hKrb524 = 0;\r
+HINSTANCE hSecur32 = 0;\r
+HINSTANCE hComErr = 0;\r
+HINSTANCE hService = 0;\r
+HINSTANCE hProfile = 0;\r
+HINSTANCE hPsapi = 0; \r
+HINSTANCE hToolHelp32 = 0; \r
+HINSTANCE hCCAPI = 0;\r
+\r
+DWORD AfsAvailable = 0;\r
+\r
+// CCAPI\r
+DECL_FUNC_PTR(cc_initialize);\r
+DECL_FUNC_PTR(cc_shutdown);\r
+DECL_FUNC_PTR(cc_get_NC_info);\r
+DECL_FUNC_PTR(cc_free_NC_info);\r
+\r
+// krb4 functions\r
+DECL_FUNC_PTR(get_krb_err_txt_entry);\r
+DECL_FUNC_PTR(k_isinst);\r
+DECL_FUNC_PTR(k_isname);\r
+DECL_FUNC_PTR(k_isrealm);\r
+DECL_FUNC_PTR(kadm_change_your_password);\r
+DECL_FUNC_PTR(kname_parse);\r
+DECL_FUNC_PTR(krb_get_cred);\r
+DECL_FUNC_PTR(krb_get_krbhst);\r
+DECL_FUNC_PTR(krb_get_lrealm);\r
+DECL_FUNC_PTR(krb_get_pw_in_tkt);\r
+DECL_FUNC_PTR(krb_get_tf_realm);\r
+DECL_FUNC_PTR(krb_mk_req);\r
+DECL_FUNC_PTR(krb_realmofhost);\r
+DECL_FUNC_PTR(tf_init);\r
+DECL_FUNC_PTR(tf_close);\r
+DECL_FUNC_PTR(tf_get_cred);\r
+DECL_FUNC_PTR(tf_get_pname);\r
+DECL_FUNC_PTR(tf_get_pinst);\r
+DECL_FUNC_PTR(LocalHostAddr);\r
+DECL_FUNC_PTR(tkt_string);\r
+DECL_FUNC_PTR(krb_set_tkt_string);\r
+DECL_FUNC_PTR(initialize_krb_error_func);\r
+DECL_FUNC_PTR(initialize_kadm_error_table);\r
+DECL_FUNC_PTR(dest_tkt);\r
+DECL_FUNC_PTR(krb_in_tkt);\r
+DECL_FUNC_PTR(krb_save_credentials);\r
+DECL_FUNC_PTR(krb_get_krbconf2);\r
+DECL_FUNC_PTR(krb_get_krbrealm2);\r
+DECL_FUNC_PTR(krb_life_to_time);\r
+\r
+// krb5 functions\r
+DECL_FUNC_PTR(krb5_change_password);\r
+DECL_FUNC_PTR(krb5_get_init_creds_opt_init);\r
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);\r
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);\r
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);\r
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);\r
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);\r
+DECL_FUNC_PTR(krb5_get_init_creds_password);\r
+DECL_FUNC_PTR(krb5_get_prompt_types);\r
+DECL_FUNC_PTR(krb5_build_principal_ext);\r
+DECL_FUNC_PTR(krb5_cc_get_name);\r
+DECL_FUNC_PTR(krb5_cc_resolve);\r
+DECL_FUNC_PTR(krb5_cc_default);\r
+DECL_FUNC_PTR(krb5_cc_default_name);\r
+DECL_FUNC_PTR(krb5_cc_set_default_name);\r
+DECL_FUNC_PTR(krb5_cc_initialize);\r
+DECL_FUNC_PTR(krb5_cc_destroy);\r
+DECL_FUNC_PTR(krb5_cc_close);\r
+DECL_FUNC_PTR(krb5_cc_store_cred);\r
+DECL_FUNC_PTR(krb5_cc_copy_creds);\r
+DECL_FUNC_PTR(krb5_cc_retrieve_cred);\r
+DECL_FUNC_PTR(krb5_cc_get_principal);\r
+DECL_FUNC_PTR(krb5_cc_start_seq_get);\r
+DECL_FUNC_PTR(krb5_cc_next_cred);\r
+DECL_FUNC_PTR(krb5_cc_end_seq_get);\r
+DECL_FUNC_PTR(krb5_cc_remove_cred);\r
+DECL_FUNC_PTR(krb5_cc_set_flags);\r
+// DECL_FUNC_PTR(krb5_cc_get_type);\r
+DECL_FUNC_PTR(krb5_free_context);\r
+DECL_FUNC_PTR(krb5_free_cred_contents);\r
+DECL_FUNC_PTR(krb5_free_principal);\r
+DECL_FUNC_PTR(krb5_get_in_tkt_with_password);\r
+DECL_FUNC_PTR(krb5_init_context);\r
+DECL_FUNC_PTR(krb5_parse_name);\r
+DECL_FUNC_PTR(krb5_timeofday);\r
+DECL_FUNC_PTR(krb5_timestamp_to_sfstring);\r
+DECL_FUNC_PTR(krb5_unparse_name);\r
+DECL_FUNC_PTR(krb5_get_credentials);\r
+DECL_FUNC_PTR(krb5_mk_req);\r
+DECL_FUNC_PTR(krb5_sname_to_principal);\r
+DECL_FUNC_PTR(krb5_get_credentials_renew);\r
+DECL_FUNC_PTR(krb5_free_data);\r
+DECL_FUNC_PTR(krb5_free_data_contents);\r
+// DECL_FUNC_PTR(krb5_get_realm_domain);\r
+DECL_FUNC_PTR(krb5_free_unparsed_name);\r
+DECL_FUNC_PTR(krb5_os_localaddr);\r
+DECL_FUNC_PTR(krb5_copy_keyblock_contents);\r
+DECL_FUNC_PTR(krb5_copy_data);\r
+DECL_FUNC_PTR(krb5_free_creds);\r
+DECL_FUNC_PTR(krb5_build_principal);\r
+DECL_FUNC_PTR(krb5_get_renewed_creds);\r
+DECL_FUNC_PTR(krb5_get_default_config_files);\r
+DECL_FUNC_PTR(krb5_free_config_files);\r
+DECL_FUNC_PTR(krb5_get_default_realm);\r
+DECL_FUNC_PTR(krb5_free_ticket);\r
+DECL_FUNC_PTR(krb5_decode_ticket);\r
+DECL_FUNC_PTR(krb5_get_host_realm);\r
+DECL_FUNC_PTR(krb5_free_host_realm);\r
+DECL_FUNC_PTR(krb5_c_random_make_octets);\r
+DECL_FUNC_PTR(krb5_free_addresses);\r
+DECL_FUNC_PTR(krb5_free_default_realm);\r
+\r
+// Krb524 functions\r
+DECL_FUNC_PTR(krb524_init_ets);\r
+DECL_FUNC_PTR(krb524_convert_creds_kdc);\r
+\r
+// ComErr functions\r
+DECL_FUNC_PTR(com_err);\r
+DECL_FUNC_PTR(error_message);\r
+\r
+// Profile functions\r
+DECL_FUNC_PTR(profile_init); \r
+DECL_FUNC_PTR(profile_release); \r
+DECL_FUNC_PTR(profile_get_subsection_names);\r
+DECL_FUNC_PTR(profile_free_list);\r
+DECL_FUNC_PTR(profile_get_string);\r
+DECL_FUNC_PTR(profile_release_string);\r
+\r
+// Service functions\r
+DECL_FUNC_PTR(OpenSCManagerA);\r
+DECL_FUNC_PTR(OpenServiceA);\r
+DECL_FUNC_PTR(QueryServiceStatus);\r
+DECL_FUNC_PTR(CloseServiceHandle);\r
+DECL_FUNC_PTR(LsaNtStatusToWinError);\r
+\r
+// LSA Functions\r
+DECL_FUNC_PTR(LsaConnectUntrusted);\r
+DECL_FUNC_PTR(LsaLookupAuthenticationPackage);\r
+DECL_FUNC_PTR(LsaCallAuthenticationPackage);\r
+DECL_FUNC_PTR(LsaFreeReturnBuffer);\r
+DECL_FUNC_PTR(LsaGetLogonSessionData);\r
+\r
+// CCAPI\r
+FUNC_INFO ccapi_fi[] = {\r
+ MAKE_FUNC_INFO(cc_initialize),\r
+ MAKE_FUNC_INFO(cc_shutdown),\r
+ MAKE_FUNC_INFO(cc_get_NC_info),\r
+ MAKE_FUNC_INFO(cc_free_NC_info),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO k4_fi[] = {\r
+ MAKE_FUNC_INFO(get_krb_err_txt_entry),\r
+ MAKE_FUNC_INFO(k_isinst),\r
+ MAKE_FUNC_INFO(k_isname),\r
+ MAKE_FUNC_INFO(k_isrealm),\r
+ MAKE_FUNC_INFO(kadm_change_your_password),\r
+ MAKE_FUNC_INFO(kname_parse),\r
+ MAKE_FUNC_INFO(krb_get_cred),\r
+ MAKE_FUNC_INFO(krb_get_krbhst),\r
+ MAKE_FUNC_INFO(krb_get_lrealm),\r
+ MAKE_FUNC_INFO(krb_get_pw_in_tkt),\r
+ MAKE_FUNC_INFO(krb_get_tf_realm),\r
+ MAKE_FUNC_INFO(krb_mk_req),\r
+ MAKE_FUNC_INFO(krb_realmofhost),\r
+ MAKE_FUNC_INFO(tf_init),\r
+ MAKE_FUNC_INFO(tf_close),\r
+ MAKE_FUNC_INFO(tf_get_cred),\r
+ MAKE_FUNC_INFO(tf_get_pname),\r
+ MAKE_FUNC_INFO(tf_get_pinst),\r
+ MAKE_FUNC_INFO(LocalHostAddr),\r
+ MAKE_FUNC_INFO(tkt_string),\r
+ MAKE_FUNC_INFO(krb_set_tkt_string),\r
+ MAKE_FUNC_INFO(initialize_krb_error_func),\r
+ MAKE_FUNC_INFO(initialize_kadm_error_table),\r
+ MAKE_FUNC_INFO(dest_tkt),\r
+ /* MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX\r
+ MAKE_FUNC_INFO(krb_in_tkt),\r
+ MAKE_FUNC_INFO(krb_save_credentials),\r
+ MAKE_FUNC_INFO(krb_get_krbconf2),\r
+ MAKE_FUNC_INFO(krb_get_krbrealm2),\r
+ MAKE_FUNC_INFO(krb_life_to_time),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO k5_fi[] = {\r
+ MAKE_FUNC_INFO(krb5_change_password),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),\r
+ MAKE_FUNC_INFO(krb5_get_init_creds_password),\r
+ MAKE_FUNC_INFO(krb5_get_prompt_types),\r
+ MAKE_FUNC_INFO(krb5_build_principal_ext),\r
+ MAKE_FUNC_INFO(krb5_cc_get_name),\r
+ MAKE_FUNC_INFO(krb5_cc_resolve),\r
+ MAKE_FUNC_INFO(krb5_cc_default),\r
+ MAKE_FUNC_INFO(krb5_cc_default_name),\r
+ MAKE_FUNC_INFO(krb5_cc_set_default_name),\r
+ MAKE_FUNC_INFO(krb5_cc_initialize),\r
+ MAKE_FUNC_INFO(krb5_cc_destroy),\r
+ MAKE_FUNC_INFO(krb5_cc_close),\r
+ MAKE_FUNC_INFO(krb5_cc_copy_creds),\r
+ MAKE_FUNC_INFO(krb5_cc_store_cred),\r
+ MAKE_FUNC_INFO(krb5_cc_retrieve_cred),\r
+ MAKE_FUNC_INFO(krb5_cc_get_principal),\r
+ MAKE_FUNC_INFO(krb5_cc_start_seq_get),\r
+ MAKE_FUNC_INFO(krb5_cc_next_cred),\r
+ MAKE_FUNC_INFO(krb5_cc_end_seq_get),\r
+ MAKE_FUNC_INFO(krb5_cc_remove_cred),\r
+ MAKE_FUNC_INFO(krb5_cc_set_flags),\r
+ // MAKE_FUNC_INFO(krb5_cc_get_type),\r
+ MAKE_FUNC_INFO(krb5_free_context),\r
+ MAKE_FUNC_INFO(krb5_free_cred_contents),\r
+ MAKE_FUNC_INFO(krb5_free_principal),\r
+ MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),\r
+ MAKE_FUNC_INFO(krb5_init_context),\r
+ MAKE_FUNC_INFO(krb5_parse_name),\r
+ MAKE_FUNC_INFO(krb5_timeofday),\r
+ MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),\r
+ MAKE_FUNC_INFO(krb5_unparse_name),\r
+ MAKE_FUNC_INFO(krb5_get_credentials),\r
+ MAKE_FUNC_INFO(krb5_mk_req),\r
+ MAKE_FUNC_INFO(krb5_sname_to_principal),\r
+ MAKE_FUNC_INFO(krb5_get_credentials_renew),\r
+ MAKE_FUNC_INFO(krb5_free_data),\r
+ MAKE_FUNC_INFO(krb5_free_data_contents),\r
+ // MAKE_FUNC_INFO(krb5_get_realm_domain),\r
+ MAKE_FUNC_INFO(krb5_free_unparsed_name),\r
+ MAKE_FUNC_INFO(krb5_os_localaddr),\r
+ MAKE_FUNC_INFO(krb5_copy_keyblock_contents),\r
+ MAKE_FUNC_INFO(krb5_copy_data),\r
+ MAKE_FUNC_INFO(krb5_free_creds),\r
+ MAKE_FUNC_INFO(krb5_build_principal),\r
+ MAKE_FUNC_INFO(krb5_get_renewed_creds),\r
+ MAKE_FUNC_INFO(krb5_free_addresses),\r
+ MAKE_FUNC_INFO(krb5_get_default_config_files),\r
+ MAKE_FUNC_INFO(krb5_free_config_files),\r
+ MAKE_FUNC_INFO(krb5_get_default_realm),\r
+ MAKE_FUNC_INFO(krb5_free_ticket),\r
+ MAKE_FUNC_INFO(krb5_decode_ticket),\r
+ MAKE_FUNC_INFO(krb5_get_host_realm),\r
+ MAKE_FUNC_INFO(krb5_free_host_realm),\r
+ MAKE_FUNC_INFO(krb5_c_random_make_octets),\r
+ MAKE_FUNC_INFO(krb5_free_default_realm),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO k524_fi[] = {\r
+ MAKE_FUNC_INFO(krb524_init_ets),\r
+ MAKE_FUNC_INFO(krb524_convert_creds_kdc),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO profile_fi[] = {\r
+ MAKE_FUNC_INFO(profile_init),\r
+ MAKE_FUNC_INFO(profile_release), \r
+ MAKE_FUNC_INFO(profile_get_subsection_names),\r
+ MAKE_FUNC_INFO(profile_free_list),\r
+ MAKE_FUNC_INFO(profile_get_string),\r
+ MAKE_FUNC_INFO(profile_release_string),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO ce_fi[] = {\r
+ MAKE_FUNC_INFO(com_err),\r
+ MAKE_FUNC_INFO(error_message),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO service_fi[] = {\r
+ MAKE_FUNC_INFO(OpenSCManagerA),\r
+ MAKE_FUNC_INFO(OpenServiceA),\r
+ MAKE_FUNC_INFO(QueryServiceStatus),\r
+ MAKE_FUNC_INFO(CloseServiceHandle),\r
+ MAKE_FUNC_INFO(LsaNtStatusToWinError),\r
+ END_FUNC_INFO\r
+};\r
+\r
+FUNC_INFO lsa_fi[] = {\r
+ MAKE_FUNC_INFO(LsaConnectUntrusted),\r
+ MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),\r
+ MAKE_FUNC_INFO(LsaCallAuthenticationPackage),\r
+ MAKE_FUNC_INFO(LsaFreeReturnBuffer),\r
+ MAKE_FUNC_INFO(LsaGetLogonSessionData),\r
+ END_FUNC_INFO\r
+};\r
+\r
+// psapi functions\r
+DECL_FUNC_PTR(GetModuleFileNameExA);\r
+DECL_FUNC_PTR(EnumProcessModules);\r
+\r
+FUNC_INFO psapi_fi[] = {\r
+ MAKE_FUNC_INFO(GetModuleFileNameExA),\r
+ MAKE_FUNC_INFO(EnumProcessModules),\r
+ END_FUNC_INFO\r
+};\r
+\r
+// toolhelp functions\r
+DECL_FUNC_PTR(CreateToolhelp32Snapshot);\r
+DECL_FUNC_PTR(Module32First);\r
+DECL_FUNC_PTR(Module32Next);\r
+\r
+FUNC_INFO toolhelp_fi[] = {\r
+ MAKE_FUNC_INFO(CreateToolhelp32Snapshot),\r
+ MAKE_FUNC_INFO(Module32First),\r
+ MAKE_FUNC_INFO(Module32Next),\r
+ END_FUNC_INFO\r
+};\r
+\r
+khm_int32 init_imports(void) {\r
+ OSVERSIONINFO osvi;\r
+\r
+ LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);\r
+ LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);\r
+ LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);\r
+ LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);\r
+ LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);\r
+ LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);\r
+ LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);\r
+ LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);\r
+\r
+ memset(&osvi, 0, sizeof(OSVERSIONINFO));\r
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
+ GetVersionEx(&osvi);\r
+\r
+ // XXX: We should really use feature testing, first\r
+ // checking for CreateToolhelp32Snapshot. If that's\r
+ // not around, we try the psapi stuff.\r
+ //\r
+ // Only load LSA functions if on NT/2000/XP\r
+ if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)\r
+ {\r
+ // Windows 9x\r
+ LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0);\r
+ hPsapi = 0;\r
+ } \r
+ else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)\r
+ {\r
+ // Windows NT\r
+ LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0);\r
+ hToolHelp32 = 0;\r
+ }\r
+\r
+ AfsAvailable = TRUE; //afscompat_init();\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 exit_imports(void) {\r
+ //afscompat_close();\r
+\r
+ if (hKrb4)\r
+ FreeLibrary(hKrb4);\r
+ if (hKrb5)\r
+ FreeLibrary(hKrb5);\r
+ if (hProfile)\r
+ FreeLibrary(hProfile);\r
+ if (hComErr)\r
+ FreeLibrary(hComErr);\r
+ if (hService)\r
+ FreeLibrary(hService);\r
+ if (hSecur32)\r
+ FreeLibrary(hSecur32);\r
+ if (hKrb524)\r
+ FreeLibrary(hKrb524);\r
+ if (hPsapi)\r
+ FreeLibrary(hPsapi);\r
+ if (hToolHelp32)\r
+ FreeLibrary(hToolHelp32);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+int (*Lcom_err)(LPSTR,long,LPSTR,...);\r
+LPSTR (*Lerror_message)(long);\r
+LPSTR (*Lerror_table_name)(long);\r
+\r
+void Leash_load_com_err_callback(FARPROC ce,\r
+ FARPROC em,\r
+ FARPROC etn)\r
+{\r
+ (FARPROC)Lcom_err=ce;\r
+ (FARPROC)Lerror_message=em;\r
+ (FARPROC)Lerror_table_name=etn;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_DYNIMPORT_H\r
+#define __KHIMAIRA_DYNIMPORT_H\r
+\r
+/* Dynamic imports */\r
+#include<khdefs.h>\r
+#include<tlhelp32.h>\r
+#include<ntsecapi.h>\r
+\r
+extern HINSTANCE hKrb4;\r
+extern HINSTANCE hKrb5;\r
+extern HINSTANCE hProfile;\r
+\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#define CCAPI_DLL "krbcc32.dll"\r
+#define KRBCC32_DLL "krbcc32.dll"\r
+#define SERVICE_DLL "advapi32.dll"\r
+#define SECUR32_DLL "secur32.dll"\r
+#define PROFILE_DLL "xpprof32.dll"\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <loadfuncs-com_err.h>\r
+#include <loadfuncs-krb5.h>\r
+#include <loadfuncs-profile.h>\r
+#include <loadfuncs-krb.h>\r
+#include <loadfuncs-krb524.h>\r
+#include <loadfuncs-lsa.h>\r
+\r
+//// CCAPI\r
+/* In order to avoid including the private CCAPI headers */\r
+typedef int cc_int32;\r
+\r
+#define CC_API_VER_1 1\r
+#define CC_API_VER_2 2\r
+\r
+#define CCACHE_API cc_int32\r
+\r
+/*\r
+** The Official Error Codes\r
+*/\r
+#define CC_NOERROR 0\r
+#define CC_BADNAME 1\r
+#define CC_NOTFOUND 2\r
+#define CC_END 3\r
+#define CC_IO 4\r
+#define CC_WRITE 5\r
+#define CC_NOMEM 6\r
+#define CC_FORMAT 7\r
+#define CC_LOCKED 8\r
+#define CC_BAD_API_VERSION 9\r
+#define CC_NO_EXIST 10\r
+#define CC_NOT_SUPP 11\r
+#define CC_BAD_PARM 12\r
+#define CC_ERR_CACHE_ATTACH 13\r
+#define CC_ERR_CACHE_RELEASE 14\r
+#define CC_ERR_CACHE_FULL 15\r
+#define CC_ERR_CRED_VERSION 16\r
+\r
+enum {\r
+ CC_CRED_VUNKNOWN = 0, // For validation\r
+ CC_CRED_V4 = 1,\r
+ CC_CRED_V5 = 2,\r
+ CC_CRED_VMAX = 3 // For validation\r
+};\r
+\r
+typedef struct opaque_dll_control_block_type* apiCB;\r
+typedef struct _infoNC {\r
+ char* name;\r
+ char* principal;\r
+ cc_int32 vers;\r
+} infoNC;\r
+\r
+TYPEDEF_FUNC(\r
+CCACHE_API,\r
+CALLCONV_C,\r
+cc_initialize,\r
+ (\r
+ apiCB** cc_ctx, // < DLL's primary control structure.\r
+ // returned here, passed everywhere else\r
+ cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1)\r
+ cc_int32* api_supported, // < if ~NULL, max ver supported by DLL\r
+ const char** vendor // < if ~NULL, vendor name in read only C string\r
+ )\r
+);\r
+\r
+TYPEDEF_FUNC(\r
+CCACHE_API,\r
+CALLCONV_C,\r
+cc_shutdown,\r
+ (\r
+ apiCB** cc_ctx // <> DLL's primary control structure. NULL after\r
+ )\r
+);\r
+\r
+TYPEDEF_FUNC(\r
+CCACHE_API,\r
+CALLCONV_C,\r
+cc_get_NC_info,\r
+ (\r
+ apiCB* cc_ctx, // > DLL's primary control structure\r
+ struct _infoNC*** ppNCi // < (NULL before call) null terminated,\r
+ // list of a structs (free via cc_free_infoNC())\r
+ )\r
+);\r
+\r
+TYPEDEF_FUNC(\r
+CCACHE_API,\r
+CALLCONV_C,\r
+cc_free_NC_info,\r
+ (\r
+ apiCB* cc_ctx,\r
+ struct _infoNC*** ppNCi // < free list of structs returned by\r
+ // cc_get_cache_names(). set to NULL on return\r
+ )\r
+);\r
+//// \CCAPI\r
+\r
+extern DWORD AfsAvailable;\r
+\r
+// service definitions\r
+typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD);\r
+typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD);\r
+typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS);\r
+typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE);\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+// CCAPI\r
+extern DECL_FUNC_PTR(cc_initialize);\r
+extern DECL_FUNC_PTR(cc_shutdown);\r
+extern DECL_FUNC_PTR(cc_get_NC_info);\r
+extern DECL_FUNC_PTR(cc_free_NC_info);\r
+\r
+// krb4 functions\r
+extern DECL_FUNC_PTR(get_krb_err_txt_entry);\r
+extern DECL_FUNC_PTR(k_isinst);\r
+extern DECL_FUNC_PTR(k_isname);\r
+extern DECL_FUNC_PTR(k_isrealm);\r
+extern DECL_FUNC_PTR(kadm_change_your_password);\r
+extern DECL_FUNC_PTR(kname_parse);\r
+extern DECL_FUNC_PTR(krb_get_cred);\r
+extern DECL_FUNC_PTR(krb_get_krbhst);\r
+extern DECL_FUNC_PTR(krb_get_lrealm);\r
+extern DECL_FUNC_PTR(krb_get_pw_in_tkt);\r
+extern DECL_FUNC_PTR(krb_get_tf_realm);\r
+extern DECL_FUNC_PTR(krb_mk_req);\r
+extern DECL_FUNC_PTR(krb_realmofhost);\r
+extern DECL_FUNC_PTR(tf_init);\r
+extern DECL_FUNC_PTR(tf_close);\r
+extern DECL_FUNC_PTR(tf_get_cred);\r
+extern DECL_FUNC_PTR(tf_get_pname);\r
+extern DECL_FUNC_PTR(tf_get_pinst);\r
+extern DECL_FUNC_PTR(LocalHostAddr);\r
+extern DECL_FUNC_PTR(tkt_string);\r
+extern DECL_FUNC_PTR(krb_set_tkt_string);\r
+extern DECL_FUNC_PTR(initialize_krb_error_func);\r
+extern DECL_FUNC_PTR(initialize_kadm_error_table);\r
+extern DECL_FUNC_PTR(dest_tkt);\r
+extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX\r
+extern DECL_FUNC_PTR(krb_in_tkt);\r
+extern DECL_FUNC_PTR(krb_save_credentials);\r
+extern DECL_FUNC_PTR(krb_get_krbconf2);\r
+extern DECL_FUNC_PTR(krb_get_krbrealm2);\r
+extern DECL_FUNC_PTR(krb_life_to_time);\r
+\r
+// krb5 functions\r
+extern DECL_FUNC_PTR(krb5_change_password);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);\r
+extern DECL_FUNC_PTR(krb5_get_init_creds_password);\r
+extern DECL_FUNC_PTR(krb5_get_prompt_types);\r
+extern DECL_FUNC_PTR(krb5_build_principal_ext);\r
+extern DECL_FUNC_PTR(krb5_cc_get_name);\r
+extern DECL_FUNC_PTR(krb5_cc_resolve);\r
+extern DECL_FUNC_PTR(krb5_cc_default);\r
+extern DECL_FUNC_PTR(krb5_cc_default_name);\r
+extern DECL_FUNC_PTR(krb5_cc_set_default_name);\r
+extern DECL_FUNC_PTR(krb5_cc_initialize);\r
+extern DECL_FUNC_PTR(krb5_cc_destroy);\r
+extern DECL_FUNC_PTR(krb5_cc_close);\r
+extern DECL_FUNC_PTR(krb5_cc_copy_creds);\r
+extern DECL_FUNC_PTR(krb5_cc_store_cred);\r
+extern DECL_FUNC_PTR(krb5_cc_retrieve_cred);\r
+extern DECL_FUNC_PTR(krb5_cc_get_principal);\r
+extern DECL_FUNC_PTR(krb5_cc_start_seq_get);\r
+extern DECL_FUNC_PTR(krb5_cc_next_cred);\r
+extern DECL_FUNC_PTR(krb5_cc_end_seq_get);\r
+extern DECL_FUNC_PTR(krb5_cc_remove_cred);\r
+extern DECL_FUNC_PTR(krb5_cc_set_flags);\r
+// extern DECL_FUNC_PTR(krb5_cc_get_type);\r
+extern DECL_FUNC_PTR(krb5_free_context);\r
+extern DECL_FUNC_PTR(krb5_free_cred_contents);\r
+extern DECL_FUNC_PTR(krb5_free_principal);\r
+extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password);\r
+extern DECL_FUNC_PTR(krb5_init_context);\r
+extern DECL_FUNC_PTR(krb5_parse_name);\r
+extern DECL_FUNC_PTR(krb5_timeofday);\r
+extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring);\r
+extern DECL_FUNC_PTR(krb5_unparse_name);\r
+extern DECL_FUNC_PTR(krb5_get_credentials);\r
+extern DECL_FUNC_PTR(krb5_mk_req);\r
+extern DECL_FUNC_PTR(krb5_sname_to_principal);\r
+extern DECL_FUNC_PTR(krb5_get_credentials_renew);\r
+extern DECL_FUNC_PTR(krb5_free_data);\r
+extern DECL_FUNC_PTR(krb5_free_data_contents);\r
+// extern DECL_FUNC_PTR(krb5_get_realm_domain);\r
+extern DECL_FUNC_PTR(krb5_free_unparsed_name);\r
+extern DECL_FUNC_PTR(krb5_os_localaddr);\r
+extern DECL_FUNC_PTR(krb5_copy_keyblock_contents);\r
+extern DECL_FUNC_PTR(krb5_copy_data);\r
+extern DECL_FUNC_PTR(krb5_free_creds);\r
+extern DECL_FUNC_PTR(krb5_build_principal);\r
+extern DECL_FUNC_PTR(krb5_get_renewed_creds);\r
+extern DECL_FUNC_PTR(krb5_free_addresses);\r
+extern DECL_FUNC_PTR(krb5_get_default_config_files);\r
+extern DECL_FUNC_PTR(krb5_free_config_files);\r
+extern DECL_FUNC_PTR(krb5_get_default_realm);\r
+extern DECL_FUNC_PTR(krb5_free_ticket);\r
+extern DECL_FUNC_PTR(krb5_decode_ticket);\r
+extern DECL_FUNC_PTR(krb5_get_host_realm);\r
+extern DECL_FUNC_PTR(krb5_free_host_realm);\r
+extern DECL_FUNC_PTR(krb5_c_random_make_octets);\r
+extern DECL_FUNC_PTR(krb5_free_default_realm);\r
+\r
+// Krb524 functions\r
+extern DECL_FUNC_PTR(krb524_init_ets);\r
+extern DECL_FUNC_PTR(krb524_convert_creds_kdc);\r
+\r
+// ComErr functions\r
+extern DECL_FUNC_PTR(com_err);\r
+extern DECL_FUNC_PTR(error_message);\r
+\r
+// Profile functions\r
+extern DECL_FUNC_PTR(profile_init);\r
+extern DECL_FUNC_PTR(profile_release);\r
+extern DECL_FUNC_PTR(profile_get_subsection_names);\r
+extern DECL_FUNC_PTR(profile_free_list);\r
+extern DECL_FUNC_PTR(profile_get_string);\r
+extern DECL_FUNC_PTR(profile_release_string);\r
+\r
+// Service functions\r
+extern DECL_FUNC_PTR(OpenSCManagerA);\r
+extern DECL_FUNC_PTR(OpenServiceA);\r
+extern DECL_FUNC_PTR(QueryServiceStatus);\r
+extern DECL_FUNC_PTR(CloseServiceHandle);\r
+extern DECL_FUNC_PTR(LsaNtStatusToWinError);\r
+\r
+// LSA Functions\r
+extern DECL_FUNC_PTR(LsaConnectUntrusted);\r
+extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage);\r
+extern DECL_FUNC_PTR(LsaCallAuthenticationPackage);\r
+extern DECL_FUNC_PTR(LsaFreeReturnBuffer);\r
+extern DECL_FUNC_PTR(LsaGetLogonSessionData);\r
+\r
+// toolhelp functions\r
+TYPEDEF_FUNC(\r
+ HANDLE,\r
+ WINAPI,\r
+ CreateToolhelp32Snapshot,\r
+ (DWORD, DWORD)\r
+ );\r
+TYPEDEF_FUNC(\r
+ BOOL,\r
+ WINAPI,\r
+ Module32First,\r
+ (HANDLE, LPMODULEENTRY32)\r
+ );\r
+TYPEDEF_FUNC(\r
+ BOOL,\r
+ WINAPI,\r
+ Module32Next,\r
+ (HANDLE, LPMODULEENTRY32)\r
+ );\r
+\r
+// psapi functions\r
+TYPEDEF_FUNC(\r
+ DWORD,\r
+ WINAPI,\r
+ GetModuleFileNameExA,\r
+ (HANDLE, HMODULE, LPSTR, DWORD)\r
+ );\r
+\r
+TYPEDEF_FUNC(\r
+ BOOL,\r
+ WINAPI,\r
+ EnumProcessModules,\r
+ (HANDLE, HMODULE*, DWORD, LPDWORD)\r
+ );\r
+\r
+#define pGetModuleFileNameEx pGetModuleFileNameExA\r
+#define TOOLHELPDLL "kernel32.dll"\r
+#define PSAPIDLL "psapi.dll"\r
+\r
+// psapi functions\r
+extern DECL_FUNC_PTR(GetModuleFileNameExA);\r
+extern DECL_FUNC_PTR(EnumProcessModules);\r
+\r
+// toolhelp functions\r
+extern DECL_FUNC_PTR(CreateToolhelp32Snapshot);\r
+extern DECL_FUNC_PTR(Module32First);\r
+extern DECL_FUNC_PTR(Module32Next);\r
+\r
+khm_int32 init_imports(void);\r
+khm_int32 exit_imports(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<windows.h>\r
+#include<kcreddb.h>\r
+#include<kherror.h>\r
+#include<dynimport.h>\r
+\r
+/**************************************/\r
+/* khm_krb5_error(): */\r
+/**************************************/\r
+int \r
+khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, \r
+ int FreeContextFlag, krb5_context * ctx, \r
+ krb5_ccache * cache)\r
+{\r
+#ifdef NO_KRB5\r
+ return 0;\r
+#else\r
+\r
+#ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY\r
+ char message[256];\r
+ const char *errText;\r
+ int krb5Error = ((int)(rc & 255)); \r
+\r
+ errText = perror_message(rc); \r
+ _snprintf(message, sizeof(message), \r
+ "%s\n(Kerberos error %ld)\n\n%s failed", \r
+ errText, \r
+ krb5Error, \r
+ FailedFunctionName);\r
+\r
+ MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | \r
+ MB_TASKMODAL | \r
+ MB_SETFOREGROUND);\r
+#endif\r
+\r
+ if (FreeContextFlag == 1)\r
+ {\r
+ if (*ctx != NULL)\r
+ {\r
+ if (*cache != NULL) {\r
+ pkrb5_cc_close(*ctx, *cache);\r
+ *cache = NULL;\r
+ }\r
+\r
+ pkrb5_free_context(*ctx);\r
+ *ctx = NULL;\r
+ }\r
+ }\r
+\r
+ return rc;\r
+\r
+#endif //!NO_KRB5\r
+}\r
+\r
+int \r
+khm_krb5_initialize(khm_handle ident, \r
+ krb5_context *ctx, \r
+ krb5_ccache *cache)\r
+{\r
+#ifdef NO_KRB5\r
+ return(0);\r
+#else\r
+\r
+ LPCSTR functionName;\r
+ int freeContextFlag;\r
+ krb5_error_code rc;\r
+ krb5_flags flags = 0;\r
+\r
+ if (pkrb5_init_context == NULL)\r
+ return 1;\r
+\r
+ if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx)))\r
+ {\r
+ functionName = "krb5_init_context()";\r
+ freeContextFlag = 0;\r
+ goto on_error;\r
+ }\r
+\r
+ if(*cache == 0) {\r
+ wchar_t wccname[256];\r
+ khm_size cbwccname;\r
+\r
+ if(ident != NULL) {\r
+ cbwccname = sizeof(wccname);\r
+ do {\r
+ char ccname[256];\r
+\r
+ if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName", NULL, wccname, &cbwccname)))\r
+ break;\r
+\r
+ if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0)\r
+ break;\r
+\r
+ if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) {\r
+ functionName = "krb5_cc_resolve()";\r
+ freeContextFlag = 1;\r
+ goto on_error;\r
+ }\r
+ } while(FALSE);\r
+ }\r
+\r
+ if (*cache == 0 && (rc = (*pkrb5_cc_default)(*ctx, cache)))\r
+ {\r
+ functionName = "krb5_cc_default()";\r
+ freeContextFlag = 1;\r
+ goto on_error;\r
+ }\r
+ }\r
+\r
+#ifdef KRB5_TC_NOTICKET\r
+ flags = KRB5_TC_NOTICKET;\r
+#endif\r
+\r
+ if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags)))\r
+ {\r
+ if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND)\r
+ khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, \r
+ cache);\r
+ else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL)\r
+ {\r
+ if (*cache != NULL)\r
+ (*pkrb5_cc_close)(*ctx, *cache);\r
+ }\r
+ return rc;\r
+ }\r
+ return 0;\r
+\r
+on_error:\r
+ return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache);\r
+#endif //!NO_KRB5\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Adapted from multiple Leash header files */\r
+\r
+#ifndef __KHIMAIRA_KRB5COMMON_H\r
+#define __KHIMAIRA_KRB5COMMON_H\r
+\r
+#include<krb5.h>\r
+\r
+#ifndef NO_KRB5\r
+int khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, \r
+ int FreeContextFlag, krb5_context *ctx,\r
+ krb5_ccache *cache);\r
+\r
+\r
+int khm_krb5_initialize(khm_handle ident, krb5_context *, krb5_ccache *);\r
+#endif /* NO_KRB5 */\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=plugins\krb4\r
+!include <../../config/Makefile.w32>\r
+\r
+DLLFILE=$(BINDIR)\krb4cred.dll\r
+\r
+LIBFILE=$(LIBDIR)\krb4cred.lib\r
+\r
+OBJFILES= \\r
+ $(LIBDIR)\dynimport.obj \\r
+ $(LIBDIR)\krb5common.obj \\r
+ $(OBJ)\main.obj \\r
+ $(OBJ)\krb4plugin.obj \\r
+ $(OBJ)\krb4funcs.obj \\r
+ $(OBJ)\errorfuncs.obj \\r
+ $(OBJ)\krb4config.obj \\r
+ $(OBJ)\krb4configdlg.obj\r
+\r
+LIBFILES= \\r
+ $(LIBDIR)\nidmgr32.lib \\r
+ $(KFWLIBDIR)\loadfuncs.lib\r
+\r
+SDKLIBFILES=\r
+\r
+$(OBJ)\krb4config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg\r
+ $(CCSV) $** $@\r
+\r
+$(DLLFILE): $(OBJFILES)\r
+ $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES)\r
+\r
+all: mkdirs $(DLLFILE) lang\r
+\r
+lang::\r
+\r
+# Repeat this block as necessary redefining LANG for additional\r
+# languages.\r
+\r
+# Begin language block\r
+LANG=en_us\r
+\r
+LANGDLL=$(BINDIR)\krb4cred_$(LANG).dll\r
+\r
+lang:: $(LANGDLL)\r
+\r
+$(LANGDLL): $(OBJ)\langres_$(LANG).res\r
+ $(DLLRESLINK)\r
+\r
+$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc\r
+ $(RC2RES)\r
+# End language block\r
+\r
+clean::\r
+!if defined(INCFILES)\r
+ $(RM) $(INCFILES)\r
+!endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KRB_DATAREP_H\r
+#define __KHIMAIRA_KRB_DATAREP_H\r
+\r
+\r
+khm_int32 KHMAPI enctype_toString(const void * data, khm_int32 cbdata, wchar_t *destbuf, khm_int32 *pcbdestbuf, khm_int32 flags);\r
+khm_int32 KHMAPI addr_list_toString(const void *, khm_int32, wchar_t *, khm_int32 *, khm_int32);\r
+khm_int32 KHMAPI krb5flags_toString(const void *, khm_int32, wchar_t *, khm_int32 *, khm_int32);\r
+khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_int32 * pcbsize);\r
+\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+\r
+extern void (__cdecl *pinitialize_krb_error_func)();\r
+extern void (__cdecl *pinitialize_kadm_error_table)();\r
+\r
+\r
+khm_int32 init_error_funcs()\r
+{\r
+\r
+#if 0\r
+ /*TODO: Do something about this */\r
+ if (plsh_LoadKrb4LeashErrorTables)\r
+ plsh_LoadKrb4LeashErrorTables(hLeashInst, 0);\r
+#endif\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 exit_error_funcs()\r
+{\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+// Global Variables.\r
+static long lsh_errno;\r
+static char *err_context; /* error context */\r
+extern int (*Lcom_err)(LPSTR,long,LPSTR,...);\r
+extern LPSTR (*Lerror_message)(long);\r
+extern LPSTR (*Lerror_table_name)(long);\r
+\r
+#ifdef WIN16\r
+#define UNDERSCORE "_"\r
+#else\r
+#define UNDERSCORE\r
+#endif\r
+\r
+HWND GetRootParent (HWND Child)\r
+{\r
+ HWND Last;\r
+ while (Child)\r
+ {\r
+ Last = Child;\r
+ Child = GetParent (Child);\r
+ }\r
+ return Last;\r
+}\r
+\r
+\r
+LPSTR err_describe(LPSTR buf, long code)\r
+{\r
+ LPSTR cp, com_err_msg;\r
+ int offset;\r
+ long table_num;\r
+ char *etype;\r
+\r
+ offset = (int) (code & 255);\r
+ table_num = code - offset;\r
+ com_err_msg = Lerror_message(code);\r
+\r
+ switch(table_num)\r
+ {\r
+ case krb_err_base:\r
+ case kadm_err_base:\r
+ break;\r
+ default:\r
+ strcpy(buf, com_err_msg);\r
+ return buf;\r
+ }\r
+\r
+ cp = buf;\r
+ if (table_num == krb_err_base)\r
+ switch(offset)\r
+ {\r
+ case KDC_NAME_EXP: /* 001 Principal expired */\r
+ case KDC_SERVICE_EXP: /* 002 Service expired */\r
+ case KDC_AUTH_EXP: /* 003 Auth expired */\r
+ case KDC_PKT_VER: /* 004 Protocol version unknown */\r
+ case KDC_P_MKEY_VER: /* 005 Wrong master key version */\r
+ case KDC_S_MKEY_VER: /* 006 Wrong master key version */\r
+ case KDC_BYTE_ORDER: /* 007 Byte order unknown */\r
+ case KDC_PR_N_UNIQUE: /* 009 Principal not unique */\r
+ case KDC_NULL_KEY: /* 010 Principal has null key */\r
+ case KDC_GEN_ERR: /* 011 Generic error from KDC */\r
+ case INTK_W_NOTALL : /* 061 Not ALL tickets returned */\r
+ case INTK_PROT : /* 063 Protocol Error */\r
+ case INTK_ERR : /* 070 Other error */\r
+ com_err_msg = "Something weird happened... try again, and if Leash"\r
+ " continues to fail, contact Network Services as listed in the "\r
+ "About box.";\r
+ break;\r
+ case KDC_PR_UNKNOWN: /* 008 Principal unknown */\r
+ com_err_msg = "You have entered an unknown username/instance/realm"\r
+ " combination.";\r
+ break;\r
+ case GC_TKFIL : /* 021 Can't read ticket file */\r
+ case GC_NOTKT : /* 022 Can't find ticket or TGT */\r
+ com_err_msg = "Something is wrong with the memory where your "\r
+ "tickets are stored. Try exiting Windows and restarting your "\r
+ "computer.";\r
+ break;\r
+ case MK_AP_TGTEXP : /* 026 TGT Expired */\r
+ /* no extra error msg */\r
+ break;\r
+ case RD_AP_TIME : /* 037 delta_t too big */\r
+ com_err_msg = "Your computer's clock is out of sync with the "\r
+ "Kerberos server. Please see the help file about correcting "\r
+ "your clock.";\r
+ break;\r
+\r
+ case RD_AP_UNDEC : /* 031 Can't decode authenticator */\r
+ case RD_AP_EXP : /* 032 Ticket expired */\r
+ case RD_AP_NYV : /* 033 Ticket not yet valid */\r
+ case RD_AP_REPEAT : /* 034 Repeated request */\r
+ case RD_AP_NOT_US : /* 035 The ticket isn't for us */\r
+ case RD_AP_INCON : /* 036 Request is inconsistent */\r
+ case RD_AP_BADD : /* 038 Incorrect net address */\r
+ case RD_AP_VERSION : /* 039 protocol version mismatch */\r
+ case RD_AP_MSG_TYPE : /* 040 invalid msg type */\r
+ case RD_AP_MODIFIED : /* 041 message stream modified */\r
+ case RD_AP_ORDER : /* 042 message out of order */\r
+ case RD_AP_UNAUTHOR : /* 043 unauthorized request */\r
+ /* no extra error msg */\r
+ break;\r
+ case GT_PW_NULL: /* 51 Current PW is null */\r
+ case GT_PW_BADPW: /* 52 Incorrect current password */\r
+ case GT_PW_PROT: /* 53 Protocol Error */\r
+ case GT_PW_KDCERR: /* 54 Error returned by KDC */\r
+ case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */\r
+ /* no error msg yet */\r
+ break;\r
+ \r
+ /* Values returned by send_to_kdc */\r
+ case SKDC_RETRY : /* 56 Retry count exceeded */\r
+ case SKDC_CANT : /* 57 Can't send request */\r
+ com_err_msg = "Cannot contact the kerberos server for the selected realm.";\r
+ break;\r
+ /* no error message on purpose: */\r
+ case INTK_BADPW : /* 062 Incorrect password */\r
+ break;\r
+ default:\r
+ /* no extra error msg */\r
+ break;\r
+ }\r
+ else\r
+ switch(code)\r
+ {\r
+ case KADM_INSECURE_PW:\r
+ /* if( kadm_info != NULL ){\r
+ * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info);\r
+ * } else {\r
+ * wsprintf(buf, "%s\nPlease see the help file for information "\r
+ * "about secure passwords.", com_err_msg);\r
+ * }\r
+ * com_err_msg = buf;\r
+ */\r
+\r
+ /* The above code would be preferred since it allows site specific\r
+ * information to be delivered from the Kerberos server. However the\r
+ * message box is too small for VGA screens.\r
+ * It does work well if we only have to support 1024x768\r
+ */\r
+ \r
+ com_err_msg = "You have entered an insecure or weak password.";\r
+ \r
+ default:\r
+ /* no extra error msg */\r
+ break;\r
+ }\r
+ if(com_err_msg != buf)\r
+ strcpy(buf, com_err_msg);\r
+ cp = buf + strlen(buf);\r
+ *cp++ = '\n';\r
+ switch(table_num) {\r
+ case krb_err_base:\r
+ etype = "Kerberos";\r
+ break;\r
+ case kadm_err_base:\r
+ etype = "Kerberos supplemental";\r
+ break;\r
+ default:\r
+ etype = Lerror_table_name(table_num);\r
+ break;\r
+ }\r
+ wsprintfA((LPSTR) cp, (LPSTR) "(%s error %d"\r
+#ifdef DEBUG_COM_ERR\r
+ " (absolute error %ld)"\r
+#endif\r
+ ")", etype, offset\r
+ //")\nPress F1 for help on this error.", etype, offset\r
+#ifdef DEBUG_COM_ERR \r
+ , code\r
+#endif\r
+ );\r
+ \r
+ return (LPSTR)buf;\r
+}\r
+\r
+int lsh_com_err_proc (LPSTR whoami, long code,\r
+ LPSTR fmt, va_list args)\r
+{\r
+ int retval;\r
+ HWND hOldFocus;\r
+ char buf[1024], *cp; /* changed to 512 by jms 8/23/93 */\r
+ WORD mbformat = MB_OK | MB_ICONEXCLAMATION;\r
+ \r
+ cp = buf;\r
+ memset(buf, '\0', sizeof(buf));\r
+ cp[0] = '\0';\r
+ \r
+ if (code)\r
+ {\r
+ err_describe(buf, code);\r
+ while (*cp)\r
+ cp++;\r
+ }\r
+ \r
+ if (fmt)\r
+ {\r
+ if (fmt[0] == '%' && fmt[1] == 'b')\r
+ {\r
+ fmt += 2;\r
+ mbformat = va_arg(args, WORD);\r
+ /* if the first arg is a %b, we use it for the message\r
+ box MB_??? flags. */\r
+ }\r
+ if (code)\r
+ {\r
+ *cp++ = '\n';\r
+ *cp++ = '\n';\r
+ }\r
+ wvsprintfA((LPSTR)cp, fmt, args);\r
+ }\r
+ hOldFocus = GetFocus();\r
+ retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, \r
+ mbformat | MB_ICONHAND | MB_TASKMODAL);\r
+ SetFocus(hOldFocus);\r
+ return retval;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_ERR_H\r
+#define __KHIMAIRA_ERR_H\r
+\r
+/* All error handling and reporting related functions for the krb4/5\r
+ and AFS plugins */\r
+\r
+#include <errno.h>\r
+#include <com_err.h>\r
+/*\r
+ * This is a hack needed because the real com_err.h does\r
+ * not define err_func. We need it in the case where\r
+ * we pull in the real com_err instead of the krb4 \r
+ * impostor.\r
+ */\r
+#ifndef _DCNS_MIT_COM_ERR_H\r
+typedef LPSTR (*err_func)(int, long);\r
+#endif\r
+\r
+#include <krberr.h>\r
+extern void Leash_initialize_krb_error_func(err_func func,struct et_list **);\r
+#undef init_krb_err_func\r
+#define init_krb_err_func(erf) Leash_initialize_krb_error_func(erf,&_et_list)\r
+\r
+#include <kadm_err.h>\r
+\r
+extern void Leash_initialize_kadm_error_table(struct et_list **);\r
+#undef init_kadm_err_tbl\r
+#define init_kadm_err_tbl() Leash_initialize_kadm_error_table(&_et_list)\r
+#define kadm_err_base ERROR_TABLE_BASE_kadm\r
+\r
+#define krb_err_func Leash_krb_err_func\r
+\r
+#include <stdarg.h>\r
+int lsh_com_err_proc (LPSTR whoami, long code,\r
+ LPSTR fmt, va_list args);\r
+void FAR Leash_load_com_err_callback(FARPROC,FARPROC,FARPROC);\r
+\r
+#ifndef KRBERR\r
+#define KRBERR(code) (code + krb_err_base)\r
+#endif\r
+\r
+int lsh_com_err_proc (LPSTR whoami, long code, LPSTR fmt, va_list args);\r
+int DoNiftyErrorReport(long errnum, LPSTR what);\r
+\r
+LPSTR err_describe(LPSTR buf, long code);\r
+\r
+\r
+/* */\r
+khm_int32 init_error_funcs();\r
+\r
+khm_int32 exit_error_funcs();\r
+\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+#include<khuidefs.h>\r
+#include<strsafe.h>\r
+\r
+INT_PTR CALLBACK\r
+krb4_confg_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ wchar_t wbuf[MAX_PATH];\r
+ CHAR krb_path[MAX_PATH];\r
+ CHAR krbrealm_path[MAX_PATH];\r
+ CHAR ticketName[MAX_PATH];\r
+ char * pticketName;\r
+ unsigned int krb_path_sz = sizeof(krb_path);\r
+ unsigned int krbrealm_path_sz = sizeof(krbrealm_path); \r
+ \r
+ // Set KRB.CON \r
+ memset(krb_path, '\0', sizeof(krb_path));\r
+ if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) {\r
+ // Error has happened\r
+ } else { // normal find\r
+ AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path);\r
+ SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf);\r
+ }\r
+\r
+ // Set KRBREALM.CON \r
+ memset(krbrealm_path, '\0', sizeof(krbrealm_path));\r
+ if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) { \r
+ // Error has happened\r
+ } else {\r
+ AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path);\r
+ SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf);\r
+ }\r
+\r
+ // Set TICKET.KRB file Editbox\r
+ *ticketName = 0;\r
+ pkrb_set_tkt_string(0);\r
+ \r
+ pticketName = ptkt_string(); \r
+ if (pticketName)\r
+ StringCbCopyA(ticketName, sizeof(ticketName), pticketName);\r
+ \r
+ if (!*ticketName) {\r
+ // error\r
+ } else {\r
+ AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName);\r
+ SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2004 Massachusetts Institute of Technology\r
+*\r
+* Permission is hereby granted, free of charge, to any person\r
+* obtaining a copy of this software and associated documentation\r
+* files (the "Software"), to deal in the Software without\r
+* restriction, including without limitation the rights to use, copy,\r
+* modify, merge, publish, distribute, sublicense, and/or sell copies\r
+* of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be\r
+* included in all copies or substantial portions of the Software.\r
+*\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+* SOFTWARE.\r
+*/\r
+\r
+/* $Id$ */\r
+\r
+/* Originally this was krb5routines.c in Leash sources. Subsequently\r
+modified and adapted for NetIDMgr */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+\r
+#define SECURITY_WIN32\r
+#include <security.h>\r
+#include <ntsecapi.h>\r
+\r
+#include <string.h>\r
+#include <time.h>\r
+#include <assert.h>\r
+#include <strsafe.h>\r
+\r
+\r
+\r
+int com_addr(void)\r
+{\r
+ long ipAddr;\r
+ char loc_addr[ADDR_SZ];\r
+ CREDENTIALS cred; \r
+ char service[40];\r
+ char instance[40];\r
+ // char addr[40];\r
+ char realm[40];\r
+ struct in_addr LocAddr;\r
+ int k_errno;\r
+\r
+ if (pkrb_get_cred == NULL)\r
+ return(KSUCCESS);\r
+\r
+ k_errno = (*pkrb_get_cred)(service,instance,realm,&cred);\r
+ if (k_errno)\r
+ return KRBERR(k_errno);\r
+\r
+ while(1) {\r
+ ipAddr = (*pLocalHostAddr)();\r
+ LocAddr.s_addr = ipAddr;\r
+ StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr));\r
+ if ( strcmp(cred.address,loc_addr) != 0) {\r
+ /* TODO: do something about this */\r
+ //Leash_kdestroy ();\r
+ break;\r
+ }\r
+ break;\r
+ } // while()\r
+ return 0;\r
+} \r
+\r
+\r
+long \r
+khm_krb4_list_tickets(void) \r
+{\r
+ char pname[ANAME_SZ];\r
+ char pinst[INST_SZ];\r
+ char prealm[REALM_SZ];\r
+ wchar_t wbuf[256];\r
+ int k_errno;\r
+ CREDENTIALS c;\r
+ int newtickets = 0;\r
+ int open = 0;\r
+ khm_handle ident = NULL;\r
+ khm_handle cred = NULL;\r
+ time_t tt;\r
+ FILETIME ft;\r
+\r
+ // Since krb_get_tf_realm will return a ticket_file error,\r
+ // we will call tf_init and tf_close first to filter out\r
+ // things like no ticket file. Otherwise, the error that\r
+ // the user would see would be\r
+ // klist: can't find realm of ticket file: No ticket file (tf_util)\r
+ // instead of klist: No ticket file (tf_util)\r
+ if (ptf_init == NULL)\r
+ return(KSUCCESS);\r
+\r
+ com_addr();\r
+ \r
+ // Open ticket file\r
+ if ((k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)))\r
+ {\r
+ goto cleanup;\r
+ }\r
+ // Close ticket file \r
+ (void) (*ptf_close)();\r
+ \r
+ // We must find the realm of the ticket file here before calling\r
+ // tf_init because since the realm of the ticket file is not\r
+ // really stored in the principal section of the file, the\r
+ // routine we use must itself call tf_init and tf_close.\r
+\r
+ if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS)\r
+ {\r
+ goto cleanup;\r
+ }\r
+ \r
+ // Open ticket file \r
+ if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) \r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+ open = 1;\r
+\r
+ // Get principal name and instance \r
+ if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) \r
+ {\r
+ goto cleanup;\r
+ }\r
+ \r
+ // You may think that this is the obvious place to get the\r
+ // realm of the ticket file, but it can't be done here as the\r
+ // routine to do this must open the ticket file. This is why\r
+ // it was done before tf_init.\r
+ StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", (LPSTR)pname,\r
+ (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst,\r
+ (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm);\r
+\r
+ if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, &ident)))\r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+ kcdb_credset_flush(krb4_credset);\r
+\r
+ // Get KRB4 tickets\r
+ while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS)\r
+ {\r
+ StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S",\r
+ c.service,\r
+ (c.instance[0] ? "." : ""),\r
+ c.instance,\r
+ (c.realm[0] ? "@" : ""),\r
+ c.realm);\r
+\r
+ if(KHM_FAILED(kcdb_cred_create(wbuf, ident, credtype_id_krb4, &cred)))\r
+ continue;\r
+\r
+ tt = c.issue_date + c.lifetime * 5L * 60L;\r
+ TimetToFileTime(tt, &ft);\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));\r
+\r
+ tt = c.issue_date;\r
+ TimetToFileTime(tt, &ft);\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));\r
+\r
+ tt = c.lifetime * 5L * 60L;\r
+ TimetToFileTimeInterval(tt, &ft);\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ft, sizeof(ft));\r
+\r
+ kcdb_credset_add_cred(krb4_credset, cred, -1);\r
+\r
+ } // while\r
+\r
+ kcdb_credset_collect(NULL, krb4_credset, ident, credtype_id_krb4, NULL);\r
+\r
+cleanup:\r
+ if (ptf_close == NULL)\r
+ return(KSUCCESS);\r
+\r
+ if (open)\r
+ (*ptf_close)(); //close ticket file \r
+ \r
+ if (k_errno == EOF)\r
+ k_errno = 0;\r
+\r
+ // XXX the if statement directly below was inserted to eliminate\r
+ // an error NO_TKT_FIL on Leash startup. The error occurs from an\r
+ // error number thrown from krb_get_tf_realm. We believe this\r
+ // change does not eliminate other errors, but it may.\r
+\r
+ if (k_errno == NO_TKT_FIL)\r
+ k_errno = 0;\r
+\r
+ if(ident)\r
+ kcdb_identity_release(ident);\r
+\r
+#if 0\r
+ /*TODO: Handle errors here */\r
+ if (k_errno)\r
+ {\r
+ CHAR message[256];\r
+ CHAR errBuf[256];\r
+ LPCSTR errText; \r
+\r
+ if (!Lerror_message)\r
+ return -1;\r
+\r
+ errText = err_describe(errBuf, KRBERR(k_errno));\r
+\r
+ sprintf(message, "%s\n\n%s failed", errText, functionName);\r
+ MessageBox(NULL, message, "Kerberos Four", \r
+ MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);\r
+ }\r
+#endif\r
+ return k_errno;\r
+}\r
+\r
+#define KRB_FILE "KRB.CON"\r
+#define KRBREALM_FILE "KRBREALM.CON"\r
+#define KRB5_FILE "KRB5.INI"\r
+\r
+BOOL \r
+khm_get_profile_file(LPSTR confname, UINT szConfname)\r
+{\r
+ char **configFile = NULL;\r
+ if (pkrb5_get_default_config_files(&configFile)) \r
+ {\r
+ GetWindowsDirectoryA(confname,szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, "\\",sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ return FALSE;\r
+ }\r
+ \r
+ *confname = 0;\r
+ \r
+ if (configFile)\r
+ {\r
+ strncpy(confname, *configFile, szConfname);\r
+ pkrb5_free_config_files(configFile); \r
+ }\r
+ \r
+ if (!*confname)\r
+ {\r
+ GetWindowsDirectoryA(confname,szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, "\\",sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+BOOL\r
+khm_get_krb4_con_file(LPSTR confname, UINT szConfname)\r
+{\r
+ if (hKrb5 && !hKrb4)\r
+ { // hold krb.con where krb5.ini is located\r
+ CHAR krbConFile[MAX_PATH]="";\r
+ LPSTR pFind;\r
+\r
+ //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename);\r
+ if (khm_get_profile_file(krbConFile, sizeof(krbConFile))) \r
+ {\r
+ GetWindowsDirectoryA(krbConFile,sizeof(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ }\r
+\r
+ pFind = strrchr(krbConFile, '\\');\r
+ if (pFind)\r
+ {\r
+ *pFind = 0;\r
+ strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ }\r
+ else\r
+ krbConFile[0] = 0;\r
+ \r
+ strncpy(confname, krbConFile, szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ }\r
+ else if (hKrb4)\r
+ { \r
+ unsigned int size = szConfname;\r
+ memset(confname, '\0', szConfname);\r
+ if (!pkrb_get_krbconf2(confname, &size))\r
+ { // Error has happened\r
+ GetWindowsDirectoryA(confname,szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, "\\",szConfname-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname,KRB_FILE,szConfname-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+int\r
+readstring(FILE * file, char * buf, int len)\r
+{\r
+ int c,i;\r
+ memset(buf, '\0', sizeof(buf));\r
+ for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++)\r
+ { \r
+ if (i < sizeof(buf)) {\r
+ if (c == '\n') {\r
+ buf[i] = '\0';\r
+ return i;\r
+ } else {\r
+ buf[i] = c;\r
+ }\r
+ } else {\r
+ if (c == '\n') {\r
+ buf[len-1] = '\0';\r
+ return(i);\r
+ }\r
+ }\r
+ }\r
+ if (c == EOF) {\r
+ if (i > 0 && i < len) {\r
+ buf[i] = '\0';\r
+ return(i);\r
+ } else {\r
+ buf[len-1] = '\0';\r
+ return(-1);\r
+ }\r
+ }\r
+ return(-1);\r
+}\r
+\r
+/*! \internal\r
+ \brief Return a list of configured realms\r
+\r
+ The string that is returned is a set of null terminated unicode strings, \r
+ each of which denotes one realm. The set is terminated by a zero length\r
+ null terminated string.\r
+\r
+ The caller should free the returned string using free()\r
+\r
+ \return The string with the list of realms or NULL if the operation fails.\r
+*/\r
+wchar_t * khm_krb5_get_realm_list(void) \r
+{\r
+ wchar_t * rlist = NULL;\r
+\r
+ if (pprofile_get_subsection_names && pprofile_free_list) {\r
+ const char* rootSection[] = {"realms", NULL};\r
+ const char** rootsec = rootSection;\r
+ char **sections = NULL, **cpp = NULL, *value = NULL;\r
+\r
+ char krb5_conf[MAX_PATH+1];\r
+\r
+ if (!khm_get_profile_file(krb5_conf,sizeof(krb5_conf))) {\r
+ profile_t profile;\r
+ long retval;\r
+ const char *filenames[2];\r
+ wchar_t * d;\r
+ size_t cbsize;\r
+ size_t t;\r
+\r
+ filenames[0] = krb5_conf;\r
+ filenames[1] = NULL;\r
+ retval = pprofile_init(filenames, &profile);\r
+ if (!retval) {\r
+ retval = pprofile_get_subsection_names(profile, rootsec, §ions);\r
+\r
+ if (!retval)\r
+ {\r
+ /* first figure out how much space to allocate */\r
+ cbsize = 0;\r
+ for (cpp = sections; *cpp; cpp++) \r
+ {\r
+ cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1);\r
+ }\r
+ cbsize += sizeof(wchar_t); /* double null terminated */\r
+\r
+ rlist = malloc(cbsize);\r
+ d = rlist;\r
+ for (cpp = sections; *cpp; cpp++)\r
+ {\r
+ AnsiStrToUnicode(d, cbsize, *cpp);\r
+ t = wcslen(d) + 1;\r
+ d += t;\r
+ cbsize -= sizeof(wchar_t) * t;\r
+ }\r
+ *d = L'\0';\r
+ }\r
+\r
+ pprofile_free_list(sections);\r
+\r
+#if 0\r
+ retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value);\r
+ if ( value ) {\r
+ disable_noaddresses = config_boolean_to_int(value);\r
+ pprofile_release_string(value);\r
+ }\r
+#endif\r
+ pprofile_release(profile);\r
+ }\r
+ }\r
+ } else {\r
+ FILE * file;\r
+ char krb_conf[MAX_PATH+1];\r
+ char * p;\r
+ size_t cbsize, t;\r
+ wchar_t * d;\r
+\r
+ if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && \r
+ (file = fopen(krb_conf, "rt")))\r
+ {\r
+ char lineBuf[256];\r
+\r
+ /*TODO: compute the actual required buffer size instead of hardcoding */\r
+ cbsize = 16384; // arbitrary\r
+ rlist = malloc(cbsize);\r
+ d = rlist;\r
+\r
+ // Skip the default realm\r
+ readstring(file,lineBuf,sizeof(lineBuf));\r
+\r
+ // Read the defined realms\r
+ while (TRUE)\r
+ {\r
+ if (readstring(file,lineBuf,sizeof(lineBuf)) < 0)\r
+ break;\r
+\r
+ if (*(lineBuf + strlen(lineBuf) - 1) == '\r')\r
+ *(lineBuf + strlen(lineBuf) - 1) = 0;\r
+\r
+ for (p=lineBuf; *p ; p++)\r
+ {\r
+ if (isspace(*p)) {\r
+ *p = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) {\r
+ t = strlen(lineBuf) + 1;\r
+ if(cbsize > (1 + t*sizeof(wchar_t))) {\r
+ AnsiStrToUnicode(d, cbsize, lineBuf);\r
+ d += t;\r
+ cbsize -= t * sizeof(wchar_t);\r
+ } else\r
+ break;\r
+ }\r
+ }\r
+\r
+ *d = L'\0';\r
+\r
+ fclose(file);\r
+ }\r
+ }\r
+\r
+ return rlist;\r
+}\r
+\r
+/*! \internal\r
+ \brief Get the default realm\r
+\r
+ A string will be returned that specifies the default realm. The caller\r
+ should free the string using free().\r
+\r
+ Returns NULL if the operation fails.\r
+*/\r
+wchar_t * khm_krb5_get_default_realm(void)\r
+{\r
+ wchar_t * realm;\r
+ size_t cch;\r
+ krb5_context ctx=0;\r
+ char * def = 0;\r
+\r
+ pkrb5_init_context(&ctx);\r
+ pkrb5_get_default_realm(ctx,&def);\r
+ \r
+ if (def) {\r
+ cch = strlen(def) + 1;\r
+ realm = malloc(sizeof(wchar_t) * cch);\r
+ AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def);\r
+ pkrb5_free_default_realm(ctx, def);\r
+ } else\r
+ realm = NULL;\r
+\r
+ pkrb5_free_context(ctx);\r
+\r
+ return realm;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Adapted from multiple Leash header files */\r
+\r
+#ifndef __KHIMAIRA_KRB5FUNCS_H\r
+#define __KHIMAIRA_KRB5FUNCS_H\r
+\r
+#include<stdlib.h>\r
+#include<krb5.h>\r
+\r
+#include <windows.h>\r
+#define SECURITY_WIN32\r
+#include <security.h>\r
+#include <ntsecapi.h>\r
+\r
+#include <krb5common.h>\r
+\r
+#define LEASH_DEBUG_CLASS_GENERIC 0\r
+#define LEASH_DEBUG_CLASS_KRB4 1\r
+#define LEASH_DEBUG_CLASS_KRB4_APP 2\r
+\r
+#define LEASH_PRIORITY_LOW 0\r
+#define LEASH_PRIORITY_HIGH 1\r
+\r
+#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */\r
+\r
+// Function Prototypes.\r
+BOOL khm_krb5_ms2mit(BOOL);\r
+\r
+int\r
+khm_krb5_kinit(krb5_context alt_ctx,\r
+ char * principal_name,\r
+ char * password,\r
+ krb5_deltat lifetime,\r
+ DWORD forwardable,\r
+ DWORD proxiable,\r
+ krb5_deltat renew_life,\r
+ DWORD addressless,\r
+ DWORD publicIP,\r
+ krb5_prompter_fct prompter,\r
+ void * p_data\r
+ );\r
+\r
+long\r
+Leash_int_kinit_ex(\r
+ krb5_context ctx,\r
+ HWND hParent,\r
+ char * principal, \r
+ char * password, \r
+ int lifetime,\r
+ int forwardable,\r
+ int proxiable,\r
+ int renew_life,\r
+ int addressless,\r
+ unsigned long publicIP,\r
+ int displayErrors\r
+ );\r
+\r
+long\r
+Leash_int_checkpwd(\r
+ char * principal,\r
+ char * password,\r
+ int displayErrors\r
+ );\r
+\r
+long\r
+Leash_int_changepwd(\r
+ char * principal, \r
+ char * password, \r
+ char * newpassword,\r
+ char** result_string,\r
+ int displayErrors\r
+ );\r
+\r
+int\r
+Leash_krb5_kdestroy(\r
+ void\r
+ );\r
+\r
+int\r
+Leash_krb5_kinit(\r
+ krb5_context,\r
+ HWND hParent,\r
+ char * principal_name, \r
+ char * password,\r
+ krb5_deltat lifetime,\r
+ DWORD forwardable,\r
+ DWORD proxiable,\r
+ krb5_deltat renew_life,\r
+ DWORD addressless,\r
+ DWORD publicIP\r
+ );\r
+\r
+long\r
+khm_convert524(\r
+ krb5_context ctx\r
+ );\r
+ \r
+int\r
+Leash_afs_unlog(\r
+ void\r
+ );\r
+\r
+int\r
+Leash_afs_klog(\r
+ char *, \r
+ char *, \r
+ char *, \r
+ int\r
+ );\r
+\r
+int \r
+LeashKRB5_renew(void);\r
+\r
+LONG\r
+write_registry_setting(\r
+ char* setting,\r
+ DWORD type,\r
+ void* buffer,\r
+ size_t size\r
+ );\r
+\r
+LONG\r
+read_registry_setting_user(\r
+ char* setting,\r
+ void* buffer,\r
+ size_t size\r
+ );\r
+\r
+LONG\r
+read_registry_setting(\r
+ char* setting,\r
+ void* buffer,\r
+ size_t size\r
+ );\r
+\r
+BOOL\r
+get_STRING_from_registry(\r
+ HKEY hBaseKey,\r
+ char * key,\r
+ char * value,\r
+ char * outbuf,\r
+ DWORD outlen\r
+ );\r
+\r
+BOOL\r
+get_DWORD_from_registry(\r
+ HKEY hBaseKey,\r
+ char * key,\r
+ char * value,\r
+ DWORD * result\r
+ );\r
+\r
+int\r
+config_boolean_to_int(\r
+ const char *s\r
+ );\r
+\r
+\r
+wchar_t * khm_krb5_get_default_realm(void);\r
+wchar_t * khm_krb5_get_realm_list(void);\r
+long khm_krb5_list_tickets(krb5_context *krbv5Context);\r
+long khm_krb4_list_tickets(void);\r
+\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<khuidefs.h>\r
+#include<commctrl.h>\r
+#include<strsafe.h>\r
+#include<krb5.h>\r
+\r
+khm_int32 credtype_id_krb4 = KCDB_CREDTYPE_INVALID;\r
+khm_boolean krb4_initialized = FALSE;\r
+khm_handle krb4_credset = NULL;\r
+\r
+/* Kerberos IV stuff */\r
+khm_int32 KHMAPI \r
+krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, void * vparam)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ switch(msg_subtype) {\r
+ case KMSG_SYSTEM_INIT:\r
+ {\r
+ kcdb_credtype ct;\r
+ wchar_t buf[KCDB_MAXCCH_SHORT_DESC];\r
+ size_t cbsize;\r
+ khui_config_node_reg reg;\r
+ wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC];\r
+ wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC];\r
+\r
+ /* perform critical registrations and initialization\r
+ stuff */\r
+ ZeroMemory(&ct, sizeof(ct));\r
+ ct.id = KCDB_CREDTYPE_AUTO;\r
+ ct.name = KRB4_CREDTYPE_NAME;\r
+\r
+ if(LoadString(hResModule, IDS_KRB4_SHORT_DESC, \r
+ buf, ARRAYLENGTH(buf)))\r
+ {\r
+ StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+ ct.short_desc = malloc(cbsize);\r
+ StringCbCopy(ct.short_desc, cbsize, buf);\r
+ }\r
+\r
+ /* even though ideally we should be setting limits\r
+ based KCDB_MAXCB_LONG_DESC, our long description\r
+ actually fits nicely in KCDB_MAXCB_SHORT_DESC */\r
+ if(LoadString(hResModule, IDS_KRB4_LONG_DESC, \r
+ buf, ARRAYLENGTH(buf)))\r
+ {\r
+ StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+ ct.long_desc = malloc(cbsize);\r
+ StringCbCopy(ct.long_desc, cbsize, buf);\r
+ }\r
+\r
+ ct.icon = NULL; /* TODO: set a proper icon */\r
+ kmq_create_subscription(krb4_cb, &ct.sub);\r
+\r
+ rv = kcdb_credtype_register(&ct, &credtype_id_krb4);\r
+\r
+ if(KHM_SUCCEEDED(rv))\r
+ rv = kcdb_credset_create(&krb4_credset);\r
+\r
+ if(ct.short_desc)\r
+ free(ct.short_desc);\r
+\r
+ if(ct.long_desc)\r
+ free(ct.long_desc);\r
+\r
+ ZeroMemory(®, sizeof(reg));\r
+\r
+ reg.name = KRB4_CONFIG_NODE_NAME;\r
+ reg.short_desc = wshort_desc;\r
+ reg.long_desc = wlong_desc;\r
+ reg.h_module = hResModule;\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_KRB4);\r
+ reg.dlg_proc = krb4_confg_proc;\r
+ reg.flags = 0;\r
+\r
+ LoadString(hResModule, IDS_CFG_KRB4_LONG,\r
+ wlong_desc, ARRAYLENGTH(wlong_desc));\r
+ LoadString(hResModule, IDS_CFG_KRB4_SHORT,\r
+ wshort_desc, ARRAYLENGTH(wshort_desc));\r
+\r
+ khui_cfg_register(NULL, ®);\r
+\r
+ if(KHM_SUCCEEDED(rv)) {\r
+ krb4_initialized = TRUE;\r
+\r
+ khm_krb4_list_tickets();\r
+ }\r
+ }\r
+ break;\r
+\r
+ case KMSG_SYSTEM_EXIT:\r
+ if(credtype_id_krb4 >= 0)\r
+ {\r
+ /* basically just unregister the credential type */\r
+ kcdb_credtype_unregister(credtype_id_krb4);\r
+\r
+ kcdb_credset_delete(krb4_credset);\r
+ }\r
+ break;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+khm_int32 KHMAPI \r
+krb4_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, void * vparam)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ switch(msg_subtype) {\r
+ case KMSG_CRED_REFRESH:\r
+ {\r
+ khm_krb4_list_tickets();\r
+ }\r
+ break;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+khm_int32 KHMAPI \r
+krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, void * vparam)\r
+{\r
+ switch(msg_type) {\r
+ case KMSG_SYSTEM:\r
+ return krb4_msg_system(msg_type, msg_subtype, uparam, vparam);\r
+ case KMSG_CRED:\r
+ return krb4_msg_cred(msg_type, msg_subtype, uparam, vparam);\r
+ }\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+Name,Type,Value,Description\r
+Krb4Cred,KC_SPACE,0,"Kerberos IV Credentials Provider"\r
+ Module,KC_STRING,"MITKrb4",\r
+ Description,KC_STRING,"Kerberos IV Credentials Provider",\r
+ Dependencies,KC_STRING,Krb5Cred,\r
+ Type,KC_INT32,1,\r
+ Flags,KC_INT32,0,\r
+ Parameters,KC_SPACE,0,Parameters for KrbCred\r
+ CreateMissingConfig,KC_INT32,0,Create missing configuration files\r
+ MsLsaImport,KC_INT32,2,Automatically import MSLSA credentials\r
+ AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets\r
+ DefaultLifetime,KC_INT32,36000,Default ticket lifetime\r
+ MaxLifetime,KC_INT32,86400,Maximum lifetime\r
+ MinLifetime,KC_INT32,60,Minimum lifetime\r
+ Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean)\r
+ Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean)\r
+ Addressless,KC_INT32,1,Obtain addressless tickets (boolean)\r
+ Renewable,KC_INT32,1,Obtain renewable tickets (boolean)\r
+ DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime\r
+ MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime\r
+ MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime\r
+ Parameters,KC_ENDSPACE,0,\r
+Krb4Cred,KC_ENDSPACE,0,\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KRBAFSCRED_H\r
+#define __KHIMAIRA_KRBAFSCRED_H\r
+\r
+#include<windows.h>\r
+\r
+#include<khdefs.h>\r
+#include<kcreddb.h>\r
+#include<kmm.h>\r
+#include<kconfig.h>\r
+\r
+\r
+#include<krb4funcs.h>\r
+#include<krb5common.h>\r
+#include<errorfuncs.h>\r
+#include<dynimport.h>\r
+\r
+#include<langres.h>\r
+#include<datarep.h>\r
+\r
+#define TYPENAME_ENCTYPE L"EncType"\r
+#define TYPENAME_ADDR_LIST L"AddrList"\r
+#define TYPENAME_KRB5_FLAGS L"Krb5Flags"\r
+\r
+#define ATTRNAME_KEY_ENCTYPE L"KeyEncType"\r
+#define ATTRNAME_TKT_ENCTYPE L"TktEncType"\r
+#define ATTRNAME_ADDR_LIST L"AddrList"\r
+#define ATTRNAME_KRB5_FLAGS L"Krb5Flags"\r
+#define ATTRNAME_RENEW_TILL L"RenewTill"\r
+#define ATTRNAME_RENEW_FOR L"RenewFor"\r
+\r
+void init_krb();\r
+void exit_krb();\r
+KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module);\r
+KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module);\r
+\r
+/* globals */\r
+extern kmm_module h_khModule;\r
+extern HMODULE hResModule;\r
+extern HINSTANCE hInstance;\r
+\r
+extern khm_int32 type_id_enctype;\r
+extern khm_int32 type_id_addr_list;\r
+extern khm_int32 type_id_krb5_flags;\r
+\r
+extern khm_int32 attr_id_key_enctype;\r
+extern khm_int32 attr_id_tkt_enctype;\r
+extern khm_int32 attr_id_addr_list;\r
+extern khm_int32 attr_id_krb5_flags;\r
+extern khm_int32 attr_id_renew_till;\r
+extern khm_int32 attr_id_renew_for;\r
+\r
+/* Configuration spaces */\r
+#define CSNAME_KRB4CRED L"Krb4Cred"\r
+#define CSNAME_PARAMS L"Parameters"\r
+\r
+/* plugin constants */\r
+#define KRB4_PLUGIN_NAME L"Krb4Cred"\r
+\r
+#define KRB4_PLUGIN_DEPS L"Krb5Cred\0"\r
+\r
+#define KRB4_CREDTYPE_NAME L"Krb4Cred"\r
+\r
+#define KRB4_CONFIG_NODE_NAME L"Krb4Config"\r
+\r
+extern khm_handle csp_plugins;\r
+extern khm_handle csp_krbcred;\r
+extern khm_handle csp_params;\r
+\r
+extern kconf_schema schema_krbconfig[];\r
+\r
+/* other globals */\r
+extern khm_int32 credtype_id_krb4;\r
+\r
+extern khm_boolean krb4_initialized;\r
+\r
+extern khm_handle krb4_credset;\r
+\r
+/* plugin callbacks */\r
+khm_int32 KHMAPI \r
+krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, void * vparam);\r
+\r
+INT_PTR CALLBACK\r
+krb4_confg_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+#endif\r
--- /dev/null
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "..\..\langres.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "..\\..\\langres.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_NC_KRB4 DIALOGEX 0, 0, 300, 166\r
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "kRB4",IDC_STATIC,38,43,71,24\r
+END\r
+\r
+IDD_CFG_KRB4 DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "Ticket cache location",IDC_CFG_LBL_CACHE,7,10,67,8\r
+ EDITTEXT IDC_CFG_CACHE,83,7,165,14,ES_AUTOHSCROLL\r
+ LTEXT "Config file path",IDC_CFG_LBL_CFGFILE,7,30,50,8\r
+ EDITTEXT IDC_CFG_CFGPATH,83,27,113,14,ES_AUTOHSCROLL\r
+ PUSHBUTTON "Browse...",IDC_CFG_CFGBROW,200,27,48,14\r
+ LTEXT "Realm file path",IDC_CFG_LBL_RLMPATH,7,50,48,8\r
+ EDITTEXT IDC_CFG_RLMPATH,83,47,113,14,ES_AUTOHSCROLL\r
+ PUSHBUTTON "Browse...",IDC_CFG_RLMBROW,200,47,48,14\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO \r
+BEGIN\r
+ IDD_NC_KRB4, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 293\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 159\r
+ END\r
+\r
+ IDD_CFG_KRB4, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 83\r
+ VERTGUIDE, 196\r
+ VERTGUIDE, 200\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+END\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_PLUGIN_DESC "Kerberos 4 Credentials Provider"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_KRB4_SHORT_DESC "Kerberos 4 tickets"\r
+ IDS_KRB4_LONG_DESC "Kerberos 4 tickets"\r
+ IDS_CFG_KRB4_LONG "Kerberos 4 Configuration"\r
+ IDS_CFG_KRB4_SHORT "Kerberos 4"\r
+END\r
+\r
+#endif // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
+\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by D:\work\khimaira\src\plugins\krb4\lang\en_us\langres.rc\r
+//\r
+#define IDS_UNK_ADDR_FMT 101\r
+#define IDS_KRB5_CREDTEXT_0 102\r
+#define IDD_NC_KRB4 103\r
+#define IDS_PLUGIN_DESC 103\r
+#define IDS_KEY_ENCTYPE_SHORT_DESC 104\r
+#define IDD_CFG_KRB4 104\r
+#define IDS_TKT_ENCTYPE_SHORT_DESC 105\r
+#define IDS_KEY_ENCTYPE_LONG_DESC 106\r
+#define IDS_TKT_ENCTYPE_LONG_DESC 107\r
+#define IDS_ADDR_LIST_SHORT_DESC 108\r
+#define IDS_ADDR_LIST_LONG_DESC 109\r
+#define IDS_ETYPE_NULL 110\r
+#define IDS_ETYPE_DES_CBC_CRC 111\r
+#define IDS_ETYPE_DES_CBC_MD4 112\r
+#define IDS_ETYPE_DES_CBC_MD5 113\r
+#define IDS_ETYPE_DES_CBC_RAW 114\r
+#define IDS_ETYPE_DES3_CBC_SHA 115\r
+#define IDS_ETYPE_DES3_CBC_RAW 116\r
+#define IDS_ETYPE_DES_HMAC_SHA1 117\r
+#define IDS_ETYPE_DES3_CBC_SHA1 118\r
+#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119\r
+#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120\r
+#define IDS_ETYPE_ARCFOUR_HMAC 121\r
+#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122\r
+#define IDS_ETYPE_UNKNOWN 123\r
+#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124\r
+#define IDS_ETYPE_LOCAL_RC4_MD4 125\r
+#define IDS_KRB5_SHORT_DESC 126\r
+#define IDS_KRB5_LONG_DESC 127\r
+#define IDS_KRB4_SHORT_DESC 128\r
+#define IDS_KRB4_LONG_DESC 129\r
+#define IDS_KRB5_FLAGS_SHORT_DESC 130\r
+#define IDS_RENEW_TILL_SHORT_DESC 131\r
+#define IDS_RENEW_TILL_LONG_DESC 132\r
+#define IDS_RENEW_FOR_SHORT_DESC 133\r
+#define IDS_RENEW_FOR_LONG_DESC 134\r
+#define IDS_CFG_KRB4_LONG 135\r
+#define IDS_CFG_KRB4_SHORT 136\r
+#define IDC_NCK5_RENEWABLE 1002\r
+#define IDC_NCK5_FORWARDABLE 1004\r
+#define IDC_NCK5_REALM 1005\r
+#define IDC_NCK5_ADD_REALMS 1006\r
+#define IDC_NCK5_LIFETIME_EDIT 1008\r
+#define IDC_NCK5_RENEW_EDIT 1009\r
+#define IDC_PPK5_CRENEW 1014\r
+#define IDC_PPK5_CFORWARD 1015\r
+#define IDC_PPK5_CPROXY 1016\r
+#define IDC_PPK5_NAME 1017\r
+#define IDC_PPK5_ISSUE 1018\r
+#define IDC_PPK5_VALID 1019\r
+#define IDC_PPK5_RENEW 1020\r
+#define IDC_CHECK2 1022\r
+#define IDC_CHECK4 1024\r
+#define IDC_PPK5_LIFETIME 1024\r
+#define IDC_CHECK5 1025\r
+#define IDC_CFG_LBL_CACHE 1025\r
+#define IDC_CFG_LBL_CFGFILE 1026\r
+#define IDC_CFG_LBL_RLMPATH 1027\r
+#define IDC_CFG_CACHE 1028\r
+#define IDC_CFG_CFGPATH 1029\r
+#define IDC_CFG_RLMPATH 1030\r
+#define IDC_CFG_CFGBROW 1031\r
+#define IDC_CFG_RLMBROW 1032\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 105\r
+#define _APS_NEXT_COMMAND_VALUE 40001\r
+#define _APS_NEXT_CONTROL_VALUE 1033\r
+#define _APS_NEXT_SYMED_VALUE 101\r
+#endif\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+\r
+kmm_module h_khModule; /* KMM's handle to this module */\r
+HINSTANCE hInstance;\r
+HMODULE hResModule; /* HMODULE to the resource library */\r
+\r
+khm_int32 type_id_enctype = -1;\r
+khm_int32 type_id_addr_list = -1;\r
+khm_int32 type_id_krb5_flags = -1;\r
+\r
+khm_int32 attr_id_key_enctype = -1;\r
+khm_int32 attr_id_tkt_enctype = -1;\r
+khm_int32 attr_id_addr_list = -1;\r
+khm_int32 attr_id_krb5_flags = -1;\r
+khm_int32 attr_id_renew_till = -1;\r
+khm_int32 attr_id_renew_for = -1;\r
+\r
+khm_handle csp_plugins = NULL;\r
+khm_handle csp_krbcred = NULL;\r
+khm_handle csp_params = NULL;\r
+\r
+kmm_module_locale locales[] = {\r
+ LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb4cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT)\r
+};\r
+\r
+int n_locales = ARRAYLENGTH(locales);\r
+\r
+/* These two probably should not do anything */\r
+void init_krb() {\r
+}\r
+\r
+void exit_krb() {\r
+}\r
+\r
+/* called by the NetIDMgr module manager */\r
+KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ kmm_plugin_reg pi;\r
+ wchar_t buf[256];\r
+\r
+ h_khModule = h_module;\r
+\r
+ rv = kmm_set_locale_info(h_module, locales, n_locales);\r
+ if(KHM_SUCCEEDED(rv)) {\r
+ hResModule = kmm_get_resource_hmodule(h_module);\r
+ } else\r
+ goto _exit;\r
+\r
+ ZeroMemory(&pi, sizeof(pi));\r
+ pi.name = KRB4_PLUGIN_NAME;\r
+ pi.type = KHM_PITYPE_CRED;\r
+ pi.icon = NULL; /*TODO: Assign icon */\r
+ pi.flags = 0;\r
+ pi.msg_proc = krb4_cb;\r
+ pi.dependencies = KRB4_PLUGIN_DEPS;\r
+ pi.description = buf;\r
+ LoadString(hResModule, IDS_PLUGIN_DESC,\r
+ buf, ARRAYLENGTH(buf));\r
+ kmm_provide_plugin(h_module, &pi);\r
+\r
+ if(KHM_FAILED(rv = init_imports()))\r
+ goto _exit;\r
+\r
+ if(KHM_FAILED(rv = init_error_funcs()))\r
+ goto _exit;\r
+\r
+ /* Lookup common data types */\r
+ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) {\r
+ goto _exit;\r
+ }\r
+\r
+ /* Lookup common attributes */\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_RENEW_TILL, &attr_id_renew_till))) {\r
+ goto _exit;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_RENEW_FOR, &attr_id_renew_for))) {\r
+ goto _exit;\r
+ }\r
+\r
+ rv = kmm_get_plugins_config(0, &csp_plugins);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+ rv = khc_load_schema(csp_plugins, schema_krbconfig);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+ rv = khc_open_space(csp_plugins, CSNAME_KRB4CRED, 0, &csp_krbcred);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+ rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+_exit:\r
+ return rv;\r
+}\r
+\r
+/* called by the NetIDMgr module manager */\r
+KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) {\r
+ exit_imports();\r
+ exit_error_funcs();\r
+\r
+ if(csp_params) {\r
+ khc_close_space(csp_params);\r
+ csp_params = NULL;\r
+ }\r
+ if(csp_krbcred) {\r
+ khc_close_space(csp_krbcred);\r
+ csp_krbcred = NULL;\r
+ }\r
+ if(csp_plugins) {\r
+ khc_unload_schema(csp_plugins, schema_krbconfig);\r
+ khc_close_space(csp_plugins);\r
+ csp_plugins = NULL;\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS; /* the return code is ignored */\r
+}\r
+\r
+BOOL WINAPI DllMain(\r
+ HINSTANCE hinstDLL,\r
+ DWORD fdwReason,\r
+ LPVOID lpvReserved\r
+)\r
+{\r
+ switch(fdwReason) {\r
+ case DLL_PROCESS_ATTACH:\r
+ hInstance = hinstDLL;\r
+ init_krb();\r
+ break;\r
+ case DLL_PROCESS_DETACH:\r
+ exit_krb();\r
+ break;\r
+ case DLL_THREAD_ATTACH:\r
+ break;\r
+ case DLL_THREAD_DETACH:\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=plugins\krb5\r
+!include <../../config/Makefile.w32>\r
+\r
+DLLFILE=$(BINDIR)\krb5cred.dll\r
+\r
+LIBFILE=$(LIBDIR)\krb5cred.lib\r
+\r
+OBJFILES= \\r
+ $(LIBDIR)\dynimport.obj \\r
+ $(LIBDIR)\krb5common.obj \\r
+ $(OBJ)\main.obj \\r
+ $(OBJ)\datarep.obj \\r
+ $(OBJ)\errorfuncs.obj \\r
+ $(OBJ)\krb5plugin.obj \\r
+ $(OBJ)\krb5props.obj \\r
+ $(OBJ)\krb5newcreds.obj \\r
+ $(OBJ)\krb5funcs.obj \\r
+ $(OBJ)\krb5config.obj \\r
+ $(OBJ)\krb5identpro.obj \\r
+ $(OBJ)\krb5configdlg.obj\r
+\r
+LIBFILES= \\r
+ $(LIBDIR)\nidmgr32.lib \\r
+ $(KFWLIBDIR)\loadfuncs.lib\r
+\r
+SDKLIBFILES= \\r
+ netapi32.lib\r
+\r
+MSGRESFILE=$(OBJ)\krb5_msgs.res\r
+\r
+$(OBJ)\krb5config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg\r
+ $(CCSV) $** $@\r
+\r
+$(DLLFILE): $(MSGRESFILE) $(OBJFILES)\r
+ $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES)\r
+\r
+$(MSGRESFILE): $(OBJ)\krb5_msgs.rc\r
+\r
+$(OBJ)\krb5_msgs.rc: lang\krb5_msgs.mc\r
+ $(MC2RC)\r
+\r
+all: mkdirs $(DLLFILE) lang\r
+\r
+lang::\r
+\r
+# Repeat this block as necessary redefining LANG for additional\r
+# languages.\r
+\r
+# Begin language block\r
+LANG=en_us\r
+\r
+LANGDLL=$(BINDIR)\krb5cred_$(LANG).dll\r
+\r
+lang:: $(LANGDLL)\r
+\r
+$(LANGDLL): $(OBJ)\langres_$(LANG).res\r
+ $(DLLRESLINK)\r
+\r
+$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc\r
+ $(RC2RES)\r
+\r
+# End language block\r
+\r
+clean::\r
+!if defined(INCFILES)\r
+ $(RM) $(INCFILES)\r
+!endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Data representation and related functions */\r
+\r
+#include<krbcred.h>\r
+#include<krb5.h>\r
+#include<kherror.h>\r
+#include<strsafe.h>\r
+\r
+khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags)\r
+{\r
+ int resid = 0;\r
+ int etype;\r
+ wchar_t buf[256];\r
+ size_t cblength;\r
+\r
+ if(cbdata != sizeof(khm_int32))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ etype = *((khm_int32 *) data);\r
+\r
+ switch(etype) {\r
+ case ENCTYPE_NULL:\r
+ resid = IDS_ETYPE_NULL;\r
+ break;\r
+\r
+ case ENCTYPE_DES_CBC_CRC:\r
+ resid = IDS_ETYPE_DES_CBC_CRC;\r
+ break;\r
+\r
+ case ENCTYPE_DES_CBC_MD4:\r
+ resid = IDS_ETYPE_DES_CBC_MD4;\r
+ break;\r
+\r
+ case ENCTYPE_DES_CBC_MD5:\r
+ resid = IDS_ETYPE_DES_CBC_MD5;\r
+ break;\r
+\r
+ case ENCTYPE_DES_CBC_RAW:\r
+ resid = IDS_ETYPE_DES_CBC_RAW;\r
+ break;\r
+\r
+ case ENCTYPE_DES3_CBC_SHA:\r
+ resid = IDS_ETYPE_DES3_CBC_SHA;\r
+ break;\r
+\r
+ case ENCTYPE_DES3_CBC_RAW:\r
+ resid = IDS_ETYPE_DES3_CBC_RAW;\r
+ break;\r
+\r
+ case ENCTYPE_DES_HMAC_SHA1:\r
+ resid = IDS_ETYPE_DES_HMAC_SHA1;\r
+ break;\r
+\r
+ case ENCTYPE_DES3_CBC_SHA1:\r
+ resid = IDS_ETYPE_DES3_CBC_SHA1;\r
+ break;\r
+\r
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:\r
+ resid = IDS_ETYPE_AES128_CTS_HMAC_SHA1_96;\r
+ break;\r
+\r
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:\r
+ resid = IDS_ETYPE_AES256_CTS_HMAC_SHA1_96;\r
+ break;\r
+\r
+ case ENCTYPE_ARCFOUR_HMAC:\r
+ resid = IDS_ETYPE_ARCFOUR_HMAC;\r
+ break;\r
+\r
+ case ENCTYPE_ARCFOUR_HMAC_EXP:\r
+ resid = IDS_ETYPE_ARCFOUR_HMAC_EXP;\r
+ break;\r
+\r
+ case ENCTYPE_UNKNOWN:\r
+ resid = IDS_ETYPE_UNKNOWN;\r
+ break;\r
+\r
+#if 0\r
+ case ENCTYPE_LOCAL_DES3_HMAC_SHA1:\r
+ resid = IDS_ETYPE_LOCAL_DES3_HMAC_SHA1;\r
+ break;\r
+\r
+ case ENCTYPE_LOCAL_RC4_MD4:\r
+ resid = IDS_ETYPE_LOCAL_RC4_MD4;\r
+ break;\r
+#endif\r
+ }\r
+\r
+ if(resid != 0) {\r
+ LoadString(hResModule, (UINT) resid, buf, ARRAYLENGTH(buf));\r
+ } else {\r
+ StringCbPrintf(buf, sizeof(buf), L"#%d", etype);\r
+ }\r
+\r
+ StringCbLength(buf, ARRAYLENGTH(buf), &cblength);\r
+ cblength += sizeof(wchar_t);\r
+\r
+ if(!destbuf || *pcbdestbuf < cblength) {\r
+ *pcbdestbuf = cblength;\r
+ return KHM_ERROR_TOO_LONG;\r
+ } else {\r
+ StringCbCopy(destbuf, *pcbdestbuf, buf);\r
+ *pcbdestbuf = cblength;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+}\r
+\r
+khm_int32 KHMAPI addr_list_toString(const void *d, khm_size cb_d, wchar_t *buf, khm_size *pcb_buf, khm_int32 flags)\r
+{\r
+ /*TODO: implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+khm_int32 KHMAPI krb5flags_toString(const void *d, \r
+ khm_size cb_d, \r
+ wchar_t *buf, \r
+ khm_size *pcb_buf, \r
+ khm_int32 f)\r
+{\r
+ wchar_t sbuf[32];\r
+ int i = 0;\r
+ khm_size cb;\r
+ khm_int32 flags;\r
+\r
+ flags = *((khm_int32 *) d);\r
+\r
+ if (flags & TKT_FLG_FORWARDABLE)\r
+ sbuf[i++] = L'F';\r
+\r
+ if (flags & TKT_FLG_FORWARDED)\r
+ sbuf[i++] = L'f';\r
+\r
+ if (flags & TKT_FLG_PROXIABLE)\r
+ sbuf[i++] = L'P';\r
+\r
+ if (flags & TKT_FLG_PROXY)\r
+ sbuf[i++] = L'p';\r
+\r
+ if (flags & TKT_FLG_MAY_POSTDATE)\r
+ sbuf[i++] = L'D';\r
+\r
+ if (flags & TKT_FLG_POSTDATED)\r
+ sbuf[i++] = L'd';\r
+\r
+ if (flags & TKT_FLG_INVALID)\r
+ sbuf[i++] = L'i';\r
+\r
+ if (flags & TKT_FLG_RENEWABLE)\r
+ sbuf[i++] = L'R';\r
+\r
+ if (flags & TKT_FLG_INITIAL)\r
+ sbuf[i++] = L'I';\r
+\r
+ if (flags & TKT_FLG_HW_AUTH)\r
+ sbuf[i++] = L'H';\r
+\r
+ if (flags & TKT_FLG_PRE_AUTH)\r
+ sbuf[i++] = L'A';\r
+\r
+ sbuf[i++] = L'\0';\r
+\r
+ cb = i * sizeof(wchar_t);\r
+\r
+ if (!buf || *pcb_buf < cb) {\r
+ *pcb_buf = cb;\r
+ return KHM_ERROR_TOO_LONG;\r
+ } else {\r
+ StringCbCopy(buf, *pcb_buf, sbuf);\r
+ *pcb_buf = cb;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+}\r
+\r
+khm_int32 serialize_krb5_addresses(krb5_address ** a, void ** buf, size_t * pcbbuf)\r
+{\r
+ /*TODO: implement this */\r
+ return KHM_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+#if 0\r
+\r
+wchar_t * \r
+one_addr(krb5_address *a)\r
+{\r
+ static wchar_t retstr[256];\r
+ struct hostent *h;\r
+ int no_resolve = 1;\r
+\r
+ retstr[0] = L'\0';\r
+\r
+ if ((a->addrtype == ADDRTYPE_INET && a->length == 4)\r
+#ifdef AF_INET6\r
+ || (a->addrtype == ADDRTYPE_INET6 && a->length == 16)\r
+#endif\r
+ ) \r
+ {\r
+ int af = AF_INET;\r
+#ifdef AF_INET6\r
+ if (a->addrtype == ADDRTYPE_INET6)\r
+ af = AF_INET6;\r
+#endif\r
+ if (!no_resolve) {\r
+#ifdef HAVE_GETIPNODEBYADDR\r
+ int err;\r
+ h = getipnodebyaddr(a->contents, a->length, af, &err);\r
+ if (h) {\r
+ StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name);\r
+ freehostent(h);\r
+ }\r
+#else\r
+ h = gethostbyaddr(a->contents, a->length, af);\r
+ if (h) {\r
+ StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name);\r
+ }\r
+#endif\r
+ if (h)\r
+ return(retstr);\r
+ }\r
+ if (no_resolve || !h) {\r
+#ifdef HAVE_INET_NTOP\r
+ char buf[46];\r
+ const char *name = inet_ntop(a->addrtype, a->contents, buf, sizeof(buf));\r
+ if (name) {\r
+ StringCbPrintf(retstr, sizeof(retstr), L"%S", name);\r
+ return;\r
+ }\r
+#else\r
+ if (a->addrtype == ADDRTYPE_INET) {\r
+ StringCbPrintf(retstr, sizeof(retstr),\r
+ L"%d.%d.%d.%d", a->contents[0], a->contents[1],\r
+ a->contents[2], a->contents[3]);\r
+ return(retstr);\r
+ }\r
+#endif\r
+ }\r
+ }\r
+ {\r
+ wchar_t tmpfmt[128];\r
+ LoadString(hResModule, IDS_UNK_ADDR_FMT, tmpfmt, sizeof(tmpfmt)/sizeof(wchar_t));\r
+ StringCbPrintf(retstr, sizeof(retstr), tmpfmt, a->addrtype);\r
+ }\r
+ return(retstr);\r
+}\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KRB_DATAREP_H\r
+#define __KHIMAIRA_KRB_DATAREP_H\r
+\r
+\r
+khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags);\r
+khm_int32 KHMAPI addr_list_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32);\r
+khm_int32 KHMAPI krb5flags_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32);\r
+khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_size * pcbsize);\r
+\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+\r
+extern void (__cdecl *pinitialize_krb_error_func)();\r
+extern void (__cdecl *pinitialize_kadm_error_table)();\r
+\r
+\r
+khm_int32 init_error_funcs()\r
+{\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 exit_error_funcs()\r
+{\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+#ifdef DEPRECATED_REMOVABLE\r
+HWND GetRootParent (HWND Child)\r
+{\r
+ HWND Last;\r
+ while (Child)\r
+ {\r
+ Last = Child;\r
+ Child = GetParent (Child);\r
+ }\r
+ return Last;\r
+}\r
+#endif\r
+\r
+void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, \r
+ DWORD * suggestion,\r
+ kherr_suggestion * suggest_code)\r
+{\r
+ const char * com_err_msg;\r
+ int offset;\r
+ long table_num;\r
+ DWORD msg_id = 0;\r
+ DWORD sugg_id = 0;\r
+ kherr_suggestion sugg_code = KHERR_SUGGEST_NONE;\r
+\r
+ if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0)\r
+ return;\r
+\r
+ *buf = L'\0';\r
+\r
+ offset = (int) (code & 255);\r
+ table_num = code - offset;\r
+ com_err_msg = perror_message(code);\r
+\r
+ *suggestion = 0;\r
+ *suggest_code = KHERR_SUGGEST_NONE;\r
+\r
+ switch(table_num)\r
+ {\r
+ case krb_err_base:\r
+ case kadm_err_base:\r
+ break;\r
+ default:\r
+ *suggest_code = KHERR_SUGGEST_RETRY;\r
+ AnsiStrToUnicode(buf, cbbuf, com_err_msg);\r
+ return;\r
+ }\r
+\r
+ if (table_num == krb_err_base)\r
+ switch(offset)\r
+ {\r
+ case KDC_NAME_EXP: /* 001 Principal expired */\r
+ case KDC_SERVICE_EXP: /* 002 Service expired */\r
+ case KDC_AUTH_EXP: /* 003 Auth expired */\r
+ case KDC_PKT_VER: /* 004 Protocol version unknown */\r
+ case KDC_P_MKEY_VER: /* 005 Wrong master key version */\r
+ case KDC_S_MKEY_VER: /* 006 Wrong master key version */\r
+ case KDC_BYTE_ORDER: /* 007 Byte order unknown */\r
+ case KDC_PR_N_UNIQUE: /* 009 Principal not unique */\r
+ case KDC_NULL_KEY: /* 010 Principal has null key */\r
+ case KDC_GEN_ERR: /* 011 Generic error from KDC */\r
+ case INTK_W_NOTALL : /* 061 Not ALL tickets returned */\r
+ case INTK_PROT : /* 063 Protocol Error */\r
+ case INTK_ERR : /* 070 Other error */\r
+ msg_id = MSG_ERR_UNKNOWN;\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+\r
+ case KDC_PR_UNKNOWN: /* 008 Principal unknown */\r
+ msg_id = MSG_ERR_PR_UNKNOWN;\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+ case GC_TKFIL : /* 021 Can't read ticket file */\r
+ case GC_NOTKT : /* 022 Can't find ticket or TGT */\r
+ msg_id = MSG_ERR_TKFIL;\r
+ sugg_id = MSG_ERR_S_TKFIL;\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+ case MK_AP_TGTEXP : /* 026 TGT Expired */\r
+ /* no extra error msg */\r
+ break;\r
+\r
+ case RD_AP_TIME : /* 037 delta_t too big */\r
+ msg_id = MSG_ERR_CLOCKSKEW;\r
+ sugg_id = MSG_ERR_S_CLOCKSKEW;\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+\r
+ case RD_AP_UNDEC : /* 031 Can't decode\r
+ authenticator */\r
+ case RD_AP_EXP : /* 032 Ticket expired */\r
+ case RD_AP_NYV : /* 033 Ticket not yet valid */\r
+ case RD_AP_REPEAT : /* 034 Repeated request */\r
+ case RD_AP_NOT_US : /* 035 The ticket isn't for us */\r
+ case RD_AP_INCON : /* 036 Request is inconsistent */\r
+ case RD_AP_BADD : /* 038 Incorrect net address */\r
+ case RD_AP_VERSION : /* 039 protocol version mismatch */\r
+ case RD_AP_MSG_TYPE : /* 040 invalid msg type */\r
+ case RD_AP_MODIFIED : /* 041 message stream modified */\r
+ case RD_AP_ORDER : /* 042 message out of order */\r
+ case RD_AP_UNAUTHOR : /* 043 unauthorized request */\r
+ /* no extra error msg */\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+\r
+ case GT_PW_NULL: /* 51 Current PW is null */\r
+ case GT_PW_BADPW: /* 52 Incorrect current password */\r
+ case GT_PW_PROT: /* 53 Protocol Error */\r
+ case GT_PW_KDCERR: /* 54 Error returned by KDC */\r
+ case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */\r
+ /* no error msg yet */\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+ \r
+ /* Values returned by send_to_kdc */\r
+ case SKDC_RETRY : /* 56 Retry count exceeded */\r
+ case SKDC_CANT : /* 57 Can't send request */\r
+ msg_id = MSG_ERR_KDC_CONTACT;\r
+ break;\r
+ /* no error message on purpose: */\r
+ case INTK_BADPW : /* 062 Incorrect password */\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+ default:\r
+ /* no extra error msg */\r
+ break;\r
+ }\r
+ else\r
+ switch(code)\r
+ {\r
+ case KADM_INSECURE_PW:\r
+ /* if( kadm_info != NULL ){\r
+ * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info);\r
+ * } else {\r
+ * wsprintf(buf, "%s\nPlease see the help file for information "\r
+ * "about secure passwords.", com_err_msg);\r
+ * }\r
+ * com_err_msg = buf;\r
+ */\r
+\r
+ /* The above code would be preferred since it allows site\r
+ * specific information to be delivered from the Kerberos\r
+ * server. However the message box is too small for VGA\r
+ * screens. It does work well if we only have to support\r
+ * 1024x768\r
+ */\r
+\r
+ msg_id = MSG_ERR_INSECURE_PW;\r
+ sugg_code = KHERR_SUGGEST_RETRY;\r
+ break;\r
+ \r
+ default:\r
+ /* no extra error msg */\r
+ break;\r
+ }\r
+\r
+ if (msg_id != 0) {\r
+ FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |\r
+ FORMAT_MESSAGE_IGNORE_INSERTS,\r
+ KHERR_HMODULE,\r
+ msg_id,\r
+ 0,\r
+ buf,\r
+ (int) (cbbuf / sizeof(buf[0])),\r
+ NULL);\r
+ }\r
+\r
+ if (sugg_id != 0) {\r
+ *suggestion = sugg_id;\r
+ }\r
+\r
+ if (sugg_code != KHERR_SUGGEST_NONE)\r
+ *suggest_code = sugg_code;\r
+}\r
+\r
+#ifdef DEPRECATED_REMOVABLE\r
+int lsh_com_err_proc (LPSTR whoami, long code,\r
+ LPSTR fmt, va_list args)\r
+{\r
+ int retval;\r
+ HWND hOldFocus;\r
+ char buf[1024], *cp;\r
+ WORD mbformat = MB_OK | MB_ICONEXCLAMATION;\r
+ \r
+ cp = buf;\r
+ memset(buf, '\0', sizeof(buf));\r
+ cp[0] = '\0';\r
+ \r
+ if (code)\r
+ {\r
+ err_describe(buf, code);\r
+ while (*cp)\r
+ cp++;\r
+ }\r
+ \r
+ if (fmt)\r
+ {\r
+ if (fmt[0] == '%' && fmt[1] == 'b')\r
+ {\r
+ fmt += 2;\r
+ mbformat = va_arg(args, WORD);\r
+ /* if the first arg is a %b, we use it for the message\r
+ box MB_??? flags. */\r
+ }\r
+ if (code)\r
+ {\r
+ *cp++ = '\n';\r
+ *cp++ = '\n';\r
+ }\r
+ wvsprintfA((LPSTR)cp, fmt, args);\r
+ }\r
+ hOldFocus = GetFocus();\r
+ retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, \r
+ mbformat | MB_ICONHAND | MB_TASKMODAL);\r
+ SetFocus(hOldFocus);\r
+ return retval;\r
+}\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_ERR_H\r
+#define __KHIMAIRA_ERR_H\r
+\r
+/* All error handling and reporting related functions for the krb4/5\r
+ and AFS plugins */\r
+\r
+#include <errno.h>\r
+#include <com_err.h>\r
+/*\r
+ * This is a hack needed because the real com_err.h does\r
+ * not define err_func. We need it in the case where\r
+ * we pull in the real com_err instead of the krb4 \r
+ * impostor.\r
+ */\r
+#ifndef _DCNS_MIT_COM_ERR_H\r
+typedef LPSTR (*err_func)(int, long);\r
+#endif\r
+\r
+#include <krberr.h>\r
+#include <kadm_err.h>\r
+\r
+#define kadm_err_base ERROR_TABLE_BASE_kadm\r
+\r
+#include <stdarg.h>\r
+\r
+#ifndef KRBERR\r
+#define KRBERR(code) (code + krb_err_base)\r
+#endif\r
+\r
+/*! \internal\r
+ \brief Describe an error \r
+\r
+ \param[in] code Error code returned by Kerberos\r
+ \param[out] buf Receives the error string\r
+ \param[in] cbbuf Size of buffer pointed to by \a buf\r
+ \param[out] suggestion Message ID of suggestion\r
+ \param[out] suggest_code Suggestion ID\r
+*/\r
+void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, \r
+ DWORD * suggestion, \r
+ kherr_suggestion * suggest_code);\r
+\r
+/* */\r
+khm_int32 init_error_funcs();\r
+\r
+khm_int32 exit_error_funcs();\r
+\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<krb5.h>\r
+#include<assert.h>\r
+#include<lm.h>\r
+\r
+INT_PTR CALLBACK \r
+k5_config_dlgproc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ HWND hw;\r
+ wchar_t * realms;\r
+ wchar_t * defrealm;\r
+ wchar_t * t;\r
+ char conffile[MAX_PATH];\r
+ wchar_t wconffile[MAX_PATH];\r
+ wchar_t importopts[256];\r
+ WKSTA_INFO_100 * winfo100;\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_DEFREALM);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ realms = khm_krb5_get_realm_list();\r
+ defrealm = khm_krb5_get_default_realm();\r
+#ifdef DEBUG\r
+ assert(realms);\r
+ assert(defrealm);\r
+#endif\r
+\r
+ SendMessage(hw, CB_RESETCONTENT, 0, 0);\r
+\r
+ for(t = realms; t && *t; t = multi_string_next(t)) {\r
+ SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t);\r
+ }\r
+\r
+ SendMessage(hw, CB_SELECTSTRING, -1, (LPARAM) defrealm);\r
+\r
+ free(defrealm);\r
+ free(realms);\r
+\r
+ khm_get_profile_file(conffile, sizeof(conffile));\r
+\r
+ AnsiStrToUnicode(wconffile, sizeof(wconffile), conffile);\r
+\r
+ SetDlgItemText(hwnd, IDC_CFG_CFGFILE, wconffile);\r
+\r
+ /* hostname/domain */\r
+ if (NetWkstaGetInfo(NULL, 100, (LPBYTE *) &winfo100) == NERR_Success) {\r
+ SetDlgItemText(hwnd, IDC_CFG_HOSTNAME, winfo100->wki100_computername);\r
+ SetDlgItemText(hwnd, IDC_CFG_DOMAIN, winfo100->wki100_langroup);\r
+ NetApiBufferFree(winfo100);\r
+ }\r
+\r
+ /* and the import ticket options */\r
+ LoadString(hResModule, IDS_K5CFG_IMPORT_OPTIONS,\r
+ importopts, ARRAYLENGTH(importopts));\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_IMPORT);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ SendMessage(hw, CB_RESETCONTENT, 0, 0);\r
+\r
+ for (t=importopts; \r
+ t && *t && *t != L' ' &&\r
+ t < importopts + ARRAYLENGTH(importopts);\r
+ t = multi_string_next(t)) {\r
+\r
+ SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t);\r
+ }\r
+\r
+ SendMessage(hw, CB_SETCURSEL, 0, 0);\r
+ \r
+ }\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+INT_PTR CALLBACK \r
+k5_realms_dlgproc(HWND hwndDlg,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+typedef struct tag_k5_ids_dlg_data {\r
+ khui_tracker tc_life;\r
+ khui_tracker tc_renew;\r
+ khui_tracker tc_life_min;\r
+ khui_tracker tc_life_max;\r
+ khui_tracker tc_renew_min;\r
+ khui_tracker tc_renew_max;\r
+\r
+ time_t life;\r
+ time_t renew_life;\r
+ time_t life_min;\r
+ time_t life_max;\r
+ time_t renew_min;\r
+ time_t renew_max;\r
+} k5_ids_dlg_data;\r
+\r
+static void\r
+k5_ids_read_params(k5_ids_dlg_data * d) {\r
+ khm_int32 t;\r
+ khm_int32 rv;\r
+\r
+#ifdef DEBUG\r
+ assert(csp_params);\r
+#endif\r
+\r
+ rv = khc_read_int32(csp_params, L"DefaultLifetime", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->life = t;\r
+\r
+ rv = khc_read_int32(csp_params, L"DefaultRenewLifetime", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->renew_life = t;\r
+\r
+ rv = khc_read_int32(csp_params, L"MaxLifetime", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->life_max = t;\r
+\r
+ rv = khc_read_int32(csp_params, L"MinLifetime", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->life_min = t;\r
+\r
+ rv = khc_read_int32(csp_params, L"MaxRenewLifetime", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->renew_max = t;\r
+\r
+ rv = khc_read_int32(csp_params, L"MinRenewLifetime", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->renew_min = t;\r
+\r
+ khui_tracker_initialize(&d->tc_life);\r
+ d->tc_life.current = d->life;\r
+ d->tc_life.min = 0;\r
+ d->tc_life.max = 3600 * 24 * 7;\r
+\r
+ khui_tracker_initialize(&d->tc_renew);\r
+ d->tc_renew.current = d->renew_life;\r
+ d->tc_renew.min = 0;\r
+ d->tc_renew.max = 3600 * 24 * 30;\r
+\r
+ khui_tracker_initialize(&d->tc_life_min);\r
+ d->tc_life_min.current = d->life_min;\r
+ d->tc_life_min.min = d->tc_life.min;\r
+ d->tc_life_min.max = d->tc_life.max;\r
+\r
+ khui_tracker_initialize(&d->tc_life_max);\r
+ d->tc_life_max.current = d->life_max;\r
+ d->tc_life_max.min = d->tc_life.min;\r
+ d->tc_life_max.max = d->tc_life.max;\r
+\r
+ khui_tracker_initialize(&d->tc_renew_min);\r
+ d->tc_renew_min.current = d->renew_min;\r
+ d->tc_renew_min.min = d->tc_renew.min;\r
+ d->tc_renew_min.max = d->tc_renew.max;\r
+\r
+ khui_tracker_initialize(&d->tc_renew_max);\r
+ d->tc_renew_max.current = d->renew_max;\r
+ d->tc_renew_max.min = d->tc_renew.min;\r
+ d->tc_renew_max.max = d->tc_renew.max;\r
+}\r
+\r
+INT_PTR CALLBACK \r
+k5_ids_tab_dlgproc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ k5_ids_dlg_data * d;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ d = malloc(sizeof(*d));\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ ZeroMemory(d, sizeof(*d));\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ k5_ids_read_params(d);\r
+\r
+ khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE),\r
+ &d->tc_life);\r
+ khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE),\r
+ &d->tc_renew);\r
+ khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MIN),\r
+ &d->tc_life_min);\r
+ khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MAX),\r
+ &d->tc_life_max);\r
+ khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MIN),\r
+ &d->tc_renew_min);\r
+ khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MAX),\r
+ &d->tc_renew_max);\r
+ khui_tracker_refresh(&d->tc_life);\r
+ khui_tracker_refresh(&d->tc_life_min);\r
+ khui_tracker_refresh(&d->tc_life_max);\r
+ khui_tracker_refresh(&d->tc_renew);\r
+ khui_tracker_refresh(&d->tc_renew_min);\r
+ khui_tracker_refresh(&d->tc_renew_max);\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ d = (k5_ids_dlg_data *) (LONG_PTR)\r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ khui_tracker_kill_controls(&d->tc_life);\r
+ khui_tracker_kill_controls(&d->tc_renew);\r
+ khui_tracker_kill_controls(&d->tc_life_min);\r
+ khui_tracker_kill_controls(&d->tc_life_max);\r
+ khui_tracker_kill_controls(&d->tc_renew_min);\r
+ khui_tracker_kill_controls(&d->tc_renew_max);\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+INT_PTR CALLBACK \r
+k5_id_tab_dlgproc(HWND hwndDlg,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+\r
+void\r
+k5_register_config_panels(void) {\r
+ khui_config_node node;\r
+ khui_config_node_reg reg;\r
+ wchar_t wshort[KHUI_MAXCCH_SHORT_DESC];\r
+ wchar_t wlong[KHUI_MAXCCH_LONG_DESC];\r
+\r
+ ZeroMemory(®, sizeof(reg));\r
+\r
+ LoadString(hResModule, IDS_K5CFG_SHORT_DESC,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(hResModule, IDS_K5CFG_LONG_DESC,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ reg.name = L"Kerberos5";\r
+ reg.short_desc = wshort;\r
+ reg.long_desc = wlong;\r
+ reg.h_module = hResModule;\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG);\r
+ reg.dlg_proc = k5_config_dlgproc;\r
+ reg.flags = 0;\r
+\r
+ khui_cfg_register(NULL, ®);\r
+\r
+ if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node))) {\r
+ node = NULL;\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+\r
+ ZeroMemory(®, sizeof(reg));\r
+\r
+ LoadString(hResModule, IDS_K5RLM_SHORT_DESC,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(hResModule, IDS_K5RLM_LONG_DESC,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ reg.name = L"KerberosRealms";\r
+ reg.short_desc = wshort;\r
+ reg.long_desc = wlong;\r
+ reg.h_module = hResModule;\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_REALMS);\r
+ reg.dlg_proc = k5_realms_dlgproc;\r
+ reg.flags = 0;\r
+\r
+ khui_cfg_register(node, ®);\r
+\r
+ khui_cfg_release(node);\r
+\r
+ if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node))) {\r
+ node = NULL;\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+\r
+ ZeroMemory(®, sizeof(reg));\r
+\r
+ LoadString(hResModule, IDS_K5CFG_IDS_SHORT_DESC,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(hResModule, IDS_K5CFG_IDS_LONG_DESC,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ reg.name = L"KerberosIdentities";\r
+ reg.short_desc = wshort;\r
+ reg.long_desc = wlong;\r
+ reg.h_module = hResModule;\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB);\r
+ reg.dlg_proc = k5_ids_tab_dlgproc;\r
+ reg.flags = KHUI_CNFLAG_SUBPANEL;\r
+\r
+ khui_cfg_register(node, ®);\r
+\r
+ ZeroMemory(®, sizeof(reg));\r
+\r
+ LoadString(hResModule, IDS_K5CFG_ID_SHORT_DESC,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(hResModule, IDS_K5CFG_ID_LONG_DESC,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ reg.name = L"KerberosIdentitiesPlural";\r
+ reg.short_desc = wshort;\r
+ reg.long_desc = wlong;\r
+ reg.h_module = hResModule;\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB);\r
+ reg.dlg_proc = k5_id_tab_dlgproc;\r
+ reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL;\r
+\r
+ khui_cfg_register(node, ®);\r
+\r
+ khui_cfg_release(node);\r
+}\r
+\r
+void\r
+k5_unregister_config_panels(void) {\r
+ khui_config_node node_main;\r
+ khui_config_node node_realms;\r
+ khui_config_node node_ids;\r
+ khui_config_node node_tab;\r
+\r
+ if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node_main))) {\r
+ node_main = NULL;\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+\r
+ if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosRealms", \r
+ &node_realms))) {\r
+ khui_cfg_remove(node_realms);\r
+ khui_cfg_release(node_realms);\r
+ }\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+\r
+ if (node_main) {\r
+ khui_cfg_remove(node_main);\r
+ khui_cfg_release(node_main);\r
+ }\r
+\r
+ if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node_ids))) {\r
+ node_ids = NULL;\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+\r
+ if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentities", &node_tab))) {\r
+ khui_cfg_remove(node_tab);\r
+ khui_cfg_release(node_tab);\r
+ }\r
+ if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentitiesPlural", &node_tab))) {\r
+ khui_cfg_remove(node_tab);\r
+ khui_cfg_release(node_tab);\r
+ }\r
+\r
+ if (node_ids)\r
+ khui_cfg_release(node_ids);\r
+}\r
--- /dev/null
+/*\r
+* Copyright (c) 2004 Massachusetts Institute of Technology\r
+*\r
+* Permission is hereby granted, free of charge, to any person\r
+* obtaining a copy of this software and associated documentation\r
+* files (the "Software"), to deal in the Software without\r
+* restriction, including without limitation the rights to use, copy,\r
+* modify, merge, publish, distribute, sublicense, and/or sell copies\r
+* of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be\r
+* included in all copies or substantial portions of the Software.\r
+*\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+* SOFTWARE.\r
+*/\r
+\r
+/* $Id$ */\r
+\r
+/* Originally this was krb5routines.c in Leash sources. Subsequently\r
+modified and adapted for NetIDMgr */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+\r
+#define SECURITY_WIN32\r
+#include <security.h>\r
+#include <ntsecapi.h>\r
+\r
+#include <string.h>\r
+#include <time.h>\r
+#include <assert.h>\r
+#include <strsafe.h>\r
+\r
+long\r
+khm_convert524(krb5_context alt_ctx)\r
+{\r
+ krb5_context ctx = 0;\r
+ krb5_error_code code = 0;\r
+ int icode = 0;\r
+ krb5_principal me = 0;\r
+ krb5_principal server = 0;\r
+ krb5_creds *v5creds = 0;\r
+ krb5_creds increds;\r
+ krb5_ccache cc = 0;\r
+ CREDENTIALS * v4creds = NULL;\r
+ static int init_ets = 1;\r
+\r
+ if (!pkrb5_init_context ||\r
+ !pkrb_in_tkt ||\r
+ !pkrb524_init_ets ||\r
+ !pkrb524_convert_creds_kdc)\r
+ return 0;\r
+\r
+ v4creds = (CREDENTIALS *) malloc(sizeof(CREDENTIALS));\r
+ memset((char *) v4creds, 0, sizeof(CREDENTIALS));\r
+\r
+ memset((char *) &increds, 0, sizeof(increds));\r
+ /*\r
+ From this point on, we can goto cleanup because increds is\r
+ initialized.\r
+ */\r
+\r
+ if (alt_ctx)\r
+ {\r
+ ctx = alt_ctx;\r
+ }\r
+ else\r
+ {\r
+ code = pkrb5_init_context(&ctx);\r
+ if (code) goto cleanup;\r
+ }\r
+\r
+ code = pkrb5_cc_default(ctx, &cc);\r
+ if (code) goto cleanup;\r
+\r
+ if ( init_ets ) {\r
+ pkrb524_init_ets(ctx);\r
+ init_ets = 0;\r
+ }\r
+\r
+ if (code = pkrb5_cc_get_principal(ctx, cc, &me))\r
+ goto cleanup;\r
+\r
+ if ((code = pkrb5_build_principal(ctx,\r
+ &server,\r
+ krb5_princ_realm(ctx, me)->length,\r
+ krb5_princ_realm(ctx, me)->data,\r
+ "krbtgt",\r
+ krb5_princ_realm(ctx, me)->data,\r
+ NULL))) \r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+ increds.client = me;\r
+ increds.server = server;\r
+ increds.times.endtime = 0;\r
+ increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;\r
+ if ((code = pkrb5_get_credentials(ctx, 0,\r
+ cc,\r
+ &increds,\r
+ &v5creds))) \r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+ if ((icode = pkrb524_convert_creds_kdc(ctx,\r
+ v5creds,\r
+ v4creds))) \r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+ /* initialize ticket cache */\r
+ if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm)\r
+ != KSUCCESS)) \r
+ {\r
+ goto cleanup;\r
+ }\r
+ /* stash ticket, session key, etc. for future use */\r
+ if ((icode = pkrb_save_credentials(v4creds->service,\r
+ v4creds->instance,\r
+ v4creds->realm,\r
+ v4creds->session,\r
+ v4creds->lifetime,\r
+ v4creds->kvno,\r
+ &(v4creds->ticket_st),\r
+ v4creds->issue_date))) \r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+cleanup:\r
+ memset(v4creds, 0, sizeof(v4creds));\r
+ free(v4creds);\r
+\r
+ if (v5creds) {\r
+ pkrb5_free_creds(ctx, v5creds);\r
+ }\r
+ if (increds.client == me)\r
+ me = 0;\r
+ if (increds.server == server)\r
+ server = 0;\r
+ pkrb5_free_cred_contents(ctx, &increds);\r
+ if (server) {\r
+ pkrb5_free_principal(ctx, server);\r
+ }\r
+ if (me) {\r
+ pkrb5_free_principal(ctx, me);\r
+ }\r
+ pkrb5_cc_close(ctx, cc);\r
+\r
+ if (ctx && (ctx != alt_ctx)) {\r
+ pkrb5_free_context(ctx);\r
+ }\r
+ return !(code || icode);\r
+}\r
+\r
+#ifdef DEPRECATED_REMOVABLE\r
+int com_addr(void)\r
+{\r
+ long ipAddr;\r
+ char loc_addr[ADDR_SZ];\r
+ CREDENTIALS cred; \r
+ char service[40];\r
+ char instance[40];\r
+ // char addr[40];\r
+ char realm[40];\r
+ struct in_addr LocAddr;\r
+ int k_errno;\r
+\r
+ if (pkrb_get_cred == NULL)\r
+ return(KSUCCESS);\r
+\r
+ k_errno = (*pkrb_get_cred)(service,instance,realm,&cred);\r
+ if (k_errno)\r
+ return KRBERR(k_errno);\r
+\r
+ while(1) {\r
+ ipAddr = (*pLocalHostAddr)();\r
+ LocAddr.s_addr = ipAddr;\r
+ StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr));\r
+ if ( strcmp(cred.address, loc_addr) != 0) {\r
+ /* TODO: do something about this */\r
+ //Leash_kdestroy ();\r
+ break;\r
+ }\r
+ break;\r
+ } // while()\r
+ return 0;\r
+} \r
+#endif\r
+\r
+#ifndef ENCTYPE_LOCAL_RC4_MD4\r
+#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80\r
+#endif\r
+\r
+static long get_tickets_from_cache(krb5_context ctx, \r
+ krb5_ccache cache)\r
+{\r
+ krb5_error_code code;\r
+ krb5_principal KRBv5Principal;\r
+ krb5_flags flags = 0;\r
+ krb5_cc_cursor KRBv5Cursor;\r
+ krb5_creds KRBv5Credentials;\r
+ krb5_ticket *tkt=NULL;\r
+ char *ClientName;\r
+ char *PrincipalName;\r
+ wchar_t wbuf[256]; /* temporary conversion buffer */\r
+ wchar_t *wcc_name = NULL; /* credential cache name */\r
+ char *sServerName;\r
+ khm_handle ident = NULL;\r
+ khm_handle cred = NULL;\r
+ time_t tt;\r
+ khm_int64 ft, eft;\r
+ khm_int32 ti;\r
+\r
+\r
+#ifdef KRB5_TC_NOTICKET\r
+ flags = KRB5_TC_NOTICKET;\r
+#else\r
+ flags = 0;\r
+#endif\r
+\r
+ {\r
+ char * cc_name;\r
+ size_t namelen;\r
+\r
+ cc_name = (*pkrb5_cc_get_name)(ctx, cache);\r
+ if(cc_name) {\r
+ namelen = strlen(cc_name);\r
+ namelen = (namelen + 1 + 4) * sizeof(wchar_t);\r
+ /* the +4 is for the possible addtion of API: during the\r
+ cannonicalization process */\r
+ wcc_name = malloc(namelen);\r
+ AnsiStrToUnicode(wcc_name, namelen, cc_name);\r
+ khm_krb5_canon_cc_name(wcc_name, namelen);\r
+ }\r
+ }\r
+\r
+ if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags)))\r
+ {\r
+ if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND)\r
+ khm_krb5_error(code, "krb5_cc_set_flags()", 0, &ctx, &cache);\r
+\r
+ goto _exit;\r
+ }\r
+\r
+ if ((code = (*pkrb5_cc_get_principal)(ctx, cache, &KRBv5Principal)))\r
+ {\r
+ if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND)\r
+ khm_krb5_error(code, "krb5_cc_get_principal()", 0, &ctx, &cache);\r
+\r
+ goto _exit;\r
+ }\r
+\r
+ PrincipalName = NULL;\r
+ ClientName = NULL;\r
+ sServerName = NULL;\r
+ if ((code = (*pkrb5_unparse_name)(ctx, KRBv5Principal, \r
+ (char **)&PrincipalName))) \r
+ {\r
+ if (PrincipalName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, PrincipalName);\r
+\r
+ (*pkrb5_free_principal)(ctx, KRBv5Principal);\r
+\r
+ goto _exit;\r
+ }\r
+\r
+ if (!strcspn(PrincipalName, "@" ))\r
+ {\r
+ if (PrincipalName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, PrincipalName);\r
+\r
+ (*pkrb5_free_principal)(ctx, KRBv5Principal);\r
+\r
+ goto _exit;\r
+ }\r
+\r
+ AnsiStrToUnicode(wbuf, sizeof(wbuf), PrincipalName);\r
+ if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, \r
+ &ident))) {\r
+ /* something bad happened */\r
+ code = 1;\r
+ goto _exit;\r
+ }\r
+\r
+ (*pkrb5_free_principal)(ctx, KRBv5Principal);\r
+\r
+ if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) \r
+ {\r
+ goto _exit; \r
+ }\r
+\r
+ memset(&KRBv5Credentials, '\0', sizeof(KRBv5Credentials));\r
+\r
+ ClientName = NULL;\r
+ sServerName = NULL;\r
+ cred = NULL;\r
+\r
+ while (!(code = pkrb5_cc_next_cred(ctx, cache, &KRBv5Cursor, \r
+ &KRBv5Credentials))) \r
+ {\r
+ khm_handle tident = NULL;\r
+\r
+ if(ClientName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, ClientName);\r
+ if(sServerName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, sServerName);\r
+ if(cred)\r
+ kcdb_cred_release(cred);\r
+\r
+ ClientName = NULL;\r
+ sServerName = NULL;\r
+ cred = NULL;\r
+\r
+ if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.client, &ClientName))\r
+ {\r
+ (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials);\r
+ khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache);\r
+ continue;\r
+ }\r
+\r
+ if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName))\r
+ {\r
+ (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials);\r
+ khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache);\r
+ continue;\r
+ }\r
+\r
+ /* if the ClientName differs from PrincipalName for some\r
+ reason, we need to create a new identity */\r
+ if(strcmp(ClientName, PrincipalName)) {\r
+ AnsiStrToUnicode(wbuf, sizeof(wbuf), ClientName);\r
+ if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, \r
+ &tident))) {\r
+ (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials);\r
+ continue;\r
+ }\r
+ } else {\r
+ tident = ident;\r
+ }\r
+\r
+ AnsiStrToUnicode(wbuf, sizeof(wbuf), sServerName);\r
+ if(KHM_FAILED(kcdb_cred_create(wbuf, tident, credtype_id_krb5, \r
+ &cred))) {\r
+ (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials);\r
+ continue;\r
+ }\r
+\r
+ if (!KRBv5Credentials.times.starttime)\r
+ KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime;\r
+\r
+ tt = KRBv5Credentials.times.starttime;\r
+ TimetToFileTime(tt, (LPFILETIME) &ft);\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));\r
+\r
+ tt = KRBv5Credentials.times.endtime;\r
+ TimetToFileTime(tt, (LPFILETIME) &eft);\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &eft, sizeof(eft));\r
+\r
+ eft -= ft;\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &eft, sizeof(eft));\r
+\r
+ if (KRBv5Credentials.times.renew_till >= 0) {\r
+ tt = KRBv5Credentials.times.renew_till;\r
+ TimetToFileTime(tt, (LPFILETIME) &eft);\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_EXPIRE, &eft, \r
+ sizeof(eft));\r
+\r
+ eft -= ft;\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_LIFETIME, &eft, \r
+ sizeof(eft));\r
+ }\r
+\r
+ ti = KRBv5Credentials.ticket_flags;\r
+ kcdb_cred_set_attr(cred, attr_id_krb5_flags, &ti, sizeof(ti));\r
+\r
+ /* special flags understood by NetIDMgr */\r
+ {\r
+ khm_int32 oflags, nflags;\r
+\r
+ kcdb_cred_get_flags(cred, &oflags);\r
+ nflags = oflags;\r
+\r
+ if (ti & TKT_FLG_RENEWABLE)\r
+ nflags |= KCDB_CRED_FLAG_RENEWABLE;\r
+ if (ti & TKT_FLG_INITIAL)\r
+ nflags |= KCDB_CRED_FLAG_INITIAL;\r
+\r
+ if (oflags != nflags)\r
+ kcdb_cred_set_flags(cred, nflags, KCDB_CRED_FLAGMASK_ALL);\r
+ }\r
+\r
+ if ( !pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) {\r
+ ti = tkt->enc_part.enctype;\r
+ kcdb_cred_set_attr(cred, attr_id_tkt_enctype, &ti, sizeof(ti));\r
+ pkrb5_free_ticket(ctx, tkt);\r
+ tkt = NULL;\r
+ }\r
+\r
+ ti = KRBv5Credentials.keyblock.enctype;\r
+ kcdb_cred_set_attr(cred, attr_id_key_enctype, &ti, sizeof(ti));\r
+\r
+ kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wcc_name, KCDB_CBSIZE_AUTO);\r
+\r
+ /*TODO: going here */\r
+#if 0\r
+ if ( KRBv5Credentials.addresses && KRBv5Credentials.addresses[0] ) {\r
+ int n = 0;\r
+ while ( KRBv5Credentials.addresses[n] )\r
+ n++;\r
+ list->addrList = calloc(1, n * sizeof(char *));\r
+ if (!list->addrList) {\r
+ MessageBox(NULL, "Memory Error", "Error", MB_OK);\r
+ return ENOMEM; \r
+ }\r
+ list->addrCount = n;\r
+ for ( n=0; n<list->addrCount; n++ ) {\r
+ wsprintf(Buffer, "Address: %s", one_addr(KRBv5Credentials.addresses[n]));\r
+ list->addrList[n] = (char*) calloc(1, strlen(Buffer)+1);\r
+ if (!list->addrList[n])\r
+ {\r
+ MessageBox(NULL, "Memory Error", "Error", MB_OK);\r
+ return ENOMEM; \r
+ } \r
+ strcpy(list->addrList[n], Buffer);\r
+ } \r
+ }\r
+#endif\r
+\r
+ if(KRBv5Credentials.ticket_flags & TKT_FLG_INITIAL) {\r
+ __int64 t_expire_old;\r
+ __int64 t_expire_new;\r
+ khm_size cb;\r
+\r
+ /* an initial ticket! If we find one, we generally set\r
+ the lifetime, and primary ccache based on this, but\r
+ only if this initial cred has a greater lifetime than\r
+ the current primary credential. */\r
+\r
+ tt = KRBv5Credentials.times.endtime;\r
+ TimetToFileTime(tt, (LPFILETIME) &t_expire_new);\r
+\r
+ cb = sizeof(t_expire_old);\r
+ if(KHM_FAILED(kcdb_identity_get_attr(tident, \r
+ KCDB_ATTR_EXPIRE, \r
+ NULL, &t_expire_old, \r
+ &cb))\r
+ || t_expire_new > t_expire_old)\r
+ {\r
+ kcdb_identity_set_attr(tident, attr_id_krb5_ccname, \r
+ wcc_name, KCDB_CBSIZE_AUTO);\r
+ kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, \r
+ &t_expire_new, \r
+ sizeof(t_expire_new));\r
+\r
+ if (KRBv5Credentials.times.renew_till >= 0) {\r
+ tt = KRBv5Credentials.times.renew_till;\r
+ TimetToFileTime(tt, (LPFILETIME) &ft);\r
+ kcdb_identity_set_attr(tident, \r
+ KCDB_ATTR_RENEW_EXPIRE, \r
+ &ft, sizeof(ft));\r
+ } else {\r
+ kcdb_identity_set_attr(tident,\r
+ KCDB_ATTR_RENEW_EXPIRE,\r
+ NULL, 0);\r
+ }\r
+\r
+ ti = KRBv5Credentials.ticket_flags;\r
+ kcdb_identity_set_attr(tident, attr_id_krb5_flags, \r
+ &ti, sizeof(ti));\r
+ }\r
+ }\r
+\r
+ kcdb_credset_add_cred(krb5_credset, cred, -1);\r
+\r
+ (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials);\r
+\r
+ if(tident != ident)\r
+ kcdb_identity_release(tident);\r
+ }\r
+\r
+ if (PrincipalName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, PrincipalName);\r
+\r
+ if (ClientName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, ClientName);\r
+\r
+ if (sServerName != NULL)\r
+ (*pkrb5_free_unparsed_name)(ctx, sServerName);\r
+\r
+ if (cred)\r
+ kcdb_cred_release(cred);\r
+\r
+ if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND))\r
+ {\r
+ if ((code = pkrb5_cc_end_seq_get(ctx, cache, &KRBv5Cursor))) \r
+ {\r
+ goto _exit;\r
+ }\r
+\r
+ flags = KRB5_TC_OPENCLOSE;\r
+#ifdef KRB5_TC_NOTICKET\r
+ flags |= KRB5_TC_NOTICKET;\r
+#endif\r
+ if ((code = pkrb5_cc_set_flags(ctx, cache, flags))) \r
+ {\r
+ goto _exit;\r
+ }\r
+ }\r
+ else \r
+ {\r
+ goto _exit;\r
+ }\r
+\r
+_exit:\r
+ if(wcc_name)\r
+ free(wcc_name);\r
+\r
+ return code;\r
+}\r
+\r
+long \r
+khm_krb5_list_tickets(krb5_context *krbv5Context)\r
+{\r
+ krb5_context ctx;\r
+ krb5_ccache cache;\r
+ krb5_error_code code;\r
+ apiCB * cc_ctx = 0;\r
+ struct _infoNC ** pNCi = NULL;\r
+ int i;\r
+\r
+ ctx = NULL;\r
+ cache = NULL;\r
+\r
+ kcdb_credset_flush(krb5_credset);\r
+\r
+ code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);\r
+ if (code)\r
+ goto _exit;\r
+\r
+ code = pcc_get_NC_info(cc_ctx, &pNCi);\r
+ if (code) \r
+ goto _exit;\r
+\r
+ if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) {\r
+ goto _exit;\r
+ }\r
+\r
+ ctx = (*krbv5Context);\r
+\r
+ for(i=0; pNCi[i]; i++) {\r
+ if (pNCi[i]->vers != CC_CRED_V5)\r
+ continue;\r
+\r
+ code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache);\r
+\r
+ if (code)\r
+ continue;\r
+\r
+ code = get_tickets_from_cache(ctx, cache);\r
+\r
+ if(ctx != NULL && cache != NULL)\r
+ (*pkrb5_cc_close)(ctx, cache);\r
+\r
+ cache = 0;\r
+ }\r
+\r
+_exit:\r
+ if (pNCi)\r
+ (*pcc_free_NC_info)(cc_ctx, &pNCi);\r
+ if (cc_ctx)\r
+ (*pcc_shutdown)(&cc_ctx);\r
+\r
+ kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL);\r
+\r
+ return(code);\r
+\r
+}\r
+\r
+int\r
+khm_krb5_renew(khm_handle identity)\r
+{\r
+ krb5_error_code code = 0;\r
+ krb5_context ctx = 0;\r
+ krb5_ccache cc = 0;\r
+ krb5_principal me = 0;\r
+ krb5_principal server = 0;\r
+ krb5_creds my_creds;\r
+ krb5_data *realm = 0;\r
+\r
+ if ( !pkrb5_init_context )\r
+ goto cleanup;\r
+\r
+ memset(&my_creds, 0, sizeof(krb5_creds));\r
+\r
+ code = khm_krb5_initialize(identity, &ctx, &cc);\r
+ if (code) \r
+ goto cleanup;\r
+\r
+ code = pkrb5_cc_get_principal(ctx, cc, &me);\r
+ if (code) \r
+ goto cleanup;\r
+\r
+ realm = krb5_princ_realm(ctx, me);\r
+\r
+ code = pkrb5_build_principal_ext(ctx, &server,\r
+ realm->length,realm->data,\r
+ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,\r
+ realm->length,realm->data,\r
+ 0);\r
+\r
+ if (code) \r
+ goto cleanup;\r
+\r
+ my_creds.client = me;\r
+ my_creds.server = server;\r
+\r
+#ifdef KRB5_TC_NOTICKET\r
+ pkrb5_cc_set_flags(ctx, cc, 0);\r
+#endif\r
+ code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);\r
+#ifdef KRB5_TC_NOTICKET\r
+ pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET);\r
+#endif\r
+ if (code) {\r
+ if ( code != KRB5KDC_ERR_ETYPE_NOSUPP ||\r
+ code != KRB5_KDC_UNREACH)\r
+ khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc);\r
+ goto cleanup;\r
+ }\r
+\r
+ code = pkrb5_cc_initialize(ctx, cc, me);\r
+ if (code) goto cleanup;\r
+\r
+ code = pkrb5_cc_store_cred(ctx, cc, &my_creds);\r
+ if (code) goto cleanup;\r
+\r
+cleanup:\r
+ if (my_creds.client == me)\r
+ my_creds.client = 0;\r
+ if (my_creds.server == server)\r
+ my_creds.server = 0;\r
+\r
+ pkrb5_free_cred_contents(ctx, &my_creds);\r
+\r
+ if (me)\r
+ pkrb5_free_principal(ctx, me);\r
+ if (server)\r
+ pkrb5_free_principal(ctx, server);\r
+ if (cc)\r
+ pkrb5_cc_close(ctx, cc);\r
+ if (ctx)\r
+ pkrb5_free_context(ctx);\r
+ return(code);\r
+}\r
+\r
+int\r
+khm_krb5_kinit(krb5_context alt_ctx,\r
+ char * principal_name,\r
+ char * password,\r
+ char * ccache,\r
+ krb5_deltat lifetime,\r
+ DWORD forwardable,\r
+ DWORD proxiable,\r
+ krb5_deltat renew_life,\r
+ DWORD addressless,\r
+ DWORD publicIP,\r
+ krb5_prompter_fct prompter,\r
+ void * p_data)\r
+{\r
+ krb5_error_code code = 0;\r
+ krb5_context ctx = 0;\r
+ krb5_ccache cc = 0;\r
+ krb5_principal me = 0;\r
+ char* name = 0;\r
+ krb5_creds my_creds;\r
+ krb5_get_init_creds_opt options;\r
+ krb5_address ** addrs = NULL;\r
+ int i = 0, addr_count = 0;\r
+\r
+ if (!pkrb5_init_context)\r
+ return 0;\r
+\r
+ pkrb5_get_init_creds_opt_init(&options);\r
+ memset(&my_creds, 0, sizeof(my_creds));\r
+\r
+ if (alt_ctx)\r
+ {\r
+ ctx = alt_ctx;\r
+ }\r
+ else\r
+ {\r
+ code = pkrb5_init_context(&ctx);\r
+ if (code) goto cleanup;\r
+ }\r
+\r
+// code = pkrb5_cc_default(ctx, &cc);\r
+ if (ccache)\r
+ code = pkrb5_cc_resolve(ctx, ccache, &cc);\r
+ else\r
+ code = pkrb5_cc_resolve(ctx, principal_name, &cc);\r
+ if (code) goto cleanup;\r
+\r
+ code = pkrb5_parse_name(ctx, principal_name, &me);\r
+ if (code) goto cleanup;\r
+\r
+ code = pkrb5_unparse_name(ctx, me, &name);\r
+ if (code) goto cleanup;\r
+\r
+ if (lifetime == 0) {\r
+ khc_read_int32(csp_params, L"DefaultLifetime", &lifetime);\r
+ }\r
+\r
+ if (lifetime)\r
+ pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);\r
+ pkrb5_get_init_creds_opt_set_forwardable(&options,\r
+ forwardable ? 1 : 0);\r
+ pkrb5_get_init_creds_opt_set_proxiable(&options,\r
+ proxiable ? 1 : 0);\r
+ pkrb5_get_init_creds_opt_set_renew_life(&options,\r
+ renew_life);\r
+ if (addressless)\r
+ pkrb5_get_init_creds_opt_set_address_list(&options,NULL);\r
+ else {\r
+ if (publicIP)\r
+ {\r
+ // we are going to add the public IP address specified by the user\r
+ // to the list provided by the operating system\r
+ krb5_address ** local_addrs=NULL;\r
+ DWORD netIPAddr;\r
+\r
+ pkrb5_os_localaddr(ctx, &local_addrs);\r
+ while ( local_addrs[i++] );\r
+ addr_count = i + 1;\r
+\r
+ addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));\r
+ if ( !addrs ) {\r
+ pkrb5_free_addresses(ctx, local_addrs);\r
+ assert(0);\r
+ }\r
+ memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));\r
+ i = 0;\r
+ while ( local_addrs[i] ) {\r
+ addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));\r
+ if (addrs[i] == NULL) {\r
+ pkrb5_free_addresses(ctx, local_addrs);\r
+ assert(0);\r
+ }\r
+\r
+ addrs[i]->magic = local_addrs[i]->magic;\r
+ addrs[i]->addrtype = local_addrs[i]->addrtype;\r
+ addrs[i]->length = local_addrs[i]->length;\r
+ addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);\r
+ if (!addrs[i]->contents) {\r
+ pkrb5_free_addresses(ctx, local_addrs);\r
+ assert(0);\r
+ }\r
+\r
+ memcpy(addrs[i]->contents,local_addrs[i]->contents,\r
+ local_addrs[i]->length); /* safe */\r
+ i++;\r
+ }\r
+ pkrb5_free_addresses(ctx, local_addrs);\r
+\r
+ addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));\r
+ if (addrs[i] == NULL)\r
+ assert(0);\r
+\r
+ addrs[i]->magic = KV5M_ADDRESS;\r
+ addrs[i]->addrtype = AF_INET;\r
+ addrs[i]->length = 4;\r
+ addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);\r
+ if (!addrs[i]->contents)\r
+ assert(0);\r
+\r
+ netIPAddr = htonl(publicIP);\r
+ memcpy(addrs[i]->contents,&netIPAddr,4);\r
+\r
+ pkrb5_get_init_creds_opt_set_address_list(&options,addrs);\r
+\r
+ }\r
+ }\r
+\r
+ code = pkrb5_get_init_creds_password(ctx,\r
+ &my_creds,\r
+ me,\r
+ password, // password\r
+ prompter, // prompter\r
+ p_data, // prompter data\r
+ 0, // start time\r
+ 0, // service name\r
+ &options);\r
+ if (code) goto cleanup;\r
+\r
+ code = pkrb5_cc_initialize(ctx, cc, me);\r
+ if (code) goto cleanup;\r
+\r
+ code = pkrb5_cc_store_cred(ctx, cc, &my_creds);\r
+ if (code) goto cleanup;\r
+\r
+cleanup:\r
+ if ( addrs ) {\r
+ for ( i=0;i<addr_count;i++ ) {\r
+ if ( addrs[i] ) {\r
+ if ( addrs[i]->contents )\r
+ free(addrs[i]->contents);\r
+ free(addrs[i]);\r
+ }\r
+ }\r
+ }\r
+ if (my_creds.client == me)\r
+ my_creds.client = 0;\r
+ pkrb5_free_cred_contents(ctx, &my_creds);\r
+ if (name)\r
+ pkrb5_free_unparsed_name(ctx, name);\r
+ if (me)\r
+ pkrb5_free_principal(ctx, me);\r
+ if (cc)\r
+ pkrb5_cc_close(ctx, cc);\r
+ if (ctx && (ctx != alt_ctx))\r
+ pkrb5_free_context(ctx);\r
+ return(code);\r
+}\r
+\r
+long\r
+khm_krb5_copy_ccache_by_name(krb5_context in_ctx,\r
+ wchar_t * wscc_dest,\r
+ wchar_t * wscc_src) {\r
+ krb5_context ctx = NULL;\r
+ krb5_error_code code = 0;\r
+ khm_boolean free_ctx;\r
+ krb5_ccache cc_src = NULL;\r
+ krb5_ccache cc_dest = NULL;\r
+ krb5_principal princ_src = NULL;\r
+ char scc_dest[KRB5_MAXCCH_CCNAME];\r
+ char scc_src[KRB5_MAXCCH_CCNAME];\r
+ int t;\r
+\r
+ t = UnicodeStrToAnsi(scc_dest, sizeof(scc_dest), wscc_dest);\r
+ if (t == 0)\r
+ return KHM_ERROR_TOO_LONG;\r
+ t = UnicodeStrToAnsi(scc_src, sizeof(scc_src), wscc_src);\r
+ if (t == 0)\r
+ return KHM_ERROR_TOO_LONG;\r
+\r
+ if (in_ctx) {\r
+ ctx = in_ctx;\r
+ free_ctx = FALSE;\r
+ } else {\r
+ code = pkrb5_init_context(&ctx);\r
+ if (code) {\r
+ if (ctx)\r
+ pkrb5_free_context(ctx);\r
+ return code;\r
+ }\r
+ free_ctx = TRUE;\r
+ }\r
+\r
+ code = pkrb5_cc_resolve(ctx, scc_dest, &cc_dest);\r
+ if (code)\r
+ goto _cleanup;\r
+\r
+ code = pkrb5_cc_resolve(ctx, scc_src, &cc_src);\r
+ if (code)\r
+ goto _cleanup;\r
+\r
+ code = pkrb5_cc_get_principal(ctx, cc_src, &princ_src);\r
+ if (code)\r
+ goto _cleanup;\r
+\r
+ code = pkrb5_cc_initialize(ctx, cc_dest, princ_src);\r
+ if (code)\r
+ goto _cleanup;\r
+\r
+ code = pkrb5_cc_copy_creds(ctx, cc_src, cc_dest);\r
+\r
+ _cleanup:\r
+ if (princ_src)\r
+ pkrb5_free_principal(ctx, princ_src);\r
+\r
+ if (cc_dest)\r
+ pkrb5_cc_close(ctx, cc_dest);\r
+\r
+ if (cc_src)\r
+ pkrb5_cc_close(ctx, cc_src);\r
+\r
+ if (free_ctx && ctx)\r
+ pkrb5_free_context(ctx);\r
+\r
+ return code;\r
+}\r
+\r
+long\r
+khm_krb5_canon_cc_name(wchar_t * wcc_name,\r
+ size_t cb_cc_name) {\r
+ size_t cb_len;\r
+ wchar_t * colon;\r
+\r
+ if (FAILED(StringCbLength(wcc_name, \r
+ cb_cc_name,\r
+ &cb_len))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return KHM_ERROR_TOO_LONG;\r
+#endif\r
+ }\r
+\r
+ cb_len += sizeof(wchar_t);\r
+\r
+ colon = wcschr(wcc_name, L':');\r
+\r
+ if (colon)\r
+ return 0;\r
+\r
+ if (cb_len + 4 * sizeof(wchar_t) > cb_cc_name)\r
+ return KHM_ERROR_TOO_LONG;\r
+\r
+ memmove(&wcc_name[4], &wcc_name[0], cb_len);\r
+ memmove(&wcc_name[0], L"API:", sizeof(wchar_t) * 4);\r
+\r
+ return 0;\r
+}\r
+\r
+int \r
+khm_krb5_cc_name_cmp(const wchar_t * cc_name_1,\r
+ const wchar_t * cc_name_2) {\r
+ if (!wcsncmp(cc_name_1, L"API:", 4))\r
+ cc_name_1 += 4;\r
+\r
+ if (!wcsncmp(cc_name_2, L"API:", 4))\r
+ cc_name_2 += 4;\r
+\r
+ return wcscmp(cc_name_1, cc_name_2);\r
+}\r
+\r
+static khm_int32 KHMAPI\r
+khmint_location_comp_func(khm_handle cred1,\r
+ khm_handle cred2,\r
+ void * rock) {\r
+ return kcdb_creds_comp_attr(cred1, cred2, KCDB_ATTR_LOCATION);\r
+}\r
+\r
+struct khmint_location_check {\r
+ khm_handle credset;\r
+ khm_handle cred;\r
+ wchar_t * ccname;\r
+ khm_boolean success;\r
+};\r
+\r
+static khm_int32 KHMAPI\r
+khmint_find_matching_cred_func(khm_handle cred,\r
+ void * rock) {\r
+ struct khmint_location_check * lc;\r
+\r
+ lc = (struct khmint_location_check *) rock;\r
+\r
+ if (!kcdb_creds_is_equal(cred, lc->cred))\r
+ return KHM_ERROR_SUCCESS;\r
+ if (kcdb_creds_comp_attr(cred, lc->cred, KCDB_ATTR_LOCATION))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ /* found it */\r
+ lc->success = TRUE;\r
+\r
+ /* break the search */\r
+ return !KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32 KHMAPI\r
+khmint_location_check_func(khm_handle cred,\r
+ void * rock) {\r
+ khm_int32 t;\r
+ khm_size cb;\r
+ wchar_t ccname[KRB5_MAXCCH_CCNAME];\r
+ struct khmint_location_check * lc;\r
+\r
+ lc = (struct khmint_location_check *) rock;\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_type(cred, &t)))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if (t != credtype_id_krb5)\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ cb = sizeof(ccname);\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ ccname,\r
+ &cb)))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if(wcscmp(ccname, lc->ccname))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ lc->cred = cred;\r
+\r
+ lc->success = FALSE;\r
+\r
+ kcdb_credset_apply(lc->credset,\r
+ khmint_find_matching_cred_func,\r
+ (void *) lc);\r
+\r
+ if (!lc->success)\r
+ return KHM_ERROR_NOT_FOUND;\r
+ else\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32 KHMAPI\r
+khmint_delete_location_func(khm_handle cred,\r
+ void * rock) {\r
+ wchar_t cc_cred[KRB5_MAXCCH_CCNAME];\r
+ struct khmint_location_check * lc;\r
+ khm_size cb;\r
+\r
+ lc = (struct khmint_location_check *) rock;\r
+\r
+ cb = sizeof(cc_cred);\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ cc_cred,\r
+ &cb)))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if (wcscmp(cc_cred, lc->ccname))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ kcdb_credset_del_cred_ref(lc->credset,\r
+ cred);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+int\r
+khm_krb5_destroy_by_credset(khm_handle p_cs)\r
+{\r
+ khm_handle d_cs = NULL;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_size s, cb;\r
+ krb5_context ctx;\r
+ krb5_error_code code = 0;\r
+ int i;\r
+ wchar_t ccname[KRB5_MAXCCH_CCNAME];\r
+ struct khmint_location_check lc;\r
+\r
+ rv = kcdb_credset_create(&d_cs);\r
+\r
+ assert(KHM_SUCCEEDED(rv) && d_cs != NULL);\r
+\r
+ kcdb_credset_extract(d_cs, p_cs, NULL, credtype_id_krb5);\r
+\r
+ kcdb_credset_get_size(d_cs, &s);\r
+\r
+ if (s == 0) {\r
+ /* nothing to do */\r
+ kcdb_credset_delete(d_cs);\r
+ return 0;\r
+ }\r
+\r
+ code = pkrb5_init_context(&ctx);\r
+ if (code != 0) {\r
+ rv = code;\r
+ goto _cleanup;\r
+ }\r
+\r
+ /* we should synchronize the credential lists before we attempt to\r
+ make any assumptions on the state of the root credset */\r
+ khm_krb5_list_tickets(&ctx);\r
+\r
+ /* so, we need to make a decision about whether to destroy entire\r
+ ccaches or just individual credentials. Therefore we first\r
+ sort them by ccache. */\r
+ kcdb_credset_sort(d_cs,\r
+ khmint_location_comp_func,\r
+ NULL);\r
+\r
+ /* now, for each ccache we encounter, we check if we have all the\r
+ credentials from that ccache in the to-be-deleted list. */\r
+ for (i=0; i < (int) s; i++) {\r
+ khm_handle cred;\r
+\r
+ if (KHM_FAILED(kcdb_credset_get_cred(d_cs,\r
+ i,\r
+ &cred)))\r
+ continue;\r
+\r
+ cb = sizeof(ccname);\r
+ rv = kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ ccname,\r
+ &cb);\r
+\r
+#ifdef DEBUG\r
+ assert(KHM_SUCCEEDED(rv));\r
+#endif\r
+ kcdb_cred_release(cred);\r
+\r
+ lc.credset = d_cs;\r
+ lc.cred = NULL;\r
+ lc.ccname = ccname;\r
+ lc.success = FALSE;\r
+\r
+ kcdb_credset_apply(NULL,\r
+ khmint_location_check_func,\r
+ (void *) &lc);\r
+\r
+ if (lc.success) {\r
+ /* ok the destroy the ccache */\r
+ char a_ccname[KRB5_MAXCCH_CCNAME];\r
+ krb5_ccache cc = NULL;\r
+\r
+ UnicodeStrToAnsi(a_ccname,\r
+ sizeof(a_ccname),\r
+ ccname);\r
+\r
+ code = pkrb5_cc_resolve(ctx,\r
+ a_ccname,\r
+ &cc);\r
+ if (code)\r
+ goto _delete_this_set;\r
+\r
+ code = pkrb5_cc_destroy(ctx, cc);\r
+\r
+ if (code) {\r
+ /*TODO: report error */\r
+ }\r
+\r
+ _delete_this_set:\r
+\r
+ lc.credset = d_cs;\r
+ lc.ccname = ccname;\r
+\r
+ /* note that although we are deleting credentials off the\r
+ credential set, the size of the credential set does not\r
+ decrease since we are doing it from inside\r
+ kcdb_credset_apply(). The deleted creds will simply be\r
+ marked as deleted until kcdb_credset_purge() is\r
+ called. */\r
+\r
+ kcdb_credset_apply(d_cs,\r
+ khmint_delete_location_func,\r
+ (void *) &lc);\r
+ }\r
+ }\r
+\r
+ kcdb_credset_purge(d_cs);\r
+\r
+ /* the remainder need to be deleted one by one */\r
+\r
+ kcdb_credset_get_size(d_cs, &s);\r
+\r
+ for (i=0; i < (int) s; ) {\r
+ khm_handle cred;\r
+ char a_ccname[KRB5_MAXCCH_CCNAME];\r
+ char a_srvname[KCDB_CRED_MAXCCH_NAME];\r
+ wchar_t srvname[KCDB_CRED_MAXCCH_NAME];\r
+ krb5_ccache cc;\r
+ krb5_creds in_cred, out_cred;\r
+ krb5_principal princ;\r
+ khm_int32 etype;\r
+\r
+ if (KHM_FAILED(kcdb_credset_get_cred(d_cs,\r
+ i,\r
+ &cred))) {\r
+ i++;\r
+ continue;\r
+ }\r
+\r
+ cb = sizeof(ccname);\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ ccname,\r
+ &cb)))\r
+ goto _done_with_this_cred;\r
+\r
+ UnicodeStrToAnsi(a_ccname,\r
+ sizeof(a_ccname),\r
+ ccname);\r
+\r
+ code = pkrb5_cc_resolve(ctx,\r
+ a_ccname,\r
+ &cc);\r
+\r
+ if (code)\r
+ goto _skip_similar;\r
+\r
+ code = pkrb5_cc_get_principal(ctx, cc, &princ);\r
+\r
+ if (code) {\r
+ pkrb5_cc_close(ctx, cc);\r
+ goto _skip_similar;\r
+ }\r
+\r
+ _del_this_cred:\r
+\r
+ cb = sizeof(etype);\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ attr_id_key_enctype,\r
+ NULL,\r
+ &etype,\r
+ &cb)))\r
+ goto _do_next_cred;\r
+\r
+ cb = sizeof(srvname);\r
+ if (KHM_FAILED(kcdb_cred_get_name(cred,\r
+ srvname,\r
+ &cb)))\r
+ goto _do_next_cred;\r
+\r
+ UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname);\r
+\r
+ ZeroMemory(&in_cred, sizeof(in_cred));\r
+\r
+ code = pkrb5_parse_name(ctx, a_srvname, &in_cred.server);\r
+ if (code)\r
+ goto _do_next_cred;\r
+ in_cred.client = princ;\r
+ in_cred.keyblock.enctype = etype;\r
+\r
+ code = pkrb5_cc_retrieve_cred(ctx,\r
+ cc,\r
+ KRB5_TC_MATCH_SRV_NAMEONLY |\r
+ KRB5_TC_SUPPORTED_KTYPES,\r
+ &in_cred,\r
+ &out_cred);\r
+ if (code)\r
+ goto _do_next_cred_0;\r
+\r
+ code = pkrb5_cc_remove_cred(ctx, cc,\r
+ KRB5_TC_MATCH_SRV_NAMEONLY |\r
+ KRB5_TC_SUPPORTED_KTYPES |\r
+ KRB5_TC_MATCH_AUTHDATA,\r
+ &out_cred);\r
+\r
+ pkrb5_free_cred_contents(ctx, &out_cred);\r
+ _do_next_cred_0:\r
+ pkrb5_free_principal(ctx, in_cred.server);\r
+ _do_next_cred:\r
+\r
+ /* check if the next cred is also of the same ccache */\r
+ kcdb_cred_release(cred);\r
+\r
+ for (i++; i < (int) s; i++) {\r
+ if (KHM_FAILED(kcdb_credset_get_cred(d_cs,\r
+ i,\r
+ &cred)))\r
+ continue;\r
+ }\r
+\r
+ if (i < (int) s) {\r
+ wchar_t newcc[KRB5_MAXCCH_CCNAME];\r
+\r
+ cb = sizeof(newcc);\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ newcc,\r
+ &cb)) ||\r
+ wcscmp(newcc, ccname)) {\r
+ i--; /* we have to look at this again */\r
+ goto _done_with_this_set;\r
+ }\r
+ goto _del_this_cred;\r
+ }\r
+ \r
+\r
+ _done_with_this_set:\r
+ pkrb5_free_principal(ctx, princ);\r
+\r
+ pkrb5_cc_close(ctx, cc);\r
+\r
+ _done_with_this_cred:\r
+ kcdb_cred_release(cred);\r
+ i++;\r
+ continue;\r
+\r
+ _skip_similar:\r
+ kcdb_cred_release(cred);\r
+\r
+ for (++i; i < (int) s; i++) {\r
+ wchar_t newcc[KRB5_MAXCCH_CCNAME];\r
+\r
+ if (KHM_FAILED(kcdb_credset_get_cred(d_cs,\r
+ i,\r
+ &cred)))\r
+ continue;\r
+\r
+ cb = sizeof(newcc);\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ &newcc,\r
+ &cb))) {\r
+ kcdb_cred_release(cred);\r
+ continue;\r
+ }\r
+\r
+ if (wcscmp(newcc, ccname)) {\r
+ kcdb_cred_release(cred);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ _cleanup:\r
+\r
+ if (d_cs)\r
+ kcdb_credset_delete(&d_cs);\r
+\r
+ return rv;\r
+}\r
+\r
+int\r
+khm_krb5_destroy_identity(khm_handle identity)\r
+{\r
+ krb5_context ctx;\r
+ krb5_ccache cache;\r
+ krb5_error_code rc;\r
+\r
+ ctx = NULL;\r
+ cache = NULL;\r
+\r
+ if (rc = khm_krb5_initialize(identity, &ctx, &cache))\r
+ return(rc);\r
+\r
+ rc = pkrb5_cc_destroy(ctx, cache);\r
+\r
+ if (ctx != NULL)\r
+ pkrb5_free_context(ctx);\r
+\r
+ return(rc);\r
+}\r
+\r
+static BOOL\r
+GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)\r
+{\r
+ NTSTATUS Status = 0;\r
+ HANDLE TokenHandle;\r
+ TOKEN_STATISTICS Stats;\r
+ DWORD ReqLen;\r
+ BOOL Success;\r
+\r
+ if (!ppSessionData)\r
+ return FALSE;\r
+ *ppSessionData = NULL;\r
+\r
+ Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );\r
+ if ( !Success )\r
+ return FALSE;\r
+\r
+ Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );\r
+ CloseHandle( TokenHandle );\r
+ if ( !Success )\r
+ return FALSE;\r
+\r
+ Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );\r
+ if ( FAILED(Status) || !ppSessionData )\r
+ return FALSE;\r
+\r
+ return TRUE;\r
+}\r
+\r
+// IsKerberosLogon() does not validate whether or not there are valid\r
+// tickets in the cache. It validates whether or not it is reasonable\r
+// to assume that if we attempted to retrieve valid tickets we could\r
+// do so. Microsoft does not automatically renew expired tickets.\r
+// Therefore, the cache could contain expired or invalid tickets.\r
+// Microsoft also caches the user's password and will use it to\r
+// retrieve new TGTs if the cache is empty and tickets are requested.\r
+\r
+static BOOL\r
+IsKerberosLogon(VOID)\r
+{\r
+ PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;\r
+ BOOL Success = FALSE;\r
+\r
+ if ( GetSecurityLogonSessionData(&pSessionData) ) {\r
+ if ( pSessionData->AuthenticationPackage.Buffer ) {\r
+ WCHAR buffer[256];\r
+ WCHAR *usBuffer;\r
+ int usLength;\r
+\r
+ Success = FALSE;\r
+ usBuffer = (pSessionData->AuthenticationPackage).Buffer;\r
+ usLength = (pSessionData->AuthenticationPackage).Length;\r
+ if (usLength < 256)\r
+ {\r
+ lstrcpynW (buffer, usBuffer, usLength);\r
+ StringCbCatW (buffer, sizeof(buffer), L"");\r
+ if ( !lstrcmpW(L"Kerberos",buffer) )\r
+ Success = TRUE;\r
+ }\r
+ }\r
+ pLsaFreeReturnBuffer(pSessionData);\r
+ }\r
+ return Success;\r
+}\r
+\r
+\r
+BOOL\r
+khm_krb5_ms2mit(BOOL save_creds)\r
+{\r
+#ifdef NO_KRB5\r
+ return(FALSE);\r
+#else /* NO_KRB5 */\r
+ krb5_context kcontext = 0;\r
+ krb5_error_code code;\r
+ krb5_ccache ccache=0;\r
+ krb5_ccache mslsa_ccache=0;\r
+ krb5_creds creds;\r
+ krb5_cc_cursor cursor=0;\r
+ krb5_principal princ = 0;\r
+ char *cache_name = NULL;\r
+ char *princ_name = NULL;\r
+ BOOL rc = FALSE;\r
+\r
+ if ( !pkrb5_init_context )\r
+ goto cleanup;\r
+\r
+ if (code = pkrb5_init_context(&kcontext))\r
+ goto cleanup;\r
+\r
+ if (code = pkrb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache))\r
+ goto cleanup;\r
+\r
+ if ( save_creds ) {\r
+ if (code = pkrb5_cc_get_principal(kcontext, mslsa_ccache, &princ))\r
+ goto cleanup;\r
+\r
+ if (code = pkrb5_unparse_name(kcontext, princ, &princ_name))\r
+ goto cleanup;\r
+\r
+ /* TODO: actually look up the preferred ccache name */\r
+ if ((code = pkrb5_cc_resolve(kcontext, princ_name, &ccache)) ||\r
+ (code = pkrb5_cc_default(kcontext, &ccache)))\r
+ goto cleanup;\r
+\r
+ if (code = pkrb5_cc_initialize(kcontext, ccache, princ))\r
+ goto cleanup;\r
+\r
+ if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache))\r
+ goto cleanup;\r
+\r
+ rc = TRUE;\r
+ } else {\r
+ /* Enumerate tickets from cache looking for an initial ticket */\r
+ if ((code = pkrb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) \r
+ goto cleanup;\r
+\r
+ while (!(code = pkrb5_cc_next_cred(kcontext, mslsa_ccache, &cursor, &creds))) \r
+ {\r
+ if ( creds.ticket_flags & TKT_FLG_INITIAL ) {\r
+ rc = TRUE;\r
+ pkrb5_free_cred_contents(kcontext, &creds);\r
+ break;\r
+ }\r
+ pkrb5_free_cred_contents(kcontext, &creds);\r
+ }\r
+ pkrb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor);\r
+ }\r
+\r
+cleanup:\r
+ if (princ_name)\r
+ pkrb5_free_unparsed_name(kcontext, princ_name);\r
+ if (princ)\r
+ pkrb5_free_principal(kcontext, princ);\r
+ if (ccache)\r
+ pkrb5_cc_close(kcontext, ccache);\r
+ if (mslsa_ccache)\r
+ pkrb5_cc_close(kcontext, mslsa_ccache);\r
+ if (kcontext)\r
+ pkrb5_free_context(kcontext);\r
+ return(rc);\r
+#endif /* NO_KRB5 */\r
+}\r
+\r
+#define KRB_FILE "KRB.CON"\r
+#define KRBREALM_FILE "KRBREALM.CON"\r
+#define KRB5_FILE "KRB5.INI"\r
+\r
+BOOL \r
+khm_get_profile_file(LPSTR confname, UINT szConfname)\r
+{\r
+ char **configFile = NULL;\r
+ if (pkrb5_get_default_config_files(&configFile)) \r
+ {\r
+ GetWindowsDirectoryA(confname,szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, "\\",sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ return FALSE;\r
+ }\r
+ \r
+ *confname = 0;\r
+ \r
+ if (configFile)\r
+ {\r
+ strncpy(confname, *configFile, szConfname);\r
+ pkrb5_free_config_files(configFile); \r
+ }\r
+ \r
+ if (!*confname)\r
+ {\r
+ GetWindowsDirectoryA(confname,szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, "\\",sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+BOOL\r
+khm_get_krb4_con_file(LPSTR confname, UINT szConfname)\r
+{\r
+ if (hKrb5 && !hKrb4) { // hold krb.con where krb5.ini is located\r
+ CHAR krbConFile[MAX_PATH]="";\r
+ LPSTR pFind;\r
+\r
+ //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename);\r
+ if (khm_get_profile_file(krbConFile, sizeof(krbConFile))) {\r
+ GetWindowsDirectoryA(krbConFile,sizeof(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ }\r
+ \r
+ pFind = strrchr(krbConFile, '\\');\r
+ if (pFind) {\r
+ *pFind = 0;\r
+ strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile));\r
+ krbConFile[MAX_PATH-1] = '\0';\r
+ }\r
+ else\r
+ krbConFile[0] = 0;\r
+ \r
+ strncpy(confname, krbConFile, szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ }\r
+ else if (hKrb4) { \r
+ unsigned int size = szConfname;\r
+ memset(confname, '\0', szConfname);\r
+ if (!pkrb_get_krbconf2(confname, &size))\r
+ { // Error has happened\r
+ GetWindowsDirectoryA(confname,szConfname);\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname, "\\",szConfname-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ strncat(confname,KRB_FILE,szConfname-strlen(confname));\r
+ confname[szConfname-1] = '\0';\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+int\r
+readstring(FILE * file, char * buf, int len)\r
+{\r
+ int c,i;\r
+ memset(buf, '\0', sizeof(buf));\r
+ for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) { \r
+ if (i < sizeof(buf)) {\r
+ if (c == '\n') {\r
+ buf[i] = '\0';\r
+ return i;\r
+ } else {\r
+ buf[i] = c;\r
+ }\r
+ } else {\r
+ if (c == '\n') {\r
+ buf[len-1] = '\0';\r
+ return(i);\r
+ }\r
+ }\r
+ }\r
+ if (c == EOF) {\r
+ if (i > 0 && i < len) {\r
+ buf[i] = '\0';\r
+ return(i);\r
+ } else {\r
+ buf[len-1] = '\0';\r
+ return(-1);\r
+ }\r
+ }\r
+ return(-1);\r
+}\r
+\r
+/*! \internal\r
+ \brief Return a list of configured realms\r
+\r
+ The string that is returned is a set of null terminated unicode\r
+ strings, each of which denotes one realm. The set is terminated\r
+ by a zero length null terminated string.\r
+\r
+ The caller should free the returned string using free()\r
+\r
+ \return The string with the list of realms or NULL if the\r
+ operation fails.\r
+*/\r
+wchar_t * khm_krb5_get_realm_list(void) \r
+{\r
+ wchar_t * rlist = NULL;\r
+\r
+ if (pprofile_get_subsection_names && pprofile_free_list) {\r
+ const char* rootSection[] = {"realms", NULL};\r
+ const char** rootsec = rootSection;\r
+ char **sections = NULL, **cpp = NULL, *value = NULL;\r
+\r
+ char krb5_conf[MAX_PATH+1];\r
+\r
+ if (!khm_get_profile_file(krb5_conf,sizeof(krb5_conf))) {\r
+ profile_t profile;\r
+ long retval;\r
+ const char *filenames[2];\r
+ wchar_t * d;\r
+ size_t cbsize;\r
+ size_t t;\r
+\r
+ filenames[0] = krb5_conf;\r
+ filenames[1] = NULL;\r
+ retval = pprofile_init(filenames, &profile);\r
+ if (!retval) {\r
+ retval = pprofile_get_subsection_names(profile, rootsec, \r
+ §ions);\r
+\r
+ if (!retval)\r
+ {\r
+ /* first figure out how much space to allocate */\r
+ cbsize = 0;\r
+ for (cpp = sections; *cpp; cpp++) \r
+ {\r
+ cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1);\r
+ }\r
+ cbsize += sizeof(wchar_t); /* double null terminated */\r
+\r
+ rlist = malloc(cbsize);\r
+ d = rlist;\r
+ for (cpp = sections; *cpp; cpp++)\r
+ {\r
+ AnsiStrToUnicode(d, cbsize, *cpp);\r
+ t = wcslen(d) + 1;\r
+ d += t;\r
+ cbsize -= sizeof(wchar_t) * t;\r
+ }\r
+ *d = L'\0';\r
+ }\r
+\r
+ pprofile_free_list(sections);\r
+\r
+#if 0\r
+ retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value);\r
+ if ( value ) {\r
+ disable_noaddresses = config_boolean_to_int(value);\r
+ pprofile_release_string(value);\r
+ }\r
+#endif\r
+ pprofile_release(profile);\r
+ }\r
+ }\r
+ } else {\r
+ FILE * file;\r
+ char krb_conf[MAX_PATH+1];\r
+ char * p;\r
+ size_t cbsize, t;\r
+ wchar_t * d;\r
+\r
+ if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && \r
+ (file = fopen(krb_conf, "rt")))\r
+ {\r
+ char lineBuf[256];\r
+\r
+ /*TODO: compute the actual required buffer size instead of hardcoding */\r
+ cbsize = 16384; // arbitrary\r
+ rlist = malloc(cbsize);\r
+ d = rlist;\r
+\r
+ // Skip the default realm\r
+ readstring(file,lineBuf,sizeof(lineBuf));\r
+\r
+ // Read the defined realms\r
+ while (TRUE)\r
+ {\r
+ if (readstring(file,lineBuf,sizeof(lineBuf)) < 0)\r
+ break;\r
+\r
+ if (*(lineBuf + strlen(lineBuf) - 1) == '\r')\r
+ *(lineBuf + strlen(lineBuf) - 1) = 0;\r
+\r
+ for (p=lineBuf; *p ; p++)\r
+ {\r
+ if (isspace(*p)) {\r
+ *p = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) {\r
+ t = strlen(lineBuf) + 1;\r
+ if(cbsize > (1 + t*sizeof(wchar_t))) {\r
+ AnsiStrToUnicode(d, cbsize, lineBuf);\r
+ d += t;\r
+ cbsize -= t * sizeof(wchar_t);\r
+ } else\r
+ break;\r
+ }\r
+ }\r
+\r
+ *d = L'\0';\r
+\r
+ fclose(file);\r
+ }\r
+ }\r
+\r
+ return rlist;\r
+}\r
+\r
+/*! \internal\r
+ \brief Get the default realm\r
+\r
+ A string will be returned that specifies the default realm. The\r
+ caller should free the string using free().\r
+\r
+ Returns NULL if the operation fails.\r
+*/\r
+wchar_t * khm_krb5_get_default_realm(void)\r
+{\r
+ wchar_t * realm;\r
+ size_t cch;\r
+ krb5_context ctx=0;\r
+ char * def = 0;\r
+\r
+ pkrb5_init_context(&ctx);\r
+ pkrb5_get_default_realm(ctx,&def);\r
+ \r
+ if (def) {\r
+ cch = strlen(def) + 1;\r
+ realm = malloc(sizeof(wchar_t) * cch);\r
+ AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def);\r
+ pkrb5_free_default_realm(ctx, def);\r
+ } else\r
+ realm = NULL;\r
+\r
+ pkrb5_free_context(ctx);\r
+\r
+ return realm;\r
+}\r
+\r
+wchar_t * khm_get_realm_from_princ(wchar_t * princ) {\r
+ wchar_t * t;\r
+\r
+ if(!princ)\r
+ return NULL;\r
+\r
+ for (t = princ; *t; t++) {\r
+ if(*t == L'\\') { /* escape */\r
+ t++;\r
+ if(! *t) /* malformed */\r
+ break;\r
+ } else if (*t == L'@')\r
+ break;\r
+ }\r
+\r
+ if (*t == '@' && *(t+1) != L'\0')\r
+ return (t+1);\r
+ else\r
+ return NULL;\r
+}\r
+\r
+long\r
+khm_krb5_changepwd(char * principal,\r
+ char * password,\r
+ char * newpassword,\r
+ char** error_str)\r
+{\r
+ krb5_error_code rc = 0;\r
+ int result_code;\r
+ krb5_data result_code_string, result_string;\r
+ krb5_context context = 0;\r
+ krb5_principal princ = 0;\r
+ krb5_get_init_creds_opt opts;\r
+ krb5_creds creds;\r
+\r
+ result_string.data = 0;\r
+ result_code_string.data = 0;\r
+\r
+ if ( !pkrb5_init_context )\r
+ goto cleanup;\r
+\r
+ if (rc = pkrb5_init_context(&context)) {\r
+ goto cleanup;\r
+ }\r
+\r
+ if (rc = pkrb5_parse_name(context, principal, &princ)) {\r
+ goto cleanup;\r
+ }\r
+\r
+ pkrb5_get_init_creds_opt_init(&opts);\r
+ pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);\r
+ pkrb5_get_init_creds_opt_set_renew_life(&opts, 0);\r
+ pkrb5_get_init_creds_opt_set_forwardable(&opts, 0);\r
+ pkrb5_get_init_creds_opt_set_proxiable(&opts, 0);\r
+ pkrb5_get_init_creds_opt_set_address_list(&opts,NULL);\r
+\r
+ if (rc = pkrb5_get_init_creds_password(context, &creds, princ, \r
+ password, 0, 0, 0, \r
+ "kadmin/changepw", &opts)) {\r
+ if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) {\r
+#if 0\r
+ com_err(argv[0], 0,\r
+ "Password incorrect while getting initial ticket");\r
+#endif\r
+ }\r
+ else {\r
+#if 0\r
+ com_err(argv[0], ret, "getting initial ticket");\r
+#endif\r
+ }\r
+ goto cleanup;\r
+ }\r
+\r
+ if (rc = pkrb5_change_password(context, &creds, newpassword,\r
+ &result_code, &result_code_string,\r
+ &result_string)) {\r
+#if 0\r
+ com_err(argv[0], ret, "changing password");\r
+#endif\r
+ goto cleanup;\r
+ }\r
+\r
+ if (result_code) {\r
+ int len = result_code_string.length + \r
+ (result_string.length ? (sizeof(": ") - 1) : 0) +\r
+ result_string.length;\r
+ if (len && error_str) {\r
+ *error_str = malloc(len + 1);\r
+ if (*error_str)\r
+ StringCchPrintfA(*error_str, len+1,\r
+ "%.*s%s%.*s",\r
+ result_code_string.length, \r
+ result_code_string.data,\r
+ result_string.length?": ":"",\r
+ result_string.length, \r
+ result_string.data);\r
+ }\r
+ rc = result_code;\r
+ goto cleanup;\r
+ }\r
+\r
+ cleanup:\r
+ if (result_string.data)\r
+ pkrb5_free_data_contents(context, &result_string);\r
+\r
+ if (result_code_string.data)\r
+ pkrb5_free_data_contents(context, &result_code_string);\r
+\r
+ if (princ)\r
+ pkrb5_free_principal(context, princ);\r
+\r
+ if (context)\r
+ pkrb5_free_context(context);\r
+\r
+ return rc;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+/* Adapted from multiple Leash header files */\r
+\r
+#ifndef __KHIMAIRA_KRB5FUNCS_H\r
+#define __KHIMAIRA_KRB5FUNCS_H\r
+\r
+#include<stdlib.h>\r
+#include<krb5.h>\r
+\r
+#include <windows.h>\r
+#define SECURITY_WIN32\r
+#include <security.h>\r
+#include <ntsecapi.h>\r
+\r
+#include <krb5common.h>\r
+\r
+#define LEASH_DEBUG_CLASS_GENERIC 0\r
+#define LEASH_DEBUG_CLASS_KRB4 1\r
+#define LEASH_DEBUG_CLASS_KRB4_APP 2\r
+\r
+#define LEASH_PRIORITY_LOW 0\r
+#define LEASH_PRIORITY_HIGH 1\r
+\r
+#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */\r
+\r
+#define KRB5_MAXCCH_CCNAME 1024\r
+\r
+// Function Prototypes.\r
+\r
+BOOL \r
+khm_krb5_ms2mit(BOOL);\r
+\r
+int\r
+khm_krb5_kinit(krb5_context alt_ctx,\r
+ char * principal_name,\r
+ char * password,\r
+ char * ccache,\r
+ krb5_deltat lifetime,\r
+ DWORD forwardable,\r
+ DWORD proxiable,\r
+ krb5_deltat renew_life,\r
+ DWORD addressless,\r
+ DWORD publicIP,\r
+ krb5_prompter_fct prompter,\r
+ void * p_data);\r
+\r
+long\r
+khm_krb5_changepwd(char * principal,\r
+ char * password,\r
+ char * newpassword,\r
+ char** error_str);\r
+\r
+int\r
+khm_krb5_destroy_by_credset(khm_handle p_cs);\r
+\r
+int\r
+khm_krb5_destroy_identity(khm_handle identity);\r
+\r
+long\r
+khm_convert524(krb5_context ctx);\r
+\r
+int \r
+khm_krb5_renew(khm_handle identity);\r
+\r
+wchar_t * \r
+khm_krb5_get_default_realm(void);\r
+\r
+wchar_t * \r
+khm_krb5_get_realm_list(void);\r
+\r
+long \r
+khm_krb5_list_tickets(krb5_context *krbv5Context);\r
+\r
+long \r
+khm_krb4_list_tickets(void);\r
+\r
+wchar_t * \r
+khm_get_realm_from_princ(wchar_t * princ);\r
+\r
+long\r
+khm_krb5_copy_ccache_by_name(krb5_context in_ctx,\r
+ wchar_t * wscc_dest,\r
+ wchar_t * wscc_src);\r
+\r
+long\r
+khm_krb5_canon_cc_name(wchar_t * wcc_name,\r
+ size_t cb_cc_name);\r
+\r
+int \r
+khm_krb5_cc_name_cmp(const wchar_t * cc_name_1,\r
+ const wchar_t * cc_name_2);\r
+\r
+BOOL \r
+khm_get_profile_file(LPSTR confname, UINT szConfname);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<commctrl.h>\r
+#include<strsafe.h>\r
+#include<krb5.h>\r
+#include<assert.h>\r
+\r
+#define K5_NCID_UN_LABEL (KHUI_CW_ID_MIN + 0)\r
+#define K5_NCID_UN (KHUI_CW_ID_MIN + 1)\r
+#define K5_NCID_REALM_LABEL (KHUI_CW_ID_MIN + 2)\r
+#define K5_NCID_REALM (KHUI_CW_ID_MIN + 3)\r
+\r
+#define NC_UNCHANGE_TIMEOUT 3000\r
+#define NC_UNCHANGE_TIMER 2\r
+#define NC_REALMCHANGE_TIMEOUT NC_UNCHANGE_TIMEOUT\r
+#define NC_REALMCHANGE_TIMER 3\r
+\r
+typedef struct tag_k5_new_cred_data {\r
+ HWND hw_username_label;\r
+ HWND hw_username;\r
+ HWND hw_realm_label;\r
+ HWND hw_realm;\r
+} k5_new_cred_data;\r
+\r
+int \r
+k5_get_realm_from_nc(khui_new_creds * nc, \r
+ wchar_t * buf, \r
+ khm_size cch_buf) {\r
+ k5_new_cred_data * d;\r
+\r
+ d = (k5_new_cred_data *) nc->ident_aux;\r
+ return GetWindowText(d->hw_realm, buf, (int) cch_buf);\r
+}\r
+\r
+/* set the primary identity of a new credentials dialog depending on\r
+ the selection of the username and realm\r
+\r
+ Runs in the UI thread\r
+*/\r
+static void \r
+set_identity_from_ui(khui_new_creds * nc,\r
+ k5_new_cred_data * d) {\r
+ wchar_t un[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t * realm;\r
+ khm_size cch;\r
+ khm_size cch_left;\r
+ khm_handle ident;\r
+ LRESULT idx = CB_ERR;\r
+\r
+ cch = GetWindowTextLength(d->hw_username);\r
+\r
+ /* we already set the max length of the edit control to be this.\r
+ shouldn't exceed it unless the edit control is confused. */\r
+ assert(cch < KCDB_IDENT_MAXCCH_NAME - 1);\r
+\r
+ GetWindowText(d->hw_username, un, ARRAYLENGTH(un));\r
+\r
+ realm = khm_get_realm_from_princ(un);\r
+ if (realm) /* realm was specified */\r
+ goto _set_ident;\r
+\r
+ /* the cch we got from GetWindowTextLength can not be trusted to\r
+ be exact. For caveats see MSDN for GetWindowTextLength. */\r
+ StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch);\r
+\r
+ realm = un + cch; /* now points at terminating NULL */\r
+ cch_left = KCDB_IDENT_MAXCCH_NAME - cch;\r
+\r
+ *realm++ = L'@';\r
+ cch_left--;\r
+\r
+ cch = GetWindowTextLength(d->hw_realm);\r
+ if (cch == 0 || cch >= cch_left)\r
+ goto _set_null_ident;\r
+\r
+ GetWindowText(d->hw_realm, realm, (int) cch_left);\r
+\r
+ _set_ident:\r
+ if (KHM_FAILED(kcdb_identity_create(un,\r
+ KCDB_IDENT_FLAG_CREATE,\r
+ &ident)))\r
+ goto _set_null_ident;\r
+\r
+ khui_cw_set_primary_id(nc, ident);\r
+\r
+ kcdb_identity_release(ident);\r
+ return;\r
+\r
+ _set_null_ident:\r
+ khui_cw_set_primary_id(nc, NULL);\r
+ return;\r
+}\r
+\r
+static BOOL\r
+update_crossfeed(khui_new_creds * nc,\r
+ k5_new_cred_data * d,\r
+ int ctrl_id_src) {\r
+ wchar_t un[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t * un_realm;\r
+ wchar_t realm[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_size cch;\r
+ khm_size cch_left;\r
+\r
+ cch = (khm_size) GetWindowTextLength(d->hw_username);\r
+#ifdef DEBUG\r
+ assert(cch < KCDB_IDENT_MAXCCH_NAME);\r
+#endif\r
+ if (cch == 0)\r
+ return FALSE;\r
+\r
+ GetWindowText(d->hw_username,\r
+ un,\r
+ ARRAYLENGTH(un));\r
+\r
+ un_realm = khm_get_realm_from_princ(un);\r
+\r
+ if (un_realm == NULL)\r
+ return FALSE;\r
+\r
+ if (ctrl_id_src == K5_NCID_UN) {\r
+ SendMessage(d->hw_realm,\r
+ CB_SELECTSTRING,\r
+ (WPARAM) -1,\r
+ (LPARAM) un_realm);\r
+\r
+ SetWindowText(d->hw_realm,\r
+ un_realm);\r
+\r
+ return TRUE;\r
+ }\r
+ /* else... */\r
+\r
+ cch_left = KCDB_IDENT_MAXCCH_NAME - (un_realm - un);\r
+\r
+ cch = (khm_size) GetWindowTextLength(d->hw_realm);\r
+\r
+#ifdef DEBUG\r
+ assert(cch < KCDB_IDENT_MAXCCH_NAME);\r
+#endif\r
+ if (cch == 0)\r
+ return FALSE;\r
+\r
+ GetWindowText(d->hw_realm, realm,\r
+ ARRAYLENGTH(realm));\r
+\r
+ StringCchCopy(un_realm, cch_left, realm);\r
+\r
+ SendMessage(d->hw_username,\r
+ CB_SELECTSTRING,\r
+ (WPARAM) -1,\r
+ (LPARAM) un);\r
+\r
+ SetWindowText(d->hw_username, un);\r
+\r
+ return TRUE; \r
+}\r
+\r
+/* Handle window messages for the identity specifiers\r
+\r
+ runs in UI thread */\r
+static LRESULT \r
+handle_wnd_msg(khui_new_creds * nc,\r
+ HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ k5_new_cred_data * d;\r
+\r
+ d = (k5_new_cred_data *) nc->ident_aux;\r
+\r
+ switch(uMsg) {\r
+ case WM_COMMAND:\r
+ switch(wParam) {\r
+ case MAKEWPARAM(K5_NCID_UN, CBN_EDITCHANGE):\r
+ /* the username has changed. Instead of handling this\r
+ for every keystroke, set a timer that elapses some\r
+ time afterwards and then handle the event. */\r
+ SetTimer(hwnd, NC_UNCHANGE_TIMER, \r
+ NC_UNCHANGE_TIMEOUT, NULL);\r
+ return TRUE;\r
+\r
+ case MAKEWPARAM(K5_NCID_UN, CBN_KILLFOCUS):\r
+ case MAKEWPARAM(K5_NCID_UN, CBN_CLOSEUP):\r
+ KillTimer(hwnd, NC_UNCHANGE_TIMER);\r
+\r
+ update_crossfeed(nc,d,K5_NCID_UN);\r
+ set_identity_from_ui(nc,d);\r
+ return TRUE;\r
+\r
+ case MAKEWPARAM(K5_NCID_REALM,CBN_EDITCHANGE):\r
+ SetTimer(hwnd, NC_REALMCHANGE_TIMER,\r
+ NC_REALMCHANGE_TIMEOUT, NULL);\r
+ return TRUE;\r
+\r
+ case MAKEWPARAM(K5_NCID_REALM,CBN_KILLFOCUS):\r
+ case MAKEWPARAM(K5_NCID_REALM,CBN_CLOSEUP):\r
+ KillTimer(hwnd, NC_REALMCHANGE_TIMER);\r
+\r
+ update_crossfeed(nc,d,K5_NCID_REALM);\r
+ set_identity_from_ui(nc, d);\r
+ return TRUE;\r
+ }\r
+ break;\r
+\r
+ case WM_TIMER:\r
+ if(wParam == NC_UNCHANGE_TIMER) {\r
+ KillTimer(hwnd, NC_UNCHANGE_TIMER);\r
+\r
+ update_crossfeed(nc, d, K5_NCID_UN);\r
+ set_identity_from_ui(nc,d);\r
+ return TRUE;\r
+ } else if (wParam == NC_REALMCHANGE_TIMER) {\r
+ KillTimer(hwnd, NC_REALMCHANGE_TIMER);\r
+\r
+ update_crossfeed(nc, d, K5_NCID_REALM);\r
+ set_identity_from_ui(nc, d);\r
+ return TRUE;\r
+ }\r
+ break;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/* UI Callback\r
+\r
+ runs in UI thread */\r
+static LRESULT KHMAPI \r
+ui_cb(khui_new_creds * nc,\r
+ UINT cmd,\r
+ HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ k5_new_cred_data * d;\r
+\r
+ d = (k5_new_cred_data *) nc->ident_aux;\r
+\r
+ switch(cmd) {\r
+ case WMNC_IDENT_INIT:\r
+ {\r
+ wchar_t defident[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t wbuf[1024];\r
+ wchar_t * ms = NULL;\r
+ wchar_t * t;\r
+ wchar_t * defrealm = NULL;\r
+ LRESULT lr;\r
+ khm_size cb_ms;\r
+ khm_size cb;\r
+ HWND hw_parent;\r
+ khm_int32 rv;\r
+ khm_handle hident;\r
+\r
+ hw_parent = (HWND) lParam;\r
+ defident[0] = L'\0';\r
+\r
+#ifdef DEBUG\r
+ assert(d == NULL);\r
+ assert(hw_parent != NULL);\r
+#endif\r
+\r
+ d = malloc(sizeof(*d));\r
+ assert(d);\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ khui_cw_lock_nc(nc);\r
+ nc->ident_aux = (LPARAM) d;\r
+ khui_cw_unlock_nc(nc);\r
+\r
+ LoadString(hResModule, IDS_NC_USERNAME, \r
+ wbuf, ARRAYLENGTH(wbuf));\r
+\r
+ d->hw_username_label = CreateWindow\r
+ (L"STATIC",\r
+ wbuf,\r
+ SS_SIMPLE | WS_CHILD | WS_VISIBLE,\r
+ 0, 0, 100, 100, /* bogus values */\r
+ hw_parent,\r
+ (HMENU) K5_NCID_UN_LABEL,\r
+ hInstance,\r
+ NULL);\r
+ assert(d->hw_username_label != NULL);\r
+\r
+ d->hw_username = CreateWindow\r
+ (L"COMBOBOX",\r
+ L"",\r
+ CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | \r
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP,\r
+ 0, 0, 100, 100, /* bogus values */\r
+ hw_parent,\r
+ (HMENU) K5_NCID_UN,\r
+ hInstance,\r
+ NULL);\r
+ assert(d->hw_username != NULL);\r
+\r
+ SendMessage(d->hw_username,\r
+ CB_LIMITTEXT,\r
+ (WPARAM)(KCDB_IDENT_MAXCCH_NAME - 1),\r
+ 0);\r
+\r
+ SendMessage(d->hw_username,\r
+ CB_SETEXTENDEDUI,\r
+ (WPARAM) TRUE,\r
+ 0);\r
+\r
+ khui_cw_add_control_row(nc,\r
+ d->hw_username_label,\r
+ d->hw_username,\r
+ KHUI_CTRLSIZE_SMALL);\r
+\r
+ LoadString(hResModule, IDS_NC_REALM,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+\r
+ d->hw_realm_label = CreateWindow\r
+ (L"STATIC",\r
+ wbuf,\r
+ SS_SIMPLE | WS_CHILD | WS_VISIBLE,\r
+ 0, 0, 100, 100, /* bogus */\r
+ hw_parent,\r
+ (HMENU) K5_NCID_REALM_LABEL,\r
+ hInstance,\r
+ NULL);\r
+ assert(d->hw_realm_label != NULL);\r
+\r
+ d->hw_realm = CreateWindow\r
+ (L"COMBOBOX",\r
+ L"",\r
+ CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | \r
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP,\r
+ 0, 0, 100, 100, /* bogus */\r
+ hw_parent,\r
+ (HMENU) K5_NCID_REALM,\r
+ hInstance,\r
+ NULL);\r
+ assert(d->hw_realm != NULL);\r
+\r
+ SendMessage(d->hw_realm,\r
+ CB_LIMITTEXT,\r
+ (WPARAM) (KCDB_IDENT_MAXCCH_NAME - 1),\r
+ 0);\r
+\r
+ SendMessage(d->hw_realm,\r
+ CB_SETEXTENDEDUI,\r
+ (WPARAM) TRUE,\r
+ 0);\r
+\r
+ khui_cw_add_control_row(nc,\r
+ d->hw_realm_label,\r
+ d->hw_realm,\r
+ KHUI_CTRLSIZE_SMALL);\r
+\r
+ /* add the LRU realms and principals to the dropdown\r
+ lists */\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRUPrincipals",\r
+ NULL,\r
+ &cb_ms);\r
+\r
+ if (rv != KHM_ERROR_TOO_LONG)\r
+ goto _add_lru_realms;\r
+\r
+ ms = malloc(cb_ms);\r
+ assert(ms != NULL);\r
+\r
+ cb = cb_ms;\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRUPrincipals",\r
+ ms,\r
+ &cb);\r
+\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ /* the first of these is considered the default identity\r
+ if no other default is known */\r
+ StringCbCopy(defident, sizeof(defident), ms);\r
+\r
+ t = ms;\r
+ while(t && *t) {\r
+ SendMessage(d->hw_username,\r
+ CB_ADDSTRING,\r
+ 0,\r
+ (LPARAM) t);\r
+\r
+ t = multi_string_next(t);\r
+ }\r
+\r
+ _add_lru_realms:\r
+ /* add the default realm first */\r
+ defrealm = khm_krb5_get_default_realm();\r
+ if (defrealm) {\r
+ SendMessage(d->hw_realm,\r
+ CB_ADDSTRING,\r
+ 0,\r
+ (LPARAM) defrealm);\r
+ }\r
+\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRURealms",\r
+ NULL,\r
+ &cb);\r
+\r
+ if (rv != KHM_ERROR_TOO_LONG)\r
+ goto _done_adding_lru;\r
+\r
+ if (ms != NULL) {\r
+ if (cb_ms < cb) {\r
+ free(ms);\r
+ ms = malloc(cb);\r
+ assert(ms);\r
+ cb_ms = cb;\r
+ }\r
+ } else {\r
+ ms = malloc(cb);\r
+ cb_ms = cb;\r
+ }\r
+\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRURealms",\r
+ ms,\r
+ &cb);\r
+\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ for (t = ms; t && *t; t = multi_string_next(t)) {\r
+ lr = SendMessage(d->hw_realm,\r
+ CB_FINDSTRINGEXACT,\r
+ (WPARAM) -1,\r
+ (LPARAM) t);\r
+ if (lr != CB_ERR)\r
+ continue;\r
+\r
+ SendMessage(d->hw_realm,\r
+ CB_ADDSTRING,\r
+ 0,\r
+ (LPARAM) t);\r
+ }\r
+\r
+ _done_adding_lru:\r
+ /* set the current selection of the realms list */\r
+ if (defrealm) {\r
+ SendMessage(d->hw_realm,\r
+ CB_SELECTSTRING,\r
+ (WPARAM) -1,\r
+ (LPARAM) defrealm);\r
+ } else {\r
+ SendMessage(d->hw_realm,\r
+ CB_SETCURSEL,\r
+ (WPARAM) 0,\r
+ (LPARAM) 0);\r
+ }\r
+\r
+ if (defrealm)\r
+ free(defrealm);\r
+\r
+ if (ms)\r
+ free(ms);\r
+\r
+ /* now see about that default identity */\r
+ if (nc->ctx.identity) {\r
+ cb = sizeof(defident);\r
+ kcdb_identity_get_name(nc->ctx.identity,\r
+ defident,\r
+ &cb);\r
+ }\r
+\r
+ if (defident[0] == L'\0' &&\r
+ KHM_SUCCEEDED(kcdb_identity_get_default(&hident))) {\r
+ cb = sizeof(defident);\r
+ kcdb_identity_get_name(hident, defident, &cb);\r
+ kcdb_identity_release(hident);\r
+ }\r
+\r
+ if (defident[0] == L'\0') {\r
+ DWORD dw;\r
+\r
+ dw = ARRAYLENGTH(defident);\r
+ GetUserName(defident, &dw);\r
+ }\r
+\r
+ t = khm_get_realm_from_princ(defident);\r
+ if (t) {\r
+ /* there is a realm */\r
+ assert(t != defident);\r
+ *--t = L'\0';\r
+ t++;\r
+\r
+ SendMessage(d->hw_realm,\r
+ CB_SELECTSTRING,\r
+ (WPARAM) -1,\r
+ (LPARAM) t);\r
+\r
+ SendMessage(d->hw_realm,\r
+ WM_SETTEXT,\r
+ 0,\r
+ (LPARAM) t);\r
+ }\r
+\r
+ if (defident[0] != L'\0') {\r
+ /* there is a username */\r
+ SendMessage(d->hw_username,\r
+ CB_SELECTSTRING,\r
+ (WPARAM) -1,\r
+ (LPARAM) defident);\r
+\r
+ SendMessage(d->hw_username,\r
+ WM_SETTEXT,\r
+ 0,\r
+ (LPARAM) defident);\r
+ }\r
+\r
+ set_identity_from_ui(nc, d);\r
+ }\r
+ return TRUE;\r
+\r
+ case WMNC_IDENT_WMSG:\r
+ return handle_wnd_msg(nc, hwnd, uMsg, wParam, lParam);\r
+\r
+ case WMNC_IDENT_EXIT:\r
+ {\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+ khui_cw_lock_nc(nc);\r
+ nc->ident_aux = 0;\r
+ khui_cw_unlock_nc(nc);\r
+ \r
+ /* since we created all the windows as child windows of\r
+ the new creds window, they will be destroyed when that\r
+ window is destroyed. */\r
+ free(d);\r
+ }\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+static khm_int32\r
+k5_ident_valiate_name(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+ krb5_principal princ = NULL;\r
+ char princ_name[KCDB_IDENT_MAXCCH_NAME];\r
+ kcdb_ident_name_xfer * nx;\r
+ krb5_error_code code;\r
+\r
+ nx = (kcdb_ident_name_xfer *) vparam;\r
+\r
+ if(UnicodeStrToAnsi(princ_name, sizeof(princ_name),\r
+ nx->name_src) == 0) {\r
+ nx->result = KHM_ERROR_INVALID_NAME;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ assert(k5_identpro_ctx != NULL);\r
+\r
+ code = pkrb5_parse_name(k5_identpro_ctx,\r
+ princ_name,\r
+ &princ);\r
+\r
+ if (code) {\r
+ nx->result = KHM_ERROR_INVALID_NAME;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ if (princ != NULL) \r
+ pkrb5_free_principal(k5_identpro_ctx,\r
+ princ);\r
+\r
+ nx->result = KHM_ERROR_SUCCESS;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32\r
+k5_ident_set_default(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+\r
+ /* Logic for setting the default identity:\r
+\r
+ When setting identity I as the default;\r
+\r
+ - If KRB5CCNAME is set\r
+ - If I["Krb5CCName"] == %KRB5CCNAME%\r
+ - do nothing\r
+ - Else\r
+ - Copy the contents of I["Krb5CCName"] to %KRB5CCNAME\r
+ - Set I["Krb5CCName"] to %KRB5CCNAME\r
+ - Else\r
+ - Set HKCU\Software\MIT\kerberos5,ccname to \r
+ "API:".I["Krb5CCName"]\r
+ */\r
+\r
+ if (uparam) {\r
+ /* an identity is being made default */\r
+ khm_handle def_ident = (khm_handle) vparam;\r
+ wchar_t env_ccname[KRB5_MAXCCH_CCNAME];\r
+ wchar_t id_ccname[KRB5_MAXCCH_CCNAME];\r
+ khm_size cb;\r
+ DWORD dw;\r
+ LONG l;\r
+\r
+#ifdef DEBUG\r
+ assert(def_ident != NULL);\r
+#endif\r
+\r
+ cb = sizeof(id_ccname);\r
+ if (KHM_FAILED(kcdb_identity_get_attr(def_ident,\r
+ attr_id_krb5_ccname,\r
+ NULL,\r
+ id_ccname,\r
+ &cb)))\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname));\r
+\r
+ StringCbLength(id_ccname, sizeof(id_ccname), &cb);\r
+ cb += sizeof(wchar_t);\r
+\r
+ dw = GetEnvironmentVariable(L"KRB5CCNAME",\r
+ env_ccname,\r
+ ARRAYLENGTH(env_ccname));\r
+\r
+ if (dw == 0 &&\r
+ GetLastError() == ERROR_ENVVAR_NOT_FOUND) {\r
+ /* KRB5CCNAME not set */\r
+ HKEY hk_ccname;\r
+ DWORD dwType;\r
+ DWORD dwSize;\r
+ wchar_t reg_ccname[KRB5_MAXCCH_CCNAME];\r
+\r
+ l = RegOpenKeyEx(HKEY_CURRENT_USER,\r
+ L"Software\\MIT\\kerberos5",\r
+ 0,\r
+ KEY_READ | KEY_WRITE,\r
+ &hk_ccname);\r
+\r
+ if (l != ERROR_SUCCESS)\r
+ l = RegCreateKeyEx(HKEY_CURRENT_USER,\r
+ L"Software\\MIT\\kerberos5",\r
+ 0,\r
+ NULL,\r
+ REG_OPTION_NON_VOLATILE,\r
+ KEY_READ | KEY_WRITE,\r
+ NULL,\r
+ &hk_ccname,\r
+ &dw);\r
+\r
+ if (l != ERROR_SUCCESS)\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ dwSize = sizeof(reg_ccname);\r
+\r
+ l = RegQueryValueEx(hk_ccname,\r
+ L"ccname",\r
+ NULL,\r
+ &dwType,\r
+ (LPBYTE) reg_ccname,\r
+ &dwSize);\r
+\r
+ if (l != ERROR_SUCCESS ||\r
+ dwType != REG_SZ ||\r
+ khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) {\r
+\r
+ /* we have to write the new value in */\r
+\r
+ l = RegSetValueEx(hk_ccname,\r
+ L"ccname",\r
+ 0,\r
+ REG_SZ,\r
+ (BYTE *) id_ccname,\r
+ (DWORD) cb);\r
+ }\r
+\r
+ RegCloseKey(hk_ccname);\r
+\r
+ if (l == ERROR_SUCCESS)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ } else if (dw > ARRAYLENGTH(env_ccname)) {\r
+ /* buffer was not enough */\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return KHM_ERROR_UNKNOWN;\r
+#endif\r
+ } else {\r
+ /* KRB5CCNAME is set */\r
+ long code;\r
+ krb5_context ctx;\r
+\r
+ /* if the %KRB5CCNAME is the same as the identity\r
+ ccache, then it is already the default. */\r
+ if (!khm_krb5_cc_name_cmp(id_ccname, env_ccname))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ /* if not, we have to copy the contents of id_ccname\r
+ to env_ccname */\r
+ code = pkrb5_init_context(&ctx);\r
+ if (code)\r
+ return KHM_ERROR_UNKNOWN;\r
+\r
+ code = khm_krb5_copy_ccache_by_name(ctx, \r
+ env_ccname, \r
+ id_ccname);\r
+\r
+ if (code == 0)\r
+ khm_krb5_list_tickets(&ctx);\r
+\r
+ if (ctx)\r
+ pkrb5_free_context(ctx);\r
+\r
+ return (code == 0)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN;\r
+ }\r
+ } else {\r
+ /* the default identity is being forgotten */\r
+\r
+ /* we don't really do anything about this case */\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32\r
+k5_ident_get_ui_cb(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+ khui_ident_new_creds_cb * cb;\r
+\r
+ cb = (khui_ident_new_creds_cb *) vparam;\r
+\r
+ *cb = ui_cb;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32\r
+k5_ident_notify_create(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+\r
+ /* a new identity has been created. What we want to do at\r
+ this point is to check if the identity belongs to krb5\r
+ and to see if it is the default. */\r
+\r
+ krb5_ccache cc = NULL;\r
+ krb5_error_code code;\r
+ krb5_principal princ = NULL;\r
+ char * princ_nameA = NULL;\r
+ wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t id_nameW[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_size cb;\r
+ khm_handle ident;\r
+\r
+ ident = (khm_handle) vparam;\r
+\r
+ assert(k5_identpro_ctx != NULL);\r
+\r
+ code = pkrb5_cc_default(k5_identpro_ctx, &cc);\r
+ if (code)\r
+ goto _nc_cleanup;\r
+\r
+ code = pkrb5_cc_get_principal(k5_identpro_ctx,\r
+ cc,\r
+ &princ);\r
+ if (code)\r
+ goto _nc_cleanup;\r
+\r
+ code = pkrb5_unparse_name(k5_identpro_ctx,\r
+ princ,\r
+ &princ_nameA);\r
+ if (code)\r
+ goto _nc_cleanup;\r
+\r
+ AnsiStrToUnicode(princ_nameW,\r
+ sizeof(princ_nameW),\r
+ princ_nameA);\r
+\r
+ cb = sizeof(id_nameW);\r
+\r
+ if (KHM_FAILED(kcdb_identity_get_name(ident,\r
+ id_nameW,\r
+ &cb)))\r
+ goto _nc_cleanup;\r
+\r
+ if (!wcscmp(id_nameW, princ_nameW)) {\r
+ kcdb_identity_set_default_int(ident);\r
+ }\r
+\r
+ _nc_cleanup:\r
+ if (princ_nameA)\r
+ pkrb5_free_unparsed_name(k5_identpro_ctx,\r
+ princ_nameA);\r
+ if (princ)\r
+ pkrb5_free_principal(k5_identpro_ctx,\r
+ princ);\r
+ if (cc)\r
+ pkrb5_cc_close(k5_identpro_ctx, cc);\r
+\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32 KHMAPI\r
+k5_ident_update_apply_proc(khm_handle cred,\r
+ void * rock) {\r
+ wchar_t ccname[KRB5_MAXCCH_CCNAME];\r
+ khm_handle tident = (khm_handle) rock;\r
+ khm_handle ident = NULL;\r
+ khm_int32 t;\r
+ khm_int32 flags;\r
+ __int64 t_expire;\r
+ __int64 t_rexpire;\r
+ khm_size cb;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) ||\r
+ t != credtype_id_krb5 ||\r
+ KHM_FAILED(kcdb_cred_get_identity(cred, &ident)))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if (ident != tident)\r
+ goto _cleanup;\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_flags(cred, &flags)))\r
+ flags = 0;\r
+\r
+ cb = sizeof(t_expire);\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_EXPIRE,\r
+ NULL,\r
+ &t_expire,\r
+ &cb))) {\r
+ __int64 t_cexpire;\r
+\r
+ cb = sizeof(t_cexpire);\r
+ if ((flags & KCDB_CRED_FLAG_INITIAL) ||\r
+ KHM_FAILED(kcdb_identity_get_attr(tident,\r
+ KCDB_ATTR_EXPIRE,\r
+ NULL,\r
+ &t_cexpire,\r
+ &cb)) ||\r
+ t_cexpire > t_expire)\r
+ kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE,\r
+ &t_expire, sizeof(t_expire));\r
+ } else if (flags & KCDB_CRED_FLAG_INITIAL) {\r
+ kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, NULL, 0);\r
+ }\r
+\r
+ cb = sizeof(ccname);\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION,\r
+ NULL,\r
+ ccname,\r
+ &cb))) {\r
+ kcdb_identity_set_attr(tident, attr_id_krb5_ccname,\r
+ ccname, cb);\r
+ } else {\r
+ kcdb_identity_set_attr(tident, attr_id_krb5_ccname,\r
+ NULL, 0);\r
+ }\r
+\r
+ if (!(flags & KCDB_CRED_FLAG_INITIAL))\r
+ goto _cleanup;\r
+\r
+ cb = sizeof(t);\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred,\r
+ attr_id_krb5_flags,\r
+ NULL,\r
+ &t,\r
+ &cb))) {\r
+ kcdb_identity_set_attr(tident, attr_id_krb5_flags, \r
+ &t, sizeof(t));\r
+\r
+ cb = sizeof(t_rexpire);\r
+ if (!(t & TKT_FLG_RENEWABLE) ||\r
+ KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ KCDB_ATTR_RENEW_EXPIRE,\r
+ NULL,\r
+ &t_rexpire,\r
+ &cb))) {\r
+ kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE,\r
+ NULL, 0);\r
+ } else {\r
+ kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE,\r
+ &t_rexpire, sizeof(t_rexpire));\r
+ }\r
+ } else {\r
+ kcdb_identity_set_attr(tident, attr_id_krb5_flags,\r
+ NULL, 0);\r
+ kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE,\r
+ NULL, 0);\r
+ }\r
+\r
+ rv = KHM_ERROR_EXIT;\r
+\r
+ _cleanup:\r
+ if (ident)\r
+ kcdb_identity_release(ident);\r
+\r
+ return rv;\r
+}\r
+\r
+static khm_int32\r
+k5_ident_update(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+\r
+ khm_handle ident;\r
+\r
+ ident = (khm_handle) vparam;\r
+ if (ident == NULL)\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ kcdb_credset_apply(NULL,\r
+ k5_ident_update_apply_proc,\r
+ (void *) ident);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+\r
+static khm_int32\r
+k5_ident_init(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+ /* just like notify_create, except now we set the default identity\r
+ based on what we find in the configuration */\r
+ krb5_ccache cc = NULL;\r
+ krb5_error_code code;\r
+ krb5_principal princ = NULL;\r
+ char * princ_nameA = NULL;\r
+ wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_handle ident = NULL;\r
+\r
+ assert(k5_identpro_ctx != NULL);\r
+\r
+ code = pkrb5_cc_default(k5_identpro_ctx, &cc);\r
+ if (code)\r
+ goto _nc_cleanup;\r
+\r
+ code = pkrb5_cc_get_principal(k5_identpro_ctx,\r
+ cc,\r
+ &princ);\r
+ if (code)\r
+ goto _nc_cleanup;\r
+\r
+ code = pkrb5_unparse_name(k5_identpro_ctx,\r
+ princ,\r
+ &princ_nameA);\r
+ if (code)\r
+ goto _nc_cleanup;\r
+\r
+ AnsiStrToUnicode(princ_nameW,\r
+ sizeof(princ_nameW),\r
+ princ_nameA);\r
+\r
+ if (KHM_FAILED(kcdb_identity_create(princ_nameW,\r
+ 0,\r
+ &ident)))\r
+ goto _nc_cleanup;\r
+\r
+ kcdb_identity_set_default_int(ident);\r
+\r
+ _nc_cleanup:\r
+ if (princ_nameA)\r
+ pkrb5_free_unparsed_name(k5_identpro_ctx,\r
+ princ_nameA);\r
+ if (princ)\r
+ pkrb5_free_principal(k5_identpro_ctx,\r
+ princ);\r
+ if (cc)\r
+ pkrb5_cc_close(k5_identpro_ctx, cc);\r
+\r
+ if (ident)\r
+ kcdb_identity_release(ident);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32\r
+k5_ident_exit(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+ /* don't really do anything */\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+#if 0\r
+/* copy and paste template for ident provider messages */\r
+static khm_int32\r
+k5_ident_(khm_int32 msg_type,\r
+ khm_int32 msg_subtype,\r
+ khm_ui_4 uparam,\r
+ void * vparam) {\r
+}\r
+#endif\r
+\r
+khm_int32 KHMAPI \r
+k5_msg_ident(khm_int32 msg_type, \r
+ khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam)\r
+{\r
+ switch(msg_subtype) {\r
+ case KMSG_IDENT_INIT:\r
+ return k5_ident_init(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+\r
+ case KMSG_IDENT_EXIT:\r
+ return k5_ident_exit(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+\r
+ case KMSG_IDENT_VALIDATE_NAME:\r
+ return k5_ident_valiate_name(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+\r
+ case KMSG_IDENT_VALIDATE_IDENTITY:\r
+ /* TODO: handle KMSG_IDENT_VALIDATE_IDENTITY */\r
+ break;\r
+\r
+ case KMSG_IDENT_CANON_NAME:\r
+ /* TODO: handle KMSG_IDENT_CANON_NAME */\r
+ break;\r
+\r
+ case KMSG_IDENT_COMPARE_NAME:\r
+ /* TODO: handle KMSG_IDENT_COMPARE_NAME */\r
+ break;\r
+\r
+ case KMSG_IDENT_SET_DEFAULT:\r
+ return k5_ident_set_default(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+\r
+ case KMSG_IDENT_SET_SEARCHABLE:\r
+ /* TODO: handle KMSG_IDENT_SET_SEARCHABLE */\r
+ break;\r
+\r
+ case KMSG_IDENT_GET_INFO:\r
+ /* TODO: handle KMSG_IDENT_GET_INFO */\r
+ break;\r
+\r
+ case KMSG_IDENT_UPDATE:\r
+ return k5_ident_update(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+\r
+ case KMSG_IDENT_ENUM_KNOWN:\r
+ /* TODO: handle KMSG_IDENT_ENUM_KNOWN */\r
+ break;\r
+\r
+ case KMSG_IDENT_GET_UI_CALLBACK:\r
+ return k5_ident_get_ui_cb(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+\r
+ case KMSG_IDENT_NOTIFY_CREATE:\r
+ return k5_ident_notify_create(msg_type,\r
+ msg_subtype,\r
+ uparam,\r
+ vparam);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<strsafe.h>\r
+#include<krb5.h>\r
+\r
+#include<assert.h>\r
+\r
+extern LPVOID k5_main_fiber;\r
+extern LPVOID k5_kinit_fiber;\r
+\r
+typedef struct k5_dlg_data_t {\r
+ khui_new_creds * nc;\r
+\r
+ khui_tracker tc_lifetime;\r
+ khui_tracker tc_renew;\r
+\r
+ BOOL dirty;\r
+\r
+ DWORD renewable;\r
+ DWORD forwardable;\r
+ DWORD proxiable;\r
+ DWORD addressless;\r
+ DWORD publicIP;\r
+\r
+ wchar_t * cred_message; /* overrides the credential text, if\r
+ non-NULL */\r
+} k5_dlg_data;\r
+\r
+\r
+INT_PTR\r
+k5_handle_wm_initdialog(HWND hwnd,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ HWND hw;\r
+ k5_dlg_data * d;\r
+ khui_new_creds_by_type * nct;\r
+ \r
+ d = malloc(sizeof(*d));\r
+ ZeroMemory(d, sizeof(*d));\r
+ /* lParam is a pointer to a khui_new_creds structure */\r
+ d->nc = (khui_new_creds *) lParam;\r
+ khui_cw_find_type(d->nc, credtype_id_krb5, &nct);\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d);\r
+#pragma warning(pop)\r
+\r
+ nct->aux = (LPARAM) d;\r
+\r
+ if (d->nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ khui_tracker_initialize(&d->tc_lifetime);\r
+ khui_tracker_initialize(&d->tc_renew);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_NCK5_LIFETIME_EDIT);\r
+ khui_tracker_install(hw, &d->tc_lifetime);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT);\r
+ khui_tracker_install(hw, &d->tc_renew);\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+INT_PTR\r
+k5_handle_wm_destroy(HWND hwnd,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ k5_dlg_data * d;\r
+ khui_new_creds_by_type * nct = NULL;\r
+\r
+ d = (k5_dlg_data *) (LONG_PTR)\r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+\r
+ khui_cw_find_type(d->nc, credtype_id_krb5, &nct);\r
+\r
+#ifdef DEBUG\r
+ assert(nct);\r
+#endif\r
+\r
+ nct->aux = 0;\r
+\r
+ if (d->nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ khui_tracker_kill_controls(&d->tc_renew);\r
+ khui_tracker_kill_controls(&d->tc_lifetime);\r
+ }\r
+\r
+ free(d);\r
+\r
+ return TRUE;\r
+}\r
+\r
+INT_PTR\r
+k5_handle_wmnc_notify(HWND hwnd,\r
+ WPARAM wParam, \r
+ LPARAM lParam)\r
+{\r
+ switch(HIWORD(wParam)) {\r
+ case WMNC_DIALOG_MOVE:\r
+ {\r
+ k5_dlg_data * d;\r
+ \r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (d->nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ khui_tracker_reposition(&d->tc_lifetime);\r
+ khui_tracker_reposition(&d->tc_renew);\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+ break;\r
+\r
+ case WMNC_DIALOG_SETUP:\r
+ {\r
+ k5_dlg_data * d;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (d->nc->subtype == KMSG_CRED_PASSWORD)\r
+ return TRUE;\r
+\r
+ /* need to update the controls with d->* */\r
+ if(d->renewable) {\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, \r
+ BM_SETCHECK, BST_CHECKED, \r
+ 0);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), \r
+ TRUE);\r
+ } else {\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, \r
+ BM_SETCHECK, BST_UNCHECKED, 0);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), \r
+ FALSE);\r
+ }\r
+\r
+ khui_tracker_refresh(&d->tc_lifetime);\r
+ khui_tracker_refresh(&d->tc_renew);\r
+\r
+ if(d->forwardable) {\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, \r
+ BM_SETCHECK, BST_CHECKED, 0);\r
+ } else {\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, \r
+ BM_SETCHECK, BST_UNCHECKED, 0);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WMNC_UPDATE_CREDTEXT:\r
+ {\r
+ k5_dlg_data * d;\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ wchar_t sbuf[1024];\r
+ wchar_t fbuf[256];\r
+ wchar_t tbuf[256];\r
+ size_t cbsize;\r
+ khm_int32 flags;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+ nc = d->nc;\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+\r
+ if(nct == NULL)\r
+ break;\r
+\r
+ if(nct->credtext)\r
+ free(nct->credtext);\r
+ nct->credtext = NULL;\r
+\r
+ tbuf[0] = L'\0';\r
+\r
+ if (nc->n_identities > 0 &&\r
+ KHM_SUCCEEDED(kcdb_identity_get_flags(nc->identities[0], \r
+ &flags)) &&\r
+ (flags & KCDB_IDENT_FLAG_VALID) &&\r
+ nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+\r
+ if (is_k5_identpro)\r
+ k5_get_realm_from_nc(nc, tbuf, ARRAYLENGTH(tbuf));\r
+ else\r
+ GetDlgItemText(hwnd, IDC_NCK5_REALM, tbuf, \r
+ ARRAYLENGTH(tbuf));\r
+\r
+ /*TODO: if additional realms were specified, then those\r
+ must be listed as well */\r
+ LoadString(hResModule, IDS_KRB5_CREDTEXT_0, \r
+ fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(sbuf, sizeof(sbuf), fbuf, \r
+ tbuf);\r
+\r
+ StringCbLength(sbuf, sizeof(sbuf), &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ nct->credtext = malloc(cbsize);\r
+\r
+ StringCbCopy(nct->credtext, cbsize, sbuf);\r
+ } else if (nc->n_identities > 0 &&\r
+ nc->subtype == KMSG_CRED_PASSWORD) {\r
+ cbsize = sizeof(tbuf);\r
+ kcdb_identity_get_name(nc->identities[0], tbuf, &cbsize);\r
+\r
+ LoadString(hResModule, IDS_KRB5_CREDTEXT_P0,\r
+ fbuf, ARRAYLENGTH(fbuf));\r
+ StringCbPrintf(sbuf, sizeof(sbuf), fbuf, tbuf);\r
+\r
+ StringCbLength(sbuf, sizeof(sbuf), &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ nct->credtext = malloc(cbsize);\r
+\r
+ StringCbCopy(nct->credtext, cbsize, sbuf);\r
+ } else {\r
+ if (d->cred_message) {\r
+ StringCbLength(d->cred_message, KHUI_MAXCB_BANNER,\r
+ &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ nct->credtext = malloc(cbsize);\r
+\r
+ StringCbCopy(nct->credtext, cbsize, d->cred_message);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WMNC_IDENTITY_CHANGE:\r
+ {\r
+ /* There has been a change of identity */\r
+ k5_dlg_data * d;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ kmq_post_sub_msg(k5_sub, KMSG_CRED, \r
+ KMSG_CRED_DIALOG_NEW_IDENTITY, \r
+ 0, (void *) d->nc);\r
+ }\r
+ break;\r
+\r
+ case WMNC_DIALOG_PREPROCESS:\r
+ {\r
+ k5_dlg_data * d;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if(d->dirty) {\r
+ kmq_post_sub_msg(k5_sub, KMSG_CRED, \r
+ KMSG_CRED_DIALOG_NEW_OPTIONS, \r
+ 0, (void *) d->nc);\r
+\r
+ /* the above notification effectively takes\r
+ all our changes into account. The data we\r
+ have is no longer dirty */\r
+ d->dirty = FALSE;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+INT_PTR\r
+k5_handle_wm_command(HWND hwnd,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ int cid;\r
+ int notif;\r
+ k5_dlg_data * d;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ cid = LOWORD(wParam);\r
+ notif = HIWORD(wParam);\r
+\r
+ if(notif == BN_CLICKED && cid == IDC_NCK5_RENEWABLE) {\r
+ int c;\r
+ c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, \r
+ BM_GETCHECK, 0, 0);\r
+ if(c==BST_CHECKED) {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), TRUE);\r
+ d->renewable = TRUE;\r
+ } else {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), FALSE);\r
+ d->renewable = FALSE;\r
+ }\r
+ d->dirty = TRUE;\r
+ } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) {\r
+ int c;\r
+ c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, \r
+ BM_GETCHECK, 0, 0);\r
+ if(c==BST_CHECKED) {\r
+ d->forwardable = TRUE;\r
+ } else {\r
+ d->forwardable = FALSE;\r
+ }\r
+ d->dirty = TRUE;\r
+ } else if((notif == CBN_SELCHANGE || \r
+ notif == CBN_KILLFOCUS) && \r
+ cid == IDC_NCK5_REALM &&\r
+ !is_k5_identpro) {\r
+ /* find out what the realm of the current identity\r
+ is, and if they are the same, then we don't do\r
+ anything */\r
+ wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t realm[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t *r;\r
+ khm_size cbsize;\r
+ khm_handle ident;\r
+ int idx;\r
+\r
+ if(d->nc->n_identities > 0) {\r
+ if(notif == CBN_SELCHANGE) {\r
+ idx = (int) SendDlgItemMessage(hwnd, IDC_NCK5_REALM, \r
+ CB_GETCURSEL, 0, 0);\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_REALM, \r
+ CB_GETLBTEXT, idx, (LPARAM) realm);\r
+ } else {\r
+ GetDlgItemText(hwnd, IDC_NCK5_REALM, \r
+ realm, ARRAYLENGTH(realm));\r
+ }\r
+ cbsize = sizeof(idname);\r
+ if(KHM_SUCCEEDED(kcdb_identity_get_name(d->nc->identities[0], \r
+ idname, &cbsize))) {\r
+ r = wcschr(idname, L'@');\r
+ if(r && !wcscmp(realm, r+1))\r
+ return 0; /* nothing to do */\r
+\r
+ if(!r) {\r
+ r = idname + wcslen(idname);\r
+ *r++ = L'@';\r
+ *r++ = 0;\r
+ }\r
+\r
+ /* if we get here, we have a new user */\r
+ StringCchCopy(r+1, \r
+ ARRAYLENGTH(idname) - ((r+1) - idname), \r
+ realm);\r
+ if(KHM_SUCCEEDED(kcdb_identity_create(idname, \r
+ KCDB_IDENT_FLAG_CREATE, \r
+ &ident))) {\r
+ khui_cw_set_primary_id(d->nc, ident);\r
+ kcdb_identity_release(ident);\r
+ }\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ /* if we get here, we have a new realm, but there is no\r
+ identity */\r
+ PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);\r
+ }\r
+\r
+ return 0;\r
+}\r
+ \r
+\r
+/* Dialog procedure for the Krb5 credentials type panel.\r
+\r
+ NOTE: Runs in the context of the UI thread\r
+*/\r
+INT_PTR CALLBACK \r
+k5_nc_dlg_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG: \r
+ return k5_handle_wm_initdialog(hwnd, wParam, lParam);\r
+\r
+ case WM_COMMAND:\r
+ return k5_handle_wm_command(hwnd, wParam, lParam);\r
+\r
+ case KHUI_WM_NC_NOTIFY:\r
+ return k5_handle_wmnc_notify(hwnd, wParam, lParam);\r
+\r
+ case WM_DESTROY:\r
+ return k5_handle_wm_destroy(hwnd, wParam, lParam);\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/* forward dcl */\r
+krb5_error_code KRB5_CALLCONV \r
+k5_kinit_prompter(krb5_context context,\r
+ void *data,\r
+ const char *name,\r
+ const char *banner,\r
+ int num_prompts,\r
+ krb5_prompt prompts[]);\r
+\r
+\r
+\r
+fiber_job g_fjob; /* global fiber job object */\r
+\r
+static BOOL \r
+k5_cached_kinit_prompter(void);\r
+\r
+static BOOL\r
+k5_cp_check_continue(void);\r
+\r
+/*\r
+ Runs in the context of the krb5 plugin's slave fiber\r
+*/\r
+VOID CALLBACK \r
+k5_kinit_fiber_proc(PVOID lpParameter)\r
+{\r
+ while(TRUE)\r
+ {\r
+ if(g_fjob.command == FIBER_CMD_KINIT) {\r
+ g_fjob.state = FIBER_STATE_KINIT;\r
+\r
+ g_fjob.prompt_set = 0;\r
+\r
+ if (k5_cached_kinit_prompter()) {\r
+ SwitchToFiber(k5_main_fiber);\r
+\r
+ if (g_fjob.command != FIBER_CMD_CONTINUE)\r
+ goto _switch_to_main;\r
+\r
+ if (!k5_cp_check_continue()) {\r
+ goto _switch_to_main;\r
+ }\r
+ }\r
+\r
+ g_fjob.code = khm_krb5_kinit(\r
+ 0,\r
+ g_fjob.principal,\r
+ g_fjob.password,\r
+ g_fjob.ccache,\r
+ g_fjob.lifetime,\r
+ g_fjob.forwardable,\r
+ g_fjob.proxiable,\r
+ (g_fjob.renewable ? g_fjob.renew_life : 0),\r
+ g_fjob.addressless,\r
+ g_fjob.publicIP,\r
+ k5_kinit_prompter,\r
+ &g_fjob);\r
+ }\r
+\r
+ _switch_to_main:\r
+ g_fjob.state = FIBER_STATE_NONE;\r
+\r
+ SwitchToFiber(k5_main_fiber);\r
+ }\r
+}\r
+\r
+/* return TRUE if we should go ahead with creds acquisition */\r
+static BOOL\r
+k5_cp_check_continue(void) {\r
+ khm_size i;\r
+ khm_size n_p;\r
+ khui_new_creds_prompt * p;\r
+ size_t cch;\r
+\r
+#ifdef DEBUG\r
+ assert(g_fjob.nc);\r
+#endif\r
+\r
+ if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, &n_p))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ return TRUE;\r
+ }\r
+\r
+ khui_cw_sync_prompt_values(g_fjob.nc);\r
+\r
+ g_fjob.null_password = FALSE;\r
+\r
+ /* we are just checking whether there was a password field that\r
+ was left empty, in which case we can't continue with the\r
+ credentials acquisition. */\r
+ for (i=0; i < n_p; i++) {\r
+ if(KHM_FAILED(khui_cw_get_prompt(g_fjob.nc,\r
+ (int) i,\r
+ &p)))\r
+ continue;\r
+ if(p->type == KHUI_NCPROMPT_TYPE_PASSWORD) {\r
+ if (p->value == NULL ||\r
+ FAILED(StringCchLength(p->value, KHUI_MAXCCH_PROMPT,\r
+ &cch)) ||\r
+ cch == 0) {\r
+ g_fjob.null_password = TRUE;\r
+ return FALSE;\r
+ } else\r
+ break;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/* returns true if we find cached prompts */\r
+static BOOL \r
+k5_cached_kinit_prompter(void) {\r
+ BOOL rv = FALSE;\r
+ khm_handle ident;\r
+ khm_handle csp_idconfig = NULL;\r
+ khm_handle csp_k5config = NULL;\r
+ khm_handle csp_prcache = NULL;\r
+ khm_size cb;\r
+ khm_size n_cur_prompts;\r
+ khm_int32 n_prompts;\r
+ khm_int32 i;\r
+\r
+#ifdef DEBUG\r
+ assert(g_fjob.nc);\r
+#endif\r
+\r
+ ident = g_fjob.identity;\r
+ if (!ident)\r
+ return FALSE;\r
+\r
+ /* don't need to hold ident, since it is already held in g_fjob\r
+ and it doesn't change until we return */\r
+\r
+ if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_idconfig)) ||\r
+\r
+ KHM_FAILED(khc_open_space(csp_idconfig, CSNAME_KRB5CRED,\r
+ 0, &csp_k5config)) ||\r
+\r
+ KHM_FAILED(khc_open_space(csp_k5config, CSNAME_PROMPTCACHE,\r
+ 0, &csp_prcache)) ||\r
+\r
+ KHM_FAILED(khc_read_int32(csp_prcache, L"PromptCount",\r
+ &n_prompts)) ||\r
+ n_prompts == 0)\r
+\r
+ goto _cleanup;\r
+\r
+ /* check if there are any prompts currently showing. If there are\r
+ we check if they are the same as the ones we are going to show.\r
+ In which case we just reuse the exisitng prompts */\r
+ if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, \r
+ &n_cur_prompts)) ||\r
+ n_prompts != (khm_int32) n_cur_prompts)\r
+ goto _show_new_prompts;\r
+\r
+ for(i = 0; i < n_prompts; i++) {\r
+ wchar_t wsname[8];\r
+ wchar_t wprompt[KHUI_MAXCCH_PROMPT];\r
+ khm_handle csp_p = NULL;\r
+ khm_int32 p_type;\r
+ khm_int32 p_flags;\r
+ khui_new_creds_prompt * p;\r
+\r
+ if (KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, i, &p)))\r
+ break;\r
+\r
+ StringCbPrintf(wsname, sizeof(wsname), L"%d", i);\r
+\r
+ if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p)))\r
+ break;\r
+\r
+ cb = sizeof(wprompt);\r
+ if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", \r
+ wprompt, &cb))) {\r
+ khc_close_space(csp_p);\r
+ break;\r
+ }\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type)))\r
+ p_type = 0;\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags)))\r
+ p_flags = 0;\r
+\r
+ if ( /* if we received a prompt string,\r
+ then it should be the same as the\r
+ one that is displayed */\r
+ (wprompt[0] &&\r
+ (p->prompt == NULL ||\r
+ wcscmp(wprompt, p->prompt))) ||\r
+\r
+ /* if we didn't receive one, then\r
+ there shouldn't be one displayed.\r
+ This case really shouldn't happen\r
+ in reality, but we check anyway. */\r
+ (!wprompt[0] &&\r
+ p->prompt != NULL) ||\r
+\r
+ /* the type should match */\r
+ (p_type != p->type) ||\r
+\r
+ /* if this prompt should be hidden,\r
+ then it must also be so */\r
+ (p_flags != p->flags)\r
+ ) {\r
+\r
+ khc_close_space(csp_p);\r
+ break;\r
+\r
+ }\r
+ \r
+\r
+ khc_close_space(csp_p);\r
+ }\r
+\r
+ if (i == n_prompts) {\r
+ rv = TRUE;\r
+ goto _cleanup;\r
+ }\r
+\r
+ _show_new_prompts:\r
+\r
+ khui_cw_clear_prompts(g_fjob.nc);\r
+\r
+ {\r
+ wchar_t wbanner[KHUI_MAXCCH_BANNER];\r
+ wchar_t wpname[KHUI_MAXCCH_PNAME];\r
+\r
+ cb = sizeof(wbanner);\r
+ if (KHM_FAILED(khc_read_string(csp_prcache, L"Banner", \r
+ wbanner, &cb)))\r
+ wbanner[0] = 0;\r
+\r
+ cb = sizeof(wpname);\r
+ if (KHM_FAILED(khc_read_string(csp_prcache, L"Name",\r
+ wpname, &cb)))\r
+ wpname[0] = 0;\r
+\r
+ khui_cw_begin_custom_prompts(g_fjob.nc,\r
+ n_prompts,\r
+ (wbanner[0]? wbanner: NULL),\r
+ (wpname[0]? wpname: NULL));\r
+ }\r
+\r
+ for(i = 0; i < n_prompts; i++) {\r
+ wchar_t wsname[8];\r
+ wchar_t wprompt[KHUI_MAXCCH_PROMPT];\r
+ khm_handle csp_p = NULL;\r
+ khm_int32 p_type;\r
+ khm_int32 p_flags;\r
+\r
+ StringCbPrintf(wsname, sizeof(wsname), L"%d", i);\r
+\r
+ if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p)))\r
+ break;\r
+\r
+ cb = sizeof(wprompt);\r
+ if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", \r
+ wprompt, &cb))) {\r
+ khc_close_space(csp_p);\r
+ break;\r
+ }\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type)))\r
+ p_type = 0;\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags)))\r
+ p_flags = 0;\r
+\r
+ khui_cw_add_prompt(g_fjob.nc, p_type, wprompt, NULL, p_flags);\r
+\r
+ khc_close_space(csp_p);\r
+ }\r
+\r
+ if (i < n_prompts) {\r
+ khui_cw_clear_prompts(g_fjob.nc);\r
+ } else {\r
+ rv = TRUE;\r
+ }\r
+ \r
+ _cleanup:\r
+\r
+ if (csp_prcache)\r
+ khc_close_space(csp_prcache);\r
+\r
+ if (csp_k5config)\r
+ khc_close_space(csp_k5config);\r
+\r
+ if (csp_idconfig)\r
+ khc_close_space(csp_idconfig);\r
+\r
+ return rv;\r
+}\r
+\r
+/* Runs in the context of the Krb5 plugin's slave fiber */\r
+krb5_error_code KRB5_CALLCONV \r
+k5_kinit_prompter(krb5_context context,\r
+ void *data,\r
+ const char *name,\r
+ const char *banner,\r
+ int num_prompts,\r
+ krb5_prompt prompts[])\r
+{\r
+ int i;\r
+ khui_new_creds * nc;\r
+ krb5_prompt_type * ptypes;\r
+ khm_size ncp;\r
+ krb5_error_code code = 0;\r
+ BOOL new_prompts = TRUE;\r
+\r
+ khm_handle csp_prcache = NULL;\r
+\r
+ nc = g_fjob.nc;\r
+\r
+ if(pkrb5_get_prompt_types)\r
+ ptypes = pkrb5_get_prompt_types(context);\r
+ else\r
+ ptypes = NULL;\r
+\r
+ /* check if we are already showing the right prompts */\r
+ khui_cw_get_prompt_count(nc, &ncp);\r
+\r
+ if (num_prompts != (int) ncp)\r
+ goto _show_new_prompts;\r
+\r
+ for (i=0; i < num_prompts; i++) {\r
+ wchar_t wprompt[KHUI_MAXCCH_PROMPT];\r
+ khui_new_creds_prompt * p;\r
+\r
+ if(prompts[i].prompt) {\r
+ AnsiStrToUnicode(wprompt, sizeof(wprompt), \r
+ prompts[i].prompt);\r
+ } else {\r
+ wprompt[0] = 0;\r
+ }\r
+\r
+ if (KHM_FAILED(khui_cw_get_prompt(nc, i, &p)))\r
+ break;\r
+\r
+ if ( /* if we received a prompt string,\r
+ then it should be the same as the\r
+ one that is displayed */\r
+ (wprompt[0] &&\r
+ (p->prompt == NULL ||\r
+ wcscmp(wprompt, p->prompt))) ||\r
+ /* if we didn't receive one, then\r
+ there shouldn't be one displayed.\r
+ This case really shouldn't happen\r
+ in reality, but we check anyway. */\r
+ (!wprompt[0] &&\r
+ p->prompt != NULL) ||\r
+ /* the type should match */\r
+ (ptypes &&\r
+ ptypes[i] != p->type) ||\r
+ (!ptypes &&\r
+ p->type != 0) ||\r
+ /* if this prompt should be hidden,\r
+ then it must also be so */\r
+ (prompts[i].hidden &&\r
+ !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) ||\r
+ (!prompts[i].hidden &&\r
+ (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN))\r
+ )\r
+ break;\r
+ }\r
+\r
+ if (i < num_prompts)\r
+ goto _show_new_prompts;\r
+\r
+ new_prompts = FALSE;\r
+\r
+ /* ok. looks like we are already showing the same set of prompts\r
+ that we were supposed to show. Sync up the values and go\r
+ ahead. */\r
+ khui_cw_sync_prompt_values(nc);\r
+ goto _process_prompts;\r
+\r
+ _show_new_prompts:\r
+ /* special case. if there are no actual input controls involved,\r
+ then we have to show an alerter window and pass through */\r
+ if (num_prompts == 0) {\r
+ wchar_t wbanner[KHUI_MAXCCH_BANNER];\r
+ wchar_t wname[KHUI_MAXCCH_PNAME];\r
+ wchar_t wident[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t wmsg[KHUI_MAXCCH_MESSAGE];\r
+ wchar_t wfmt[KHUI_MAXCCH_BANNER];\r
+ khm_size cb;\r
+\r
+ if (!banner) {\r
+ code = 0;\r
+ g_fjob.null_password = FALSE;\r
+ goto _exit;\r
+ } else {\r
+ AnsiStrToUnicode(wbanner, sizeof(wbanner), banner);\r
+ }\r
+\r
+ if (name) {\r
+ AnsiStrToUnicode(wname, sizeof(wname), name);\r
+ } else {\r
+ LoadString(hResModule,\r
+ IDS_KRB5_WARNING,\r
+ wname,\r
+ ARRAYLENGTH(wname));\r
+ }\r
+\r
+ cb = sizeof(wident);\r
+ if (KHM_FAILED(kcdb_identity_get_name(g_fjob.identity, wident, &cb)))\r
+ wident[0] = L'\0';\r
+\r
+ LoadString(hResModule,\r
+ IDS_KRB5_WARN_FMT,\r
+ wfmt,\r
+ ARRAYLENGTH(wfmt));\r
+\r
+ StringCbPrintf(wmsg, sizeof(wmsg), wfmt, wident, wbanner);\r
+\r
+ khui_alert_show_simple(wname, wmsg, KHERR_WARNING);\r
+\r
+ code = 0;\r
+ g_fjob.null_password = FALSE;\r
+ goto _exit;\r
+ }\r
+\r
+ /* in addition to showing new prompts, we also cache the set of\r
+ prompts. */\r
+ if(g_fjob.prompt_set == 0) {\r
+ khm_handle csp_idconfig = NULL;\r
+ khm_handle csp_idk5 = NULL;\r
+\r
+ kcdb_identity_get_config(g_fjob.identity,\r
+ KHM_FLAG_CREATE,\r
+ &csp_idconfig);\r
+\r
+ if (csp_idconfig != NULL)\r
+ khc_open_space(csp_idconfig,\r
+ CSNAME_KRB5CRED,\r
+ KHM_FLAG_CREATE,\r
+ &csp_idk5);\r
+\r
+ if (csp_idk5 != NULL)\r
+ khc_open_space(csp_idk5,\r
+ CSNAME_PROMPTCACHE,\r
+ KHM_FLAG_CREATE,\r
+ &csp_prcache);\r
+\r
+ khc_close_space(csp_idconfig);\r
+ khc_close_space(csp_idk5);\r
+ }\r
+\r
+ {\r
+ wchar_t wbanner[KHUI_MAXCCH_BANNER];\r
+ wchar_t wname[KHUI_MAXCCH_PNAME];\r
+\r
+ if(banner)\r
+ AnsiStrToUnicode(wbanner, sizeof(wbanner), banner);\r
+ if(name)\r
+ AnsiStrToUnicode(wname, sizeof(wname), name);\r
+\r
+ khui_cw_clear_prompts(nc);\r
+\r
+ khui_cw_begin_custom_prompts(\r
+ nc, \r
+ num_prompts, \r
+ (banner)?wbanner:NULL,\r
+ (name)?wname:NULL);\r
+\r
+ if (banner && csp_prcache)\r
+ khc_write_string(csp_prcache,\r
+ L"Banner",\r
+ wbanner);\r
+ else if (csp_prcache)\r
+ khc_write_string(csp_prcache,\r
+ L"Banner",\r
+ L"");\r
+\r
+ if (name && csp_prcache)\r
+ khc_write_string(csp_prcache,\r
+ L"Name",\r
+ wname);\r
+ else if (csp_prcache)\r
+ khc_write_string(csp_prcache,\r
+ L"Name",\r
+ L"");\r
+\r
+ if (csp_prcache)\r
+ khc_write_int32(csp_prcache,\r
+ L"PromptCount",\r
+ (khm_int32) num_prompts);\r
+ }\r
+\r
+ for(i=0; i < num_prompts; i++) {\r
+ wchar_t wprompt[KHUI_MAXCCH_PROMPT];\r
+\r
+ if(prompts[i].prompt) {\r
+ AnsiStrToUnicode(wprompt, sizeof(wprompt), \r
+ prompts[i].prompt);\r
+ } else {\r
+ wprompt[0] = 0;\r
+ }\r
+\r
+ khui_cw_add_prompt(\r
+ nc,\r
+ (ptypes?ptypes[i]:0),\r
+ wprompt,\r
+ NULL,\r
+ (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0));\r
+\r
+ if (csp_prcache) {\r
+ khm_handle csp_p = NULL;\r
+ wchar_t wnum[8]; /* should be enough for 10\r
+ million prompts */\r
+\r
+ wnum[0] = 0;\r
+ StringCbPrintf(wnum, sizeof(wnum), L"%d", i);\r
+\r
+ khc_open_space(csp_prcache, wnum, \r
+ KHM_FLAG_CREATE, &csp_p);\r
+\r
+ if (csp_p) {\r
+ khc_write_string(csp_p, L"Prompt", wprompt);\r
+ khc_write_int32(csp_p, L"Type", (ptypes?ptypes[i]:0));\r
+ khc_write_int32(csp_p, L"Flags",\r
+ (prompts[i].hidden?\r
+ KHUI_NCPROMPT_FLAG_HIDDEN:0));\r
+\r
+ khc_close_space(csp_p);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (csp_prcache) {\r
+ khc_close_space(csp_prcache);\r
+ csp_prcache = NULL;\r
+ }\r
+\r
+ _process_prompts:\r
+ /* switch back to main thread if we showed new prompts */\r
+ if (new_prompts)\r
+ SwitchToFiber(k5_main_fiber);\r
+\r
+ /* we get here after the user selects an action that either\r
+ cancles the credentials acquisition operation or triggers the\r
+ actual acquisition of credentials. */\r
+ if(g_fjob.command != FIBER_CMD_CONTINUE &&\r
+ g_fjob.command != FIBER_CMD_KINIT) {\r
+ code = -2;\r
+ goto _exit;\r
+ }\r
+\r
+ g_fjob.null_password = FALSE;\r
+\r
+ /* otherwise, we need to get the data back from the UI and\r
+ return 0 */\r
+ for(i=0; i<num_prompts; i++) {\r
+ krb5_data * d;\r
+ wchar_t wbuf[512];\r
+ khm_size cbbuf;\r
+ size_t cch;\r
+\r
+ d = prompts[i].reply;\r
+\r
+ cbbuf = sizeof(wbuf);\r
+ if(KHM_SUCCEEDED(khui_cw_get_prompt_value(nc, i, wbuf, &cbbuf))) {\r
+ UnicodeStrToAnsi(d->data, d->length, wbuf);\r
+ if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch)))\r
+ d->length = (unsigned int) cch;\r
+ else\r
+ d->length = 0;\r
+ } else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ d->length = 0;\r
+ }\r
+\r
+ if (ptypes && \r
+ ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD &&\r
+ d->length == 0)\r
+\r
+ g_fjob.null_password = TRUE;\r
+ }\r
+\r
+ _exit:\r
+\r
+ g_fjob.prompt_set++;\r
+\r
+ /* entering a NULL password is equivalent to cancelling out */\r
+ if (g_fjob.null_password)\r
+ return -2;\r
+ else\r
+ return code;\r
+}\r
+\r
+\r
+void \r
+k5_read_dlg_params(khm_handle conf, \r
+ k5_dlg_data * d)\r
+{\r
+ khm_int32 i;\r
+\r
+ khc_read_int32(conf, L"Renewable", &d->renewable);\r
+ khc_read_int32(conf, L"Forwardable", &d->forwardable);\r
+ khc_read_int32(conf, L"Proxiable", &d->proxiable);\r
+ khc_read_int32(conf, L"Addressless", &d->addressless);\r
+\r
+ khc_read_int32(conf, L"DefaultLifetime", &i);\r
+ d->tc_lifetime.current = i;\r
+ khc_read_int32(conf, L"MaxLifetime", &i);\r
+ d->tc_lifetime.max = i;\r
+ khc_read_int32(conf, L"MinLifetime", &i);\r
+ d->tc_lifetime.min = i;\r
+\r
+ khc_read_int32(conf, L"DefaultRenewLifetime", &i);\r
+ d->tc_renew.current = i;\r
+ khc_read_int32(conf, L"MaxRenewLifetime", &i);\r
+ d->tc_renew.max = i;\r
+ khc_read_int32(conf, L"MinRenewLifetime", &i);\r
+ d->tc_renew.min = i;\r
+\r
+ /* however, if this has externally supplied defaults, we have to\r
+ use them too. */\r
+ if (d->nc && d->nc->ctx.vparam &&\r
+ d->nc->ctx.cb_vparam == sizeof(NETID_DLGINFO)) {\r
+ LPNETID_DLGINFO pdlginfo;\r
+\r
+ pdlginfo = (LPNETID_DLGINFO) d->nc->ctx.vparam;\r
+ if (pdlginfo->size == NETID_DLGINFO_V1_SZ &&\r
+ pdlginfo->in.use_defaults == 0) {\r
+ d->forwardable = pdlginfo->in.forwardable;\r
+ d->addressless = pdlginfo->in.noaddresses;\r
+ d->tc_lifetime.current = pdlginfo->in.lifetime;\r
+ d->tc_renew.current = pdlginfo->in.renew_till;\r
+\r
+ if (pdlginfo->in.renew_till == 0)\r
+ d->renewable = FALSE;\r
+ else\r
+ d->renewable = TRUE;\r
+\r
+ d->proxiable = pdlginfo->in.proxiable;\r
+ d->publicIP = pdlginfo->in.publicip;\r
+ }\r
+ }\r
+\r
+ /* once we read the new data, in, it is no longer considered\r
+ dirty */\r
+ d->dirty = FALSE;\r
+}\r
+\r
+void \r
+k5_write_dlg_params(khm_handle conf, \r
+ k5_dlg_data * d)\r
+{\r
+ khc_write_int32(conf, L"Renewable", d->renewable);\r
+ khc_write_int32(conf, L"Forwardable", d->forwardable);\r
+ khc_write_int32(conf, L"Proxiable", d->proxiable);\r
+ khc_write_int32(conf, L"Addressless", d->addressless);\r
+\r
+ khc_write_int32(conf, L"DefaultLifetime", \r
+ (khm_int32) d->tc_lifetime.current);\r
+ khc_write_int32(conf, L"MaxLifetime", \r
+ (khm_int32) d->tc_lifetime.max);\r
+ khc_write_int32(conf, L"MinLifetime", \r
+ (khm_int32) d->tc_lifetime.min);\r
+\r
+ khc_write_int32(conf, L"DefaultRenewLifetime", \r
+ (khm_int32) d->tc_renew.current);\r
+ khc_write_int32(conf, L"MaxRenewLifetime", \r
+ (khm_int32) d->tc_renew.max);\r
+ khc_write_int32(conf, L"MinRenewLifetime", \r
+ (khm_int32) d->tc_renew.min);\r
+\r
+ /* as in k5_read_dlg_params, once we write the data in, the local\r
+ data is no longer dirty */\r
+ d->dirty = FALSE;\r
+}\r
+\r
+void \r
+k5_prep_kinit_job(khui_new_creds * nc)\r
+{\r
+ khui_new_creds_by_type * nct;\r
+ k5_dlg_data * d;\r
+ wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_size cbbuf;\r
+ size_t size;\r
+ khm_handle ident;\r
+ LPNETID_DLGINFO pdlginfo;\r
+\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+ if (!nct)\r
+ return;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(nct->hwnd_panel, DWLP_USER);\r
+\r
+ khui_cw_lock_nc(nc);\r
+ ident = nc->identities[0];\r
+ kcdb_identity_hold(ident);\r
+ khui_cw_unlock_nc(nc);\r
+\r
+ cbbuf = sizeof(idname);\r
+ kcdb_identity_get_name(ident, idname, &cbbuf);\r
+ StringCchLength(idname, ARRAYLENGTH(idname), &size);\r
+ size++;\r
+ \r
+ ZeroMemory(&g_fjob, sizeof(g_fjob));\r
+ g_fjob.command = FIBER_CMD_KINIT;\r
+ g_fjob.nc = nc;\r
+ g_fjob.nct = nct;\r
+ g_fjob.dialog = nct->hwnd_panel;\r
+ g_fjob.principal = malloc(size);\r
+ UnicodeStrToAnsi(g_fjob.principal, size, idname);\r
+ g_fjob.password = NULL;\r
+ g_fjob.lifetime = (krb5_deltat) d->tc_lifetime.current;\r
+ g_fjob.forwardable = d->forwardable;\r
+ g_fjob.proxiable = d->proxiable;\r
+ g_fjob.renewable = d->renewable;\r
+ g_fjob.renew_life = (krb5_deltat) d->tc_renew.current;\r
+ g_fjob.addressless = d->addressless;\r
+ g_fjob.publicIP = 0;\r
+ g_fjob.code = 0;\r
+ g_fjob.identity = ident;\r
+ g_fjob.prompt_set = 0;\r
+\r
+ /* if we have external parameters, we should use them as well */\r
+ if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) &&\r
+ (pdlginfo = nc->ctx.vparam) &&\r
+ pdlginfo->size == NETID_DLGINFO_V1_SZ) {\r
+ wchar_t * t;\r
+\r
+ if (pdlginfo->in.ccache[0] &&\r
+ SUCCEEDED(StringCchLength(pdlginfo->in.ccache,\r
+ NETID_CCACHE_NAME_SZ,\r
+ &size))) {\r
+ g_fjob.ccache = malloc(sizeof(char) * (size + 1));\r
+#ifdef DEBUG\r
+ assert(g_fjob.ccache);\r
+#endif\r
+ UnicodeStrToAnsi(g_fjob.ccache, size + 1,\r
+ pdlginfo->in.ccache);\r
+\r
+ /* this is the same as the output cache */\r
+\r
+ StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache),\r
+ pdlginfo->in.ccache);\r
+ } else {\r
+ g_fjob.ccache = NULL;\r
+\r
+ StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache),\r
+ idname);\r
+\r
+ khm_krb5_canon_cc_name(pdlginfo->out.ccache,\r
+ sizeof(pdlginfo->out.ccache));\r
+ }\r
+\r
+ t = khm_get_realm_from_princ(idname);\r
+\r
+ if (t) {\r
+ StringCbCopy(pdlginfo->out.realm,\r
+ sizeof(pdlginfo->out.realm),\r
+ t);\r
+\r
+ if ((t - idname) > 1) {\r
+ StringCchCopyN(pdlginfo->out.username,\r
+ ARRAYLENGTH(pdlginfo->out.username),\r
+ idname,\r
+ (t - idname) - 1);\r
+ } else {\r
+ StringCbCopy(pdlginfo->out.username,\r
+ sizeof(pdlginfo->out.username),\r
+ L"");\r
+ }\r
+ } else {\r
+ StringCbCopy(pdlginfo->out.username,\r
+ sizeof(pdlginfo->out.username),\r
+ idname);\r
+ StringCbCopy(pdlginfo->out.realm,\r
+ sizeof(pdlginfo->out.realm),\r
+ L"");\r
+ }\r
+ }\r
+\r
+ /* leave identity held, since we added a reference above */\r
+}\r
+\r
+void \r
+k5_free_kinit_job(void)\r
+{\r
+ if (g_fjob.principal)\r
+ free(g_fjob.principal);\r
+\r
+ if (g_fjob.password)\r
+ free(g_fjob.password);\r
+\r
+ if (g_fjob.identity)\r
+ kcdb_identity_release(g_fjob.identity);\r
+\r
+ if (g_fjob.ccache)\r
+ free(g_fjob.ccache);\r
+\r
+ ZeroMemory(&g_fjob, sizeof(g_fjob));\r
+}\r
+\r
+static khm_int32 KHMAPI \r
+k5_find_tgt_filter(khm_handle cred,\r
+ khm_int32 flags,\r
+ void * rock) {\r
+ khm_handle ident = (khm_handle) rock;\r
+ khm_handle cident = NULL;\r
+ khm_int32 f;\r
+ khm_int32 rv;\r
+\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred,\r
+ &cident)) &&\r
+ cident == ident &&\r
+ KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) &&\r
+ (f & KCDB_CRED_FLAG_INITIAL))\r
+ rv = 1;\r
+ else\r
+ rv = 0;\r
+\r
+ if (cident)\r
+ kcdb_identity_release(cident);\r
+\r
+ return rv;\r
+}\r
+\r
+/* Handler for CRED type messages\r
+\r
+ Runs in the context of the Krb5 plugin\r
+*/\r
+khm_int32 KHMAPI \r
+k5_msg_cred_dialog(khm_int32 msg_type, \r
+ khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ switch(msg_subtype) {\r
+\r
+ case KMSG_CRED_PASSWORD:\r
+ case KMSG_CRED_NEW_CREDS:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ wchar_t wbuf[256];\r
+ size_t cbsize;\r
+\r
+ nc = (khui_new_creds *) vparam;\r
+\r
+ nct = malloc(sizeof(*nct));\r
+ ZeroMemory(nct, sizeof(*nct));\r
+\r
+ nct->type = credtype_id_krb5;\r
+ nct->ordinal = 1;\r
+\r
+ LoadString(hResModule, IDS_KRB5_SHORT_DESC, \r
+ wbuf, ARRAYLENGTH(wbuf));\r
+ StringCbLength(wbuf, sizeof(wbuf), &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+\r
+ nct->name = malloc(cbsize);\r
+ StringCbCopy(nct->name, cbsize, wbuf);\r
+\r
+ nct->h_module = hResModule;\r
+ nct->dlg_proc = k5_nc_dlg_proc;\r
+ if (nc->subtype == KMSG_CRED_PASSWORD)\r
+ nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5_PASSWORD);\r
+ else\r
+ nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5);\r
+\r
+ khui_cw_add_type(nc, nct);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_RENEW_CREDS:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+\r
+ nc = (khui_new_creds *) vparam;\r
+\r
+ nct = malloc(sizeof(*nct));\r
+ ZeroMemory(nct, sizeof(*nct));\r
+\r
+ nct->type = credtype_id_krb5;\r
+\r
+ khui_cw_add_type(nc, nct);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_DIALOG_PRESTART:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ k5_dlg_data * d;\r
+ HWND hwnd;\r
+ wchar_t * realms;\r
+ wchar_t * t;\r
+ wchar_t * defrealm;\r
+\r
+ nc = (khui_new_creds *) vparam;\r
+\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+\r
+ if(!nct)\r
+ break;\r
+\r
+ hwnd = nct->hwnd_panel;\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(nct->hwnd_panel, DWLP_USER);\r
+\r
+ if (!is_k5_identpro) {\r
+\r
+ /* enumerate all realms and place in realms combo box */\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_REALM, \r
+ CB_RESETCONTENT, \r
+ 0, 0);\r
+\r
+ realms = khm_krb5_get_realm_list();\r
+ if(realms) {\r
+ t = realms;\r
+ while(t && *t) {\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_REALM, \r
+ CB_ADDSTRING,\r
+ 0, (LPARAM) t);\r
+ t = multi_string_next(t);\r
+ }\r
+ free(realms);\r
+ }\r
+\r
+ /* and set the default realm */\r
+ defrealm = khm_krb5_get_default_realm();\r
+ if(defrealm) {\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_REALM,\r
+ CB_SELECTSTRING,\r
+ (WPARAM) -1,\r
+ (LPARAM) defrealm);\r
+\r
+ SendDlgItemMessage(hwnd, IDC_NCK5_REALM, \r
+ WM_SETTEXT, \r
+ 0, (LPARAM) defrealm);\r
+ free(defrealm);\r
+ }\r
+ } else { /* if krb5 is the identity provider */\r
+ HWND hw_realms;\r
+\r
+ /* in this case, the realm selection is done by the\r
+ identity provider prompts. */\r
+\r
+ hw_realms = GetDlgItem(hwnd, IDC_NCK5_REALM);\r
+#ifdef DEBUG\r
+ assert(hw_realms);\r
+#endif\r
+ EnableWindow(hw_realms, FALSE);\r
+ }\r
+\r
+ if (nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ k5_read_dlg_params(csp_params, d);\r
+ }\r
+\r
+ PostMessage(hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);\r
+ }\r
+ break;\r
+ \r
+ case KMSG_CRED_DIALOG_NEW_IDENTITY:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ k5_dlg_data * d;\r
+ \r
+ nc = (khui_new_creds *) vparam;\r
+\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+ if (!nct)\r
+ break;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(nct->hwnd_panel, DWLP_USER);\r
+\r
+ /* we only load the identity specific defaults if the user\r
+ hasn't changed the options */\r
+ khui_cw_lock_nc(nc);\r
+\r
+ if(!d->dirty && nc->n_identities > 0 &&\r
+ nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+\r
+ khm_handle h_id = NULL;\r
+ khm_handle h_idk5 = NULL;\r
+\r
+ do {\r
+ if(KHM_FAILED\r
+ (kcdb_identity_get_config(nc->identities[0],\r
+ 0,\r
+ &h_id)))\r
+ break;\r
+\r
+ if(KHM_FAILED\r
+ (khc_open_space(h_id, CSNAME_KRB5CRED, \r
+ 0, &h_idk5)))\r
+ break;\r
+\r
+ if(KHM_FAILED(khc_shadow_space(h_idk5, csp_params)))\r
+ break;\r
+\r
+ k5_read_dlg_params(h_idk5, d);\r
+\r
+ PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);\r
+ } while(FALSE);\r
+\r
+ if(h_id)\r
+ khc_close_space(h_id);\r
+ if(h_idk5)\r
+ khc_close_space(h_idk5);\r
+ }\r
+\r
+ khui_cw_unlock_nc(nc);\r
+ }\r
+\r
+ /* fallthrough */\r
+ case KMSG_CRED_DIALOG_NEW_OPTIONS:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ k5_dlg_data * d;\r
+\r
+ nc = (khui_new_creds *) vparam;\r
+\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+ if (!nct)\r
+ break;\r
+\r
+ d = (k5_dlg_data *)(LONG_PTR) \r
+ GetWindowLongPtr(nct->hwnd_panel, DWLP_USER);\r
+\r
+ if (nc->subtype == KMSG_CRED_PASSWORD) {\r
+ khm_size n_prompts = 0;\r
+\r
+ khui_cw_get_prompt_count(nc, &n_prompts);\r
+\r
+ if (nc->n_identities == 0) {\r
+ if (n_prompts)\r
+ khui_cw_clear_prompts(nc);\r
+ } else if (n_prompts != 3) {\r
+ wchar_t wbuf[KHUI_MAXCCH_BANNER];\r
+\r
+ khui_cw_clear_prompts(nc);\r
+\r
+ LoadString(hResModule, IDS_NC_PWD_BANNER,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+ khui_cw_begin_custom_prompts(nc, 3, NULL, wbuf);\r
+\r
+ LoadString(hResModule, IDS_NC_PWD_PWD,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+ khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_PASSWORD, \r
+ wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN);\r
+\r
+ LoadString(hResModule, IDS_NC_PWD_NPWD,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+ khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD,\r
+ wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN);\r
+\r
+ LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+ khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN,\r
+ wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+ /* else; nc->subtype == KMSG_CRED_NEW_CREDS */\r
+\r
+ assert(nc->subtype == KMSG_CRED_NEW_CREDS);\r
+\r
+ /* if the fiber is already in a kinit, cancel it */\r
+ if(g_fjob.state == FIBER_STATE_KINIT) {\r
+ g_fjob.command = FIBER_CMD_CANCEL;\r
+ SwitchToFiber(k5_kinit_fiber);\r
+ /* we get here when the cancel operation completes */\r
+ k5_free_kinit_job();\r
+ }\r
+\r
+ khui_cw_lock_nc(nc);\r
+\r
+ if(nc->n_identities > 0) {\r
+ khm_handle ident = nc->identities[0];\r
+\r
+ kcdb_identity_hold(ident);\r
+\r
+ k5_prep_kinit_job(nc);\r
+ khui_cw_unlock_nc(nc);\r
+\r
+ SwitchToFiber(k5_kinit_fiber);\r
+ /* we get here when the fiber switches back */\r
+ if(g_fjob.state == FIBER_STATE_NONE) {\r
+ wchar_t msg[KHUI_MAXCCH_BANNER];\r
+ khm_size cb;\r
+\r
+ /* we can't possibly have succeeded without a\r
+ password */\r
+ if(g_fjob.code) {\r
+ if (is_k5_identpro)\r
+ kcdb_identity_set_flags(ident, \r
+ KCDB_IDENT_FLAG_INVALID);\r
+\r
+ khui_cw_clear_prompts(nc);\r
+ }\r
+\r
+ if (d->cred_message) {\r
+ free(d->cred_message);\r
+ d->cred_message = NULL;\r
+ }\r
+\r
+ msg[0] = L'\0';\r
+\r
+ switch(g_fjob.code) {\r
+ case KRB5KDC_ERR_NAME_EXP:\r
+ /* principal expired */\r
+ LoadString(hResModule, IDS_K5ERR_NAME_EXPIRED,\r
+ msg, ARRAYLENGTH(msg));\r
+ break;\r
+\r
+ case KRB5KDC_ERR_KEY_EXP:\r
+ /* password needs changing */\r
+ LoadString(hResModule, IDS_K5ERR_KEY_EXPIRED,\r
+ msg, ARRAYLENGTH(msg));\r
+ break;\r
+\r
+ default:\r
+ {\r
+ DWORD dw_dummy;\r
+ kherr_suggestion sug_dummy;\r
+ wchar_t fmt[KHUI_MAXCCH_BANNER];\r
+ wchar_t desc[KHUI_MAXCCH_BANNER];\r
+\r
+ LoadString(hResModule, IDS_K5ERR_FMT,\r
+ fmt, ARRAYLENGTH(fmt));\r
+\r
+ khm_err_describe(g_fjob.code,\r
+ desc,\r
+ sizeof(desc),\r
+ &dw_dummy,\r
+ &sug_dummy);\r
+\r
+ StringCbPrintf(msg, sizeof(msg), fmt, desc);\r
+ }\r
+ }\r
+\r
+ if (msg[0]) {\r
+ StringCbLength(msg, sizeof(msg), &cb);\r
+ cb += sizeof(wchar_t);\r
+\r
+ d->cred_message = malloc(cb);\r
+ StringCbCopy(d->cred_message, cb, msg);\r
+ }\r
+\r
+ k5_free_kinit_job();\r
+\r
+ } else if(g_fjob.state == FIBER_STATE_KINIT) {\r
+ /* this is what we want. Leave the fiber there. */\r
+\r
+ if(is_k5_identpro)\r
+ kcdb_identity_set_flags(ident, \r
+ KCDB_IDENT_FLAG_VALID);\r
+ } else {\r
+ /* huh?? */\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+\r
+ /* since the attributes of the identity have changed,\r
+ we should update the cred text as well */\r
+ kcdb_identity_release(ident);\r
+ khui_cw_lock_nc(nc);\r
+ PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);\r
+ } else {\r
+ khui_cw_unlock_nc(nc);\r
+ khui_cw_clear_prompts(nc);\r
+ khui_cw_lock_nc(nc);\r
+ }\r
+\r
+ khui_cw_unlock_nc(nc);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_PROCESS:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ k5_dlg_data * d;\r
+\r
+ khm_int32 r;\r
+\r
+ nc = (khui_new_creds *) vparam;\r
+\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+\r
+ if(!nct)\r
+ break;\r
+\r
+ /* reset the null_password flag, just in case */\r
+ g_fjob.null_password = FALSE;\r
+\r
+ if (nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ d = (k5_dlg_data *) nct->aux;\r
+\r
+ _begin_task(0);\r
+ _report_mr0(KHERR_NONE, MSG_CTX_INITAL_CREDS);\r
+ _describe();\r
+\r
+ if (g_fjob.state == FIBER_STATE_KINIT) {\r
+ if(nc->result == KHUI_NC_RESULT_CANCEL) {\r
+ g_fjob.command = FIBER_CMD_CANCEL;\r
+ SwitchToFiber(k5_kinit_fiber);\r
+\r
+ /* if we cancelled out, then we shouldn't care\r
+ about the return code. */\r
+#ifdef DEBUG\r
+ assert(g_fjob.state == FIBER_STATE_NONE);\r
+#endif\r
+ g_fjob.code = 0;\r
+ } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) {\r
+ khui_cw_sync_prompt_values(nc);\r
+ g_fjob.command = FIBER_CMD_CONTINUE;\r
+ SwitchToFiber(k5_kinit_fiber);\r
+\r
+ /* We get back here once the fiber finishes\r
+ processing */\r
+ }\r
+#ifdef DEBUG\r
+ else {\r
+ assert(FALSE);\r
+ }\r
+#endif\r
+ } else {\r
+ /* we weren't in a KINIT state */\r
+ if (nc->result == KHUI_NC_RESULT_CANCEL) {\r
+ /* nothing to report */\r
+ g_fjob.code = 0;\r
+ } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) {\r
+ /* g_fjob.code should have the result of the\r
+ last kinit attempt. We should leave it\r
+ as-is */\r
+ }\r
+#ifdef DEBUG\r
+ else {\r
+ /* unknown result */\r
+ assert(FALSE);\r
+ }\r
+#endif\r
+ }\r
+\r
+ /* special case: if there was no password entered, and\r
+ if there is a valid TGT we allow the credential\r
+ acquisition to go through */\r
+ if (g_fjob.state == FIBER_STATE_NONE &&\r
+ g_fjob.code &&\r
+ g_fjob.null_password &&\r
+\r
+ (nc->n_identities == 0 ||\r
+ nc->identities[0] == NULL ||\r
+ KHM_SUCCEEDED(kcdb_credset_find_filtered\r
+ (NULL,\r
+ -1,\r
+ k5_find_tgt_filter,\r
+ nc->identities[0],\r
+ NULL,\r
+ NULL))))\r
+ g_fjob.code = 0;\r
+\r
+\r
+ if(g_fjob.code != 0) {\r
+ wchar_t tbuf[1024];\r
+ DWORD suggestion;\r
+ kherr_suggestion suggest_code;\r
+\r
+ khm_err_describe(g_fjob.code, tbuf, sizeof(tbuf),\r
+ &suggestion, &suggest_code);\r
+\r
+ _report_cs0(KHERR_ERROR, tbuf);\r
+ if (suggestion != 0)\r
+ _suggest_mr(suggestion, suggest_code);\r
+\r
+ _resolve();\r
+\r
+ r = KHUI_NC_RESPONSE_FAILED;\r
+\r
+ if (suggest_code == KHERR_SUGGEST_RETRY) {\r
+ r |= KHUI_NC_RESPONSE_NOEXIT |\r
+ KHUI_NC_RESPONSE_PENDING;\r
+ }\r
+\r
+#ifdef DEBUG\r
+ assert(g_fjob.state == FIBER_STATE_NONE);\r
+#endif\r
+\r
+ } else if (nc->result == KHUI_NC_RESULT_GET_CREDS &&\r
+ g_fjob.state == FIBER_STATE_NONE) {\r
+ khm_handle sp = NULL;\r
+ khm_handle ep = NULL;\r
+ krb5_context ctx = NULL;\r
+ wchar_t * wbuf;\r
+ wchar_t * idname;\r
+ wchar_t * atsign;\r
+ khm_size cb;\r
+ khm_size cb_ms;\r
+ khm_int32 rv;\r
+\r
+ r = KHUI_NC_RESPONSE_SUCCESS |\r
+ KHUI_NC_RESPONSE_EXIT;\r
+\r
+ /* if we successfully obtained credentials, we\r
+ should save the current settings in the\r
+ identity config space */\r
+\r
+ assert(nc->n_identities > 0);\r
+ assert(nc->identities[0]);\r
+\r
+ if(KHM_SUCCEEDED\r
+ (kcdb_identity_get_config(nc->identities[0],\r
+ KHM_FLAG_CREATE,\r
+ &sp)) &&\r
+ KHM_SUCCEEDED\r
+ (khc_open_space(sp, CSNAME_KRB5CRED, \r
+ KHM_FLAG_CREATE, &ep))) {\r
+ k5_write_dlg_params(ep, d);\r
+ }\r
+\r
+ if(ep != NULL)\r
+ khc_close_space(ep);\r
+ if(sp != NULL)\r
+ khc_close_space(sp);\r
+\r
+ /* We should also quickly refresh the credentials\r
+ so that the identity flags and ccache\r
+ properties reflect the current state of\r
+ affairs. This has to be done here so that\r
+ other credentials providers which depend on\r
+ Krb5 can properly find the initial creds to\r
+ obtain their respective creds. */\r
+\r
+ khm_krb5_list_tickets(&ctx);\r
+\r
+ /* also add the principal and the realm in to the\r
+ LRU lists */\r
+ rv = kcdb_identity_get_name(nc->identities[0],\r
+ NULL,\r
+ &cb);\r
+ assert(rv == KHM_ERROR_TOO_LONG);\r
+\r
+ idname = malloc(cb);\r
+ assert(idname);\r
+\r
+ rv = kcdb_identity_get_name(nc->identities[0],\r
+ idname,\r
+ &cb);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRUPrincipals",\r
+ NULL,\r
+ &cb_ms);\r
+ if (rv != KHM_ERROR_TOO_LONG)\r
+ cb_ms = cb + sizeof(wchar_t);\r
+ else\r
+ cb_ms += cb + sizeof(wchar_t);\r
+\r
+ wbuf = malloc(cb_ms);\r
+ assert(wbuf);\r
+\r
+ cb = cb_ms;\r
+\r
+ if (rv == KHM_ERROR_TOO_LONG) {\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRUPrincipals",\r
+ wbuf,\r
+ &cb);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ if (multi_string_find(wbuf,\r
+ idname,\r
+ KHM_CASE_SENSITIVE) \r
+ != NULL)\r
+ /* it's already there */\r
+ goto _add_realm_to_LRU;\r
+ } else {\r
+ multi_string_init(wbuf, cb_ms);\r
+ }\r
+\r
+ cb = cb_ms;\r
+ rv = multi_string_prepend(wbuf, &cb, idname);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_multi_string(csp_params,\r
+ L"LRUPrincipals",\r
+ wbuf);\r
+\r
+ _add_realm_to_LRU:\r
+\r
+ atsign = wcschr(idname, L'@');\r
+ assert(atsign != NULL);\r
+\r
+ atsign++;\r
+ assert(*atsign != L'\0');\r
+\r
+ cb = cb_ms;\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRURealms",\r
+ wbuf,\r
+ &cb);\r
+\r
+ if (rv == KHM_ERROR_TOO_LONG) {\r
+ free(wbuf);\r
+ wbuf = malloc(cb);\r
+ assert(wbuf);\r
+\r
+ cb_ms = cb;\r
+\r
+ rv = khc_read_multi_string(csp_params,\r
+ L"LRURealms",\r
+ wbuf,\r
+ &cb);\r
+\r
+ assert(KHM_SUCCEEDED(rv));\r
+ } else if (rv == KHM_ERROR_SUCCESS) {\r
+ if (multi_string_find(wbuf,\r
+ atsign,\r
+ KHM_CASE_SENSITIVE)\r
+ != NULL)\r
+ goto _done_with_LRU;\r
+ } else {\r
+ multi_string_init(wbuf, cb_ms);\r
+ }\r
+\r
+ cb = cb_ms;\r
+ rv = multi_string_prepend(wbuf,\r
+ &cb,\r
+ atsign);\r
+\r
+ if (rv == KHM_ERROR_TOO_LONG) {\r
+ wbuf = realloc(wbuf, cb);\r
+\r
+ rv = multi_string_prepend(wbuf,\r
+ &cb,\r
+ atsign);\r
+\r
+ assert(KHM_SUCCEEDED(rv));\r
+ }\r
+\r
+ rv = khc_write_multi_string(csp_params,\r
+ L"LRURealms",\r
+ wbuf);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ _done_with_LRU:\r
+ \r
+ if (ctx != NULL)\r
+ pkrb5_free_context(ctx);\r
+\r
+ if (idname)\r
+ free(idname);\r
+\r
+ if (wbuf)\r
+ free(wbuf);\r
+ } else if (g_fjob.state == FIBER_STATE_NONE) {\r
+ /* the user cancelled the operation */\r
+ r = KHUI_NC_RESPONSE_EXIT | \r
+ KHUI_NC_RESPONSE_SUCCESS;\r
+ }\r
+\r
+ if(g_fjob.state == FIBER_STATE_NONE) {\r
+ khui_cw_set_response(nc, credtype_id_krb5, r);\r
+\r
+ if (r & KHUI_NC_RESPONSE_NOEXIT) {\r
+ /* if we are retrying the call, we should\r
+ restart the kinit fiber */\r
+#ifdef DEBUG\r
+ assert(r & KHUI_NC_RESPONSE_PENDING);\r
+#endif\r
+\r
+ k5_prep_kinit_job(nc);\r
+ SwitchToFiber(k5_kinit_fiber);\r
+ } else {\r
+ /* free up the fiber data fields. */\r
+ k5_free_kinit_job();\r
+ }\r
+ } else {\r
+ khui_cw_set_response(nc, credtype_id_krb5,\r
+ KHUI_NC_RESPONSE_NOEXIT | \r
+ KHUI_NC_RESPONSE_PENDING | r);\r
+ }\r
+\r
+ _end_task();\r
+ } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) {\r
+\r
+ _begin_task(0);\r
+ _report_mr0(KHERR_NONE, MSG_CTX_RENEW_CREDS);\r
+ _describe();\r
+\r
+ if (nc->ctx.scope == KHUI_SCOPE_IDENT ||\r
+ (nc->ctx.scope == KHUI_SCOPE_CREDTYPE &&\r
+ nc->ctx.cred_type == credtype_id_krb5)) {\r
+ int code;\r
+\r
+ if (nc->ctx.identity != 0)\r
+ code = khm_krb5_renew(nc->ctx.identity);\r
+ else\r
+ code = 1; /* it just has to be non-zero */\r
+\r
+ if (code == 0) {\r
+ khui_cw_set_response(nc, credtype_id_krb5, \r
+ KHUI_NC_RESPONSE_EXIT | \r
+ KHUI_NC_RESPONSE_SUCCESS);\r
+ } else if (nc->ctx.identity == 0) {\r
+\r
+ _report_mr0(KHERR_ERROR, MSG_ERR_NO_IDENTITY);\r
+\r
+ khui_cw_set_response(nc, credtype_id_krb5, \r
+ KHUI_NC_RESPONSE_EXIT | \r
+ KHUI_NC_RESPONSE_FAILED);\r
+ } else {\r
+ wchar_t tbuf[1024];\r
+ DWORD suggestion;\r
+ kherr_suggestion sug_id;\r
+\r
+ khm_err_describe(code, tbuf, sizeof(tbuf),\r
+ &suggestion, &sug_id);\r
+\r
+ _report_cs0(KHERR_ERROR, tbuf);\r
+ if (suggestion)\r
+ _suggest_mr(suggestion, sug_id);\r
+\r
+ _resolve();\r
+\r
+ khui_cw_set_response(nc, credtype_id_krb5, \r
+ ((sug_id == KHERR_SUGGEST_RETRY)?KHUI_NC_RESPONSE_NOEXIT:KHUI_NC_RESPONSE_EXIT) |\r
+ KHUI_NC_RESPONSE_FAILED);\r
+ }\r
+ } else {\r
+ khui_cw_set_response(nc, credtype_id_krb5, \r
+ KHUI_NC_RESPONSE_EXIT | \r
+ KHUI_NC_RESPONSE_SUCCESS);\r
+ }\r
+\r
+ _end_task();\r
+ } else if (nc->subtype == KMSG_CRED_PASSWORD &&\r
+ nc->result == KHUI_NC_RESULT_GET_CREDS) {\r
+\r
+ _begin_task(0);\r
+ _report_mr0(KHERR_NONE, MSG_CTX_PASSWD);\r
+ _describe();\r
+\r
+ khui_cw_lock_nc(nc);\r
+\r
+ if (nc->n_identities == 0 ||\r
+ nc->identities[0] == NULL) {\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_NO_IDENTITY);\r
+ _suggest_mr(MSG_PWD_S_NO_IDENTITY, KHERR_SUGGEST_RETRY);\r
+\r
+ khui_cw_set_response(nc, credtype_id_krb5,\r
+ KHUI_NC_RESPONSE_FAILED |\r
+ KHUI_NC_RESPONSE_NOEXIT);\r
+ } else {\r
+ wchar_t widname[KCDB_IDENT_MAXCCH_NAME];\r
+ char idname[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t wpwd[KHUI_MAXCCH_PASSWORD];\r
+ char pwd[KHUI_MAXCCH_PASSWORD];\r
+ wchar_t wnpwd[KHUI_MAXCCH_PASSWORD];\r
+ char npwd[KHUI_MAXCCH_PASSWORD];\r
+ wchar_t wnpwd2[KHUI_MAXCCH_PASSWORD];\r
+ wchar_t * wresult;\r
+ char * result;\r
+ khm_size n_prompts = 0;\r
+ khm_size cb;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ long code = 0;\r
+ khm_handle ident;\r
+\r
+ khui_cw_get_prompt_count(nc, &n_prompts);\r
+ assert(n_prompts == 3);\r
+\r
+ ident = nc->identities[0];\r
+ cb = sizeof(widname);\r
+ rv = kcdb_identity_get_name(ident, widname, &cb);\r
+ if (KHM_FAILED(rv)) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN);\r
+ goto _pwd_exit;\r
+ }\r
+\r
+ cb = sizeof(wpwd);\r
+ rv = khui_cw_get_prompt_value(nc, 0, wpwd, &cb);\r
+ if (KHM_FAILED(rv)) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN);\r
+ goto _pwd_exit;\r
+ }\r
+\r
+ cb = sizeof(wnpwd);\r
+ rv = khui_cw_get_prompt_value(nc, 1, wnpwd, &cb);\r
+ if (KHM_FAILED(rv)) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN);\r
+ goto _pwd_exit;\r
+ }\r
+\r
+ cb = sizeof(wnpwd2);\r
+ rv = khui_cw_get_prompt_value(nc, 2, wnpwd2, &cb);\r
+ if (KHM_FAILED(rv)) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN);\r
+ goto _pwd_exit;\r
+ }\r
+\r
+ if (wcscmp(wnpwd, wnpwd2)) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_NOT_SAME);\r
+ _suggest_mr(MSG_PWD_S_NOT_SAME, KHERR_SUGGEST_INTERACT);\r
+ goto _pwd_exit;\r
+ }\r
+\r
+ if (!wcscmp(wpwd, wnpwd)) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ _report_mr0(KHERR_ERROR, MSG_PWD_SAME);\r
+ _suggest_mr(MSG_PWD_S_SAME, KHERR_SUGGEST_INTERACT);\r
+ goto _pwd_exit;\r
+ }\r
+\r
+ UnicodeStrToAnsi(idname, sizeof(idname), widname);\r
+ UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd);\r
+ UnicodeStrToAnsi(npwd, sizeof(npwd), wnpwd);\r
+\r
+ result = NULL;\r
+\r
+ code = khm_krb5_changepwd(idname,\r
+ pwd,\r
+ npwd,\r
+ &result);\r
+\r
+ if (code)\r
+ rv = KHM_ERROR_UNKNOWN;\r
+\r
+ /* result is only set when code != 0 */\r
+ if (code && result) {\r
+ size_t len;\r
+\r
+ StringCchLengthA(result, KHERR_MAXCCH_STRING,\r
+ &len);\r
+ wresult = malloc((len + 1) * sizeof(wchar_t));\r
+#ifdef DEBUG\r
+ assert(wresult);\r
+#endif\r
+ AnsiStrToUnicode(wresult, (len + 1) * sizeof(wchar_t),\r
+ result);\r
+\r
+ _report_cs1(KHERR_ERROR, L"%1!s!", _cstr(wresult));\r
+ _resolve();\r
+\r
+ free(result);\r
+ free(wresult);\r
+\r
+ /* leave wresult. It will get freed when the\r
+ reported event is freed. */\r
+\r
+ /* we don't need to report anything more */\r
+ code = 0;\r
+ }\r
+\r
+ _pwd_exit:\r
+ if (KHM_FAILED(rv)) {\r
+ if (code) {\r
+ wchar_t tbuf[1024];\r
+ DWORD suggestion;\r
+ kherr_suggestion sug_id;\r
+\r
+ khm_err_describe(code, tbuf, sizeof(tbuf),\r
+ &suggestion, &sug_id);\r
+ _report_cs0(KHERR_ERROR, tbuf);\r
+\r
+ if (suggestion)\r
+ _suggest_mr(suggestion, sug_id);\r
+\r
+ _resolve();\r
+ }\r
+\r
+ khui_cw_set_response(nc, credtype_id_krb5, \r
+ KHUI_NC_RESPONSE_NOEXIT|\r
+ KHUI_NC_RESPONSE_FAILED);\r
+ } else {\r
+ khui_cw_set_response(nc, credtype_id_krb5,\r
+ KHUI_NC_RESPONSE_SUCCESS |\r
+ KHUI_NC_RESPONSE_EXIT);\r
+ }\r
+ }\r
+\r
+ khui_cw_unlock_nc(nc);\r
+\r
+ _end_task();\r
+ } /* KMSG_CRED_PASSWORD */\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_END:\r
+ {\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+\r
+ nc = (khui_new_creds *) vparam;\r
+ khui_cw_find_type(nc, credtype_id_krb5, &nct);\r
+\r
+ if(!nct)\r
+ break;\r
+\r
+ khui_cw_del_type(nc, credtype_id_krb5);\r
+ \r
+ if(nct->name)\r
+ free(nct->name);\r
+\r
+ free(nct);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_IMPORT:\r
+ {\r
+ khm_krb5_ms2mit(TRUE);\r
+ }\r
+ break;\r
+ }\r
+\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<commctrl.h>\r
+#include<strsafe.h>\r
+#include<krb5.h>\r
+\r
+khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID;\r
+khm_boolean krb5_initialized = FALSE;\r
+khm_handle krb5_credset = NULL;\r
+\r
+khm_handle k5_sub = NULL;\r
+\r
+LPVOID k5_main_fiber = NULL;\r
+LPVOID k5_kinit_fiber = NULL;\r
+\r
+VOID CALLBACK k5_kinit_fiber_proc(PVOID lpParameter);\r
+\r
+krb5_context k5_identpro_ctx = NULL;\r
+\r
+/* The system message handler.\r
+\r
+ Runs in the context of the plugin thread */\r
+khm_int32 KHMAPI k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ switch(msg_subtype) {\r
+ case KMSG_SYSTEM_INIT:\r
+ {\r
+ kcdb_credtype ct;\r
+ wchar_t buf[KCDB_MAXCCH_SHORT_DESC];\r
+ size_t cbsize;\r
+\r
+ /* perform critical registrations and initialization\r
+ stuff */\r
+ ZeroMemory(&ct, sizeof(ct));\r
+ ct.id = KCDB_CREDTYPE_AUTO;\r
+ ct.name = KRB5_CREDTYPE_NAME;\r
+\r
+ if(LoadString(hResModule, IDS_KRB5_SHORT_DESC, buf, ARRAYLENGTH(buf)))\r
+ {\r
+ StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+ ct.short_desc = malloc(cbsize);\r
+ StringCbCopy(ct.short_desc, cbsize, buf);\r
+ }\r
+\r
+ /* even though ideally we should be setting limits\r
+ based KCDB_MAXCB_LONG_DESC, our long description\r
+ actually fits nicely in KCDB_MAXCB_SHORT_DESC */\r
+ if(LoadString(hResModule, IDS_KRB5_LONG_DESC, buf, ARRAYLENGTH(buf)))\r
+ {\r
+ StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize);\r
+ cbsize += sizeof(wchar_t);\r
+ ct.long_desc = malloc(cbsize);\r
+ StringCbCopy(ct.long_desc, cbsize, buf);\r
+ }\r
+\r
+ ct.icon = NULL; /* TODO: set a proper icon */\r
+\r
+ kmq_create_subscription(k5_msg_callback, &ct.sub);\r
+\r
+ rv = kcdb_credtype_register(&ct, &credtype_id_krb5);\r
+\r
+ if(KHM_SUCCEEDED(rv))\r
+ rv = kcdb_credset_create(&krb5_credset);\r
+\r
+ if(ct.short_desc)\r
+ free(ct.short_desc);\r
+\r
+ if(ct.long_desc)\r
+ free(ct.long_desc);\r
+\r
+ if (is_k5_identpro)\r
+ kcdb_identity_set_type(credtype_id_krb5);\r
+\r
+ if(KHM_SUCCEEDED(rv)) {\r
+ krb5_context ctx = NULL;\r
+\r
+ krb5_initialized = TRUE;\r
+\r
+ khm_krb5_list_tickets(&ctx);\r
+\r
+ if(ctx != NULL)\r
+ pkrb5_free_context(ctx);\r
+\r
+ /* now convert this thread to a fiber and create a\r
+ separate fiber to do kinit stuff */\r
+ k5_main_fiber = ConvertThreadToFiber(NULL);\r
+ k5_kinit_fiber = CreateFiber(0,k5_kinit_fiber_proc,NULL);\r
+\r
+ ZeroMemory(&g_fjob, sizeof(g_fjob));\r
+\r
+ kmq_create_subscription(k5_msg_callback, &k5_sub);\r
+\r
+ pkrb5_init_context(&k5_identpro_ctx);\r
+\r
+ k5_register_config_panels();\r
+ }\r
+ }\r
+ break;\r
+\r
+ case KMSG_SYSTEM_EXIT:\r
+\r
+ k5_unregister_config_panels();\r
+\r
+ if(credtype_id_krb5 >= 0)\r
+ {\r
+ /* basically just unregister the credential type */\r
+ kcdb_credtype_unregister(credtype_id_krb5);\r
+\r
+ /* kcdb knows how to deal with bad handles */\r
+ kcdb_credset_delete(krb5_credset);\r
+ krb5_credset = NULL;\r
+ }\r
+\r
+ if(k5_main_fiber != NULL) {\r
+ ConvertFiberToThread();\r
+ k5_main_fiber = NULL;\r
+ }\r
+\r
+ if(k5_sub != NULL) {\r
+ kmq_delete_subscription(k5_sub);\r
+ k5_sub = NULL;\r
+ }\r
+\r
+ if (k5_identpro_ctx) {\r
+ pkrb5_free_context(k5_identpro_ctx);\r
+ k5_identpro_ctx = NULL;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+/* Handler for CRED type messages\r
+\r
+ Runs in the context of the Krb5 plugin\r
+*/\r
+khm_int32 KHMAPI k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ switch(msg_subtype) {\r
+ case KMSG_CRED_REFRESH:\r
+ {\r
+ krb5_context ctx = NULL;\r
+\r
+ khm_krb5_list_tickets(&ctx);\r
+\r
+ if(ctx != NULL)\r
+ pkrb5_free_context(ctx);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_DESTROY_CREDS:\r
+ {\r
+ khui_action_context * ctx;\r
+\r
+ ctx = (khui_action_context *) vparam;\r
+ \r
+ if (ctx->credset)\r
+ khm_krb5_destroy_by_credset(ctx->credset);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_PP_BEGIN:\r
+ k5_pp_begin((khui_property_sheet *) vparam);\r
+ break;\r
+\r
+ case KMSG_CRED_PP_END:\r
+ k5_pp_end((khui_property_sheet *) vparam);\r
+ break;\r
+\r
+ default:\r
+ if(IS_CRED_ACQ_MSG(msg_subtype))\r
+ return k5_msg_cred_dialog(msg_type, msg_subtype, \r
+ uparam, vparam);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+/* The main message handler. We don't do much here, except delegate\r
+ to other message handlers\r
+\r
+ Runs in the context of the Krb5 plugin\r
+*/\r
+khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam)\r
+{\r
+ switch(msg_type) {\r
+ case KMSG_SYSTEM:\r
+ return k5_msg_system(msg_type, msg_subtype, uparam, vparam);\r
+ case KMSG_CRED:\r
+ return k5_msg_cred(msg_type, msg_subtype, uparam, vparam);\r
+ case KMSG_IDENT:\r
+ return k5_msg_ident(msg_type, msg_subtype, uparam, vparam);\r
+ }\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+#include<khmsgtypes.h>\r
+#include<commctrl.h>\r
+#include<strsafe.h>\r
+#include<krb5.h>\r
+\r
+/* Property page\r
+\r
+ Runs in the context of the UI thread.\r
+ */\r
+INT_PTR CALLBACK krb5_pp_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ ) \r
+{\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ khui_property_sheet * s;\r
+ PROPSHEETPAGE * p;\r
+ wchar_t buf[512];\r
+ khm_size cbsize;\r
+\r
+ p = (PROPSHEETPAGE *) lParam;\r
+ s = (khui_property_sheet *) p->lParam;\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s);\r
+#pragma warning(pop)\r
+\r
+ if(s->cred) {\r
+ cbsize = sizeof(buf);\r
+ kcdb_cred_get_name(s->cred, buf, &cbsize);\r
+ SetDlgItemText(hwnd, IDC_PPK5_NAME, buf);\r
+\r
+ cbsize = sizeof(buf);\r
+ kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_ISSUE, buf, &cbsize, 0);\r
+ SetDlgItemText(hwnd, IDC_PPK5_ISSUE, buf);\r
+\r
+ cbsize = sizeof(buf);\r
+ kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_EXPIRE, buf, &cbsize, 0);\r
+ SetDlgItemText(hwnd, IDC_PPK5_VALID, buf);\r
+\r
+ cbsize = sizeof(buf);\r
+ kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_RENEW_EXPIRE, buf, &cbsize, 0);\r
+ SetDlgItemText(hwnd, IDC_PPK5_RENEW, buf);\r
+\r
+ /*TODO: select other properties */\r
+ } else {\r
+ /*TODO: select properties */\r
+ }\r
+ }\r
+ return FALSE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+void k5_pp_begin(khui_property_sheet * s)\r
+{\r
+ PROPSHEETPAGE *p;\r
+\r
+ if(s->credtype == credtype_id_krb5) {\r
+ p = malloc(sizeof(*p));\r
+ ZeroMemory(p, sizeof(*p));\r
+\r
+ p->dwSize = sizeof(*p);\r
+ p->dwFlags = 0;\r
+ p->hInstance = hResModule;\r
+ p->pszTemplate = (s->cred)? MAKEINTRESOURCE(IDD_PP_KRB5C): MAKEINTRESOURCE(IDD_PP_KRB5);\r
+ p->pfnDlgProc = krb5_pp_proc;\r
+ p->lParam = (LPARAM) s;\r
+ khui_ps_add_page(s, credtype_id_krb5, 0, p, NULL);\r
+ }\r
+}\r
+\r
+void k5_pp_end(khui_property_sheet * s)\r
+{\r
+ khui_property_page * p = NULL;\r
+\r
+ khui_ps_find_page(s, credtype_id_krb5, &p);\r
+ if(p) {\r
+ if(p->p_page)\r
+ free(p->p_page);\r
+ p->p_page = NULL;\r
+ }\r
+}\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include <windows.h>\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include <winsock.h>\r
+#include "leashdll.h"\r
+#include <KerberosIV/krb.h>\r
+#include <prot.h>\r
+#include <time.h>\r
+\r
+#include <leashwin.h>\r
+#include "leasherr.h"\r
+#include "leash-int.h"\r
+#include "leashids.h"\r
+\r
+#include <mitwhich.h>\r
+\r
+#include <winkrbid.h>\r
+#include "reminder.h"\r
+\r
+static char FAR *err_context;\r
+\r
+char KRB_HelpFile[_MAX_PATH] = HELPFILE;\r
+\r
+#define LEN 64 /* Maximum Hostname Length */\r
+\r
+#define LIFE DEFAULT_TKT_LIFE /* lifetime of ticket in 5-minute units */\r
+\r
+char *\r
+short_date(dp)\r
+ long *dp;\r
+{\r
+ register char *cp;\r
+ cp = ctime(dp) + 4; // skip day of week\r
+ // cp[15] = '\0';\r
+ cp[12] = '\0'; // Don't display seconds\r
+ return (cp);\r
+}\r
+\r
+\r
+static\r
+char*\r
+clean_string(\r
+ char* s\r
+ )\r
+{\r
+ char* p = s;\r
+ char* b = s;\r
+\r
+ if (!s) return s;\r
+\r
+ for (p = s; *p; p++) {\r
+ switch (*p) {\r
+ case '\007':\r
+ /* Add more cases here */\r
+ break;\r
+ default:\r
+ *b = *p;\r
+ b++;\r
+ }\r
+ }\r
+ *b = *p;\r
+ return s;\r
+}\r
+\r
+static\r
+int\r
+leash_error_message(\r
+ const char *error,\r
+ int rcL,\r
+ int rc4,\r
+ int rc5,\r
+ int rcA,\r
+ char* result_string,\r
+ int displayMB\r
+ )\r
+{\r
+ char message[2048];\r
+ char *p = message;\r
+ int size = sizeof(message);\r
+ int n;\r
+\r
+ // XXX: ignore AFS for now.\r
+\r
+ if (!rc5 && !rc4 && !rcL)\r
+ return 0;\r
+\r
+ n = _snprintf(p, size, "%s\n\n", error);\r
+ p += n;\r
+ size -= n;\r
+\r
+ if (rc5 && !result_string)\r
+ {\r
+ n = _snprintf(p, size,\r
+ "Kerberos 5: %s (error %ld)\n",\r
+ perror_message(rc5),\r
+ rc5 & 255 // XXX: & 255??!!!\r
+ );\r
+ p += n;\r
+ size -= n;\r
+ }\r
+ if (rc4 && !result_string)\r
+ {\r
+ char buffer[1024];\r
+ n = _snprintf(p, size,\r
+ "Kerberos 4: %s\n",\r
+ err_describe(buffer, rc4)\r
+ );\r
+ p += n;\r
+ size -= n;\r
+ }\r
+ if (rcL)\r
+ {\r
+ char buffer[1024];\r
+ n = _snprintf(p, size,\r
+ "\n%s\n",\r
+ err_describe(buffer, rcL)\r
+ );\r
+ p += n;\r
+ size -= n;\r
+ }\r
+ if (result_string)\r
+ {\r
+ n = _snprintf(p, size,\r
+ "%s\n",\r
+ result_string);\r
+ p += n;\r
+ size -= n;\r
+ }\r
+ if ( displayMB )\r
+ MessageBox(NULL, message, "Leash", MB_OK | MB_ICONERROR | MB_TASKMODAL | \r
+ MB_SETFOREGROUND);\r
+\r
+ if (rc5) return rc5;\r
+ if (rc4) return rc4;\r
+ if (rcL) return rcL;\r
+ return 0;\r
+}\r
+\r
+\r
+static\r
+char *\r
+make_postfix(\r
+ const char * base,\r
+ const char * postfix,\r
+ char ** rcopy\r
+ )\r
+{\r
+ int base_size;\r
+ int ret_size;\r
+ char * copy = 0;\r
+ char * ret = 0;\r
+\r
+ base_size = strlen(base) + 1;\r
+ ret_size = base_size + strlen(postfix) + 1;\r
+ copy = malloc(base_size);\r
+ ret = malloc(ret_size);\r
+\r
+ if (!copy || !ret)\r
+ goto cleanup;\r
+\r
+ strncpy(copy, base, base_size);\r
+ copy[base_size - 1] = 0;\r
+\r
+ strncpy(ret, base, base_size);\r
+ strncpy(ret + (base_size - 1), postfix, ret_size - (base_size - 1));\r
+ ret[ret_size - 1] = 0;\r
+\r
+ cleanup:\r
+ if (!copy || !ret) {\r
+ if (copy)\r
+ free(copy);\r
+ if (ret)\r
+ free(ret);\r
+ copy = ret = 0;\r
+ }\r
+ // INVARIANT: (ret ==> copy) && (copy ==> ret)\r
+ *rcopy = copy;\r
+ return ret;\r
+}\r
+\r
+static\r
+long\r
+make_temp_cache_v4(\r
+ const char * postfix\r
+ )\r
+{\r
+ static char * old_cache = 0;\r
+\r
+ if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt)\r
+ return 0; // XXX - is this appropriate?\r
+\r
+ if (old_cache) {\r
+ pdest_tkt();\r
+ pkrb_set_tkt_string(old_cache);\r
+ free(old_cache);\r
+ old_cache = 0;\r
+ }\r
+\r
+ if (postfix)\r
+ {\r
+ char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache);\r
+\r
+ if (!tmp_cache)\r
+ return KFAILURE;\r
+\r
+ pkrb_set_tkt_string(tmp_cache);\r
+ free(tmp_cache);\r
+ }\r
+ return 0;\r
+}\r
+\r
+static\r
+long\r
+make_temp_cache_v5(\r
+ const char * postfix,\r
+ krb5_context * pctx\r
+ )\r
+{\r
+ static krb5_context ctx = 0;\r
+ static char * old_cache = 0;\r
+\r
+ // INVARIANT: old_cache ==> ctx && ctx ==> old_cache\r
+\r
+ if (pctx)\r
+ *pctx = 0;\r
+\r
+ if (!pkrb5_init_context || !pkrb5_free_context || !pkrb5_cc_resolve ||\r
+ !pkrb5_cc_default_name || !pkrb5_cc_set_default_name)\r
+ return 0;\r
+\r
+ if (old_cache) {\r
+ krb5_ccache cc = 0;\r
+ if (!pkrb5_cc_resolve(ctx, pkrb5_cc_default_name(ctx), &cc))\r
+ pkrb5_cc_destroy(ctx, cc);\r
+ pkrb5_cc_set_default_name(ctx, old_cache);\r
+ free(old_cache);\r
+ old_cache = 0;\r
+ }\r
+ if (ctx) {\r
+ pkrb5_free_context(ctx);\r
+ ctx = 0;\r
+ }\r
+\r
+ if (postfix)\r
+ {\r
+ char * tmp_cache = 0;\r
+ krb5_error_code rc = 0;\r
+\r
+ rc = pkrb5_init_context(&ctx);\r
+ if (rc) goto cleanup;\r
+\r
+ tmp_cache = make_postfix(pkrb5_cc_default_name(ctx), postfix, \r
+ &old_cache);\r
+\r
+ if (!tmp_cache) {\r
+ rc = ENOMEM;\r
+ goto cleanup;\r
+ }\r
+\r
+ rc = pkrb5_cc_set_default_name(ctx, tmp_cache);\r
+\r
+ cleanup:\r
+ if (rc && ctx) {\r
+ pkrb5_free_context(ctx);\r
+ ctx = 0;\r
+ }\r
+ if (tmp_cache)\r
+ free(tmp_cache);\r
+ if (pctx)\r
+ *pctx = ctx;\r
+ return rc;\r
+ }\r
+ return 0;\r
+}\r
+\r
+long\r
+Leash_checkpwd(\r
+ char *principal, \r
+ char *password\r
+ )\r
+{\r
+ return Leash_int_checkpwd(principal, password, 0);\r
+}\r
+\r
+long \r
+Leash_int_checkpwd(\r
+ char * principal,\r
+ char * password,\r
+ int displayErrors\r
+ )\r
+{\r
+ long rc = 0;\r
+ krb5_context ctx = 0; // statically allocated in make_temp_cache_v5\r
+ // XXX - we ignore errors in make_temp_cache_v? This is BAD!!!\r
+ make_temp_cache_v4("_checkpwd");\r
+ make_temp_cache_v5("_checkpwd", &ctx);\r
+ rc = Leash_int_kinit_ex( ctx, 0,\r
+ principal, password, 0, 0, 0, 0,\r
+ Leash_get_default_noaddresses(),\r
+ Leash_get_default_publicip(),\r
+ displayErrors\r
+ );\r
+ make_temp_cache_v4(0);\r
+ make_temp_cache_v5(0, &ctx);\r
+ return rc;\r
+}\r
+\r
+static\r
+long\r
+Leash_changepwd_v5(char * principal,\r
+ char * password,\r
+ char * newpassword,\r
+ char** error_str)\r
+{\r
+ krb5_error_code rc = 0;\r
+ int result_code;\r
+ krb5_data result_code_string, result_string;\r
+ krb5_context context = 0;\r
+ krb5_principal princ = 0;\r
+ krb5_get_init_creds_opt opts;\r
+ krb5_creds creds;\r
+ DWORD addressless = 0;\r
+\r
+ result_string.data = 0;\r
+ result_code_string.data = 0;\r
+\r
+ if ( !pkrb5_init_context )\r
+ goto cleanup;\r
+\r
+ if (rc = pkrb5_init_context(&context)) {\r
+#if 0\r
+ com_err(argv[0], ret, "initializing kerberos library");\r
+#endif\r
+ goto cleanup;\r
+ }\r
+\r
+ if (rc = pkrb5_parse_name(context, principal, &princ)) {\r
+#if 0\r
+ com_err(argv[0], ret, "parsing client name");\r
+#endif\r
+ goto cleanup;\r
+ }\r
+\r
+ pkrb5_get_init_creds_opt_init(&opts);\r
+ pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);\r
+ pkrb5_get_init_creds_opt_set_renew_life(&opts, 0);\r
+ pkrb5_get_init_creds_opt_set_forwardable(&opts, 0);\r
+ pkrb5_get_init_creds_opt_set_proxiable(&opts, 0);\r
+\r
+ addressless = Leash_get_default_noaddresses();\r
+ if (addressless)\r
+ pkrb5_get_init_creds_opt_set_address_list(&opts,NULL);\r
+\r
+\r
+ if (rc = pkrb5_get_init_creds_password(context, &creds, princ, password,\r
+ 0, 0, 0, "kadmin/changepw", &opts)) {\r
+ if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) {\r
+#if 0\r
+ com_err(argv[0], 0,\r
+ "Password incorrect while getting initial ticket");\r
+#endif\r
+ }\r
+ else {\r
+#if 0\r
+ com_err(argv[0], ret, "getting initial ticket");\r
+#endif\r
+ }\r
+ goto cleanup;\r
+ }\r
+\r
+ if (rc = pkrb5_change_password(context, &creds, newpassword,\r
+ &result_code, &result_code_string,\r
+ &result_string)) {\r
+#if 0\r
+ com_err(argv[0], ret, "changing password");\r
+#endif\r
+ goto cleanup;\r
+ }\r
+\r
+ if (result_code) {\r
+ int len = result_code_string.length + \r
+ (result_string.length ? (sizeof(": ") - 1) : 0) +\r
+ result_string.length;\r
+ if (len && error_str) {\r
+ *error_str = malloc(len + 1);\r
+ if (*error_str)\r
+ _snprintf(*error_str, len + 1,\r
+ "%.*s%s%.*s",\r
+ result_code_string.length, result_code_string.data,\r
+ result_string.length?": ":"",\r
+ result_string.length, result_string.data);\r
+ }\r
+ rc = result_code;\r
+ goto cleanup;\r
+ }\r
+\r
+ cleanup:\r
+ if (result_string.data)\r
+ pkrb5_free_data_contents(context, &result_string);\r
+\r
+ if (result_code_string.data)\r
+ pkrb5_free_data_contents(context, &result_code_string);\r
+\r
+ if (princ)\r
+ pkrb5_free_principal(context, princ);\r
+\r
+ if (context)\r
+ pkrb5_free_context(context);\r
+\r
+ return rc;\r
+}\r
+\r
+static\r
+long\r
+Leash_changepwd_v4(\r
+ char * principal,\r
+ char * password,\r
+ char * newpassword,\r
+ char** error_str\r
+ )\r
+{\r
+ long k_errno;\r
+\r
+ if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password ||\r
+ !pdest_tkt)\r
+ return KFAILURE;\r
+\r
+ k_errno = make_temp_cache_v4("_chgpwd");\r
+ if (k_errno) return k_errno;\r
+ k_errno = pkadm_change_your_password(principal, password, newpassword, \r
+ error_str);\r
+ make_temp_cache_v4(0);\r
+ return k_errno;\r
+}\r
+\r
+/*\r
+ * Leash_changepwd\r
+ *\r
+ * Try to change the password using one of krb5 or krb4 -- whichever one\r
+ * works. We return ok on the first one that works.\r
+ */\r
+long\r
+Leash_changepwd(\r
+ char * principal, \r
+ char * password, \r
+ char * newpassword,\r
+ char** result_string\r
+ )\r
+{\r
+ return Leash_int_changepwd(principal, password, newpassword, result_string, 0);\r
+}\r
+\r
+long\r
+Leash_int_changepwd(\r
+ char * principal, \r
+ char * password, \r
+ char * newpassword,\r
+ char** result_string,\r
+ int displayErrors\r
+ )\r
+{\r
+ char* v5_error_str = 0;\r
+ char* v4_error_str = 0;\r
+ char* error_str = 0;\r
+ int rc4 = 0;\r
+ int rc5 = 0;\r
+ int rc = 0;\r
+ if (hKrb5)\r
+ rc = rc5 = Leash_changepwd_v5(principal, password, newpassword,\r
+ &v5_error_str);\r
+ if (hKrb4 && \r
+ Leash_get_default_use_krb4() &&\r
+ (!hKrb5 || rc5))\r
+ rc = rc4 = Leash_changepwd_v4(principal, password, newpassword, \r
+ &v4_error_str);\r
+ if (!rc)\r
+ return 0;\r
+ if (v5_error_str || v4_error_str) {\r
+ int len = 0;\r
+ char v5_prefix[] = "Kerberos 5: ";\r
+ char sep[] = "\n";\r
+ char v4_prefix[] = "Kerberos 4: ";\r
+\r
+ clean_string(v5_error_str);\r
+ clean_string(v4_error_str);\r
+\r
+ if (v5_error_str)\r
+ len += sizeof(sep) + sizeof(v5_prefix) + strlen(v5_error_str) + \r
+ sizeof(sep);\r
+ if (v4_error_str)\r
+ len += sizeof(sep) + sizeof(v4_prefix) + strlen(v4_error_str) + \r
+ sizeof(sep);\r
+ error_str = malloc(len + 1);\r
+ if (error_str) {\r
+ char* p = error_str;\r
+ int size = len + 1;\r
+ int n;\r
+ if (v5_error_str) {\r
+ n = _snprintf(p, size, "%s%s%s%s",\r
+ sep, v5_prefix, v5_error_str, sep);\r
+ p += n;\r
+ size -= n;\r
+ }\r
+ if (v4_error_str) {\r
+ n = _snprintf(p, size, "%s%s%s%s",\r
+ sep, v4_prefix, v4_error_str, sep);\r
+ p += n;\r
+ size -= n;\r
+ }\r
+ if (result_string)\r
+ *result_string = error_str;\r
+ }\r
+ }\r
+ return leash_error_message("Error while changing password.", \r
+ rc4, rc4, rc5, 0, error_str, \r
+ displayErrors\r
+ );\r
+}\r
+\r
+int (*Lcom_err)(LPSTR,long,LPSTR,...);\r
+LPSTR (*Lerror_message)(long);\r
+LPSTR (*Lerror_table_name)(long);\r
+\r
+\r
+long\r
+Leash_kinit(\r
+ char * principal,\r
+ char * password,\r
+ int lifetime\r
+ )\r
+{\r
+ return Leash_int_kinit_ex( 0, 0,\r
+ principal, \r
+ password, \r
+ lifetime,\r
+ Leash_get_default_forwardable(),\r
+ Leash_get_default_proxiable(),\r
+ Leash_get_default_renew_till(),\r
+ Leash_get_default_noaddresses(),\r
+ Leash_get_default_publicip(),\r
+ 0\r
+ );\r
+}\r
+\r
+long\r
+Leash_kinit_ex(\r
+ char * principal, \r
+ char * password, \r
+ int lifetime,\r
+ int forwardable,\r
+ int proxiable,\r
+ int renew_life,\r
+ int addressless,\r
+ unsigned long publicip\r
+ )\r
+{\r
+ return Leash_int_kinit_ex( 0, /* krb5 context */\r
+ 0, /* parent window */\r
+ principal, \r
+ password, \r
+ lifetime,\r
+ forwardable,\r
+ proxiable,\r
+ renew_life,\r
+ addressless,\r
+ publicip,\r
+ 0\r
+ );\r
+}\r
+\r
+long\r
+Leash_int_kinit_ex(\r
+ krb5_context ctx,\r
+ HWND hParent,\r
+ char * principal, \r
+ char * password, \r
+ int lifetime,\r
+ int forwardable,\r
+ int proxiable,\r
+ int renew_life,\r
+ int addressless,\r
+ unsigned long publicip,\r
+ int displayErrors\r
+ )\r
+{\r
+ LPCSTR functionName; \r
+ char aname[ANAME_SZ];\r
+ char inst[INST_SZ];\r
+ char realm[REALM_SZ];\r
+ char first_part[256];\r
+ char second_part[256];\r
+ char temp[1024];\r
+ int count;\r
+ int i;\r
+ int rc4 = 0;\r
+ int rc5 = 0;\r
+ int rcA = 0;\r
+ int rcL = 0;\r
+\r
+ if (lifetime < 5)\r
+ lifetime = 1;\r
+ else\r
+ lifetime /= 5;\r
+\r
+ if (renew_life > 0 && renew_life < 5)\r
+ renew_life = 1;\r
+ else\r
+ renew_life /= 5;\r
+\r
+ /* This should be changed if the maximum ticket lifetime */\r
+ /* changes */\r
+\r
+ if (lifetime > 255)\r
+ lifetime = 255;\r
+\r
+ err_context = "parsing principal";\r
+\r
+ memset(temp, '\0', sizeof(temp));\r
+ memset(inst, '\0', sizeof(inst));\r
+ memset(realm, '\0', sizeof(realm));\r
+ memset(first_part, '\0', sizeof(first_part));\r
+ memset(second_part, '\0', sizeof(second_part));\r
+\r
+ sscanf(principal, "%[/0-9a-zA-Z._-]@%[/0-9a-zA-Z._-]", first_part, second_part);\r
+ strcpy(temp, first_part);\r
+ strcpy(realm, second_part);\r
+ memset(first_part, '\0', sizeof(first_part));\r
+ memset(second_part, '\0', sizeof(second_part));\r
+ if (sscanf(temp, "%[@0-9a-zA-Z._-]/%[@0-9a-zA-Z._-]", first_part, second_part) == 2)\r
+ {\r
+ strcpy(aname, first_part);\r
+ strcpy(inst, second_part);\r
+ }\r
+ else\r
+ {\r
+ count = 0;\r
+ i = 0;\r
+ for (i = 0; temp[i]; i++)\r
+ {\r
+ if (temp[i] == '.')\r
+ ++count;\r
+ }\r
+ if (count > 1)\r
+ {\r
+ strcpy(aname, temp);\r
+ }\r
+ else\r
+ {\r
+ if (pkname_parse != NULL)\r
+ {\r
+ memset(first_part, '\0', sizeof(first_part));\r
+ memset(second_part, '\0', sizeof(second_part));\r
+ sscanf(temp, "%[@/0-9a-zA-Z_-].%[@/0-9a-zA-Z_-]", first_part, second_part);\r
+ strcpy(aname, first_part);\r
+ strcpy(inst, second_part);\r
+ }\r
+ else\r
+ {\r
+ strcpy(aname, temp);\r
+ }\r
+ }\r
+ }\r
+\r
+ memset(temp, '\0', sizeof(temp));\r
+ strcpy(temp, aname);\r
+ if (strlen(inst) != 0)\r
+ {\r
+ strcat(temp, "/");\r
+ strcat(temp, inst);\r
+ }\r
+ if (strlen(realm) != 0)\r
+ {\r
+ strcat(temp, "@");\r
+ strcat(temp, realm);\r
+ }\r
+\r
+ rc5 = Leash_krb5_kinit(ctx, hParent, \r
+ temp, password, lifetime,\r
+ forwardable,\r
+ proxiable,\r
+ renew_life,\r
+ addressless,\r
+ publicip\r
+ );\r
+ if ( Leash_get_default_use_krb4() ) {\r
+ if ( !rc5 ) {\r
+ if (!Leash_convert524(ctx))\r
+ rc4 = KFAILURE;\r
+ } else {\r
+ if (pkname_parse == NULL)\r
+ {\r
+ goto cleanup;\r
+ }\r
+\r
+ err_context = "getting realm";\r
+ if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) \r
+ {\r
+ functionName = "krb_get_lrealm()";\r
+ rcL = LSH_FAILEDREALM;\r
+ goto cleanup;\r
+ }\r
+\r
+ err_context = "checking principal";\r
+ if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname))))\r
+ {\r
+ functionName = "krb_get_lrealm()";\r
+ rcL = LSH_INVPRINCIPAL;\r
+ goto cleanup;\r
+ }\r
+\r
+ /* optional instance */\r
+ if (!(rc4 = (int)(*pk_isinst)(inst)))\r
+ {\r
+ functionName = "k_isinst()";\r
+ rcL = LSH_INVINSTANCE;\r
+ goto cleanup;\r
+ }\r
+\r
+ if (!(rc4 = (int)(*pk_isrealm)(realm)))\r
+ {\r
+ functionName = "k_isrealm()";\r
+ rcL = LSH_INVREALM;\r
+ goto cleanup;\r
+ }\r
+\r
+ err_context = "fetching ticket"; \r
+ rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, \r
+ lifetime, password);\r
+ if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */\r
+ { \r
+ functionName = "krb_get_pw_in_tkt()";\r
+ rcL = KRBERR(rc4);\r
+ goto cleanup;\r
+ }\r
+ }\r
+ }\r
+\r
+#ifndef NO_AFS\r
+ if ( !rc5 || (Leash_get_default_use_krb4() && !rc4) ) {\r
+ char c;\r
+ char *r;\r
+ char *t;\r
+ for ( r=realm, t=temp; c=*r; r++,t++ )\r
+ *t = isupper(c) ? tolower(c) : c;\r
+ *t = '\0';\r
+\r
+ rcA = Leash_afs_klog("afs", temp, realm, lifetime);\r
+ if (rcA)\r
+ rcA = Leash_afs_klog("afs", "", realm, lifetime);\r
+ }\r
+#endif /* NO_AFS */\r
+\r
+ cleanup:\r
+ return leash_error_message("Ticket initialization failed.", \r
+ rcL, (rc5 && rc4)?KRBERR(rc4):0, rc5, rcA, 0,\r
+ displayErrors);\r
+}\r
+\r
+long FAR\r
+Leash_renew(void)\r
+{\r
+ if ( hKrb5 && !LeashKRB5_renew() ) {\r
+ int lifetime;\r
+ lifetime = Leash_get_default_lifetime() / 5;\r
+ if (hKrb4 && Leash_get_default_use_krb4())\r
+ Leash_convert524(0);\r
+#ifndef NO_AFS\r
+ {\r
+ TicketList * list = NULL, * token;\r
+ afs_get_tokens(NULL,&list,NULL);\r
+ for ( token = list ; token ; token = token->next )\r
+ Leash_afs_klog("afs", token->realm, "", lifetime);\r
+ not_an_API_LeashFreeTicketList(&list);\r
+ }\r
+#endif /* NO_AFS */\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static BOOL\r
+GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)\r
+{\r
+ NTSTATUS Status = 0;\r
+ HANDLE TokenHandle;\r
+ TOKEN_STATISTICS Stats;\r
+ DWORD ReqLen;\r
+ BOOL Success;\r
+\r
+ if (!ppSessionData || !pLsaGetLogonSessionData)\r
+ return FALSE;\r
+ *ppSessionData = NULL;\r
+\r
+ Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );\r
+ if ( !Success )\r
+ return FALSE;\r
+\r
+ Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );\r
+ CloseHandle( TokenHandle );\r
+ if ( !Success )\r
+ return FALSE;\r
+\r
+ Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );\r
+ if ( FAILED(Status) || !ppSessionData )\r
+ return FALSE;\r
+\r
+ return TRUE;\r
+}\r
+\r
+// IsKerberosLogon() does not validate whether or not there are valid tickets in the \r
+// cache. It validates whether or not it is reasonable to assume that if we \r
+// attempted to retrieve valid tickets we could do so. Microsoft does not \r
+// automatically renew expired tickets. Therefore, the cache could contain\r
+// expired or invalid tickets. Microsoft also caches the user's password \r
+// and will use it to retrieve new TGTs if the cache is empty and tickets\r
+// are requested.\r
+\r
+static BOOL\r
+IsKerberosLogon(VOID)\r
+{\r
+ PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;\r
+ BOOL Success = FALSE;\r
+\r
+ if ( GetSecurityLogonSessionData(&pSessionData) ) {\r
+ if ( pSessionData->AuthenticationPackage.Buffer ) {\r
+ WCHAR buffer[256];\r
+ WCHAR *usBuffer;\r
+ int usLength;\r
+\r
+ Success = FALSE;\r
+ usBuffer = (pSessionData->AuthenticationPackage).Buffer;\r
+ usLength = (pSessionData->AuthenticationPackage).Length;\r
+ if (usLength < 256)\r
+ {\r
+ lstrcpyn (buffer, usBuffer, usLength);\r
+ lstrcat (buffer,L"");\r
+ if ( !lstrcmp(L"Kerberos",buffer) )\r
+ Success = TRUE;\r
+ }\r
+ }\r
+ pLsaFreeReturnBuffer(pSessionData);\r
+ }\r
+ return Success;\r
+}\r
+\r
+\r
+// This looks really ugly because it is. The result of IsKerberosLogon()\r
+// does not prove whether or not there are Kerberos tickets available to \r
+// be imported. Only the call to khm_krb5_ms2mit() which actually attempts\r
+// to import tickets can do that. However, calling khm_krb5_ms2mit() can\r
+// result in a TGS_REQ being sent to the KDC and since Leash_importable()\r
+// is called quite often we want to avoid this if at all possible.\r
+// Unfortunately, we have be shown at least one case in which the primary\r
+// authentication package was not Kerberos and yet there were Kerberos \r
+// tickets available. Therefore, if IsKerberosLogon() is not TRUE we \r
+// must call khm_krb5_ms2mit() but we still do not want to call it in a \r
+// tight loop so we cache the response and assume it won't change.\r
+long FAR\r
+Leash_importable(void)\r
+{\r
+ if ( IsKerberosLogon() )\r
+ return TRUE;\r
+ else {\r
+ static int response = -1;\r
+ if (response == -1) {\r
+ response = khm_krb5_ms2mit(0);\r
+ }\r
+ return response;\r
+ }\r
+}\r
+\r
+long FAR\r
+Leash_import(void)\r
+{\r
+ if ( khm_krb5_ms2mit(1) ) {\r
+ int lifetime;\r
+ lifetime = Leash_get_default_lifetime() / 5;\r
+ if (hKrb4 && Leash_get_default_use_krb4())\r
+ Leash_convert524(0);\r
+#ifndef NO_AFS\r
+ {\r
+ char c;\r
+ char *r;\r
+ char *t;\r
+ char cell[256];\r
+ char realm[256];\r
+ int i = 0;\r
+ int rcA = 0;\r
+\r
+ krb5_context ctx = 0;\r
+ krb5_error_code code = 0;\r
+ krb5_ccache cc = 0;\r
+ krb5_principal me = 0;\r
+\r
+ if ( !pkrb5_init_context )\r
+ goto cleanup;\r
+\r
+ code = pkrb5_init_context(&ctx);\r
+ if (code) goto cleanup;\r
+\r
+ code = pkrb5_cc_default(ctx, &cc);\r
+ if (code) goto cleanup;\r
+\r
+ if (code = pkrb5_cc_get_principal(ctx, cc, &me))\r
+ goto cleanup;\r
+\r
+ for ( r=realm, t=cell, i=0; i<krb5_princ_realm(ctx, me)->length; r++,t++,i++ ) {\r
+ c = krb5_princ_realm(ctx, me)->data[i];\r
+ *r = c;\r
+ *t = isupper(c) ? tolower(c) : c;\r
+ }\r
+ *r = *t = '\0';\r
+\r
+ rcA = Leash_afs_klog("afs", cell, realm, lifetime);\r
+ if (rcA)\r
+ rcA = Leash_afs_klog("afs", "", realm, lifetime);\r
+\r
+ cleanup:\r
+ if (me) \r
+ pkrb5_free_principal(ctx, me);\r
+ if (cc)\r
+ pkrb5_cc_close(ctx, cc);\r
+ if (ctx) \r
+ pkrb5_free_context(ctx);\r
+ }\r
+#endif /* NO_AFS */\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+long\r
+Leash_kdestroy(void)\r
+{\r
+ int k_errno;\r
+\r
+ Leash_afs_unlog();\r
+ khm_krb5_destroy_identity(NULL);\r
+\r
+ if (pdest_tkt != NULL)\r
+ {\r
+ k_errno = (*pdest_tkt)();\r
+ if (k_errno && (k_errno != RET_TKFIL))\r
+ return KRBERR(k_errno);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int com_addr(void)\r
+{\r
+ long ipAddr;\r
+ char loc_addr[ADDR_SZ];\r
+ CREDENTIALS cred; \r
+ char service[40];\r
+ char instance[40];\r
+// char addr[40];\r
+ char realm[40];\r
+ struct in_addr LocAddr;\r
+ int k_errno;\r
+\r
+ if (pkrb_get_cred == NULL)\r
+ return(KSUCCESS);\r
+\r
+ k_errno = (*pkrb_get_cred)(service,instance,realm,&cred);\r
+ if (k_errno)\r
+ return KRBERR(k_errno);\r
+\r
+\r
+ while(1) {\r
+ ipAddr = (*pLocalHostAddr)();\r
+ LocAddr.s_addr = ipAddr;\r
+ strcpy(loc_addr,inet_ntoa(LocAddr));\r
+ if ( strcmp(cred.address,loc_addr) != 0) {\r
+ Leash_kdestroy ();\r
+ break;\r
+ }\r
+ break;\r
+ } // while()\r
+ return 0;\r
+} \r
+\r
+long FAR\r
+not_an_API_LeashFreeTicketList(TicketList** ticketList) \r
+{\r
+ TicketList* tempList = *ticketList, *killList; \r
+\r
+ //if (tempList == NULL)\r
+ //return -1;\r
+\r
+ while (tempList)\r
+ {\r
+ killList = tempList;\r
+ \r
+ tempList = (TicketList*)tempList->next;\r
+ free(killList->theTicket);\r
+ if (killList->tktEncType)\r
+ free(killList->tktEncType);\r
+ if (killList->keyEncType)\r
+ free(killList->keyEncType);\r
+ if (killList->addrCount) {\r
+ int n;\r
+ for ( n=0; n<killList->addrCount; n++) {\r
+ if (killList->addrList[n])\r
+ free(killList->addrList[n]);\r
+ }\r
+ }\r
+ if (killList->addrList)\r
+ free(killList->addrList);\r
+ if (killList->name)\r
+ free(killList->name);\r
+ if (killList->inst)\r
+ free(killList->inst);\r
+ if (killList->realm)\r
+ free(killList->realm);\r
+ free(killList);\r
+ }\r
+\r
+ *ticketList = NULL;\r
+ return 0;\r
+}\r
+\r
+\r
+long FAR Leash_klist(HWND hlist, TICKETINFO FAR *ticketinfo)\r
+{\r
+ // Don't think this function will be used anymore - ADL 5-15-99 \r
+ // Old fucntion to put tickets in a listbox control \r
+ // Use function "not_an_API_LeashKRB4GetTickets()" instead! \r
+ char pname[ANAME_SZ];\r
+ char pinst[INST_SZ];\r
+ char prealm[REALM_SZ];\r
+ char buf[MAX_K_NAME_SZ+40];\r
+ LPSTR cp;\r
+ long expdate;\r
+ int k_errno;\r
+ CREDENTIALS c;\r
+ int newtickets = 0;\r
+ int open = 0;\r
+\r
+ /*\r
+ * Since krb_get_tf_realm will return a ticket_file error,\r
+ * we will call tf_init and tf_close first to filter out\r
+ * things like no ticket file. Otherwise, the error that\r
+ * the user would see would be \r
+ * klist: can't find realm of ticket file: No ticket file (tf_util)\r
+ * instead of\r
+ * klist: No ticket file (tf_util)\r
+ */\r
+ if (ptf_init == NULL)\r
+ return(KSUCCESS);\r
+\r
+ if (hlist) \r
+ { \r
+ SendMessage(hlist, WM_SETREDRAW, FALSE, 0L);\r
+ SendMessage(hlist, LB_RESETCONTENT, 0, 0L);\r
+ } \r
+ com_addr(); \r
+ newtickets = NO_TICKETS;\r
+\r
+ err_context = (LPSTR)"tktf1";\r
+\r
+ /* Open ticket file */\r
+ if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL))\r
+ {\r
+ goto cleanup;\r
+ }\r
+ /* Close ticket file */\r
+ (void) (*ptf_close)();\r
+ /*\r
+ * We must find the realm of the ticket file here before calling\r
+ * tf_init because since the realm of the ticket file is not\r
+ * really stored in the principal section of the file, the\r
+ * routine we use must itself call tf_init and tf_close.\r
+ */\r
+ err_context = "tf realm";\r
+ if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS)\r
+ {\r
+ goto cleanup;\r
+ }\r
+ /* Open ticket file */\r
+ err_context = "tf init";\r
+ if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) \r
+ {\r
+ goto cleanup; \r
+ }\r
+\r
+ open = 1;\r
+ err_context = "tf pname";\r
+ /* Get principal name and instance */\r
+ if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) \r
+ {\r
+ goto cleanup; \r
+ }\r
+\r
+ /*\r
+ * You may think that this is the obvious place to get the\r
+ * realm of the ticket file, but it can't be done here as the\r
+ * routine to do this must open the ticket file. This is why\r
+ * it was done before tf_init.\r
+ */\r
+\r
+ wsprintf((LPSTR)ticketinfo->principal,"%s%s%s%s%s", (LPSTR)pname,\r
+ (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst,\r
+ (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm);\r
+ newtickets = GOOD_TICKETS;\r
+\r
+ err_context = "tf cred";\r
+ while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) \r
+ {\r
+ expdate = c.issue_date + c.lifetime * 5L * 60L;\r
+\r
+ if (!lstrcmp((LPSTR)c.service, (LPSTR)TICKET_GRANTING_TICKET) && !lstrcmp((LPSTR)c.instance, (LPSTR)prealm)) \r
+ {\r
+ ticketinfo->issue_date = c.issue_date;\r
+ ticketinfo->lifetime = c.lifetime * 5L * 60L;\r
+ ticketinfo->renew_till = 0;\r
+ }\r
+\r
+ cp = (LPSTR)buf;\r
+ lstrcpy(cp, (LPSTR)short_date(&c.issue_date));\r
+ cp += lstrlen(cp);\r
+ wsprintf(cp,"\t%s\t%s%s%s%s%s",\r
+ (LPSTR)short_date(&expdate), (LPSTR)c.service,\r
+ (LPSTR)(c.instance[0] ? "." : ""),\r
+ (LPSTR)c.instance, (LPSTR)(c.realm[0] ? "@" : ""),\r
+ (LPSTR) c.realm);\r
+ if (hlist)\r
+ SendMessage(hlist, LB_ADDSTRING, 0, (LONG)(LPSTR)buf);\r
+ } /* WHILE */\r
+\r
+cleanup:\r
+\r
+ if (open)\r
+ (*ptf_close)(); /* close ticket file */\r
+\r
+ if (hlist) \r
+ {\r
+ SendMessage(hlist, WM_SETREDRAW, TRUE, 0L);\r
+ InvalidateRect(hlist, NULL, TRUE);\r
+ UpdateWindow(hlist);\r
+ }\r
+ if (k_errno == EOF)\r
+ k_errno = 0;\r
+\r
+ /* XXX the if statement directly below was inserted to eliminate\r
+ an error 20 on Leash startup. The error occurs from an error\r
+ number thrown from krb_get_tf_realm. We believe this change\r
+ does not eliminate other errors, but it may. */\r
+\r
+ if (k_errno == RET_NOTKT)\r
+ k_errno = 0;\r
+\r
+ ticketinfo->btickets = newtickets;\r
+ if (k_errno != 0)\r
+ return KRBERR(k_errno);\r
+ return 0;\r
+}\r
+\r
+\r
+\r
+static BOOL CALLBACK \r
+EnumChildProc(HWND hwnd, LPARAM lParam)\r
+{\r
+ HWND * h = (HWND *)lParam;\r
+ *h = hwnd;\r
+ return FALSE;\r
+}\r
+\r
+\r
+static HWND\r
+FindFirstChildWindow(HWND parent)\r
+{\r
+ HWND hFirstChild = 0;\r
+ EnumChildWindows(parent, EnumChildProc, (LPARAM) &hFirstChild);\r
+ return hFirstChild;\r
+}\r
+\r
+void FAR\r
+not_an_API_Leash_AcquireInitialTicketsIfNeeded(krb5_context context, krb5_principal desiredKrb5Principal) \r
+{\r
+ krb5_error_code err;\r
+ LSH_DLGINFO_EX dlginfo;\r
+ HGLOBAL hData;\r
+ HWND hLeash;\r
+ HWND hForeground;\r
+ char *desiredName = 0;\r
+ char *desiredRealm = 0;\r
+ char *p;\r
+ TicketList * list = NULL;\r
+ TICKETINFO ticketinfo;\r
+ krb5_context ctx;\r
+ char newenv[256];\r
+ char * env = 0;\r
+ DWORD dwMsLsaImport = Leash_get_default_mslsa_import();\r
+\r
+ char loginenv[16];\r
+ BOOL prompt;\r
+\r
+ GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", loginenv, sizeof(loginenv));\r
+ prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);\r
+\r
+ if ( !prompt || !pkrb5_init_context )\r
+ return;\r
+\r
+ ctx = context;\r
+ env = getenv("KRB5CCNAME");\r
+ if ( !env && context ) {\r
+ sprintf(newenv,"KRB5CCNAME=%s",pkrb5_cc_default_name(ctx));\r
+ env = (char *)putenv(newenv);\r
+ }\r
+\r
+ not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx);\r
+ not_an_API_LeashFreeTicketList(&list);\r
+\r
+ if ( ticketinfo.btickets != GOOD_TICKETS && \r
+ Leash_get_default_mslsa_import() && Leash_importable() ) {\r
+ // We have the option of importing tickets from the MSLSA\r
+ // but should we? Do the tickets in the MSLSA cache belong \r
+ // to the default realm used by Leash? If so, import. \r
+ int import = 0;\r
+\r
+ if ( dwMsLsaImport == 1 ) { /* always import */\r
+ import = 1;\r
+ } else if ( dwMsLsaImport == 2 ) { /* import when realms match */\r
+ krb5_error_code code;\r
+ krb5_ccache mslsa_ccache=0;\r
+ krb5_principal princ = 0;\r
+ char ms_realm[128] = "", *def_realm = 0, *r;\r
+ int i;\r
+\r
+ if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))\r
+ goto cleanup;\r
+\r
+ if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))\r
+ goto cleanup;\r
+\r
+ for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {\r
+ *r = krb5_princ_realm(ctx, princ)->data[i];\r
+ }\r
+ *r = '\0';\r
+\r
+ if (code = pkrb5_get_default_realm(ctx, &def_realm))\r
+ goto cleanup;\r
+\r
+ import = !strcmp(def_realm, ms_realm);\r
+\r
+ cleanup:\r
+ if (def_realm)\r
+ pkrb5_free_default_realm(ctx, def_realm);\r
+\r
+ if (princ)\r
+ pkrb5_free_principal(ctx, princ);\r
+\r
+ if (mslsa_ccache)\r
+ pkrb5_cc_close(ctx, mslsa_ccache);\r
+ }\r
+\r
+ if ( import ) {\r
+ Leash_import();\r
+\r
+ not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx);\r
+ not_an_API_LeashFreeTicketList(&list);\r
+ }\r
+ }\r
+\r
+ if ( ticketinfo.btickets != GOOD_TICKETS ) \r
+ {\r
+ /* do we want a specific client principal? */\r
+ if (desiredKrb5Principal != NULL) {\r
+ err = pkrb5_unparse_name (ctx, desiredKrb5Principal, &desiredName);\r
+ if (!err) {\r
+ dlginfo.username = desiredName;\r
+ for (p = desiredName; *p && *p != '@'; p++);\r
+ if ( *p == '@' ) {\r
+ *p = '\0';\r
+ desiredRealm = dlginfo.realm = ++p;\r
+ }\r
+ }\r
+ }\r
+ \r
+#ifdef COMMENT\r
+ memset(&dlginfo, 0, sizeof(LSH_DLGINFO_EX));\r
+ dlginfo.size = sizeof(LSH_DLGINFO_EX);\r
+ dlginfo.dlgtype = DLGTYPE_PASSWD;\r
+ dlginfo.title = "Obtain Kerberos Ticket Getting Tickets";\r
+ dlginfo.use_defaults = 1;\r
+\r
+ err = Leash_kinit_dlg_ex(NULL, &dlginfo);\r
+#else\r
+ /* construct a marshalling of data\r
+ * <title><principal><realm>\r
+ * then send to Leash\r
+ */\r
+\r
+ hData = GlobalAlloc( GHND, 4096 );\r
+ hForeground = GetForegroundWindow();\r
+ hLeash = FindWindow("LEASH.0WNDCLASS", NULL);\r
+ SetForegroundWindow(hLeash);\r
+ hLeash = FindFirstChildWindow(hLeash);\r
+ if ( hData && hLeash ) {\r
+ char * strs = GlobalLock( hData );\r
+ if ( strs ) {\r
+ strcpy(strs, "Obtain Kerberos Ticket Getting Tickets");\r
+ strs += strlen(strs) + 1;\r
+ if ( desiredName ) {\r
+ strcpy(strs, desiredName);\r
+ strs += strlen(strs) + 1;\r
+ if (desiredRealm) {\r
+ strcpy(strs, desiredRealm);\r
+ strs += strlen(strs) + 1;\r
+ }\r
+ } else {\r
+ *strs = 0;\r
+ strs++;\r
+ *strs = 0;\r
+ strs++;\r
+ }\r
+\r
+ GlobalUnlock( hData );\r
+ SendMessage(hLeash, 32809, 0, (LPARAM) hData);\r
+ }\r
+\r
+ GlobalFree( hData );\r
+ }\r
+ SetForegroundWindow(hForeground);\r
+#endif\r
+ if (desiredName != NULL)\r
+ pkrb5_free_unparsed_name(ctx, desiredName);\r
+ }\r
+\r
+ if ( !env && context )\r
+ putenv("KRB5CCNAME=");\r
+\r
+ if ( !context )\r
+ pkrb5_free_context(ctx);\r
+}\r
--- /dev/null
+Name,Type,Value,Description\r
+Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider\r
+ Module,KC_STRING,MITKrb5,\r
+ Description,KC_STRING,Kerberos V Credentials Provider,\r
+ Type,KC_INT32,1,\r
+ Flags,KC_INT32,0,\r
+ Parameters,KC_SPACE,0,Parameters for KrbCred\r
+ CreateMissingConfig,KC_INT32,0,Create missing configuration files\r
+ MsLsaImport,KC_INT32,2,Automatically import MSLSA credentials\r
+ AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets\r
+ DefaultLifetime,KC_INT32,36000,Default ticket lifetime\r
+ MaxLifetime,KC_INT32,86400,Maximum lifetime\r
+ MinLifetime,KC_INT32,60,Minimum lifetime\r
+ Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean)\r
+ Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean)\r
+ Addressless,KC_INT32,1,Obtain addressless tickets (boolean)\r
+ Renewable,KC_INT32,1,Obtain renewable tickets (boolean)\r
+ DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime\r
+ MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime\r
+ MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime\r
+ LRURealms,KC_STRING,,\r
+ LRUPrincipals,KC_STRING,,\r
+ PromptCache,KC_SPACE,0,Cache of prompts (only per identity)\r
+ Name,KC_STRING,,\r
+ Banner,KC_STRING,,\r
+ PromptCount,KC_INT32,0,\r
+ (n),KC_SPACE,0,Parameters for each prompt\r
+ Prompt,KC_STRING,,\r
+ Type,KC_INT32,0,\r
+ Flags,KC_INT32,0,\r
+ (n),KC_ENDSPACE,0,\r
+ PromptCache,KC_ENDSPACE,0,\r
+ Parameters,KC_ENDSPACE,0,\r
+Krb5Cred,KC_ENDSPACE,0,\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KRBAFSCRED_H\r
+#define __KHIMAIRA_KRBAFSCRED_H\r
+\r
+#include<windows.h>\r
+\r
+/* While we generally pull resources out of hResModule, the message\r
+ strings for all the languages are kept in the main DLL. */\r
+#define KHERR_HMODULE hInstance\r
+#define KHERR_FACILITY k5_facility\r
+#define KHERR_FACILITY_ID 64\r
+\r
+#include<khdefs.h>\r
+#include<kcreddb.h>\r
+#include<kmm.h>\r
+#include<kconfig.h>\r
+#include<khuidefs.h>\r
+#include<kherr.h>\r
+\r
+#include<krb5funcs.h>\r
+#include<krb5common.h>\r
+#include<errorfuncs.h>\r
+#include<dynimport.h>\r
+\r
+#include<langres.h>\r
+#include<datarep.h>\r
+#include<krb5_msgs.h>\r
+\r
+#define TYPENAME_ENCTYPE L"EncType"\r
+#define TYPENAME_ADDR_LIST L"AddrList"\r
+#define TYPENAME_KRB5_FLAGS L"Krb5Flags"\r
+\r
+#define ATTRNAME_KEY_ENCTYPE L"KeyEncType"\r
+#define ATTRNAME_TKT_ENCTYPE L"TktEncType"\r
+#define ATTRNAME_ADDR_LIST L"AddrList"\r
+#define ATTRNAME_KRB5_FLAGS L"Krb5Flags"\r
+#define ATTRNAME_KRB5_CCNAME L"Krb5CCName"\r
+\r
+void init_krb();\r
+void exit_krb();\r
+KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module);\r
+KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module);\r
+\r
+/* globals */\r
+extern kmm_module h_khModule;\r
+extern HMODULE hResModule;\r
+extern HINSTANCE hInstance;\r
+extern const wchar_t * k5_facility;\r
+\r
+extern khm_int32 type_id_enctype;\r
+extern khm_int32 type_id_addr_list;\r
+extern khm_int32 type_id_krb5_flags;\r
+\r
+extern khm_int32 attr_id_key_enctype;\r
+extern khm_int32 attr_id_tkt_enctype;\r
+extern khm_int32 attr_id_addr_list;\r
+extern khm_int32 attr_id_krb5_flags;\r
+extern khm_int32 attr_id_krb5_ccname;\r
+\r
+/* Configuration spaces */\r
+#define CSNAME_KRB5CRED L"Krb5Cred"\r
+#define CSNAME_PARAMS L"Parameters"\r
+#define CSNAME_PROMPTCACHE L"PromptCache"\r
+\r
+/* plugin constants */\r
+#define KRB5_PLUGIN_NAME L"Krb5Cred"\r
+\r
+#define KRB5_CREDTYPE_NAME L"Krb5Cred"\r
+\r
+extern khm_handle csp_plugins;\r
+extern khm_handle csp_krbcred;\r
+extern khm_handle csp_params;\r
+\r
+extern kconf_schema schema_krbconfig[];\r
+\r
+/* other globals */\r
+extern khm_int32 credtype_id_krb5;\r
+\r
+extern khm_boolean krb5_initialized;\r
+\r
+extern khm_handle krb5_credset;\r
+\r
+extern khm_handle k5_sub;\r
+\r
+extern krb5_context k5_identpro_ctx;\r
+\r
+extern BOOL is_k5_identpro;\r
+\r
+/* plugin callbacks */\r
+khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);\r
+\r
+/* kinit fiber */\r
+typedef struct _fiber_job_t {\r
+ int command;\r
+\r
+ khui_new_creds * nc;\r
+ khui_new_creds_by_type * nct;\r
+ HWND dialog;\r
+\r
+ khm_handle identity;\r
+ char * principal;\r
+ char * password;\r
+ char * ccache;\r
+ krb5_deltat lifetime;\r
+ DWORD forwardable;\r
+ DWORD proxiable;\r
+ DWORD renewable;\r
+ krb5_deltat renew_life;\r
+ DWORD addressless;\r
+ DWORD publicIP;\r
+\r
+ int code;\r
+ int state;\r
+ int prompt_set;\r
+\r
+ BOOL null_password;\r
+} fiber_job;\r
+\r
+extern fiber_job g_fjob; /* global fiber job object */\r
+\r
+#define FIBER_CMD_KINIT 1\r
+#define FIBER_CMD_CANCEL 2\r
+#define FIBER_CMD_CONTINUE 3\r
+\r
+#define FIBER_STATE_NONE 0\r
+#define FIBER_STATE_KINIT 1\r
+\r
+void \r
+k5_pp_begin(khui_property_sheet * s);\r
+\r
+void \r
+k5_pp_end(khui_property_sheet * s);\r
+\r
+khm_int32 KHMAPI \r
+k5_msg_cred_dialog(khm_int32 msg_type, \r
+ khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+khm_int32 KHMAPI \r
+k5_msg_ident(khm_int32 msg_type, \r
+ khm_int32 msg_subtype, \r
+ khm_ui_4 uparam, \r
+ void * vparam);\r
+\r
+int \r
+k5_get_realm_from_nc(khui_new_creds * nc, \r
+ wchar_t * buf, \r
+ khm_size cch_buf);\r
+\r
+void\r
+k5_register_config_panels(void);\r
+\r
+void\r
+k5_unregister_config_panels(void);\r
+\r
+#endif\r
--- /dev/null
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "..\..\langres.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "..\\..\\langres.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_NC_KRB5 DIALOGEX 0, 0, 300, 166\r
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | \r
+ WS_CLIPCHILDREN\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "Realm",IDC_STATIC,7,25,52,13\r
+ COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | \r
+ CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP\r
+ PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181,\r
+ 43,112,16,BS_NOTIFY | WS_DISABLED\r
+ LTEXT "&Lifetime",IDC_STATIC,7,67,61,12\r
+ EDITTEXT IDC_NCK5_LIFETIME_EDIT,85,67,107,12,ES_AUTOHSCROLL\r
+ CONTROL "&Renewable for",IDC_NCK5_RENEWABLE,"Button",\r
+ BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,7,87,64,12\r
+ EDITTEXT IDC_NCK5_RENEW_EDIT,85,87,108,12,ES_AUTOHSCROLL\r
+ CONTROL "Can be &forwarded to other machines",\r
+ IDC_NCK5_FORWARDABLE,"Button",BS_AUTOCHECKBOX | \r
+ BS_NOTIFY | WS_TABSTOP,7,107,132,12\r
+ CONTROL "Kerberos 5 Ticket Options",IDC_STATIC,"Static",\r
+ SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11\r
+END\r
+\r
+IDD_PP_KRB5C DIALOGEX 0, 0, 235, 156\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
+CAPTION "Kerberos 5"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+ LTEXT "Name",IDC_STATIC,7,7,19,8\r
+ LTEXT "Valid till",IDC_STATIC,7,39,24,8\r
+ LTEXT "Renewable till",IDC_STATIC,7,55,45,12\r
+ CONTROL "Renewable",IDC_PPK5_CRENEW,"Button",BS_AUTOCHECKBOX | \r
+ WS_DISABLED | WS_TABSTOP,31,125,51,10\r
+ CONTROL "Forwardable",IDC_PPK5_CFORWARD,"Button",BS_AUTOCHECKBOX | \r
+ WS_DISABLED | WS_TABSTOP,91,125,56,10\r
+ CONTROL "Proxiable",IDC_PPK5_CPROXY,"Button",BS_AUTOCHECKBOX | \r
+ WS_DISABLED | WS_TABSTOP,156,125,45,10\r
+ LTEXT "Issued on",IDC_STATIC,7,23,32,8\r
+ GROUPBOX "Ticket flags",IDC_STATIC,7,108,221,41\r
+ LTEXT "Static",IDC_PPK5_NAME,72,7,156,12,NOT WS_GROUP,\r
+ WS_EX_CLIENTEDGE\r
+ LTEXT "Static",IDC_PPK5_ISSUE,72,23,156,12,NOT WS_GROUP,\r
+ WS_EX_CLIENTEDGE\r
+ LTEXT "Static",IDC_PPK5_VALID,72,39,156,12,NOT WS_GROUP,\r
+ WS_EX_CLIENTEDGE\r
+ LTEXT "Static",IDC_PPK5_RENEW,72,55,156,12,NOT WS_GROUP,\r
+ WS_EX_CLIENTEDGE\r
+END\r
+\r
+IDD_PP_KRB5 DIALOGEX 0, 0, 235, 156\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
+CAPTION "Kerberos 5"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+ LTEXT "Default realm",IDC_STATIC,7,7,44,8\r
+ LTEXT "Default lifetime",IDC_STATIC,7,22,49,8\r
+ LTEXT "Minimum lifetime",IDC_STATIC,7,37,52,8\r
+ LTEXT "Maximum lifetime",IDC_STATIC,7,52,55,8\r
+ LTEXT "Renewable lifetime",IDC_STATIC,7,67,61,8\r
+ LTEXT "Min. Renewable lifetime",IDC_STATIC,7,82,76,8\r
+ LTEXT "Max. Renewable lifetime",IDC_STATIC,7,97,79,8\r
+ GROUPBOX "Default ticket flags",IDC_STATIC,7,113,221,36\r
+ CONTROL "Proxiable",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,160,129,45,10\r
+ CONTROL "Renewable",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,23,129,51,10\r
+ CONTROL "Forwardable",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,89,129,56,10\r
+ LTEXT "ATHENA.MIT.EDU",IDC_STATIC,95,7,133,11,0,\r
+ WS_EX_CLIENTEDGE\r
+ LTEXT "10 hours",IDC_STATIC,95,22,133,11,0,WS_EX_CLIENTEDGE\r
+ LTEXT "1 minute",IDC_STATIC,95,37,133,11,0,WS_EX_CLIENTEDGE\r
+ LTEXT "7 days",IDC_STATIC,95,52,133,11,0,WS_EX_CLIENTEDGE\r
+ LTEXT "7 days",IDC_STATIC,95,67,133,11,0,WS_EX_CLIENTEDGE\r
+ LTEXT "1 minute",IDC_STATIC,95,82,133,11,0,WS_EX_CLIENTEDGE\r
+ LTEXT "21 days",IDC_STATIC,95,97,133,11,0,WS_EX_CLIENTEDGE\r
+END\r
+\r
+IDD_CONFIG DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "Default Realm",IDC_CFG_LBL_REALM,13,9,46,8\r
+ COMBOBOX IDC_CFG_DEFREALM,76,7,166,30,CBS_DROPDOWN | CBS_SORT | \r
+ WS_VSCROLL | WS_TABSTOP\r
+ PUSHBUTTON "Configure Realms ...",IDC_CFG_CFGREALMS,76,25,84,14\r
+ GROUPBOX "Keberos Configuration File",IDC_CFG_CFGFILEGRP,7,57,241,\r
+ 48\r
+ LTEXT "Location",IDC_CFG_LBL_CFGFILE,13,71,28,8\r
+ EDITTEXT IDC_CFG_CFGFILE,76,68,119,14,ES_AUTOHSCROLL\r
+ PUSHBUTTON "Browse...",IDC_CFG_BROWSE,198,68,44,14\r
+ CONTROL "Create file if missing",IDC_CFG_CREATECONFIG,"Button",\r
+ BS_AUTOCHECKBOX | WS_TABSTOP,76,89,80,10\r
+ GROUPBOX "Windows® Options",IDC_CFG_WINGRP,7,110,241,65\r
+ LTEXT "Hostname",IDC_CFG_LBL_HOSTNAME,13,123,33,8\r
+ EDITTEXT IDC_CFG_HOSTNAME,76,120,166,14,ES_AUTOHSCROLL | \r
+ ES_READONLY\r
+ LTEXT "Domain",IDC_CFG_LBL_DOMAIN,13,141,24,8\r
+ EDITTEXT IDC_CFG_DOMAIN,76,138,166,14,ES_AUTOHSCROLL | \r
+ ES_READONLY\r
+ LTEXT "Import tickets",IDC_LBL_IMPORT,13,158,45,8\r
+ COMBOBOX IDC_CFG_IMPORT,76,156,166,30,CBS_DROPDOWNLIST | CBS_SORT | \r
+ WS_VSCROLL | WS_TABSTOP\r
+END\r
+\r
+IDD_CFG_REALMS DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "",IDC_CFG_REALMS,"SysListView32",LVS_ALIGNLEFT | \r
+ WS_BORDER | WS_TABSTOP,7,19,81,148\r
+ GROUPBOX "Servers",IDC_CFG_SERVERSGRP,93,7,155,91\r
+ GROUPBOX "Domain/Hostname mappings",IDC_CFG_DOMAINGRP,93,101,155,\r
+ 74\r
+ CONTROL "",IDC_LIST3,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | \r
+ WS_TABSTOP,99,19,143,72\r
+ CONTROL "",IDC_LIST4,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | \r
+ WS_TABSTOP,99,111,143,56\r
+END\r
+\r
+IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8\r
+ EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL\r
+ LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80,\r
+ 8\r
+ EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL\r
+ GROUPBOX "Ticket lifetime range",IDC_CFG_LIFEGRP,7,43,221,49\r
+ LTEXT "Minimum",IDC_STATIC,13,56,28,8\r
+ EDITTEXT IDC_CFG_LRNG_MIN,91,53,131,14,ES_AUTOHSCROLL\r
+ LTEXT "Maximum",IDC_STATIC,13,75,30,8\r
+ EDITTEXT IDC_CFG_LRNG_MAX,91,72,131,14,ES_AUTOHSCROLL\r
+ GROUPBOX "Ticket renewable lifetime range",IDC_STATIC,7,95,221,49\r
+ LTEXT "Minimum",IDC_STATIC,13,108,28,8\r
+ EDITTEXT IDC_CFG_RLRNG_MIN,91,105,131,14,ES_AUTOHSCROLL\r
+ LTEXT "Maximum",IDC_STATIC,13,128,30,8\r
+ EDITTEXT IDC_CFG_RLRNG_MAX,91,125,131,14,ES_AUTOHSCROLL\r
+END\r
+\r
+IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8\r
+ EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL\r
+ LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80,\r
+ 8\r
+ EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL\r
+ LTEXT "Credentials cache",IDC_STATIC,7,63,58,8\r
+ EDITTEXT IDC_CFG_CCACHE,91,60,137,14,ES_AUTOHSCROLL\r
+END\r
+\r
+IDD_NC_KRB5_PASSWORD DIALOGEX 0, 0, 300, 166\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "Kerberos 5 Change Password Options",IDC_STATIC,"Static",\r
+ SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11\r
+ LTEXT "Realm",IDC_STATIC,7,25,52,13\r
+ COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | \r
+ CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP\r
+ PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181,\r
+ 43,112,16,BS_NOTIFY | WS_DISABLED\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO \r
+BEGIN\r
+ IDD_NC_KRB5, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 293\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 159\r
+ END\r
+\r
+ IDD_PP_KRB5C, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 149\r
+ END\r
+\r
+ IDD_PP_KRB5, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 149\r
+ END\r
+\r
+ IDD_CONFIG, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 13\r
+ VERTGUIDE, 76\r
+ VERTGUIDE, 242\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+\r
+ IDD_CFG_REALMS, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 93\r
+ VERTGUIDE, 99\r
+ VERTGUIDE, 242\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ HORZGUIDE, 19\r
+ HORZGUIDE, 167\r
+ END\r
+\r
+ IDD_CFG_IDS_TAB, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ VERTGUIDE, 13\r
+ VERTGUIDE, 91\r
+ VERTGUIDE, 222\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 144\r
+ END\r
+\r
+ IDD_CFG_ID_TAB, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ VERTGUIDE, 91\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 144\r
+ END\r
+\r
+ IDD_NC_KRB5_PASSWORD, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 293\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 159\r
+ END\r
+END\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_UNK_ADDR_FMT "Unknown address type %d"\r
+ IDS_KRB5_CREDTEXT_0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Creds for realm %s</p>"\r
+ IDS_KRB5_CCNAME_SHORT_DESC "Krb5 CCache"\r
+ IDS_KEY_ENCTYPE_SHORT_DESC "Key EncType"\r
+ IDS_TKT_ENCTYPE_SHORT_DESC "Ticket EncType"\r
+ IDS_KEY_ENCTYPE_LONG_DESC "Session Key Encryption Type"\r
+ IDS_TKT_ENCTYPE_LONG_DESC "Ticket Encryption Type"\r
+ IDS_ADDR_LIST_SHORT_DESC "Addresses"\r
+ IDS_ADDR_LIST_LONG_DESC "Address List"\r
+ IDS_ETYPE_NULL "NULL"\r
+ IDS_ETYPE_DES_CBC_CRC "DES-CBC-CRC"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_ETYPE_DES_CBC_MD4 "DES-CBC-MD4"\r
+ IDS_ETYPE_DES_CBC_MD5 "DES-CBC-MD5"\r
+ IDS_ETYPE_DES_CBC_RAW "DES-CBC-RAW"\r
+ IDS_ETYPE_DES3_CBC_SHA "DES3-CBC-SHA"\r
+ IDS_ETYPE_DES3_CBC_RAW "DES3-CBC-RAW"\r
+ IDS_ETYPE_DES_HMAC_SHA1 "DES-HMAC-SHA1"\r
+ IDS_ETYPE_DES3_CBC_SHA1 "DES3-CBC-SHA1"\r
+ IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 "AES128_CTS-HMAC-SHA1_96"\r
+ IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 "AES256_CTS-HMAC-SHA1_96"\r
+ IDS_ETYPE_ARCFOUR_HMAC "RC4-HMAC-NT"\r
+ IDS_ETYPE_ARCFOUR_HMAC_EXP "RC4-HMAC-NT-EXP"\r
+ IDS_ETYPE_UNKNOWN "(Unknown)"\r
+ IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 "LOCAL-DES3-HMAC-SHA1"\r
+ IDS_ETYPE_LOCAL_RC4_MD4 "LOCAL-RC4-MD4"\r
+ IDS_KRB5_SHORT_DESC "Kerberos 5"\r
+ IDS_KRB5_LONG_DESC "Kerberos 5 tickets"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_KRB4_SHORT_DESC "Kerberos 4"\r
+ IDS_KRB4_LONG_DESC "Kerberos 4 tickets"\r
+ IDS_KRB5_FLAGS_SHORT_DESC "Flags"\r
+ IDS_RENEW_TILL_SHORT_DESC "Renew Till"\r
+ IDS_RENEW_TILL_LONG_DESC "Renewable Till"\r
+ IDS_RENEW_FOR_SHORT_DESC "Renew for"\r
+ IDS_RENEW_FOR_LONG_DESC "Renewable for"\r
+ IDS_KRB5_CCNAME_LONG_DESC "Krb5 Primary Credentials Cache"\r
+ IDS_NC_USERNAME "Username"\r
+ IDS_NC_REALM "Realm"\r
+ IDS_KRB5_WARNING "Kerberos 5 Warning"\r
+ IDS_K5ERR_NAME_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The selected principal name has expired.</p><p><tab> Please contact your system administrator.</p>"\r
+ IDS_K5ERR_KEY_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The password for the selected identity has expired.</p><p><tab> Click <a id=""Krb5Cred:Passwd"">here</a> to change the password</p>"\r
+ IDS_KRB5_WARN_FMT "Kerberos 5: %s\n\n%s"\r
+ IDS_K5ERR_FMT "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tag>: %s</p>"\r
+ IDS_K5CFG_SHORT_DESC "Kerberos 5"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_K5CFG_LONG_DESC "Kerberos 5 Configuration"\r
+ IDS_K5RLM_SHORT_DESC "Realms"\r
+ IDS_K5RLM_LONG_DESC "Kerberos Realm Configuration"\r
+ IDS_K5CFG_IDS_SHORT_DESC "Kerberos 5"\r
+ IDS_K5CFG_IDS_LONG_DESC "Kerberos 5 options for all identities"\r
+ IDS_K5CFG_ID_SHORT_DESC "Kerberos 5"\r
+ IDS_K5CFG_ID_LONG_DESC "Kerberos 5 options for this identity"\r
+ IDS_PLUGIN_DESC "Kerberos 5 Credentials Provider"\r
+ IDS_NC_PWD_BANNER "Changing Kerberos 5 Password"\r
+ IDS_NC_PWD_PWD "Current Password"\r
+ IDS_NC_PWD_NPWD "New Password"\r
+ IDS_NC_PWD_NPWD_AGAIN "New Password again"\r
+ IDS_KRB5_CREDTEXT_P0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Changing password for %s</p>"\r
+ IDS_K5CFG_IMPORT_OPTIONS \r
+ "Never\000Always\000Only when the principal name matches\000 \000"\r
+END\r
+\r
+#endif // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
+\r
--- /dev/null
+; // ** krb5_msgs.mc \r
+\r
+; /* Since .mc files can contain strings from any language, we define\r
+; all our messages in one file in the /lang/ directory instead of\r
+; language specific subdirectories. */\r
+\r
+; /* The type is set to (wchar_t *) because that's what we will be\r
+; feeding kherr_report() function. */\r
+\r
+; // MessageIdTypedef=LPWSTR\r
+\r
+; /* Severity values as defined in the message definition file are\r
+; currently ignored. */\r
+\r
+SeverityNames=(\r
+ Success=0x0\r
+)\r
+\r
+LanguageNames=(\r
+ English=0x409:MSG_ENU\r
+)\r
+\r
+OutputBase=16\r
+\r
+; /* Actual messages start here */\r
+\r
+MessageId=1\r
+Severity=Success\r
+SymbolicName=MSG_INITIAL\r
+Language=English\r
+Initial placeholder message\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_CTX_INITAL_CREDS\r
+Language=English\r
+Obtaining initial Krb5 credentials\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_CTX_RENEW_CREDS\r
+Language=English\r
+Renewing Krb5 credentials\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_UNKNOWN\r
+Language=English\r
+An unknown error has occurred.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_PR_UNKNOWN\r
+Language=English\r
+You have entered an unknown username/instance/realm combination.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_TKFIL\r
+Language=English\r
+The tickets could not be accessed from the memory location where they were stored.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_S_TKFIL\r
+Language=English\r
+This may be due to a problem with the memory where your tickets are stored. Restarting your computer might be worth a try.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_CLOCKSKEW\r
+Language=English\r
+Your computer's clock is out of sync with the Kerberos server.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_S_CLOCKSKEW\r
+Language=English\r
+Synchronize your clock withe the Kerberos server.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_KDC_CONTACT\r
+Language=English\r
+Cannot contact the Kerberos server for the requested realm.\r
+.\r
+ \r
+MessageId=\r
+SymbolicName=MSG_ERR_INSECURE_PW\r
+Language=English\r
+You have entered an insecure or weak password.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_ERR_NO_IDENTITY\r
+Language=English\r
+There were no identities for which to renew credentials.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_CTX_PASSWD\r
+Language=English\r
+Changing Kerberos 5 Password\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_UNKNOWN\r
+Language=English\r
+Unknown error\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_NOT_SAME\r
+Language=English\r
+The new passwords are not the same.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_S_NOT_SAME\r
+Language=English\r
+The new password is asked for twice to protect against a mistake when setting the new password. Both instances of the new password must be the same. Please correct this and try again.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_SAME\r
+Language=English\r
+The new and the old passwords are the same.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_S_SAME\r
+Language=English\r
+Please type a new password to continue.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_NO_IDENTITY\r
+Language=English\r
+There are no identities selected.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_PWD_S_NO_IDENTITY\r
+Language=English\r
+Please select an identity to change the password.\r
+.\r
+\r
+MessageId=\r
+SymbolicName=MSG_\r
+Language=English\r
+.\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by D:\work\khimaira\src\plugins\krb5\lang\en_us\langres.rc\r
+//\r
+#define IDS_UNK_ADDR_FMT 101\r
+#define IDD_NC_KRB5 102\r
+#define IDS_KRB5_CREDTEXT_0 102\r
+#define IDS_KRB5_CCNAME_SHORT_DESC 103\r
+#define IDS_KEY_ENCTYPE_SHORT_DESC 104\r
+#define IDD_CONFIG 104\r
+#define IDS_TKT_ENCTYPE_SHORT_DESC 105\r
+#define IDD_CFG_REALMS 105\r
+#define IDS_KEY_ENCTYPE_LONG_DESC 106\r
+#define IDD_CFG_IDS_TAB 106\r
+#define IDS_TKT_ENCTYPE_LONG_DESC 107\r
+#define IDD_PP_KRB5C 107\r
+#define IDS_ADDR_LIST_SHORT_DESC 108\r
+#define IDD_PP_KRB5 108\r
+#define IDS_ADDR_LIST_LONG_DESC 109\r
+#define IDD_CFG_ID_TAB 109\r
+#define IDS_ETYPE_NULL 110\r
+#define IDD_NC_KRB5_PASSWORD 110\r
+#define IDS_ETYPE_DES_CBC_CRC 111\r
+#define IDS_ETYPE_DES_CBC_MD4 112\r
+#define IDS_ETYPE_DES_CBC_MD5 113\r
+#define IDS_ETYPE_DES_CBC_RAW 114\r
+#define IDS_ETYPE_DES3_CBC_SHA 115\r
+#define IDS_ETYPE_DES3_CBC_RAW 116\r
+#define IDS_ETYPE_DES_HMAC_SHA1 117\r
+#define IDS_ETYPE_DES3_CBC_SHA1 118\r
+#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119\r
+#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120\r
+#define IDS_ETYPE_ARCFOUR_HMAC 121\r
+#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122\r
+#define IDS_ETYPE_UNKNOWN 123\r
+#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124\r
+#define IDS_ETYPE_LOCAL_RC4_MD4 125\r
+#define IDS_KRB5_SHORT_DESC 126\r
+#define IDS_KRB5_LONG_DESC 127\r
+#define IDS_KRB4_SHORT_DESC 128\r
+#define IDS_KRB4_LONG_DESC 129\r
+#define IDS_KRB5_FLAGS_SHORT_DESC 130\r
+#define IDS_RENEW_TILL_SHORT_DESC 131\r
+#define IDS_RENEW_TILL_LONG_DESC 132\r
+#define IDS_RENEW_FOR_SHORT_DESC 133\r
+#define IDS_RENEW_FOR_LONG_DESC 134\r
+#define IDS_KRB5_CCNAME_LONG_DESC 135\r
+#define IDS_NC_USERNAME 136\r
+#define IDS_NC_REALM 137\r
+#define IDS_KRB5_WARNING 138\r
+#define IDS_K5ERR_NAME_EXPIRED 139\r
+#define IDS_K5ERR_KEY_EXPIRED 140\r
+#define IDS_KRB5_WARN_FMT 141\r
+#define IDS_K5ERR_FMT 142\r
+#define IDS_K5CFG_SHORT_DESC 143\r
+#define IDS_K5CFG_LONG_DESC 144\r
+#define IDS_K5RLM_SHORT_DESC 145\r
+#define IDS_K5RLM_LONG_DESC 146\r
+#define IDS_K5CFG_IDS_SHORT_DESC 147\r
+#define IDS_K5CFG_IDS_LONG_DESC 148\r
+#define IDS_K5CFG_ID_SHORT_DESC 149\r
+#define IDS_K5CFG_ID_LONG_DESC 150\r
+#define IDS_PLUGIN_DESC 151\r
+#define IDS_NC_PWD_BANNER 152\r
+#define IDS_NC_PWD_PWD 153\r
+#define IDS_NC_PWD_NPWD 154\r
+#define IDS_NC_PWD_NPWD_AGAIN 155\r
+#define IDS_KRB5_CREDTEXT_P0 156\r
+#define IDS_K5CFG_IMPORT_OPTIONS 157\r
+#define IDC_NCK5_RENEWABLE 1002\r
+#define IDC_NCK5_FORWARDABLE 1004\r
+#define IDC_NCK5_REALM 1005\r
+#define IDC_NCK5_ADD_REALMS 1006\r
+#define IDC_NCK5_LIFETIME_EDIT 1008\r
+#define IDC_NCK5_RENEW_EDIT 1009\r
+#define IDC_PPK5_CRENEW 1014\r
+#define IDC_PPK5_CFORWARD 1015\r
+#define IDC_PPK5_CPROXY 1016\r
+#define IDC_PPK5_NAME 1017\r
+#define IDC_PPK5_ISSUE 1018\r
+#define IDC_PPK5_VALID 1019\r
+#define IDC_PPK5_RENEW 1020\r
+#define IDC_CHECK2 1022\r
+#define IDC_CHECK4 1024\r
+#define IDC_PPK5_LIFETIME 1024\r
+#define IDC_CHECK5 1025\r
+#define IDC_CFG_LBL_REALM 1025\r
+#define IDC_CFG_DEFREALM 1026\r
+#define IDC_CFG_LBL_CFGFILE 1029\r
+#define IDC_CFG_CFGFILE 1030\r
+#define IDC_CFG_WINGRP 1031\r
+#define IDC_LBL_IMPORT 1032\r
+#define IDC_CFG_IMPORT 1033\r
+#define IDC_CFG_LBL_HOSTNAME 1034\r
+#define IDC_CFG_HOSTNAME 1035\r
+#define IDC_CFG_LBL_DOMAIN 1036\r
+#define IDC_CFG_DOMAIN 1037\r
+#define IDC_CFG_CREATECONFIG 1038\r
+#define IDC_CFG_BROWSE 1039\r
+#define IDC_CFG_CFGFILEGRP 1040\r
+#define IDC_CFG_CFGREALMS 1041\r
+#define IDC_CFG_REALMS 1044\r
+#define IDC_CFG_DOMAINGRP 1045\r
+#define IDC_CFG_SERVERSGRP 1046\r
+#define IDC_LIST3 1047\r
+#define IDC_LIST4 1048\r
+#define IDC_CFG_LBL_DEFLIFE 1049\r
+#define IDC_CFG_DEFLIFE 1050\r
+#define IDC_CFG_LBL_DEFRLIFE 1051\r
+#define IDC_CFG_DEFRLIFE 1052\r
+#define IDC_CFG_LIFEGRP 1053\r
+#define IDC_CFG_LRNG_MIN 1054\r
+#define IDC_CFG_LRNG_MAX 1055\r
+#define IDC_CFG_RLRNG_MIN 1056\r
+#define IDC_CFG_RLRNG_MAX 1057\r
+#define IDC_CFG_CCACHE 1058\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 111\r
+#define _APS_NEXT_COMMAND_VALUE 40001\r
+#define _APS_NEXT_CONTROL_VALUE 1059\r
+#define _APS_NEXT_SYMED_VALUE 101\r
+#endif\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<krbcred.h>\r
+#include<kherror.h>\r
+\r
+kmm_module h_khModule; /* KMM's handle to this module */\r
+HINSTANCE hInstance;\r
+HMODULE hResModule; /* HMODULE to the resource library */\r
+const wchar_t * k5_facility = L"Krb5";\r
+\r
+khm_int32 type_id_enctype = -1;\r
+khm_int32 type_id_addr_list = -1;\r
+khm_int32 type_id_krb5_flags = -1;\r
+\r
+BOOL type_regd_enctype = FALSE;\r
+BOOL type_regd_addr_list = FALSE;\r
+BOOL type_regd_krb5_flags = FALSE;\r
+\r
+khm_int32 attr_id_key_enctype = -1;\r
+khm_int32 attr_id_tkt_enctype = -1;\r
+khm_int32 attr_id_addr_list = -1;\r
+khm_int32 attr_id_krb5_flags = -1;\r
+khm_int32 attr_id_krb5_ccname = -1;\r
+\r
+BOOL attr_regd_key_enctype = FALSE;\r
+BOOL attr_regd_tkt_enctype = FALSE;\r
+BOOL attr_regd_addr_list = FALSE;\r
+BOOL attr_regd_krb5_flags = FALSE;\r
+BOOL attr_regd_krb5_ccname = FALSE;\r
+\r
+khm_handle csp_plugins = NULL;\r
+khm_handle csp_krbcred = NULL;\r
+khm_handle csp_params = NULL;\r
+\r
+BOOL is_k5_identpro = TRUE;\r
+\r
+kmm_module_locale locales[] = {\r
+ LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb5cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT)\r
+};\r
+int n_locales = ARRAYLENGTH(locales);\r
+\r
+/* These two should not do anything */\r
+void init_krb() {\r
+}\r
+\r
+void exit_krb() {\r
+}\r
+\r
+/* called by the NetIDMgr module manager */\r
+KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ kmm_plugin_reg pi;\r
+ wchar_t buf[256];\r
+\r
+ h_khModule = h_module;\r
+\r
+ rv = kmm_set_locale_info(h_module, locales, n_locales);\r
+ if(KHM_SUCCEEDED(rv)) {\r
+ hResModule = kmm_get_resource_hmodule(h_module);\r
+ } else\r
+ goto _exit;\r
+\r
+ /* register the plugin */\r
+ ZeroMemory(&pi, sizeof(pi));\r
+ pi.name = KRB5_PLUGIN_NAME;\r
+ pi.type = KHM_PITYPE_CRED;\r
+ pi.icon = NULL; /*TODO: Assign icon */\r
+ pi.flags = KHM_PIFLAG_IDENTITY_PROVIDER;\r
+ pi.msg_proc = k5_msg_callback;\r
+ pi.description = buf;\r
+ LoadString(hResModule, IDS_PLUGIN_DESC,\r
+ buf, ARRAYLENGTH(buf));\r
+ kmm_provide_plugin(h_module, &pi);\r
+\r
+ if(KHM_FAILED(rv = init_imports()))\r
+ goto _exit;\r
+\r
+ if(KHM_FAILED(rv = init_error_funcs()))\r
+ goto _exit;\r
+\r
+ /* Register common data types */\r
+ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) {\r
+ kcdb_type type;\r
+ kcdb_type *t32;\r
+\r
+ kcdb_type_get_info(KCDB_TYPE_INT32, &t32);\r
+\r
+ type.id = KCDB_TYPE_INVALID;\r
+ type.name = TYPENAME_ENCTYPE;\r
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;\r
+ type.cb_max = t32->cb_max;\r
+ type.cb_min = t32->cb_min;\r
+ type.isValid = t32->isValid;\r
+ type.comp = t32->comp;\r
+ type.dup = t32->dup;\r
+ type.toString = enctype_toString;\r
+\r
+ rv = kcdb_type_register(&type, &type_id_enctype);\r
+ kcdb_type_release_info(t32);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+ type_regd_enctype = TRUE;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) {\r
+ kcdb_type type;\r
+ kcdb_type *tdata;\r
+\r
+ kcdb_type_get_info(KCDB_TYPE_DATA, &tdata);\r
+\r
+ type.id = KCDB_TYPE_INVALID;\r
+ type.name = TYPENAME_ADDR_LIST;\r
+ type.flags = KCDB_TYPE_FLAG_CB_MIN;\r
+ type.cb_min = 0;\r
+ type.cb_max = 0;\r
+ type.isValid = tdata->isValid;\r
+ type.comp = tdata->comp;\r
+ type.dup = tdata->dup;\r
+ type.toString = addr_list_toString;\r
+\r
+ rv = kcdb_type_register(&type, &type_id_addr_list);\r
+ kcdb_type_release_info(tdata);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+ type_regd_addr_list = TRUE;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) {\r
+ kcdb_type type;\r
+ kcdb_type *t32;\r
+\r
+ kcdb_type_get_info(KCDB_TYPE_INT32, &t32);\r
+\r
+ type.id = KCDB_TYPE_INVALID;\r
+ type.name = TYPENAME_KRB5_FLAGS;\r
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;\r
+ type.cb_max = t32->cb_max;\r
+ type.cb_min = t32->cb_min;\r
+ type.isValid = t32->isValid;\r
+ type.comp = t32->comp;\r
+ type.dup = t32->dup;\r
+ type.toString = krb5flags_toString;\r
+\r
+ rv = kcdb_type_register(&type, &type_id_krb5_flags);\r
+ kcdb_type_release_info(t32);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+ type_regd_krb5_flags = TRUE;\r
+ }\r
+\r
+ /* Register common attributes */\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) {\r
+ kcdb_attrib attrib;\r
+ wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ /* although we are loading a long descriptoin, it still fits\r
+ in the short descriptoin buffer */\r
+\r
+ ZeroMemory(&attrib, sizeof(attrib));\r
+\r
+ attrib.name = ATTRNAME_KEY_ENCTYPE;\r
+ attrib.id = KCDB_ATTR_INVALID;\r
+ attrib.type = type_id_enctype;\r
+ attrib.flags = 0;\r
+ LoadString(hResModule, IDS_KEY_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf));\r
+ LoadString(hResModule, IDS_KEY_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = lbuf;\r
+ \r
+ rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ attr_regd_key_enctype = TRUE;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) {\r
+ kcdb_attrib attrib;\r
+ wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ /* although we are loading a long descriptoin, it still fits\r
+ in the short descriptoin buffer */\r
+\r
+ ZeroMemory(&attrib, sizeof(attrib));\r
+\r
+ attrib.name = ATTRNAME_TKT_ENCTYPE;\r
+ attrib.id = KCDB_ATTR_INVALID;\r
+ attrib.type = type_id_enctype;\r
+ attrib.flags = 0;\r
+ LoadString(hResModule, IDS_TKT_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf));\r
+ LoadString(hResModule, IDS_TKT_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = lbuf;\r
+ \r
+ rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ attr_regd_tkt_enctype = TRUE;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) {\r
+ kcdb_attrib attrib;\r
+ wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ /* although we are loading a long descriptoin, it still fits\r
+ in the short descriptoin buffer */\r
+\r
+ ZeroMemory(&attrib, sizeof(attrib));\r
+\r
+ attrib.name = ATTRNAME_ADDR_LIST;\r
+ attrib.id = KCDB_ATTR_INVALID;\r
+ attrib.type = type_id_addr_list;\r
+ attrib.flags = 0;\r
+ LoadString(hResModule, IDS_ADDR_LIST_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf));\r
+ LoadString(hResModule, IDS_ADDR_LIST_LONG_DESC, lbuf, ARRAYLENGTH(lbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = lbuf;\r
+ \r
+ rv = kcdb_attrib_register(&attrib, &attr_id_addr_list);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ attr_regd_addr_list = TRUE;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) {\r
+ kcdb_attrib attrib;\r
+ wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC];\r
+\r
+ /* although we are loading a long descriptoin, it still fits\r
+ in the short descriptoin buffer */\r
+\r
+ ZeroMemory(&attrib, sizeof(attrib));\r
+\r
+ attrib.name = ATTRNAME_KRB5_FLAGS;\r
+ attrib.id = KCDB_ATTR_INVALID;\r
+ attrib.type = type_id_krb5_flags;\r
+ attrib.flags = 0;\r
+ LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = NULL;\r
+ \r
+ rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ attr_regd_krb5_flags = TRUE;\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) {\r
+ kcdb_attrib attrib;\r
+ wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC];\r
+ /* although we are loading a long descriptoin, it still fits\r
+ in the short descriptoin buffer */\r
+\r
+ ZeroMemory(&attrib, sizeof(attrib));\r
+\r
+ attrib.name = ATTRNAME_KRB5_CCNAME;\r
+ attrib.id = KCDB_ATTR_INVALID;\r
+ attrib.type = KCDB_TYPE_STRING;\r
+ attrib.flags = KCDB_ATTR_FLAG_PROPERTY;\r
+ LoadString(hResModule, IDS_KRB5_CCNAME_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf));\r
+ LoadString(hResModule, IDS_KRB5_CCNAME_LONG_DESC, lbuf, ARRAYLENGTH(lbuf));\r
+ attrib.short_desc = sbuf;\r
+ attrib.long_desc = lbuf;\r
+ \r
+ rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname);\r
+\r
+ if(KHM_FAILED(rv))\r
+ goto _exit;\r
+\r
+ attr_regd_krb5_ccname = TRUE;\r
+ }\r
+\r
+ rv = kmm_get_plugins_config(0, &csp_plugins);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+ rv = khc_load_schema(csp_plugins, schema_krbconfig);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+ rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+ rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params);\r
+ if(KHM_FAILED(rv)) goto _exit;\r
+\r
+_exit:\r
+ return rv;\r
+}\r
+\r
+/* called by the NetIDMgr module manager */\r
+KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) {\r
+ exit_imports();\r
+ exit_error_funcs();\r
+\r
+ if(attr_regd_key_enctype)\r
+ kcdb_attrib_unregister(attr_id_key_enctype);\r
+ if(attr_regd_tkt_enctype)\r
+ kcdb_attrib_unregister(attr_id_tkt_enctype);\r
+ if(attr_regd_addr_list)\r
+ kcdb_attrib_unregister(attr_id_addr_list);\r
+ if(attr_regd_krb5_flags)\r
+ kcdb_attrib_unregister(attr_id_krb5_flags);\r
+ if(attr_regd_krb5_ccname)\r
+ kcdb_attrib_unregister(attr_id_krb5_ccname);\r
+\r
+ if(type_regd_enctype)\r
+ kcdb_type_unregister(type_id_enctype);\r
+ if(type_regd_addr_list)\r
+ kcdb_type_unregister(type_id_addr_list);\r
+ if(type_regd_krb5_flags)\r
+ kcdb_type_unregister(type_id_krb5_flags);\r
+\r
+ if(csp_params) {\r
+ khc_close_space(csp_params);\r
+ csp_params = NULL;\r
+ }\r
+\r
+ if(csp_krbcred) {\r
+ khc_close_space(csp_krbcred);\r
+ csp_krbcred = NULL;\r
+ }\r
+\r
+ if(csp_plugins) {\r
+ khc_unload_schema(csp_plugins, schema_krbconfig);\r
+ khc_close_space(csp_plugins);\r
+ csp_plugins = NULL;\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS; /* the return code is ignored */\r
+}\r
+\r
+BOOL WINAPI DllMain(\r
+ HINSTANCE hinstDLL,\r
+ DWORD fdwReason,\r
+ LPVOID lpvReserved\r
+)\r
+{\r
+ switch(fdwReason) {\r
+ case DLL_PROCESS_ATTACH:\r
+ hInstance = hinstDLL;\r
+ init_krb();\r
+ break;\r
+ case DLL_PROCESS_DETACH:\r
+ exit_krb();\r
+ break;\r
+ case DLL_THREAD_ATTACH:\r
+ break;\r
+ case DLL_THREAD_DETACH:\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=ui\r
+!include <../config/Makefile.w32>\r
+\r
+EXEFILE=$(BINDIR)\netidmgr.exe\r
+\r
+MANIFESTFILE=$(BINDIR)\netidmgr.exe.manifest\r
+\r
+OBJFILES= \\r
+ $(OBJ)\main.obj \\r
+ $(OBJ)\mainmenu.obj \\r
+ $(OBJ)\toolbar.obj \\r
+ $(OBJ)\statusbar.obj \\r
+ $(OBJ)\notifier.obj \\r
+ $(OBJ)\timer.obj \\r
+ $(OBJ)\uiconfig.obj \\r
+ $(OBJ)\mainwnd.obj \\r
+ $(OBJ)\credwnd.obj \\r
+ $(OBJ)\htwnd.obj \\r
+ $(OBJ)\passwnd.obj \\r
+ $(OBJ)\newcredwnd.obj \\r
+ $(OBJ)\propertywnd.obj \\r
+ $(OBJ)\credfuncs.obj \\r
+ $(OBJ)\configwnd.obj \\r
+ $(OBJ)\aboutwnd.obj \\r
+ $(OBJ)\reqdaemon.obj \\r
+ $(OBJ)\cfg_general_wnd.obj \\r
+ $(OBJ)\cfg_identities_wnd.obj \\r
+ $(OBJ)\cfg_notif_wnd.obj \\r
+ $(OBJ)\cfg_plugins_wnd.obj\r
+\r
+RESFILE=$(OBJ)\khapp.res\r
+\r
+LIBFILES= \\r
+ $(LIBDIR)\nidmgr32.lib\r
+\r
+SDKLIBFILES= \\r
+ comctl32.lib \\r
+ shell32.lib\r
+\r
+$(OBJ)\uiconfig.c: uiconfig.csv $(CONFDIR)\csvschema.cfg\r
+ $(CCSV) $** $@\r
+\r
+$(RESFILE): lang\en_us\khapp.rc\r
+ $(RC2RES)\r
+\r
+!if "$(KH_BUILD)"=="RETAIL"\r
+$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER)\r
+!else\r
+$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER).debug\r
+!endif\r
+ $(CP) $** $@\r
+\r
+$(EXEFILE): $(OBJFILES) $(RESFILE) $(LIBFILES)\r
+ $(EXEGUILINK) $(SDKLIBFILES)\r
+\r
+all: mkdirs $(EXEFILE) $(MANIFESTFILE)\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<khimaira_version.h>\r
+#include<tlhelp32.h>\r
+\r
+#if DEBUG\r
+#include<assert.h>\r
+#endif\r
+\r
+INT_PTR CALLBACK\r
+about_dlg_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ HANDLE hsnap;\r
+ HWND hw;\r
+\r
+ SetDlgItemText(hwnd, IDC_PRODUCT,\r
+ TEXT(KH_VERSTR_PRODUCT_1033));\r
+ SetDlgItemText(hwnd, IDC_COPYRIGHT,\r
+ TEXT(KH_VERSTR_COPYRIGHT_1033));\r
+ SetDlgItemText(hwnd, IDC_BUILDINFO,\r
+ TEXT(KH_VERSTR_BUILDINFO_1033));\r
+\r
+ hsnap = \r
+ CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,\r
+ 0);\r
+\r
+ if (hsnap != INVALID_HANDLE_VALUE) {\r
+ LVCOLUMN lvc;\r
+ MODULEENTRY32 mod;\r
+ RECT r;\r
+\r
+ hw = GetDlgItem(hwnd, IDC_MODULES);\r
+#ifdef DEBUG\r
+ assert(hw != NULL);\r
+#endif\r
+\r
+ GetWindowRect(hw, &r);\r
+ OffsetRect(&r, -r.left, -r.top);\r
+\r
+ ZeroMemory(&lvc, sizeof(lvc));\r
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;\r
+\r
+ lvc.pszText = L"Name";\r
+ lvc.cx = r.right / 4;\r
+\r
+ ListView_InsertColumn(hw, 0, &lvc);\r
+\r
+ lvc.pszText = L"Path";\r
+ lvc.cx = (r.right * 3) / 4;\r
+ ListView_InsertColumn(hw, 1, &lvc);\r
+\r
+ ZeroMemory(&mod, sizeof(mod));\r
+ mod.dwSize = sizeof(mod);\r
+\r
+ /* done with columns, now for the actual data */\r
+ if (!Module32First(hsnap, &mod))\r
+ goto _done_with_modules;\r
+\r
+ do {\r
+\r
+ LVITEM lvi;\r
+ int idx;\r
+\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.mask = LVIF_TEXT;\r
+ lvi.pszText = mod.szModule;\r
+ idx = ListView_InsertItem(hw, &lvi);\r
+\r
+ lvi.mask = LVIF_TEXT;\r
+ lvi.iItem = idx;\r
+ lvi.iSubItem = 1;\r
+ lvi.pszText = mod.szExePath;\r
+ ListView_SetItem(hw, &lvi);\r
+\r
+ ZeroMemory(&mod, sizeof(mod));\r
+ mod.dwSize = sizeof(mod);\r
+ } while(Module32Next(hsnap, &mod));\r
+\r
+ ListView_SetView(hw, LV_VIEW_DETAILS);\r
+\r
+ _done_with_modules:\r
+ CloseHandle(hsnap);\r
+ }\r
+\r
+ khm_add_dialog(hwnd);\r
+ khm_enter_modal(hwnd);\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_DESTROY:\r
+ khm_leave_modal();\r
+ khm_del_dialog(hwnd);\r
+ return TRUE;\r
+\r
+ case WM_COMMAND:\r
+ if (wParam == MAKEWPARAM(IDOK, BN_CLICKED))\r
+ DestroyWindow(hwnd);\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+void\r
+khm_create_about_window(void) {\r
+ HWND hwnd;\r
+ hwnd = CreateDialog(khm_hInstance,\r
+ MAKEINTRESOURCE(IDD_ABOUT),\r
+ khm_hwnd_main,\r
+ about_dlg_proc);\r
+\r
+ ShowWindow(hwnd, SW_SHOW);\r
+ /* no need to keep track of the hwnd, since we add it to the\r
+ dialog chain in the dialog procedure */\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_ABOUTWND_H\r
+#define __KHIMAIRA_ABOUTWND_H\r
+\r
+void\r
+khm_create_about_window(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_APPGLOBAL_H\r
+#define __KHIMAIRA_APPGLOBAL_H\r
+\r
+/* global data */\r
+extern HINSTANCE khm_hInstance;\r
+extern int khm_nCmdShow;\r
+extern const wchar_t * khm_facility;\r
+extern kconf_schema schema_uiconfig[];\r
+\r
+typedef struct tag_khm_startup_options {\r
+ BOOL seen;\r
+ BOOL processing;\r
+\r
+ BOOL init;\r
+ BOOL import;\r
+ BOOL renew;\r
+ BOOL destroy;\r
+\r
+ BOOL autoinit;\r
+ BOOL exit;\r
+ BOOL error_exit;\r
+\r
+ BOOL no_main_window;\r
+} khm_startup_options;\r
+\r
+extern khm_startup_options khm_startup;\r
+\r
+void khm_add_dialog(HWND dlg);\r
+void khm_del_dialog(HWND dlg);\r
+BOOL khm_is_dialog_active(void);\r
+\r
+void khm_enter_modal(HWND hwnd);\r
+void khm_leave_modal(void);\r
+\r
+void khm_add_property_sheet(khui_property_sheet * s);\r
+void khm_del_property_sheet(khui_property_sheet * s);\r
+\r
+void khm_init_gui(void);\r
+void khm_exit_gui(void);\r
+\r
+void khm_parse_commandline();\r
+void khm_register_window_classes(void);\r
+\r
+#define MAX_RES_STRING 1024\r
+\r
+#define ELIPSIS L"..."\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+typedef struct tag_cfg_data {\r
+ BOOL auto_init;\r
+ BOOL auto_start;\r
+ BOOL auto_import;\r
+ BOOL keep_running;\r
+ BOOL auto_detect_net;\r
+} cfg_data;\r
+\r
+typedef struct tag_dlg_data {\r
+ khui_config_node node;\r
+ cfg_data saved;\r
+ cfg_data work;\r
+} dlg_data;\r
+\r
+static void\r
+read_params(dlg_data * dd) {\r
+ cfg_data * d;\r
+ khm_handle csp_cw;\r
+ khm_int32 t;\r
+\r
+ d = &dd->saved;\r
+\r
+ if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ,\r
+ &csp_cw))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ return;\r
+ }\r
+\r
+ khc_read_int32(csp_cw, L"AutoInit", &t);\r
+ d->auto_init = !!t;\r
+\r
+ khc_read_int32(csp_cw, L"AutoStart", &t);\r
+ d->auto_start = !!t;\r
+\r
+ khc_read_int32(csp_cw, L"AutoImport", &t);\r
+ d->auto_import = !!t;\r
+\r
+ khc_read_int32(csp_cw, L"KeepRunning", &t);\r
+ d->keep_running = !!t;\r
+\r
+ khc_read_int32(csp_cw, L"AutoDetectNet", &t);\r
+ d->auto_detect_net = !!t;\r
+\r
+ khc_close_space(csp_cw);\r
+\r
+ dd->work = *d;\r
+}\r
+\r
+static void\r
+write_params(dlg_data * dd) {\r
+ cfg_data * d, * s;\r
+ khm_handle csp_cw;\r
+\r
+ d = &dd->work;\r
+ s = &dd->saved;\r
+\r
+ if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE,\r
+ &csp_cw))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ return;\r
+ }\r
+\r
+ if (!!d->auto_init != !!s->auto_init)\r
+ khc_write_int32(csp_cw, L"AutoInit", d->auto_init);\r
+\r
+ if (!!d->auto_start != !!s->auto_start)\r
+ khc_write_int32(csp_cw, L"AutoStart", d->auto_start);\r
+\r
+ if (!!d->auto_import != !!s->auto_import)\r
+ khc_write_int32(csp_cw, L"AutoImport", d->auto_import);\r
+\r
+ if (!!d->keep_running != !!s->keep_running)\r
+ khc_write_int32(csp_cw, L"KeepRunning", d->keep_running);\r
+\r
+ if (!!d->auto_detect_net != !!s->auto_detect_net)\r
+ khc_write_int32(csp_cw, L"AutoDetectNet", d->auto_detect_net);\r
+\r
+ khc_close_space(csp_cw);\r
+\r
+ khui_cfg_set_flags(dd->node,\r
+ KHUI_CNFLAG_APPLIED,\r
+ KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED);\r
+\r
+ *s = *d;\r
+}\r
+\r
+static void\r
+check_for_modification(dlg_data * dd) {\r
+ cfg_data * d, * s;\r
+ d = &dd->work;\r
+ s = &dd->saved;\r
+\r
+ if (!!d->auto_init != !!s->auto_init ||\r
+ !!d->auto_start != !!s->auto_start ||\r
+ !!d->auto_import != !!s->auto_import ||\r
+ !!d->keep_running != !!s->keep_running ||\r
+ !!d->auto_detect_net != !!s->auto_detect_net) {\r
+\r
+ khui_cfg_set_flags(dd->node,\r
+ KHUI_CNFLAG_MODIFIED,\r
+ KHUI_CNFLAG_MODIFIED);\r
+\r
+ } else {\r
+\r
+ khui_cfg_set_flags(dd->node,\r
+ 0,\r
+ KHUI_CNFLAG_MODIFIED);\r
+\r
+ }\r
+}\r
+\r
+static void\r
+refresh_view(HWND hwnd, dlg_data * d) {\r
+ CheckDlgButton(hwnd, IDC_CFG_AUTOINIT,\r
+ (d->work.auto_init?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_CFG_AUTOSTART,\r
+ (d->work.auto_start?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_CFG_AUTOIMPORT,\r
+ (d->work.auto_import?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_CFG_KEEPRUNNING,\r
+ (d->work.keep_running?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_CFG_NETDETECT,\r
+ (d->work.auto_detect_net?BST_CHECKED:BST_UNCHECKED));\r
+}\r
+\r
+static void\r
+refresh_data(HWND hwnd, dlg_data * d) {\r
+ d->work.auto_init = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOINIT)\r
+ == BST_CHECKED);\r
+ d->work.auto_start = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOSTART)\r
+ == BST_CHECKED);\r
+ d->work.auto_import = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOIMPORT)\r
+ == BST_CHECKED);\r
+ d->work.keep_running = (IsDlgButtonChecked(hwnd, IDC_CFG_KEEPRUNNING)\r
+ == BST_CHECKED);\r
+ d->work.auto_detect_net = (IsDlgButtonChecked(hwnd, IDC_CFG_NETDETECT)\r
+ == BST_CHECKED);\r
+}\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_general_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ dlg_data * d;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ d = malloc(sizeof(*d));\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ d->node = (khui_config_node) lParam;\r
+\r
+ read_params(d);\r
+\r
+ refresh_view(hwnd, d);\r
+\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (HIWORD(wParam) == BN_CLICKED) {\r
+ refresh_data(hwnd, d);\r
+ check_for_modification(d);\r
+ }\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+\r
+ case KHUI_WM_CFG_NOTIFY:\r
+ d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (HIWORD(wParam) == WMCFG_APPLY) {\r
+ write_params(d);\r
+ }\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+static khui_config_node\r
+get_window_node(HWND hwnd) {\r
+ return (khui_config_node) (LONG_PTR)\r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+}\r
+\r
+static void\r
+set_window_node(HWND hwnd, khui_config_node node) {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER,\r
+ (LONG_PTR) node);\r
+#pragma warning(pop)\r
+}\r
+\r
+static void\r
+add_subpanels(HWND hwnd, \r
+ khui_config_node ctx_node,\r
+ khui_config_node ref_node) {\r
+ HWND hw_tab;\r
+ HWND hw_target;\r
+ khui_config_node sub;\r
+ khui_config_node_reg reg;\r
+ khui_config_init_data idata;\r
+ int idx;\r
+\r
+ hw_tab = GetDlgItem(hwnd, IDC_CFG_TAB);\r
+ hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET);\r
+#ifdef DEBUG\r
+ assert(hw_tab);\r
+ assert(hw_target);\r
+#endif\r
+\r
+ if (KHM_FAILED(khui_cfg_get_first_subpanel(ref_node, &sub))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ return;\r
+ }\r
+\r
+ idx = 0;\r
+ while(sub) {\r
+ HWND hwnd_panel;\r
+ TCITEM tci;\r
+ int iid;\r
+\r
+ khui_cfg_get_reg(sub, ®);\r
+\r
+ if ((ctx_node == ref_node && (reg.flags & KHUI_CNFLAG_PLURAL)) ||\r
+ (ctx_node != ref_node && !(reg.flags & KHUI_CNFLAG_PLURAL)))\r
+ goto _next_node;\r
+\r
+ idata.ctx_node = ctx_node;\r
+ idata.this_node = sub;\r
+ idata.ref_node = ref_node;\r
+\r
+ hwnd_panel = CreateDialogParam(reg.h_module,\r
+ reg.dlg_template,\r
+ hwnd,\r
+ reg.dlg_proc,\r
+ (LPARAM) &idata);\r
+\r
+#ifdef DEBUG\r
+ assert(hwnd_panel);\r
+#endif\r
+\r
+ ShowWindow(hwnd_panel, SW_HIDE);\r
+\r
+ ZeroMemory(&tci, sizeof(tci));\r
+\r
+ tci.mask = TCIF_PARAM | TCIF_TEXT;\r
+ tci.lParam = (LPARAM) sub;\r
+ tci.pszText = (LPWSTR) reg.short_desc;\r
+\r
+ iid = TabCtrl_InsertItem(hw_tab, 0, &tci);\r
+ idx++;\r
+\r
+ if (reg.flags & KHUI_CNFLAG_PLURAL) {\r
+ khui_cfg_set_param_inst(sub, ctx_node, iid);\r
+ khui_cfg_set_hwnd_inst(sub, ctx_node, hwnd_panel);\r
+ } else {\r
+ khui_cfg_set_param(sub, iid);\r
+ khui_cfg_set_hwnd(sub, hwnd_panel);\r
+ }\r
+\r
+ _next_node:\r
+\r
+ khui_cfg_get_next_release(&sub);\r
+ }\r
+\r
+ TabCtrl_SetCurSel(hw_tab, 0);\r
+}\r
+\r
+static void\r
+apply_all(HWND hwnd, \r
+ HWND hw_tab,\r
+ khui_config_node noderef) {\r
+ TCITEM tci;\r
+ HWND hw;\r
+ khui_config_node_reg reg;\r
+ int idx;\r
+ int count;\r
+\r
+ count = TabCtrl_GetItemCount(hw_tab);\r
+\r
+ for (idx = 0; idx < count; idx++) {\r
+\r
+ ZeroMemory(&tci, sizeof(tci));\r
+\r
+ tci.mask = TCIF_PARAM;\r
+ TabCtrl_GetItem(hw_tab,\r
+ idx,\r
+ &tci);\r
+\r
+#ifdef DEBUG\r
+ assert(tci.lParam);\r
+#endif\r
+ khui_cfg_get_reg((khui_config_node) tci.lParam, ®);\r
+ if (reg.flags & KHUI_CNFLAG_PLURAL)\r
+ hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam,\r
+ noderef);\r
+ else\r
+ hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+\r
+ PostMessage(hw, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(0, WMCFG_APPLY), 0);\r
+ }\r
+}\r
+\r
+static void\r
+show_tab_panel(HWND hwnd,\r
+ khui_config_node node,\r
+ HWND hw_tab,\r
+ int idx,\r
+ BOOL show) {\r
+ TCITEM tci;\r
+ HWND hw;\r
+ HWND hw_target;\r
+ RECT r;\r
+ RECT rref;\r
+ khui_config_node_reg reg;\r
+\r
+ ZeroMemory(&tci, sizeof(tci));\r
+\r
+ tci.mask = TCIF_PARAM;\r
+ TabCtrl_GetItem(hw_tab,\r
+ idx,\r
+ &tci);\r
+\r
+#ifdef DEBUG\r
+ assert(tci.lParam);\r
+#endif\r
+ khui_cfg_get_reg((khui_config_node) tci.lParam, ®);\r
+ if (reg.flags & KHUI_CNFLAG_PLURAL)\r
+ hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam,\r
+ node);\r
+ else\r
+ hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+\r
+ if (!show) {\r
+ ShowWindow(hw, SW_HIDE);\r
+ return;\r
+ }\r
+\r
+ hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET);\r
+#ifdef DEBUG\r
+ assert(hw_target);\r
+#endif\r
+ GetWindowRect(hwnd, &rref);\r
+ GetWindowRect(hw_target, &r);\r
+\r
+ OffsetRect(&r, -rref.left, -rref.top);\r
+\r
+ SetWindowPos(hw,\r
+ hw_tab,\r
+ r.left, r.top,\r
+ r.right - r.left, r.bottom - r.top,\r
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER |\r
+ SWP_SHOWWINDOW);\r
+}\r
+\r
+static INT_PTR\r
+handle_cfg_notify(HWND hwnd,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ khui_config_node node;\r
+ HWND hw;\r
+\r
+ node = get_window_node(hwnd);\r
+\r
+ if (HIWORD(wParam) == WMCFG_APPLY) {\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_TAB);\r
+\r
+ apply_all(hwnd,\r
+ hw,\r
+ node);\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+static INT_PTR\r
+handle_notify(HWND hwnd,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ LPNMHDR lpnm;\r
+ int i;\r
+\r
+\r
+ khui_config_node node;\r
+\r
+ lpnm = (LPNMHDR) lParam;\r
+ node = get_window_node(hwnd);\r
+\r
+ if (lpnm->idFrom == IDC_CFG_TAB) {\r
+ switch(lpnm->code) {\r
+ case TCN_SELCHANGING:\r
+ i = TabCtrl_GetCurSel(lpnm->hwndFrom);\r
+\r
+ show_tab_panel(hwnd, \r
+ node,\r
+ lpnm->hwndFrom,\r
+ i,\r
+ FALSE);\r
+ break;\r
+\r
+ case TCN_SELCHANGE:\r
+ i = TabCtrl_GetCurSel(lpnm->hwndFrom);\r
+\r
+ show_tab_panel(hwnd,\r
+ node,\r
+ lpnm->hwndFrom,\r
+ i,\r
+ TRUE);\r
+ break;\r
+ }\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+typedef struct tag_ident_props {\r
+ BOOL monitor;\r
+ BOOL auto_renew;\r
+ BOOL sticky;\r
+} ident_props;\r
+\r
+typedef struct tag_ident_data {\r
+ khm_handle ident;\r
+ wchar_t * idname;\r
+ int lv_idx;\r
+\r
+ BOOL removed;\r
+ BOOL applied;\r
+\r
+ khm_int32 flags;\r
+\r
+ ident_props saved;\r
+ ident_props work;\r
+\r
+ HWND hwnd;\r
+} ident_data;\r
+\r
+typedef struct tag_idents_data {\r
+ BOOL valid;\r
+\r
+ ident_data * idents;\r
+ khm_size n_idents;\r
+ khm_size nc_idents;\r
+\r
+ int refcount;\r
+\r
+ HIMAGELIST hi_status;\r
+ int idx_id;\r
+ int idx_default;\r
+ int idx_modified;\r
+ int idx_applied;\r
+ int idx_deleted;\r
+\r
+ HWND hwnd;\r
+} idents_data;\r
+\r
+static idents_data cfg_idents = {FALSE, NULL, 0, 0, 0, NULL };\r
+\r
+static void\r
+read_params_ident(ident_data * d) {\r
+ khm_handle csp_ident;\r
+ khm_handle csp_cw;\r
+ khm_int32 t;\r
+\r
+ if (KHM_FAILED(kcdb_identity_get_config(d->ident,\r
+ KHM_PERM_READ,\r
+ &csp_ident))) {\r
+ csp_ident = NULL;\r
+ }\r
+\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ,\r
+ &csp_cw))) {\r
+ if (csp_ident) {\r
+ khc_shadow_space(csp_ident,\r
+ csp_cw);\r
+ khc_close_space(csp_cw);\r
+ } else {\r
+ csp_ident = csp_cw;\r
+ }\r
+ csp_cw = NULL;\r
+ } else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ d->saved.monitor = TRUE;\r
+ d->saved.auto_renew = TRUE;\r
+ d->saved.sticky = FALSE;\r
+ d->work = d->saved;\r
+\r
+ if (csp_ident)\r
+ khc_close_space(csp_ident);\r
+\r
+ return;\r
+ }\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_ident, L"Monitor", &t))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ d->saved.monitor = TRUE;\r
+ } else {\r
+ d->saved.monitor = !!t;\r
+ }\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_ident, L"AllowAutoRenew", &t))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ d->saved.auto_renew = TRUE;\r
+ } else {\r
+ d->saved.auto_renew = !!t;\r
+ }\r
+\r
+ if (KHM_FAILED(khc_read_int32(csp_ident, L"Sticky", &t))) {\r
+ d->saved.sticky = FALSE;\r
+ } else {\r
+ d->saved.sticky = !!t;\r
+ }\r
+\r
+ khc_close_space(csp_ident);\r
+\r
+ d->work = d->saved;\r
+ d->applied = FALSE;\r
+}\r
+\r
+static void\r
+write_params_ident(ident_data * d) {\r
+ khm_handle csp_ident;\r
+\r
+ if (d->saved.monitor == d->work.monitor &&\r
+ d->saved.auto_renew == d->work.auto_renew &&\r
+ d->saved.sticky == d->work.sticky &&\r
+ !d->removed)\r
+ return;\r
+\r
+ if (KHM_FAILED(kcdb_identity_get_config(d->ident, KHM_PERM_WRITE,\r
+ &csp_ident))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ return;\r
+ }\r
+\r
+ if (d->saved.monitor != d->work.monitor)\r
+ khc_write_int32(csp_ident, L"Monitor", !!d->work.monitor);\r
+\r
+ if (d->saved.auto_renew != d->work.auto_renew)\r
+ khc_write_int32(csp_ident, L"AllowAutoRenew", !!d->work.auto_renew);\r
+\r
+ if (d->saved.sticky != d->work.sticky) {\r
+ khc_write_int32(csp_ident, L"Sticky", !!d->work.sticky);\r
+ if (d->work.sticky) {\r
+ kcdb_identity_set_flags(d->ident, KCDB_IDENT_FLAG_STICKY);\r
+ } else {\r
+ kcdb_identity_set_flags(d->ident, \r
+ KCDB_IDENT_FLAG_STICKY |\r
+ KCDB_IDENT_FLAG_INVERT);\r
+ }\r
+ }\r
+\r
+ khc_close_space(csp_ident);\r
+\r
+ d->saved = d->work;\r
+\r
+ d->applied = TRUE;\r
+\r
+ if (d->hwnd)\r
+ PostMessage(d->hwnd, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0);\r
+}\r
+\r
+static void\r
+write_params_idents(void) {\r
+ int i;\r
+\r
+ for (i=0; i < (int)cfg_idents.n_idents; i++) {\r
+ write_params_ident(&cfg_idents.idents[i]);\r
+ }\r
+\r
+ if (cfg_idents.hwnd)\r
+ PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0);\r
+}\r
+\r
+static void\r
+init_idents_data(void) {\r
+ khm_int32 rv;\r
+ wchar_t * t;\r
+ wchar_t * widnames = NULL;\r
+ khm_size cb;\r
+ int n_tries = 0;\r
+ int i;\r
+\r
+ if (cfg_idents.valid)\r
+ return;\r
+\r
+#ifdef DEBUG\r
+ assert(cfg_idents.idents == NULL);\r
+ assert(cfg_idents.n_idents == 0);\r
+ assert(cfg_idents.nc_idents == 0);\r
+#endif\r
+\r
+ do {\r
+ rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,\r
+ KCDB_IDENT_FLAG_CONFIG,\r
+ NULL,\r
+ &cb,\r
+ &cfg_idents.n_idents);\r
+\r
+ if (rv != KHM_ERROR_TOO_LONG ||\r
+ cfg_idents.n_idents == 0 ||\r
+ cb == 0)\r
+ break;\r
+\r
+ if (widnames)\r
+ free(widnames);\r
+ widnames = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(widnames);\r
+#endif\r
+\r
+ rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,\r
+ KCDB_IDENT_FLAG_CONFIG,\r
+ widnames,\r
+ &cb,\r
+ &cfg_idents.n_idents);\r
+ n_tries++;\r
+ } while(KHM_FAILED(rv) &&\r
+ n_tries < 5);\r
+\r
+ if (KHM_FAILED(rv) ||\r
+ cfg_idents.n_idents == 0) {\r
+ cfg_idents.n_idents = 0;\r
+ goto _cleanup;\r
+ }\r
+\r
+ cfg_idents.idents = malloc(sizeof(*cfg_idents.idents) * \r
+ cfg_idents.n_idents);\r
+#ifdef DEBUG\r
+ assert(cfg_idents.idents);\r
+#endif\r
+ ZeroMemory(cfg_idents.idents, \r
+ sizeof(*cfg_idents.idents) * cfg_idents.n_idents);\r
+ cfg_idents.nc_idents = cfg_idents.n_idents;\r
+\r
+ i = 0;\r
+ for (t = widnames; t && *t; t = multi_string_next(t)) {\r
+ khm_handle ident;\r
+\r
+ if (KHM_FAILED(kcdb_identity_create(t, 0, &ident))) {\r
+ cfg_idents.n_idents--;\r
+ continue;\r
+ }\r
+\r
+ StringCbLength(t, KCDB_IDENT_MAXCB_NAME, &cb);\r
+ cb += sizeof(wchar_t);\r
+\r
+ cfg_idents.idents[i].idname = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(cfg_idents.idents[i].idname);\r
+#endif\r
+ StringCbCopy(cfg_idents.idents[i].idname, cb, t);\r
+\r
+ cfg_idents.idents[i].ident = ident;\r
+ cfg_idents.idents[i].removed = FALSE;\r
+\r
+ kcdb_identity_get_flags(ident, &cfg_idents.idents[i].flags);\r
+\r
+ read_params_ident(&cfg_idents.idents[i]);\r
+\r
+ i++;\r
+ /* leave identity held */\r
+ }\r
+\r
+ _cleanup:\r
+\r
+ cfg_idents.valid = TRUE;\r
+\r
+ if (widnames)\r
+ free(widnames);\r
+}\r
+\r
+static void\r
+free_idents_data(void) {\r
+ int i;\r
+\r
+ if (!cfg_idents.valid)\r
+ return;\r
+\r
+ for (i=0; i< (int) cfg_idents.n_idents; i++) {\r
+ if (cfg_idents.idents[i].ident)\r
+ kcdb_identity_release(cfg_idents.idents[i].ident);\r
+ if (cfg_idents.idents[i].idname)\r
+ free(cfg_idents.idents[i].idname);\r
+ }\r
+\r
+ if (cfg_idents.idents)\r
+ free(cfg_idents.idents);\r
+\r
+ cfg_idents.idents = NULL;\r
+ cfg_idents.n_idents = 0;\r
+ cfg_idents.nc_idents = 0;\r
+ cfg_idents.valid = FALSE;\r
+}\r
+\r
+static void\r
+hold_idents_data(void) {\r
+ if (!cfg_idents.valid)\r
+ init_idents_data();\r
+#ifdef DEBUG\r
+ assert(cfg_idents.valid);\r
+#endif\r
+ cfg_idents.refcount++;\r
+}\r
+\r
+static void\r
+release_idents_data(void) {\r
+#ifdef DEBUG\r
+ assert(cfg_idents.valid);\r
+#endif\r
+ cfg_idents.refcount--;\r
+\r
+ if (cfg_idents.refcount == 0)\r
+ free_idents_data();\r
+}\r
+\r
+#define BS_TRUE 1\r
+#define BS_FALSE 2\r
+\r
+static void\r
+refresh_view_idents_sel(HWND hwnd) {\r
+ HWND hw;\r
+ int sel_count;\r
+ int i;\r
+ int idx;\r
+ ident_data * d;\r
+ LVITEM lvi;\r
+\r
+ int monitor = 0;\r
+ int auto_renew = 0;\r
+ int sticky = 0;\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_IDENTS);\r
+\r
+ sel_count = ListView_GetSelectedCount(hw);\r
+\r
+ idx = -1;\r
+ for (i=0; i < sel_count; i++) {\r
+ idx = ListView_GetNextItem(hw, idx, LVNI_SELECTED);\r
+#ifdef DEBUG\r
+ assert(idx != -1);\r
+#endif\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.iItem = idx;\r
+ lvi.iSubItem = 0;\r
+ lvi.mask = LVIF_PARAM;\r
+\r
+ ListView_GetItem(hw, &lvi);\r
+\r
+ d = (ident_data *) lvi.lParam;\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+\r
+ if (d->work.monitor)\r
+ monitor |= BS_TRUE;\r
+ else\r
+ monitor |= BS_FALSE;\r
+\r
+ if (d->work.auto_renew)\r
+ auto_renew |= BS_TRUE;\r
+ else\r
+ auto_renew |= BS_FALSE;\r
+\r
+ if (d->work.sticky)\r
+ sticky |= BS_TRUE;\r
+ else\r
+ sticky |= BS_FALSE;\r
+ }\r
+\r
+ CheckDlgButton(hwnd, IDC_CFG_MONITOR,\r
+ (monitor == BS_TRUE)? BST_CHECKED:\r
+ ((monitor == BS_FALSE)? BST_UNCHECKED:\r
+ BST_INDETERMINATE));\r
+\r
+ CheckDlgButton(hwnd, IDC_CFG_RENEW,\r
+ (auto_renew == BS_TRUE)? BST_CHECKED:\r
+ ((auto_renew == BS_FALSE)? BST_UNCHECKED:\r
+ BST_INDETERMINATE));\r
+\r
+ CheckDlgButton(hwnd, IDC_CFG_STICKY,\r
+ (sticky == BS_TRUE)? BST_CHECKED:\r
+ ((sticky == BS_FALSE)? BST_UNCHECKED:\r
+ BST_INDETERMINATE));\r
+\r
+ if (sel_count > 0) {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), TRUE);\r
+ } else {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), FALSE);\r
+ }\r
+}\r
+\r
+#undef BS_TRUE\r
+#undef BS_FALSE\r
+\r
+static void\r
+refresh_data_idents(HWND hwnd) {\r
+ HWND hw;\r
+ int sel_count;\r
+ int i;\r
+ int idx;\r
+ ident_data * d;\r
+ LVITEM lvi;\r
+\r
+ UINT monitor = IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR);\r
+ UINT auto_renew = IsDlgButtonChecked(hwnd, IDC_CFG_RENEW);\r
+ UINT sticky = IsDlgButtonChecked(hwnd, IDC_CFG_STICKY);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_IDENTS);\r
+\r
+ sel_count = ListView_GetSelectedCount(hw);\r
+\r
+ idx = -1;\r
+ for (i=0; i < sel_count; i++) {\r
+ idx = ListView_GetNextItem(hw, idx, LVNI_SELECTED);\r
+#ifdef DEBUG\r
+ assert(idx != -1);\r
+#endif\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.iItem = idx;\r
+ lvi.iSubItem = 0;\r
+ lvi.mask = LVIF_PARAM;\r
+\r
+ ListView_GetItem(hw, &lvi);\r
+\r
+ d = (ident_data *) lvi.lParam;\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+\r
+ if (monitor == BST_CHECKED)\r
+ d->work.monitor = TRUE;\r
+ else if (monitor == BST_UNCHECKED)\r
+ d->work.monitor = FALSE;\r
+\r
+ if (auto_renew == BST_CHECKED)\r
+ d->work.auto_renew = TRUE;\r
+ else if (auto_renew == BST_UNCHECKED)\r
+ d->work.auto_renew = FALSE;\r
+\r
+ if (sticky == BST_CHECKED)\r
+ d->work.sticky = TRUE;\r
+ else if (sticky == BST_UNCHECKED)\r
+ d->work.sticky = FALSE;\r
+\r
+ if (d->hwnd)\r
+ PostMessage(d->hwnd, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0);\r
+ }\r
+}\r
+\r
+static void\r
+refresh_view_idents_state(HWND hwnd) {\r
+ HWND hw;\r
+ int i;\r
+ LVITEM lvi;\r
+ ident_data * d;\r
+\r
+ BOOL modified = FALSE;\r
+ BOOL applied = FALSE;\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_IDENTS);\r
+\r
+ for (i = -1;;) {\r
+\r
+ i = ListView_GetNextItem(hw, i, LVNI_ALL);\r
+ if (i == -1)\r
+ break;\r
+\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+ lvi.iItem = i;\r
+ lvi.iSubItem = 0;\r
+ lvi.mask = LVIF_PARAM;\r
+\r
+ ListView_GetItem(hw, &lvi);\r
+\r
+ d = (ident_data *) lvi.lParam;\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.mask = LVIF_STATE;\r
+ lvi.stateMask = LVIS_STATEIMAGEMASK;\r
+ lvi.iItem = i;\r
+ lvi.iSubItem = 0;\r
+\r
+ if (d->removed) {\r
+ lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_deleted);\r
+ modified = TRUE;\r
+ } else if (d->saved.monitor != d->work.monitor ||\r
+ d->saved.auto_renew != d->work.auto_renew ||\r
+ d->saved.sticky != d->work.sticky) {\r
+ lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_modified);\r
+ modified = TRUE;\r
+ } else if (d->applied) {\r
+ lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_applied);\r
+ applied = TRUE;\r
+ } else {\r
+ lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_default);\r
+ }\r
+\r
+ ListView_SetItem(hw, &lvi);\r
+ }\r
+\r
+ {\r
+ khm_int32 flags = 0;\r
+ khui_config_node node = NULL;\r
+\r
+ if (modified)\r
+ flags |= KHUI_CNFLAG_MODIFIED;\r
+ if (applied)\r
+ flags |= KHUI_CNFLAG_APPLIED;\r
+\r
+ khui_cfg_open(NULL, L"KhmIdentities", &node);\r
+#ifdef DEBUG\r
+ assert(node);\r
+#endif\r
+ khui_cfg_set_flags(node, flags,\r
+ KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED);\r
+ }\r
+}\r
+\r
+static void\r
+remove_idents(HWND hwnd) {\r
+ HWND hw;\r
+ int sel_count;\r
+ int i;\r
+ int idx;\r
+ ident_data * d;\r
+ LVITEM lvi;\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_IDENTS);\r
+\r
+ sel_count = ListView_GetSelectedCount(hw);\r
+\r
+ idx = -1;\r
+ for (i=0; i < sel_count; i++) {\r
+ idx = ListView_GetNextItem(hw, idx, LVNI_SELECTED);\r
+#ifdef DEBUG\r
+ assert(idx != -1);\r
+#endif\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.iItem = idx;\r
+ lvi.iSubItem = 0;\r
+ lvi.mask = LVIF_PARAM;\r
+\r
+ ListView_GetItem(hw, &lvi);\r
+\r
+ d = (ident_data *) lvi.lParam;\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+\r
+ d->removed = TRUE;\r
+ }\r
+}\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_ids_tab_proc(HWND hwnd,\r
+ UINT umsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ switch(umsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ HWND hw;\r
+ HICON hicon;\r
+ LVCOLUMN lvcol;\r
+ LVITEM lvi;\r
+ wchar_t coltext[256];\r
+ RECT r;\r
+ int i;\r
+\r
+ hold_idents_data();\r
+\r
+ cfg_idents.hwnd = hwnd;\r
+\r
+ /* first add the column */\r
+ hw = GetDlgItem(hwnd, IDC_CFG_IDENTS);\r
+\r
+ ZeroMemory(&lvcol, sizeof(lvcol));\r
+ lvcol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;\r
+\r
+ lvcol.fmt = LVCFMT_IMAGE | LVCFMT_LEFT;\r
+\r
+ GetWindowRect(hw, &r);\r
+ lvcol.cx = ((r.right - r.left) * 95) / 100;\r
+\r
+ LoadString(khm_hInstance, IDS_CFG_IDS_IDENTITY,\r
+ coltext, ARRAYLENGTH(coltext));\r
+ lvcol.pszText = coltext;\r
+\r
+ ListView_InsertColumn(hw, 0, &lvcol);\r
+\r
+ /* and the status icons */\r
+ if (cfg_idents.hi_status)\r
+ goto _done_with_icons;\r
+\r
+ cfg_idents.hi_status = ImageList_Create(SM_CXICON, SM_CYICON, \r
+ ILC_COLOR8 | ILC_MASK,\r
+ 4,4);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_ID),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ cfg_idents.idx_id = ImageList_AddIcon(cfg_idents.hi_status,\r
+ hicon);\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ cfg_idents.idx_default = ImageList_AddIcon(cfg_idents.hi_status, \r
+ hicon) + 1;\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ cfg_idents.idx_modified = ImageList_AddIcon(cfg_idents.hi_status, \r
+ hicon) + 1;\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ cfg_idents.idx_applied = ImageList_AddIcon(cfg_idents.hi_status, \r
+ hicon) + 1;\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DELETED),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ cfg_idents.idx_deleted = ImageList_AddIcon(cfg_idents.hi_status, \r
+ hicon) + 1;\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ ListView_SetImageList(hw, cfg_idents.hi_status, LVSIL_SMALL);\r
+ ListView_SetImageList(hw, cfg_idents.hi_status, LVSIL_STATE);\r
+\r
+ _done_with_icons:\r
+\r
+ /* now add each identity */\r
+ for(i=0; i < (int)cfg_idents.n_idents; i++) {\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;\r
+ lvi.iImage = cfg_idents.idx_id;\r
+ lvi.lParam = (LPARAM) &cfg_idents.idents[i];\r
+ lvi.pszText = cfg_idents.idents[i].idname;\r
+ lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_default);\r
+ lvi.stateMask = LVIS_STATEIMAGEMASK;\r
+\r
+ cfg_idents.idents[i].lv_idx = ListView_InsertItem(hw, &lvi);\r
+ }\r
+\r
+ ListView_SetView(hw, LV_VIEW_DETAILS);\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_NOTIFY:\r
+ {\r
+ LPNMHDR lpnm = (LPNMHDR) lParam;\r
+\r
+ if (lpnm->code == LVN_ITEMCHANGED) {\r
+ refresh_view_idents_sel(hwnd);\r
+ }\r
+ }\r
+ return TRUE;\r
+\r
+ case WM_COMMAND:\r
+\r
+ if (HIWORD(wParam) == BN_CLICKED) {\r
+ UINT ctrl = LOWORD(wParam);\r
+ switch(ctrl) {\r
+ case IDC_CFG_MONITOR:\r
+ case IDC_CFG_RENEW:\r
+ case IDC_CFG_STICKY:\r
+ if (IsDlgButtonChecked(hwnd, ctrl) == BST_CHECKED)\r
+ CheckDlgButton(hwnd, ctrl, BST_UNCHECKED);\r
+ else\r
+ CheckDlgButton(hwnd, ctrl, BST_CHECKED);\r
+ refresh_data_idents(hwnd);\r
+ break;\r
+\r
+ case IDC_CFG_REMOVE:\r
+ remove_idents(hwnd);\r
+ break;\r
+ }\r
+\r
+ refresh_view_idents_state(hwnd);\r
+ }\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+ return TRUE;\r
+\r
+ case KHUI_WM_CFG_NOTIFY:\r
+ {\r
+ switch(HIWORD(wParam)) {\r
+ case WMCFG_APPLY:\r
+ write_params_idents();\r
+ break;\r
+\r
+ case WMCFG_UPDATE_STATE:\r
+ refresh_view_idents_state(hwnd);\r
+ refresh_view_idents_sel(hwnd);\r
+ break;\r
+ }\r
+ }\r
+ return TRUE;\r
+\r
+ case WM_DESTROY:\r
+ cfg_idents.hwnd = NULL;\r
+\r
+ if (cfg_idents.hi_status != NULL) {\r
+ ImageList_Destroy(cfg_idents.hi_status);\r
+ cfg_idents.hi_status = NULL;\r
+ }\r
+ release_idents_data();\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_identities_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ HWND hw;\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ set_window_node(hwnd, (khui_config_node) lParam);\r
+ add_subpanels(hwnd, (khui_config_node) lParam,\r
+ (khui_config_node) lParam);\r
+ hw = GetDlgItem(hwnd, IDC_CFG_TAB);\r
+ show_tab_panel(hwnd,\r
+ (khui_config_node) lParam,\r
+ hw,\r
+ TabCtrl_GetCurSel(hw),\r
+ TRUE);\r
+ return FALSE;\r
+\r
+ case WM_DESTROY:\r
+ return 0;\r
+\r
+ case KHUI_WM_CFG_NOTIFY:\r
+ return handle_cfg_notify(hwnd, wParam, lParam);\r
+\r
+ case WM_NOTIFY:\r
+ return handle_notify(hwnd, wParam, lParam);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+static ident_data *\r
+find_ident_by_node(khui_config_node node) {\r
+ khm_size cb;\r
+ wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
+ int i;\r
+\r
+ cb = sizeof(idname);\r
+ khui_cfg_get_name(node, idname, &cb);\r
+\r
+ for (i=0; i < (int)cfg_idents.n_idents; i++) {\r
+ if (!wcscmp(cfg_idents.idents[i].idname, idname))\r
+ break;\r
+ }\r
+\r
+ if (i < (int)cfg_idents.n_idents)\r
+ return &cfg_idents.idents[i];\r
+ else\r
+ return NULL;\r
+}\r
+\r
+static void\r
+refresh_view_ident(HWND hwnd, khui_config_node node) {\r
+ ident_data * d;\r
+\r
+ d = find_ident_by_node(node);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+\r
+ CheckDlgButton(hwnd, IDC_CFG_MONITOR,\r
+ (d->work.monitor? BST_CHECKED: BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_CFG_RENEW,\r
+ (d->work.auto_renew? BST_CHECKED: BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_CFG_STICKY,\r
+ (d->work.sticky? BST_CHECKED: BST_UNCHECKED));\r
+}\r
+\r
+static void\r
+refresh_data_ident(HWND hwnd, khui_config_init_data * idata) {\r
+ ident_data * d;\r
+\r
+ d = find_ident_by_node(idata->ctx_node);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+\r
+ if (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED)\r
+ d->work.monitor = TRUE;\r
+ else\r
+ d->work.monitor = FALSE;\r
+\r
+ if (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED)\r
+ d->work.auto_renew = TRUE;\r
+ else\r
+ d->work.auto_renew = FALSE;\r
+\r
+ if (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED)\r
+ d->work.sticky = TRUE;\r
+ else\r
+ d->work.sticky = FALSE;\r
+\r
+ if (d->work.monitor != d->saved.monitor ||\r
+ d->work.auto_renew != d->saved.auto_renew ||\r
+ d->work.sticky != d->saved.sticky) {\r
+\r
+ khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED,\r
+ KHUI_CNFLAG_MODIFIED);\r
+\r
+ } else {\r
+ khui_cfg_set_flags_inst(idata, 0,\r
+ KHUI_CNFLAG_MODIFIED);\r
+ }\r
+}\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_id_tab_proc(HWND hwnd,\r
+ UINT umsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ khui_config_init_data * idata;\r
+\r
+ switch(umsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ ident_data * d;\r
+\r
+ hold_idents_data();\r
+\r
+ idata = (khui_config_init_data *) lParam;\r
+\r
+ khui_cfg_init_dialog_data(hwnd, idata, 0, NULL, NULL);\r
+\r
+ refresh_view_ident(hwnd, idata->ctx_node);\r
+\r
+ d = find_ident_by_node(idata->ctx_node);\r
+ if (d)\r
+ d->hwnd = hwnd;\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_COMMAND:\r
+ khui_cfg_get_dialog_data(hwnd, &idata, NULL);\r
+\r
+ if (HIWORD(wParam) == BN_CLICKED) {\r
+ switch(LOWORD(wParam)) {\r
+ case IDC_CFG_MONITOR:\r
+ case IDC_CFG_RENEW:\r
+ case IDC_CFG_STICKY:\r
+\r
+ refresh_data_ident(hwnd, idata);\r
+ if (cfg_idents.hwnd)\r
+ PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0);\r
+ break;\r
+ }\r
+ }\r
+ khm_set_dialog_result(hwnd, 0);\r
+ return TRUE;\r
+\r
+ case WM_DESTROY:\r
+ {\r
+ ident_data * d;\r
+\r
+ khui_cfg_get_dialog_data(hwnd, &idata, NULL);\r
+\r
+ d = find_ident_by_node(idata->ctx_node);\r
+ if (d)\r
+ d->hwnd = NULL;\r
+\r
+ release_idents_data();\r
+ khui_cfg_free_dialog_data(hwnd);\r
+ khm_set_dialog_result(hwnd, 0);\r
+ }\r
+ return TRUE;\r
+\r
+ case KHUI_WM_CFG_NOTIFY:\r
+ {\r
+ ident_data * d;\r
+\r
+ khui_cfg_get_dialog_data(hwnd, &idata, NULL);\r
+\r
+ switch (HIWORD(wParam)) {\r
+ case WMCFG_APPLY:\r
+ d = find_ident_by_node(idata->ctx_node);\r
+ write_params_ident(d);\r
+ khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_APPLIED,\r
+ KHUI_CNFLAG_APPLIED | \r
+ KHUI_CNFLAG_MODIFIED);\r
+ break;\r
+\r
+ case WMCFG_UPDATE_STATE:\r
+ refresh_view_ident(hwnd, idata->ctx_node);\r
+ refresh_data_ident(hwnd, idata);\r
+ break;\r
+ }\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_identity_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ HWND hw;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ khui_config_node refnode = NULL;\r
+\r
+ set_window_node(hwnd, (khui_config_node) lParam);\r
+\r
+ khui_cfg_open(NULL, L"KhmIdentities", &refnode);\r
+#ifdef DEBUG\r
+ assert(refnode != NULL);\r
+#endif\r
+ add_subpanels(hwnd,\r
+ (khui_config_node) lParam,\r
+ refnode);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_TAB);\r
+\r
+ show_tab_panel(hwnd,\r
+ (khui_config_node) lParam,\r
+ hw,\r
+ TabCtrl_GetCurSel(hw),\r
+ TRUE);\r
+\r
+ khui_cfg_release(refnode);\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_DESTROY:\r
+ return 0;\r
+\r
+ case KHUI_WM_CFG_NOTIFY:\r
+ return handle_cfg_notify(hwnd, wParam, lParam);\r
+\r
+ case WM_NOTIFY:\r
+ return handle_notify(hwnd, wParam, lParam);\r
+ }\r
+ return FALSE;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+typedef struct tag_notif_data {\r
+ khui_config_node node;\r
+\r
+ BOOL monitor;\r
+ BOOL renew;\r
+ BOOL warn1;\r
+ BOOL warn2;\r
+\r
+ khui_tracker tc_renew;\r
+ khui_tracker tc_warn1;\r
+ khui_tracker tc_warn2;\r
+} notif_data;\r
+\r
+static void \r
+read_params(notif_data * d) {\r
+ khm_handle csp_cw;\r
+ khm_int32 rv;\r
+ khm_int32 t;\r
+\r
+ rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &csp_cw);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_read_int32(csp_cw, L"Monitor", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->monitor = !!t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"AllowAutoRenew", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->renew = !!t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"AllowWarn", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->warn1 = !!t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"AllowCritical", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->warn2 = !!t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"AutoRenewThreshold", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->tc_renew.current = t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"WarnThreshold", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->tc_warn1.current = t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"CriticalThreshold", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->tc_warn2.current = t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"MaxThreshold", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->tc_renew.max = t;\r
+ d->tc_warn1.max = t;\r
+ d->tc_warn2.max = t;\r
+\r
+ rv = khc_read_int32(csp_cw, L"MinThreshold", &t);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ d->tc_renew.min = t;\r
+ d->tc_warn1.min = t;\r
+ d->tc_warn2.min = t;\r
+\r
+ khc_close_space(csp_cw);\r
+}\r
+\r
+static void\r
+check_for_modification(notif_data * d) {\r
+ notif_data t;\r
+\r
+ ZeroMemory(&t, sizeof(t));\r
+\r
+ read_params(&t);\r
+\r
+ if ((!!d->monitor) != (!!t.monitor) ||\r
+ (!!d->renew) != (!!t.renew) ||\r
+ (!!d->warn1) != (!!t.warn1) ||\r
+ (!!d->warn2) != (!!t.warn2) ||\r
+ d->tc_renew.current != t.tc_renew.current ||\r
+ d->tc_warn1.current != t.tc_warn1.current ||\r
+ d->tc_warn2.current != t.tc_warn2.current) {\r
+\r
+ khui_cfg_set_flags(d->node, \r
+ KHUI_CNFLAG_MODIFIED,\r
+ KHUI_CNFLAG_MODIFIED);\r
+\r
+ } else {\r
+ khui_cfg_set_flags(d->node,\r
+ 0,\r
+ KHUI_CNFLAG_MODIFIED);\r
+ }\r
+}\r
+\r
+static void\r
+write_params(notif_data * d) {\r
+ khm_handle csp_cw;\r
+ khm_int32 rv;\r
+\r
+ rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, &csp_cw);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_int32(csp_cw, L"Monitor", d->monitor);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_int32(csp_cw, L"AllowAutoRenew", d->renew);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_int32(csp_cw, L"AllowWarn", d->warn1);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_int32(csp_cw, L"AllowCritical", d->warn2);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+\r
+ rv = khc_write_int32(csp_cw, L"AutoRenewThreshold", \r
+ (khm_int32) d->tc_renew.current);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_int32(csp_cw, L"WarnThreshold", \r
+ (khm_int32) d->tc_warn1.current);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = khc_write_int32(csp_cw, L"CriticalThreshold", \r
+ (khm_int32) d->tc_warn2.current);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ khc_close_space(csp_cw);\r
+\r
+ khui_cfg_set_flags(d->node,\r
+ KHUI_CNFLAG_APPLIED,\r
+ KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED);\r
+}\r
+\r
+static void\r
+refresh_view(HWND hwnd, notif_data * d) {\r
+ CheckDlgButton(hwnd, IDC_NOTIF_MONITOR, \r
+ (d->monitor?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_NOTIF_RENEW, \r
+ (d->renew?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_NOTIF_WARN1, \r
+ (d->warn1?BST_CHECKED:BST_UNCHECKED));\r
+ CheckDlgButton(hwnd, IDC_NOTIF_WARN2, \r
+ (d->warn2?BST_CHECKED:BST_UNCHECKED));\r
+ khui_tracker_refresh(&d->tc_renew);\r
+ khui_tracker_refresh(&d->tc_warn1);\r
+ khui_tracker_refresh(&d->tc_warn2);\r
+ if (!d->monitor) {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), FALSE);\r
+ } else {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW), TRUE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1), TRUE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2), TRUE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR), !!(d->renew));\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), !!(d->warn1));\r
+ EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), !!(d->warn2));\r
+ }\r
+}\r
+\r
+static void\r
+refresh_data(HWND hwnd, notif_data * d) {\r
+ d->monitor = (IsDlgButtonChecked(hwnd, IDC_NOTIF_MONITOR)\r
+ == BST_CHECKED);\r
+ d->renew = (IsDlgButtonChecked(hwnd, IDC_NOTIF_RENEW)\r
+ == BST_CHECKED);\r
+ d->warn1 = (IsDlgButtonChecked(hwnd, IDC_NOTIF_WARN1)\r
+ == BST_CHECKED);\r
+ d->warn2 = (IsDlgButtonChecked(hwnd, IDC_NOTIF_WARN2)\r
+ == BST_CHECKED);\r
+\r
+ check_for_modification(d);\r
+}\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_notifications_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ notif_data * d;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG: {\r
+ HWND hw;\r
+\r
+ d = malloc(sizeof(*d));\r
+#ifdef DEBUG\r
+ assert(d != NULL);\r
+#endif\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ d->node = (khui_config_node) lParam;\r
+\r
+ khui_tracker_initialize(&d->tc_renew);\r
+ khui_tracker_initialize(&d->tc_warn1);\r
+ khui_tracker_initialize(&d->tc_warn2);\r
+\r
+ read_params(d);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR);\r
+ khui_tracker_install(hw, &d->tc_renew);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR);\r
+ khui_tracker_install(hw, &d->tc_warn1);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR);\r
+ khui_tracker_install(hw, &d->tc_warn2);\r
+\r
+ refresh_view(hwnd, d);\r
+\r
+ /* normally we should return TRUE, but in this case we return\r
+ FALSE since we don't want to inadvertently steal the focus\r
+ from the treeview. */\r
+ return FALSE;\r
+ }\r
+\r
+ case WM_COMMAND: {\r
+ d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (HIWORD(wParam) == BN_CLICKED) {\r
+ refresh_data(hwnd, d);\r
+ refresh_view(hwnd, d);\r
+\r
+ check_for_modification(d);\r
+ } else if (HIWORD(wParam) == EN_CHANGE) {\r
+ SetTimer(hwnd, 1, 500, NULL);\r
+ }\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ case WM_TIMER: {\r
+ d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+ KillTimer(hwnd, 1);\r
+ check_for_modification(d);\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ case WM_DESTROY: {\r
+ d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ khui_tracker_kill_controls(&d->tc_renew);\r
+ khui_tracker_kill_controls(&d->tc_warn1);\r
+ khui_tracker_kill_controls(&d->tc_warn2);\r
+\r
+ free(d);\r
+\r
+ SetWindowLongPtr(hwnd, DWLP_USER, 0);\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ case KHUI_WM_CFG_NOTIFY: {\r
+ d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (HIWORD(wParam) == WMCFG_APPLY) {\r
+ write_params(d);\r
+ }\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ }\r
+\r
+ return FALSE;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+#define MAX_PLUGINS 256\r
+\r
+typedef struct tag_plugin_data {\r
+ kmm_plugin_info plugin;\r
+ kmm_module_info module;\r
+} plugin_data;\r
+\r
+typedef struct tag_plugin_dlg_data {\r
+ plugin_data * info[MAX_PLUGINS];\r
+ khm_size n_info;\r
+} plugin_dlg_data;\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_plugins_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ plugin_dlg_data * d;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ kmm_plugin p;\r
+ kmm_plugin pn;\r
+ kmm_module m;\r
+ khm_size i;\r
+ LVCOLUMN lvc;\r
+ RECT r;\r
+ HWND hw;\r
+ wchar_t buf[256];\r
+\r
+\r
+ d = malloc(sizeof(*d));\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ ZeroMemory(d, sizeof(*d));\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ p = NULL;\r
+ i = 0;\r
+ do {\r
+ if (KHM_FAILED(kmm_get_next_plugin(p, &pn)))\r
+ break;\r
+\r
+ if (p)\r
+ kmm_release_plugin(p);\r
+ p = pn;\r
+\r
+#ifdef DEBUG\r
+ assert(d->info[i] == NULL);\r
+#endif\r
+ d->info[i] = malloc(sizeof(*(d->info[i])));\r
+#ifdef DEBUG\r
+ assert(d->info[i]);\r
+#endif\r
+\r
+ if (KHM_FAILED(kmm_get_plugin_info_i(p, &d->info[i]->plugin))) {\r
+ free(d->info[i]);\r
+ d->info[i] = NULL;\r
+ break;\r
+ }\r
+\r
+ ZeroMemory(&d->info[i]->module,\r
+ sizeof(d->info[i]->module));\r
+\r
+ if (KHM_SUCCEEDED(kmm_load_module(d->info[i]->plugin.reg.module,\r
+ KMM_LM_FLAG_NOLOAD,\r
+ &m))) {\r
+ kmm_get_module_info_i(m, &d->info[i]->module);\r
+ kmm_release_module(m);\r
+ }\r
+\r
+ i ++;\r
+\r
+ if (i == MAX_PLUGINS)\r
+ break;\r
+ } while(p);\r
+\r
+ if (p)\r
+ kmm_release_plugin(p);\r
+\r
+ d->n_info = i;\r
+\r
+ /* now populate the list view */\r
+ hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ ListView_SetView(hw, LV_VIEW_DETAILS);\r
+\r
+ ZeroMemory(&lvc, sizeof(lvc));\r
+\r
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;\r
+ GetWindowRect(hw, &r);\r
+ lvc.cx = ((r.right - r.left) * 95) / 100;\r
+ lvc.pszText = buf;\r
+\r
+ LoadString(khm_hInstance, IDS_CFG_PI_COL_PLUGINS,\r
+ buf, ARRAYLENGTH(buf));\r
+\r
+ ListView_InsertColumn(hw, 0, &lvc);\r
+\r
+ for(i=0; i<d->n_info; i++) {\r
+ LVITEM lvi;\r
+\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+\r
+ lvi.mask = LVIF_PARAM | LVIF_TEXT;\r
+ lvi.lParam = (LPARAM) d->info[i];\r
+ lvi.pszText = d->info[i]->plugin.reg.name;\r
+\r
+ ListView_InsertItem(hw, &lvi);\r
+ }\r
+ }\r
+ return FALSE;\r
+\r
+ case WM_NOTIFY:\r
+ {\r
+ LPNMHDR lpnm;\r
+ HWND hw;\r
+\r
+ d = (plugin_dlg_data *) (LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (wParam == IDC_CFG_PLUGINS &&\r
+ (lpnm = (LPNMHDR) lParam) &&\r
+ lpnm->code == LVN_ITEMCHANGED) {\r
+\r
+ LVITEM lvi;\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ if (ListView_GetSelectedCount(hw) != 1) {\r
+ SetDlgItemText(hwnd, IDC_CFG_DESC, L"");\r
+ SetDlgItemText(hwnd, IDC_CFG_STATE, L"");\r
+ SetDlgItemText(hwnd, IDC_CFG_MODULE, L"");\r
+ SetDlgItemText(hwnd, IDC_CFG_VENDOR, L"");\r
+ EnableWindow(GetDlgItem(hwnd, IDC_CFG_ENABLE), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDC_CFG_DISABLE), FALSE);\r
+ SendDlgItemMessage(hwnd, IDC_CFG_DEPS, \r
+ LB_RESETCONTENT, 0, 0);\r
+ } else {\r
+ int idx;\r
+ plugin_data * info;\r
+ wchar_t buf[256];\r
+ UINT resid;\r
+ wchar_t * t;\r
+\r
+ idx = ListView_GetNextItem(hw, -1, LVNI_SELECTED);\r
+#ifdef DEBUG\r
+ assert(idx != -1);\r
+#endif\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+ lvi.iItem = idx;\r
+ lvi.iSubItem = 0;\r
+ lvi.mask = LVIF_PARAM;\r
+\r
+ ListView_GetItem(hw, &lvi);\r
+#ifdef DEBUG\r
+ assert(lvi.lParam != 0);\r
+#endif\r
+ info = (plugin_data *) lvi.lParam;\r
+\r
+ if (info->plugin.reg.description)\r
+ SetDlgItemText(hwnd, IDC_CFG_DESC, info->plugin.reg.description);\r
+ else\r
+ SetDlgItemText(hwnd, IDC_CFG_DESC, L"");\r
+\r
+ switch(info->plugin.state) {\r
+ case KMM_PLUGIN_STATE_FAIL_UNKNOWN:\r
+ resid = IDS_PISTATE_FAILUNK;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_FAIL_MAX_FAILURE:\r
+ resid = IDS_PISTATE_FAILMAX;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED:\r
+ resid = IDS_PISTATE_FAILREG;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_FAIL_DISABLED:\r
+ resid = IDS_PISTATE_FAILDIS;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_FAIL_LOAD:\r
+ resid = IDS_PISTATE_FAILLOD;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_NONE:\r
+ case KMM_PLUGIN_STATE_PLACEHOLDER:\r
+ resid = IDS_PISTATE_PLACEHOLD;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_REG:\r
+ case KMM_PLUGIN_STATE_PREINIT:\r
+ resid = IDS_PISTATE_REG;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_HOLD:\r
+ resid = IDS_PISTATE_HOLD;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_INIT:\r
+ resid = IDS_PISTATE_INIT;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_RUNNING:\r
+ resid = IDS_PISTATE_RUN;\r
+ break;\r
+\r
+ case KMM_PLUGIN_STATE_EXITED:\r
+ resid = IDS_PISTATE_EXIT;\r
+ break;\r
+\r
+ default:\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ resid = IDS_PISTATE_FAILUNK;\r
+ }\r
+\r
+ LoadString(khm_hInstance, resid,\r
+ buf, ARRAYLENGTH(buf));\r
+\r
+ SetDlgItemText(hwnd, IDC_CFG_STATE, buf);\r
+\r
+ SendDlgItemMessage(hwnd, IDC_CFG_DEPS,\r
+ LB_RESETCONTENT, 0, 0);\r
+\r
+ for (t = info->plugin.reg.dependencies; t && *t;\r
+ t = multi_string_next(t)) {\r
+ SendDlgItemMessage(hwnd, IDC_CFG_DEPS,\r
+ LB_INSERTSTRING,\r
+ -1,\r
+ (LPARAM) t);\r
+ }\r
+\r
+ if (info->plugin.reg.module)\r
+ SetDlgItemText(hwnd, IDC_CFG_MODULE,\r
+ info->plugin.reg.module);\r
+ else\r
+ SetDlgItemText(hwnd, IDC_CFG_MODULE,\r
+ L"");\r
+\r
+ if (info->module.reg.vendor)\r
+ SetDlgItemText(hwnd, IDC_CFG_VENDOR,\r
+ info->module.reg.vendor);\r
+ else\r
+ SetDlgItemText(hwnd, IDC_CFG_VENDOR,\r
+ L"");\r
+ }\r
+ }\r
+ }\r
+ return TRUE;\r
+\r
+ case WM_DESTROY:\r
+ {\r
+ khm_size i;\r
+\r
+ d = (plugin_dlg_data *) (LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ for (i=0; i<d->n_info; i++) {\r
+#ifdef DEBUG\r
+ assert(d->info[i]);\r
+#endif\r
+ kmm_release_plugin_info_i(&d->info[i]->plugin);\r
+ kmm_release_module_info_i(&d->info[i]->module);\r
+ free(d->info[i]);\r
+ }\r
+\r
+ free(d);\r
+\r
+ khm_set_dialog_result(hwnd, 0);\r
+ }\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+static HWND cfgui_hwnd = NULL;\r
+\r
+typedef struct tag_cfgui_wnd_data {\r
+ khui_config_node current;\r
+ HWND hw_current;\r
+ HWND hw_generic_pane;\r
+ HBRUSH hbr_white;\r
+ HFONT hf_title;\r
+ khui_bitmap kbmp_logo;\r
+ HIMAGELIST hi_status;\r
+ BOOL modified;\r
+ int idx_default;\r
+ int idx_modified;\r
+ int idx_applied;\r
+} cfgui_wnd_data;\r
+\r
+static cfgui_wnd_data *\r
+cfgui_get_wnd_data(HWND hwnd) {\r
+ return (cfgui_wnd_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+}\r
+\r
+static void\r
+cfgui_set_wnd_data(HWND hwnd, cfgui_wnd_data * d) {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+}\r
+\r
+static void\r
+cfgui_add_node(cfgui_wnd_data * d,\r
+ HWND hwtv,\r
+ khui_config_node node,\r
+ khui_config_node parent,\r
+ BOOL sorted) {\r
+\r
+ khui_config_node_reg reg;\r
+ khui_config_node c;\r
+ wchar_t wbuf[256];\r
+ const wchar_t * short_desc;\r
+ TVINSERTSTRUCT s;\r
+ HTREEITEM hItem;\r
+\r
+ if (node) {\r
+ khui_cfg_get_reg(node, ®);\r
+ short_desc = reg.short_desc;\r
+ } else {\r
+ short_desc = wbuf;\r
+ LoadString(khm_hInstance, IDS_CFG_ROOT_NAME,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+ reg.flags = 0;\r
+ }\r
+\r
+ ZeroMemory(&s, sizeof(s));\r
+\r
+ s.hParent = (node)?\r
+ (HTREEITEM) khui_cfg_get_param(parent):\r
+ TVI_ROOT;\r
+\r
+ s.hInsertAfter = (sorted)? TVI_SORT: TVI_FIRST;\r
+\r
+ s.itemex.mask =\r
+ TVIF_CHILDREN |\r
+ TVIF_PARAM |\r
+ TVIF_TEXT |\r
+ TVIF_STATE;\r
+\r
+ {\r
+ khui_config_node n;\r
+\r
+ if (KHM_SUCCEEDED(khui_cfg_get_first_child(node,\r
+ &n))) {\r
+ s.itemex.cChildren = 1;\r
+ s.itemex.state = TVIS_EXPANDED;\r
+ s.itemex.stateMask = TVIS_EXPANDED;\r
+ khui_cfg_release(n);\r
+ } else {\r
+ s.itemex.cChildren = 0;\r
+ s.itemex.state = 0;\r
+ s.itemex.stateMask = TVIS_EXPANDED;\r
+ }\r
+\r
+ s.itemex.state |= INDEXTOSTATEIMAGEMASK(d->idx_default);\r
+ s.itemex.stateMask |= TVIS_STATEIMAGEMASK;\r
+ }\r
+\r
+ s.itemex.lParam = (LPARAM) node;\r
+ khui_cfg_hold(node);\r
+\r
+ s.itemex.pszText = (LPWSTR) short_desc;\r
+\r
+ hItem = TreeView_InsertItem(hwtv, &s);\r
+\r
+ khui_cfg_set_param(node, (LPARAM) hItem);\r
+\r
+ if (KHM_SUCCEEDED(khui_cfg_get_first_child(node,\r
+ &c))) {\r
+ do {\r
+ cfgui_add_node(d, hwtv, c, node,\r
+ !!(reg.flags & KHUI_CNFLAG_SORT_CHILDREN));\r
+ } while (KHM_SUCCEEDED(khui_cfg_get_next_release(&c)));\r
+ }\r
+}\r
+\r
+static void \r
+cfgui_initialize_dialog(HWND hwnd) {\r
+ cfgui_wnd_data * d;\r
+ HWND hwtv;\r
+ HWND hwtitle;\r
+ HFONT hf;\r
+ HDC hdc;\r
+ HICON hicon;\r
+\r
+ d = cfgui_get_wnd_data(hwnd);\r
+\r
+ /* create and fill the image list for the treeview */\r
+\r
+ d->hi_status = ImageList_Create(SM_CXICON, SM_CYICON, \r
+ ILC_COLOR8 | ILC_MASK,\r
+ 4,4);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ /* note that we can't use index 0 because that is used to indicate\r
+ that there is no state image for the node */\r
+ do {\r
+ d->idx_default = ImageList_AddIcon(d->hi_status, hicon);\r
+ } while(d->idx_default == 0);\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ d->idx_modified = ImageList_AddIcon(d->hi_status, hicon);\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED),\r
+ IMAGE_ICON, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR);\r
+\r
+ d->idx_applied = ImageList_AddIcon(d->hi_status, hicon);\r
+\r
+ DestroyIcon(hicon);\r
+\r
+ /* now for the treeview */\r
+ hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST);\r
+\r
+ TreeView_SetImageList(hwtv, d->hi_status, TVSIL_STATE);\r
+\r
+ cfgui_add_node(d, hwtv, NULL, NULL, FALSE);\r
+\r
+ hdc = GetDC(hwnd);\r
+ hf = CreateFont(-MulDiv(12, \r
+ GetDeviceCaps(hdc, LOGPIXELSY), \r
+ 72),\r
+ 0, /* nWidth */\r
+ 0, /* nEscapement */\r
+ 0, /* nOrientation */\r
+ FW_BOLD, /* fnWeight */\r
+ TRUE, /* fdwItalic */\r
+ FALSE, /* fdwUnderline */\r
+ FALSE, /* fdwStrikeOut */\r
+ DEFAULT_CHARSET, /* fdwCharSet */\r
+ OUT_DEFAULT_PRECIS, /* fdwOutputPrecision */\r
+ CLIP_DEFAULT_PRECIS, /* fdwClipPrecision */\r
+ DEFAULT_QUALITY, /* fdwQuality */\r
+ FF_SWISS | DEFAULT_PITCH, /* pitch&family */\r
+ NULL); /* face */\r
+ ReleaseDC(hwnd, hdc);\r
+\r
+ d->hf_title = hf;\r
+\r
+ hwtitle = GetDlgItem(hwnd, IDC_CFG_TITLE);\r
+\r
+ SendMessage(hwtitle,\r
+ WM_SETFONT,\r
+ (WPARAM) hf,\r
+ (LPARAM) FALSE);\r
+}\r
+\r
+static void\r
+cfgui_free_node(HWND hwtv, HTREEITEM hItem) {\r
+ TVITEMEX iex;\r
+ HTREEITEM hChItem;\r
+\r
+ ZeroMemory(&iex, sizeof(iex));\r
+\r
+ iex.mask = TVIF_PARAM;\r
+ iex.hItem = hItem;\r
+\r
+ if (TreeView_GetItem(hwtv, &iex)) {\r
+ khui_config_node node;\r
+\r
+ node = (khui_config_node) iex.lParam;\r
+ khui_cfg_release(node);\r
+ }\r
+\r
+ hChItem = TreeView_GetChild(hwtv, hItem);\r
+ while(hChItem) {\r
+ cfgui_free_node(hwtv, hChItem);\r
+\r
+ hChItem = TreeView_GetNextSibling(hwtv, hChItem);\r
+ }\r
+}\r
+\r
+static void\r
+cfgui_uninitialize_dialog(HWND hwnd) {\r
+ cfgui_wnd_data * d;\r
+ HWND hwtv;\r
+\r
+ d = cfgui_get_wnd_data(hwnd);\r
+\r
+ hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST);\r
+\r
+ cfgui_free_node(hwtv, TreeView_GetRoot(hwtv));\r
+\r
+ if (d->hf_title)\r
+ DeleteObject(d->hf_title);\r
+\r
+ if (d->hi_status)\r
+ ImageList_Destroy(d->hi_status);\r
+}\r
+\r
+static void\r
+cfgui_activate_node(HWND hwnd, khui_config_node node) {\r
+\r
+ cfgui_wnd_data * d;\r
+ HTREEITEM hItem;\r
+ HWND hw_new;\r
+ HWND hwtv;\r
+\r
+ d = cfgui_get_wnd_data(hwnd);\r
+ hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST);\r
+ hItem = (HTREEITEM) khui_cfg_get_param(node);\r
+\r
+#ifdef DEBUG\r
+ assert(hItem);\r
+ assert(hwtv);\r
+#endif\r
+\r
+ if (node == NULL) {\r
+ hw_new = d->hw_generic_pane;\r
+ } else {\r
+ khui_config_node_reg reg;\r
+ khm_int32 rv;\r
+\r
+ hw_new = khui_cfg_get_hwnd(node);\r
+\r
+ if (hw_new == NULL) {\r
+ rv = khui_cfg_get_reg(node, ®);\r
+#ifdef DEBUG\r
+ assert(KHM_SUCCEEDED(rv));\r
+#endif\r
+ hw_new = CreateDialogParam(reg.h_module,\r
+ reg.dlg_template,\r
+ hwnd,\r
+ reg.dlg_proc,\r
+ (LPARAM) node);\r
+#ifdef DEBUG\r
+ assert(hw_new);\r
+#endif\r
+ khui_cfg_set_hwnd(node, hw_new);\r
+ }\r
+ }\r
+\r
+ if (hw_new == d->hw_current)\r
+ return; /* nothing to do */\r
+\r
+ {\r
+ RECT r_title;\r
+ RECT r_pane;\r
+ HWND hw;\r
+\r
+ if (d->hw_current)\r
+ ShowWindow(d->hw_current, SW_HIDE);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_TITLE);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r_title);\r
+\r
+ hw = GetDlgItem(hwnd, IDC_CFG_PANE);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r_pane);\r
+\r
+ OffsetRect(&r_pane, -r_title.left, -r_title.top);\r
+\r
+ SetWindowPos(hw_new,\r
+ hwtv,\r
+ r_pane.left, r_pane.top,\r
+ r_pane.right - r_pane.left,\r
+ r_pane.bottom - r_pane.top,\r
+ SWP_NOOWNERZORDER |\r
+ SWP_SHOWWINDOW |\r
+ SWP_NOACTIVATE);\r
+ }\r
+\r
+ if (node == NULL) {\r
+ wchar_t wbuf[256];\r
+\r
+ LoadString(khm_hInstance, IDS_CFG_ROOT_TITLE,\r
+ wbuf, ARRAYLENGTH(wbuf));\r
+\r
+ SetDlgItemText(hwnd, IDC_CFG_TITLE, wbuf);\r
+ } else {\r
+ khm_int32 rv;\r
+ khui_config_node_reg reg;\r
+\r
+ rv = khui_cfg_get_reg(node, ®);\r
+#ifdef DEBUG\r
+ assert(KHM_SUCCEEDED(rv));\r
+#endif\r
+ SetDlgItemText(hwnd, IDC_CFG_TITLE, reg.long_desc);\r
+ }\r
+\r
+ d->hw_current = hw_new;\r
+ d->current = node;\r
+\r
+ TreeView_SelectItem(hwtv, hItem);\r
+}\r
+\r
+static BOOL\r
+cfgui_check_mod_state(khui_config_node node) {\r
+ khm_int32 flags;\r
+ khui_config_node c = NULL;\r
+ BOOL rv = FALSE;\r
+\r
+ flags = khui_cfg_get_flags(node);\r
+\r
+ if (flags & KHUI_CNFLAG_MODIFIED)\r
+ return TRUE;\r
+\r
+ if (KHM_FAILED(khui_cfg_get_first_child(node, &c)))\r
+ return FALSE;\r
+\r
+ while(c) {\r
+ rv = (rv || cfgui_check_mod_state(c));\r
+ khui_cfg_get_next_release(&c);\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+static void\r
+cfgui_apply_settings(khui_config_node node) {\r
+ HWND hwnd;\r
+ khui_config_node c;\r
+\r
+ hwnd = khui_cfg_get_hwnd(node);\r
+\r
+ if (hwnd)\r
+ SendMessage(hwnd, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(0, WMCFG_APPLY),\r
+ (LPARAM) node);\r
+\r
+ if (KHM_FAILED(khui_cfg_get_first_child(node, &c)))\r
+ return;\r
+\r
+ while (c) {\r
+ cfgui_apply_settings(c);\r
+ khui_cfg_get_next_release(&c);\r
+ }\r
+}\r
+\r
+static void\r
+cfgui_update_state(HWND hwnd, \r
+ khm_int32 flags,\r
+ khui_config_node node) {\r
+ cfgui_wnd_data * d;\r
+ HWND hwtv;\r
+ HTREEITEM hItem;\r
+ TVITEMEX itx;\r
+ int idx;\r
+\r
+ d = cfgui_get_wnd_data(hwnd);\r
+ hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST);\r
+ hItem = (HTREEITEM) khui_cfg_get_param(node);\r
+\r
+ ZeroMemory(&itx, sizeof(itx));\r
+\r
+ if (flags & KHUI_CNFLAG_MODIFIED)\r
+ idx = d->idx_modified;\r
+ else if (flags & KHUI_CNFLAG_APPLIED)\r
+ idx = d->idx_applied;\r
+ else\r
+ idx = d->idx_default;\r
+\r
+ itx.hItem = hItem;\r
+ itx.mask = TVIF_STATE;\r
+ itx.state = INDEXTOSTATEIMAGEMASK(idx);\r
+ itx.stateMask = TVIS_STATEIMAGEMASK;\r
+\r
+ TreeView_SetItem(hwtv, &itx);\r
+\r
+ if(cfgui_check_mod_state(NULL)) {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), TRUE);\r
+ EnableWindow(GetDlgItem(hwnd, IDAPPLY), TRUE);\r
+ } else {\r
+ EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), FALSE);\r
+ EnableWindow(GetDlgItem(hwnd, IDAPPLY), FALSE);\r
+ }\r
+}\r
+\r
+\r
+/* dialog procedure for the generic dialog */\r
+static INT_PTR CALLBACK\r
+cfgui_dlgproc_generic(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ cfgui_wnd_data * d;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ d = (cfgui_wnd_data *) lParam;\r
+ cfgui_set_wnd_data(hwnd, d);\r
+ return TRUE;\r
+\r
+ case WM_CTLCOLORSTATIC:\r
+ d = cfgui_get_wnd_data(hwnd);\r
+ return (BOOL)(DWORD_PTR) d->hbr_white;\r
+\r
+ case WM_ERASEBKGND:\r
+ {\r
+ HDC hdc = (HDC) wParam;\r
+ RECT r_client;\r
+ RECT r_logo;\r
+ RECT r_fill;\r
+\r
+ d = cfgui_get_wnd_data(hwnd);\r
+\r
+ GetClientRect(hwnd, &r_client);\r
+ SetRectEmpty(&r_logo);\r
+\r
+ r_logo.right = d->kbmp_logo.cx;\r
+ r_logo.bottom = d->kbmp_logo.cy;\r
+\r
+ OffsetRect(&r_logo,\r
+ r_client.right - r_logo.right,\r
+ r_client.bottom - r_logo.bottom);\r
+\r
+ khui_draw_bitmap(hdc,\r
+ r_logo.left,\r
+ r_logo.top,\r
+ &d->kbmp_logo);\r
+\r
+ r_fill.left = 0;\r
+ r_fill.top = 0;\r
+ r_fill.right = r_logo.left;\r
+ r_fill.bottom = r_client.bottom;\r
+ FillRect(hdc, &r_fill, d->hbr_white);\r
+\r
+ r_fill.left = r_logo.left;\r
+ r_fill.right = r_client.right;\r
+ r_fill.bottom = r_logo.top;\r
+ FillRect(hdc, &r_fill, d->hbr_white);\r
+\r
+ SetWindowLong(hwnd, DWL_MSGRESULT, (LONG) TRUE);\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+static INT_PTR CALLBACK \r
+cfgui_dlgproc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ khui_config_node node;\r
+ cfgui_wnd_data * d;\r
+\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ node = (khui_config_node) lParam;\r
+\r
+ khui_cfg_clear_params();\r
+\r
+ d = malloc(sizeof(*d));\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ d->hbr_white = CreateSolidBrush(RGB(255,255,255));\r
+\r
+ d->hw_generic_pane = \r
+ CreateDialogParam(khm_hInstance,\r
+ MAKEINTRESOURCE(IDD_CFG_GENERIC),\r
+ hwnd,\r
+ cfgui_dlgproc_generic,\r
+ (LPARAM) d);\r
+\r
+ khui_bitmap_from_hbmp(&d->kbmp_logo,\r
+ LoadImage(\r
+ khm_hInstance,\r
+ MAKEINTRESOURCE(IDB_LOGO_OPAQUE),\r
+ IMAGE_BITMAP,\r
+ 0,\r
+ 0,\r
+ LR_DEFAULTCOLOR));\r
+\r
+ cfgui_set_wnd_data(hwnd, d);\r
+\r
+ cfgui_initialize_dialog(hwnd);\r
+\r
+ cfgui_activate_node(hwnd, node);\r
+\r
+ khm_add_dialog(hwnd);\r
+ khm_enter_modal(hwnd);\r
+\r
+ khui_cfg_set_configui_handle(hwnd);\r
+\r
+ return TRUE;\r
+\r
+ case WM_DESTROY:\r
+ cfgui_hwnd = NULL;\r
+\r
+ khui_cfg_set_configui_handle(NULL);\r
+\r
+ cfgui_uninitialize_dialog(hwnd);\r
+\r
+ d = cfgui_get_wnd_data(hwnd);\r
+ khui_delete_bitmap(&d->kbmp_logo);\r
+ DeleteObject(d->hbr_white);\r
+\r
+ khm_leave_modal();\r
+ khm_del_dialog(hwnd);\r
+\r
+ SetForegroundWindow(khm_hwnd_main);\r
+\r
+ return FALSE;\r
+\r
+ case WM_NOTIFY:\r
+ {\r
+ LPNMHDR lpnm;\r
+ LPNMTREEVIEW lptv;\r
+\r
+ lpnm = (LPNMHDR) lParam;\r
+\r
+ switch (lpnm->code) {\r
+ case TVN_SELCHANGED:\r
+ lptv = (LPNMTREEVIEW) lParam;\r
+ cfgui_activate_node(hwnd,\r
+ (khui_config_node) \r
+ lptv->itemNew.lParam);\r
+ return TRUE;\r
+ }\r
+ }\r
+ return TRUE;\r
+\r
+ case WM_CTLCOLORSTATIC:\r
+ {\r
+ d = cfgui_get_wnd_data(hwnd);\r
+ return (BOOL)(DWORD_PTR) d->hbr_white;\r
+ }\r
+ /* implicit break */\r
+\r
+ case WM_COMMAND:\r
+ switch(wParam) {\r
+ case MAKEWPARAM(IDCANCEL, BN_CLICKED):\r
+ DestroyWindow(hwnd);\r
+ break;\r
+\r
+ case MAKEWPARAM(IDAPPLY, BN_CLICKED):\r
+ cfgui_apply_settings(NULL);\r
+ break;\r
+\r
+ case MAKEWPARAM(IDOK, BN_CLICKED):\r
+ cfgui_apply_settings(NULL);\r
+ DestroyWindow(hwnd);\r
+ break;\r
+ }\r
+ return TRUE;\r
+\r
+ case KHUI_WM_CFG_NOTIFY:\r
+ switch(HIWORD(wParam)) {\r
+ case WMCFG_SHOW_NODE:\r
+ cfgui_activate_node(hwnd, (khui_config_node) lParam);\r
+ break;\r
+\r
+ case WMCFG_UPDATE_STATE:\r
+ cfgui_update_state(hwnd, LOWORD(wParam), \r
+ (khui_config_node) lParam);\r
+ break;\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+static void \r
+cfgui_create_window(khui_config_node node) {\r
+#ifdef DEBUG\r
+ assert(cfgui_hwnd == NULL);\r
+#endif\r
+\r
+ khm_refresh_config();\r
+\r
+ cfgui_hwnd = CreateDialogParam(khm_hInstance,\r
+ MAKEINTRESOURCE(IDD_CFG_MAIN),\r
+ khm_hwnd_main,\r
+ cfgui_dlgproc,\r
+ (LPARAM) node);\r
+#ifdef DEBUG\r
+ assert(cfgui_hwnd != NULL);\r
+#endif\r
+ ShowWindow(cfgui_hwnd,SW_SHOW);\r
+}\r
+\r
+static void \r
+cfgui_destroy_window(void) {\r
+ if (cfgui_hwnd)\r
+ DestroyWindow(cfgui_hwnd);\r
+ /* cfgui_hwnd will be set to NULL in the dialog proc */\r
+}\r
+\r
+void \r
+khm_show_config_pane(khui_config_node node) {\r
+ if (cfgui_hwnd != NULL) {\r
+ SendMessage(cfgui_hwnd, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM(0, WMCFG_SHOW_NODE),\r
+ (LPARAM) node);\r
+ } else {\r
+ cfgui_create_window(node);\r
+ }\r
+}\r
+\r
+void khm_refresh_config(void) {\r
+ khm_size cb;\r
+ khm_size n_idents;\r
+ wchar_t * idents = NULL;\r
+ wchar_t * t;\r
+ khm_int32 rv;\r
+ int n_tries = 0;\r
+ khui_config_node cfg_ids = NULL;\r
+\r
+ do {\r
+ rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,\r
+ KCDB_IDENT_FLAG_CONFIG,\r
+ NULL,\r
+ &cb,\r
+ &n_idents);\r
+\r
+ if (rv != KHM_ERROR_TOO_LONG ||\r
+ n_idents == 0)\r
+ return;\r
+\r
+ if (idents)\r
+ free(idents);\r
+ idents = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(idents);\r
+#endif\r
+\r
+ rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,\r
+ KCDB_IDENT_FLAG_CONFIG,\r
+ idents,\r
+ &cb,\r
+ &n_idents);\r
+\r
+ n_tries++;\r
+ } while(KHM_FAILED(rv) &&\r
+ n_tries < 5);\r
+\r
+ if (KHM_FAILED(rv))\r
+ goto _cleanup;\r
+\r
+ if (KHM_FAILED(khui_cfg_open(NULL,\r
+ L"KhmIdentities",\r
+ &cfg_ids)))\r
+ goto _cleanup;\r
+\r
+ for(t = idents; t && *t; t = multi_string_next(t)) {\r
+ khui_config_node cfg_id = NULL;\r
+\r
+ rv = khui_cfg_open(cfg_ids,\r
+ t,\r
+ &cfg_id);\r
+\r
+ if (KHM_FAILED(rv)) {\r
+ khui_config_node_reg reg;\r
+ wchar_t wshort[KHUI_MAXCCH_SHORT_DESC];\r
+ wchar_t wlong[KHUI_MAXCCH_LONG_DESC];\r
+ wchar_t wfmt[KHUI_MAXCCH_SHORT_DESC];\r
+\r
+ ZeroMemory(®, sizeof(reg));\r
+\r
+ reg.name = t;\r
+ reg.short_desc = wshort;\r
+ reg.long_desc = wlong;\r
+ reg.h_module = khm_hInstance;\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITY);\r
+ reg.dlg_proc = khm_cfg_identity_proc;\r
+ reg.flags = 0;\r
+\r
+ LoadString(khm_hInstance, IDS_CFG_IDENTITY_SHORT,\r
+ wfmt, ARRAYLENGTH(wfmt));\r
+ StringCbPrintf(wshort, sizeof(wshort), wfmt, t);\r
+\r
+ LoadString(khm_hInstance, IDS_CFG_IDENTITY_LONG,\r
+ wfmt, ARRAYLENGTH(wfmt));\r
+ StringCbPrintf(wlong, sizeof(wlong), wfmt, t);\r
+\r
+ khui_cfg_register(cfg_ids,\r
+ ®);\r
+ } else {\r
+ khui_cfg_release(cfg_id);\r
+ }\r
+ }\r
+\r
+ _cleanup:\r
+ if (cfg_ids)\r
+ khui_cfg_release(cfg_ids);\r
+\r
+ if (idents)\r
+ free(idents);\r
+}\r
+\r
+void khm_init_config(void) {\r
+ wchar_t wshort[KHUI_MAXCCH_SHORT_DESC];\r
+ wchar_t wlong[KHUI_MAXCCH_LONG_DESC];\r
+ khui_config_node_reg reg;\r
+ khui_config_node node;\r
+\r
+ reg.short_desc = wshort;\r
+ reg.long_desc = wlong;\r
+ reg.h_module = khm_hInstance;\r
+ reg.flags = 0;\r
+\r
+ reg.name = L"KhmGeneral";\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_GENERAL);\r
+ reg.dlg_proc = khm_cfg_general_proc;\r
+ LoadString(khm_hInstance, IDS_CFG_GENERAL_SHORT,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(khm_hInstance, IDS_CFG_GENERAL_LONG,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ khui_cfg_register(NULL, ®);\r
+\r
+ reg.name = L"KhmIdentities";\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITIES);\r
+ reg.dlg_proc = khm_cfg_identities_proc;\r
+ LoadString(khm_hInstance, IDS_CFG_IDENTITIES_SHORT,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(khm_hInstance, IDS_CFG_IDENTITIES_LONG,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ khui_cfg_register(NULL, ®);\r
+\r
+ node = NULL;\r
+ khui_cfg_open(NULL, L"KhmIdentities", &node);\r
+#ifdef DEBUG\r
+ assert(node);\r
+#endif\r
+\r
+ reg.name = L"KhmIdentitiesTab";\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB);\r
+ reg.dlg_proc = khm_cfg_ids_tab_proc;\r
+ LoadString(khm_hInstance, IDS_CFG_IDS_TAB_SHORT,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(khm_hInstance, IDS_CFG_IDS_TAB_LONG,\r
+ wlong, ARRAYLENGTH(wlong));\r
+ reg.flags = KHUI_CNFLAG_SUBPANEL;\r
+\r
+ khui_cfg_register(node, ®);\r
+\r
+ reg.name = L"KhmIdentitiesTabPlural";\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB);\r
+ reg.dlg_proc = khm_cfg_id_tab_proc;\r
+ LoadString(khm_hInstance, IDS_CFG_ID_TAB_SHORT,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(khm_hInstance, IDS_CFG_ID_TAB_LONG,\r
+ wlong, ARRAYLENGTH(wlong));\r
+ reg.flags = KHUI_CNFLAG_PLURAL | KHUI_CNFLAG_SUBPANEL;\r
+\r
+ khui_cfg_register(node, ®);\r
+\r
+ reg.flags = 0;\r
+ khui_cfg_release(node);\r
+\r
+ reg.name = L"KhmNotifications";\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_NOTIF);\r
+ reg.dlg_proc = khm_cfg_notifications_proc;\r
+ LoadString(khm_hInstance, IDS_CFG_NOTIF_SHORT,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(khm_hInstance, IDS_CFG_NOTIF_LONG,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ khui_cfg_register(NULL, ®);\r
+\r
+ reg.name = L"KhmPlugins";\r
+ reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_PLUGINS);\r
+ reg.dlg_proc = khm_cfg_plugins_proc;\r
+ LoadString(khm_hInstance, IDS_CFG_PLUGINS_SHORT,\r
+ wshort, ARRAYLENGTH(wshort));\r
+ LoadString(khm_hInstance, IDS_CFG_PLUGINS_LONG,\r
+ wlong, ARRAYLENGTH(wlong));\r
+\r
+ khui_cfg_register(NULL, ®);\r
+}\r
+\r
+void khm_exit_config(void) {\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_CONFIGWND_H\r
+#define __KHIMAIRA_CONFIGWND_H\r
+\r
+void \r
+khm_show_config_pane(khui_config_node node);\r
+\r
+void khm_init_config(void);\r
+void khm_exit_config(void);\r
+\r
+void khm_refresh_config(void);\r
+\r
+/* window procedures for other configuration windows */\r
+INT_PTR CALLBACK\r
+khm_cfg_general_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_identities_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_identity_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_id_tab_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_ids_tab_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_notifications_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+INT_PTR CALLBACK\r
+khm_cfg_plugins_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+static BOOL in_dialog = FALSE;\r
+static CRITICAL_SECTION cs_dialog;\r
+static HANDLE in_dialog_evt = NULL;\r
+static LONG init_dialog = 0;\r
+static khm_int32 dialog_result = 0;\r
+\r
+static void\r
+dialog_sync_init(void) {\r
+ if (InterlockedIncrement(&init_dialog) == 1) {\r
+#ifdef DEBUG\r
+ assert(in_dialog_evt == NULL);\r
+ assert(in_dialog == FALSE);\r
+#endif\r
+\r
+ InitializeCriticalSection(&cs_dialog);\r
+\r
+ in_dialog_evt = CreateEvent(NULL,\r
+ TRUE,\r
+ TRUE,\r
+ L"DialogCompletionEvent");\r
+ } else {\r
+ InterlockedDecrement(&init_dialog);\r
+ if (in_dialog_evt == NULL) {\r
+ Sleep(100);\r
+ }\r
+ }\r
+}\r
+\r
+BOOL \r
+khm_cred_begin_dialog(void) {\r
+ BOOL rv;\r
+\r
+ dialog_sync_init();\r
+\r
+ EnterCriticalSection(&cs_dialog);\r
+\r
+ if (in_dialog)\r
+ rv = FALSE;\r
+ else {\r
+ rv = TRUE;\r
+ in_dialog = TRUE;\r
+ ResetEvent(in_dialog_evt);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_dialog);\r
+ return rv;\r
+}\r
+\r
+void \r
+khm_cred_end_dialog(khm_int32 result) {\r
+ dialog_sync_init();\r
+\r
+ EnterCriticalSection(&cs_dialog);\r
+ if (in_dialog) {\r
+ in_dialog = FALSE;\r
+ SetEvent(in_dialog_evt);\r
+ }\r
+ dialog_result = result;\r
+ LeaveCriticalSection(&cs_dialog);\r
+}\r
+\r
+BOOL\r
+khm_cred_is_in_dialog(void) {\r
+ BOOL rv;\r
+\r
+ dialog_sync_init();\r
+\r
+ EnterCriticalSection(&cs_dialog);\r
+ rv = in_dialog;\r
+ LeaveCriticalSection(&cs_dialog);\r
+\r
+ return rv;\r
+}\r
+\r
+khm_int32\r
+khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result) {\r
+ khm_int32 rv;\r
+\r
+ dialog_sync_init();\r
+\r
+ EnterCriticalSection(&cs_dialog);\r
+ if (!in_dialog)\r
+ rv = KHM_ERROR_NOT_FOUND;\r
+ else {\r
+ DWORD dw;\r
+\r
+ do {\r
+ LeaveCriticalSection(&cs_dialog);\r
+\r
+ dw = WaitForSingleObject(in_dialog_evt, timeout);\r
+\r
+ EnterCriticalSection(&cs_dialog);\r
+\r
+ if (!in_dialog) {\r
+ rv = KHM_ERROR_SUCCESS;\r
+ if (result)\r
+ *result = dialog_result;\r
+ break;\r
+ } else if(dw == WAIT_TIMEOUT) {\r
+ rv = KHM_ERROR_TIMEOUT;\r
+ break;\r
+ }\r
+ } while(TRUE);\r
+ }\r
+ LeaveCriticalSection(&cs_dialog);\r
+\r
+ return rv;\r
+}\r
+\r
+/* completion handler for KMSG_CRED messages */\r
+void KHMAPI \r
+kmsg_cred_completion(kmq_message *m)\r
+{\r
+ khui_new_creds * nc;\r
+\r
+#ifdef DEBUG\r
+ assert(m->type == KMSG_CRED);\r
+#else\r
+ if(m->type != KMSG_CRED)\r
+ return; /* huh? */\r
+#endif\r
+\r
+ switch(m->subtype) {\r
+ case KMSG_CRED_PASSWORD:\r
+ /* fallthrough */\r
+ case KMSG_CRED_NEW_CREDS:\r
+ /* Cred types have attached themselves. Trigger the next\r
+ phase. */\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_DIALOG_SETUP, 0, \r
+ m->vparam);\r
+ break;\r
+\r
+ case KMSG_CRED_RENEW_CREDS:\r
+ nc = (khui_new_creds *) m->vparam;\r
+\r
+ /* khm_cred_dispatch_process_message() deals with the case\r
+ where there are not credential types that wants to\r
+ participate in this operation. */\r
+ khm_cred_dispatch_process_message(nc);\r
+ break;\r
+\r
+ case KMSG_CRED_DIALOG_SETUP:\r
+ nc = (khui_new_creds *) m->vparam;\r
+\r
+ khm_prep_newcredwnd(nc->hwnd);\r
+ \r
+ /* all the controls have been created. Now initialize them */\r
+ if (nc->n_types > 0) {\r
+ kmq_post_subs_msg(nc->type_subs, \r
+ nc->n_types, \r
+ KMSG_CRED, \r
+ KMSG_CRED_DIALOG_PRESTART, \r
+ 0, \r
+ m->vparam);\r
+ } else {\r
+ PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0);\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_DIALOG_PRESTART:\r
+ /* all prestart stuff is done. Now to activate the dialog */\r
+ nc = (khui_new_creds *) m->vparam;\r
+ khm_show_newcredwnd(nc->hwnd);\r
+ \r
+ kmq_post_subs_msg(nc->type_subs,\r
+ nc->n_types,\r
+ KMSG_CRED, \r
+ KMSG_CRED_DIALOG_START, \r
+ 0, \r
+ m->vparam);\r
+ /* at this point, the dialog window takes over. We let it run\r
+ the show until KMSG_CRED_DIALOG_END is posted by the dialog\r
+ procedure. */\r
+ break;\r
+\r
+ case KMSG_CRED_PROCESS:\r
+ /* a wave of these messages have completed. We should check\r
+ if there's more */\r
+ nc = (khui_new_creds *) m->vparam;\r
+\r
+ if(!khm_cred_dispatch_process_level(nc)) {\r
+\r
+ if(kherr_is_error()) {\r
+ khui_alert * alert;\r
+ kherr_event * evt;\r
+ kherr_context * ctx;\r
+ wchar_t ws_title[1024];\r
+\r
+ ctx = kherr_peek_context();\r
+ evt = kherr_get_err_event(ctx);\r
+ kherr_evaluate_event(evt);\r
+\r
+ khui_alert_create_empty(&alert);\r
+\r
+ if (nc->subtype == KMSG_CRED_PASSWORD)\r
+ LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE,\r
+ ws_title, ARRAYLENGTH(ws_title));\r
+ else\r
+ LoadString(khm_hInstance, IDS_NC_FAILED_TITLE,\r
+ ws_title, ARRAYLENGTH(ws_title));\r
+\r
+ khui_alert_set_title(alert, ws_title);\r
+ khui_alert_set_severity(alert, evt->severity);\r
+ if(!evt->long_desc)\r
+ khui_alert_set_message(alert, evt->short_desc);\r
+ else\r
+ khui_alert_set_message(alert, evt->long_desc);\r
+ if(evt->suggestion)\r
+ khui_alert_set_suggestion(alert, evt->suggestion);\r
+\r
+ khui_alert_show(alert);\r
+ khui_alert_release(alert);\r
+\r
+ kherr_release_context(ctx);\r
+\r
+ kherr_clear_error();\r
+ }\r
+\r
+ if (nc->subtype == KMSG_CRED_RENEW_CREDS) {\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, \r
+ m->vparam);\r
+ } else {\r
+ PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE),\r
+ 0);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case KMSG_CRED_END:\r
+ /* all is done. */\r
+ {\r
+ khui_new_creds * nc;\r
+\r
+ nc = (khui_new_creds *) m->vparam;\r
+\r
+ if (nc->subtype == KMSG_CRED_NEW_CREDS ||\r
+ nc->subtype == KMSG_CRED_PASSWORD) {\r
+\r
+ if (nc->subtype == KMSG_CRED_NEW_CREDS)\r
+ khui_context_reset();\r
+\r
+ khm_cred_end_dialog(nc->result);\r
+ }\r
+\r
+ khui_cw_destroy_cred_blob(nc);\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0);\r
+\r
+ khm_cred_process_commandline();\r
+ }\r
+ break;\r
+\r
+ /* property sheet stuff */\r
+\r
+ case KMSG_CRED_PP_BEGIN:\r
+ /* all the pages should have been added by now. Just send out\r
+ the precreate message */\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_PRECREATE, 0, \r
+ m->vparam);\r
+ break;\r
+\r
+ case KMSG_CRED_PP_END:\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_DESTROY, 0, \r
+ m->vparam);\r
+ break;\r
+\r
+ case KMSG_CRED_DESTROY_CREDS:\r
+#ifdef DEBUG\r
+ assert(m->vparam != NULL);\r
+#endif\r
+ khui_context_release((khui_action_context *) m->vparam);\r
+ free(m->vparam);\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0);\r
+\r
+ khm_cred_process_commandline();\r
+ break;\r
+\r
+ case KMSG_CRED_IMPORT:\r
+ khm_cred_process_commandline();\r
+ break;\r
+ }\r
+}\r
+\r
+void khm_cred_import(void)\r
+{\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_IMPORT);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_IMPORT, 0, 0);\r
+\r
+ _end_task();\r
+}\r
+\r
+void khm_cred_set_default(void)\r
+{\r
+ khui_action_context ctx;\r
+ khm_int32 rv;\r
+\r
+ khui_context_get(&ctx);\r
+\r
+ if (ctx.identity) {\r
+ rv = kcdb_identity_set_default(ctx.identity);\r
+ }\r
+\r
+ khui_context_release(&ctx);\r
+}\r
+\r
+void khm_cred_destroy_creds(void)\r
+{\r
+ khui_action_context * pctx;\r
+\r
+ pctx = malloc(sizeof(*pctx));\r
+#ifdef DEBUG\r
+ assert(pctx);\r
+#endif\r
+\r
+ khui_context_get(pctx);\r
+\r
+ if(pctx->scope == KHUI_SCOPE_NONE) {\r
+ /* this really shouldn't be necessary once we start enabling\r
+ and disbling actions based on context */\r
+ wchar_t title[256];\r
+ wchar_t message[256];\r
+\r
+ LoadString(khm_hInstance, \r
+ IDS_ALERT_NOSEL_TITLE, \r
+ title, \r
+ ARRAYLENGTH(title));\r
+\r
+ LoadString(khm_hInstance, \r
+ IDS_ALERT_NOSEL, \r
+ message, \r
+ ARRAYLENGTH(message));\r
+\r
+ khui_alert_show_simple(title, \r
+ message, \r
+ KHERR_WARNING);\r
+\r
+ khui_context_release(pctx);\r
+ free(pctx);\r
+ } else {\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED,\r
+ KMSG_CRED_DESTROY_CREDS,\r
+ 0,\r
+ (void *) pctx);\r
+\r
+ _end_task();\r
+ }\r
+}\r
+\r
+void khm_cred_renew_identity(khm_handle identity)\r
+{\r
+ khui_new_creds * c;\r
+\r
+ khui_cw_create_cred_blob(&c);\r
+\r
+ c->subtype = KMSG_CRED_RENEW_CREDS;\r
+ c->result = KHUI_NC_RESULT_GET_CREDS;\r
+ khui_context_create(&c->ctx,\r
+ KHUI_SCOPE_IDENT,\r
+ identity,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL);\r
+\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
+\r
+ _end_task();\r
+}\r
+\r
+void khm_cred_renew_cred(khm_handle cred)\r
+{\r
+ khui_new_creds * c;\r
+\r
+ khui_cw_create_cred_blob(&c);\r
+\r
+ c->subtype = KMSG_CRED_RENEW_CREDS;\r
+ c->result = KHUI_NC_RESULT_GET_CREDS;\r
+ khui_context_create(&c->ctx,\r
+ KHUI_SCOPE_CRED,\r
+ NULL,\r
+ KCDB_CREDTYPE_INVALID,\r
+ cred);\r
+\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
+\r
+ _end_task();\r
+}\r
+\r
+void khm_cred_renew_creds(void)\r
+{\r
+ khui_new_creds * c;\r
+\r
+ khui_cw_create_cred_blob(&c);\r
+ c->subtype = KMSG_CRED_RENEW_CREDS;\r
+ c->result = KHUI_NC_RESULT_GET_CREDS;\r
+ khui_context_get(&c->ctx);\r
+\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
+\r
+ _end_task();\r
+}\r
+\r
+void khm_cred_change_password(wchar_t * title)\r
+{\r
+ khui_new_creds * nc;\r
+ LPNETID_DLGINFO pdlginfo;\r
+ khm_size cb;\r
+\r
+ if (!khm_cred_begin_dialog())\r
+ return;\r
+\r
+ khui_cw_create_cred_blob(&nc);\r
+ nc->subtype = KMSG_CRED_PASSWORD;\r
+\r
+ khui_context_get(&nc->ctx);\r
+\r
+ kcdb_identpro_get_ui_cb((void *) &nc->ident_cb);\r
+\r
+ assert(nc->ident_cb);\r
+\r
+ if (title) {\r
+\r
+ if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) {\r
+ cb += sizeof(wchar_t);\r
+\r
+ nc->window_title = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(nc->window_title);\r
+#endif\r
+ StringCbCopy(nc->window_title, cb, title);\r
+ }\r
+ } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) &&\r
+ (pdlginfo = nc->ctx.vparam) &&\r
+ pdlginfo->size == NETID_DLGINFO_V1_SZ &&\r
+ pdlginfo->in.title[0] &&\r
+ SUCCEEDED(StringCchLength(pdlginfo->in.title,\r
+ NETID_TITLE_SZ,\r
+ &cb))) {\r
+\r
+ cb = (cb + 1) * sizeof(wchar_t);\r
+ nc->window_title = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(nc->window_title);\r
+#endif\r
+ StringCbCopy(nc->window_title, cb, pdlginfo->in.title);\r
+ }\r
+\r
+ khm_create_newcredwnd(khm_hwnd_main, nc);\r
+\r
+ if (nc->hwnd != NULL) {\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_PASSWORD);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PASSWORD, 0,\r
+ (void *) nc);\r
+\r
+ _end_task();\r
+ } else {\r
+ khui_cw_destroy_cred_blob(nc);\r
+ }\r
+}\r
+\r
+void khm_cred_obtain_new_creds(wchar_t * title)\r
+{\r
+ khui_new_creds * nc;\r
+ LPNETID_DLGINFO pdlginfo;\r
+ khm_size cb;\r
+\r
+ if (!khm_cred_begin_dialog())\r
+ return;\r
+\r
+ khui_cw_create_cred_blob(&nc);\r
+ nc->subtype = KMSG_CRED_NEW_CREDS;\r
+\r
+ khui_context_get(&nc->ctx);\r
+\r
+ kcdb_identpro_get_ui_cb((void *) &nc->ident_cb);\r
+\r
+ assert(nc->ident_cb);\r
+\r
+ if (title) {\r
+ if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) {\r
+ cb += sizeof(wchar_t);\r
+\r
+ nc->window_title = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(nc->window_title);\r
+#endif\r
+ StringCbCopy(nc->window_title, cb, title);\r
+ }\r
+ } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) &&\r
+ (pdlginfo = nc->ctx.vparam) &&\r
+ pdlginfo->size == NETID_DLGINFO_V1_SZ &&\r
+ pdlginfo->in.title[0] &&\r
+ SUCCEEDED(StringCchLength(pdlginfo->in.title,\r
+ NETID_TITLE_SZ,\r
+ &cb))) {\r
+\r
+ cb = (cb + 1) * sizeof(wchar_t);\r
+ nc->window_title = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(nc->window_title);\r
+#endif\r
+ StringCbCopy(nc->window_title, cb, pdlginfo->in.title);\r
+ }\r
+\r
+ khm_create_newcredwnd(khm_hwnd_main, nc);\r
+\r
+ if (nc->hwnd != NULL) {\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+ _report_sr0(KHERR_NONE, IDS_CTX_NEW_CREDS);\r
+ _describe();\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_NEW_CREDS, 0, \r
+ (void *) nc);\r
+\r
+ _end_task();\r
+ } else {\r
+ khui_cw_destroy_cred_blob(nc);\r
+ }\r
+}\r
+\r
+/* this is called by khm_cred_dispatch_process_message and the\r
+ kmsg_cred_completion to initiate and continue checked broadcasts of\r
+ KMSG_CRED_DIALOG_PROCESS messages.\r
+ \r
+ Returns TRUE if more KMSG_CRED_DIALOG_PROCESS messages were\r
+ posted. */\r
+BOOL khm_cred_dispatch_process_level(khui_new_creds *nc)\r
+{\r
+ khm_size i,j;\r
+ khm_handle subs[KHUI_MAX_NCTYPES];\r
+ int n_subs = 0;\r
+ BOOL cont = FALSE;\r
+ khui_new_creds_by_type *t, *d;\r
+\r
+ /* at each level, we dispatch a wave of notifications to plug-ins\r
+ who's dependencies are all satisfied */\r
+ EnterCriticalSection(&nc->cs);\r
+\r
+ /* if any types have already completed, we mark them are processed\r
+ and skip them */\r
+ for (i=0; i < nc->n_types; i++) {\r
+ t = nc->types[i];\r
+ if(t->flags & KHUI_NC_RESPONSE_COMPLETED)\r
+ t->flags |= KHUI_NCT_FLAG_PROCESSED;\r
+ }\r
+\r
+ for(i=0; i<nc->n_types; i++) {\r
+ t = nc->types[i];\r
+\r
+ if((t->flags & KHUI_NCT_FLAG_PROCESSED) ||\r
+ (t->flags & KHUI_NC_RESPONSE_COMPLETED))\r
+ continue;\r
+\r
+ for(j=0; j<t->n_type_deps; j++) {\r
+ if(KHM_FAILED(khui_cw_find_type(nc, t->type_deps[j], &d)))\r
+ break;\r
+\r
+ if(!(d->flags & KHUI_NC_RESPONSE_COMPLETED))\r
+ break;\r
+ }\r
+\r
+ if(j<t->n_type_deps) /* there are unmet dependencies */\r
+ continue;\r
+\r
+ /* all dependencies for this type have been met. */\r
+ subs[n_subs++] = kcdb_credtype_get_sub(t->type);\r
+ t->flags |= KHUI_NCT_FLAG_PROCESSED;\r
+ cont = TRUE;\r
+ }\r
+\r
+ LeaveCriticalSection(&nc->cs);\r
+\r
+ /* the reason why we are posting messages in batches is because\r
+ when the message has completed we know that all the types that\r
+ have the KHUI_NCT_FLAG_PROCESSED set have completed processing.\r
+ Otherwise we have to individually track each message and update\r
+ the type */\r
+ if(n_subs > 0)\r
+ kmq_post_subs_msg(subs, n_subs, KMSG_CRED, KMSG_CRED_PROCESS, 0,\r
+ (void *) nc);\r
+\r
+ return cont;\r
+}\r
+\r
+void \r
+khm_cred_dispatch_process_message(khui_new_creds *nc)\r
+{\r
+ khm_size i;\r
+ BOOL pending;\r
+ wchar_t wsinsert[512];\r
+ khm_size cbsize;\r
+\r
+ /* see if there's anything to do. We can check this without\r
+ obtaining a lock */\r
+ if(nc->n_types == 0 ||\r
+ (nc->subtype == KMSG_CRED_NEW_CREDS &&\r
+ nc->n_identities == 0) ||\r
+ (nc->subtype == KMSG_CRED_PASSWORD &&\r
+ nc->n_identities == 0))\r
+ goto _terminate_job;\r
+\r
+ /* check dependencies and stuff first */\r
+ EnterCriticalSection(&nc->cs);\r
+ for(i=0; i<nc->n_types; i++) {\r
+ nc->types[i]->flags &= ~ KHUI_NCT_FLAG_PROCESSED;\r
+ }\r
+ LeaveCriticalSection(&nc->cs);\r
+\r
+ /* Consindering all that can go wrong here and the desire to\r
+ handle errors here separately from others, we create a new task\r
+ for the purpose of tracking the credentials acquisition\r
+ process. */\r
+ _begin_task(KHERR_CF_TRANSITIVE);\r
+\r
+ /* Describe the context */\r
+ if(nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ cbsize = sizeof(wsinsert);\r
+ kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize);\r
+\r
+ _report_sr1(KHERR_NONE, IDS_CTX_PROC_NEW_CREDS,\r
+ _cstr(wsinsert));\r
+ _resolve();\r
+ } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) {\r
+ cbsize = sizeof(wsinsert);\r
+\r
+ if (nc->ctx.scope == KHUI_SCOPE_IDENT)\r
+ kcdb_identity_get_name(nc->ctx.identity, wsinsert, &cbsize);\r
+ else if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE) {\r
+ if (nc->ctx.identity != NULL)\r
+ kcdb_identity_get_name(nc->ctx.identity, wsinsert, \r
+ &cbsize);\r
+ else\r
+ kcdb_credtype_get_name(nc->ctx.cred_type, wsinsert,\r
+ &cbsize);\r
+ } else if (nc->ctx.scope == KHUI_SCOPE_CRED) {\r
+ kcdb_cred_get_name(nc->ctx.cred, wsinsert, &cbsize);\r
+ } else {\r
+ StringCbCopy(wsinsert, sizeof(wsinsert), L"(?)");\r
+ }\r
+\r
+ _report_sr1(KHERR_NONE, IDS_CTX_PROC_RENEW_CREDS, \r
+ _cstr(wsinsert));\r
+ _resolve();\r
+ } else if (nc->subtype == KMSG_CRED_PASSWORD) {\r
+ cbsize = sizeof(wsinsert);\r
+ kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize);\r
+\r
+ _report_sr1(KHERR_NONE, IDS_CTX_PROC_PASSWORD,\r
+ _cstr(wsinsert));\r
+ _resolve();\r
+ } else {\r
+ assert(FALSE);\r
+ }\r
+\r
+ _describe();\r
+\r
+ pending = khm_cred_dispatch_process_level(nc);\r
+\r
+ _end_task();\r
+\r
+ if(!pending)\r
+ goto _terminate_job;\r
+\r
+ return;\r
+\r
+ _terminate_job:\r
+ if (nc->subtype == KMSG_CRED_RENEW_CREDS)\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc);\r
+ else\r
+ PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0);\r
+}\r
+\r
+void\r
+khm_cred_process_commandline(void) {\r
+ khm_handle defident = NULL;\r
+\r
+ if (!khm_startup.processing)\r
+ return;\r
+\r
+ if (khm_startup.init ||\r
+ khm_startup.renew ||\r
+ khm_startup.destroy) {\r
+ kcdb_identity_get_default(&defident);\r
+ }\r
+\r
+ do {\r
+ if (khm_startup.init) {\r
+ if (defident)\r
+ khui_context_set(KHUI_SCOPE_IDENT,\r
+ defident,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL, NULL, 0,\r
+ NULL);\r
+ else\r
+ khui_context_reset();\r
+\r
+ khm_cred_obtain_new_creds(NULL);\r
+ khm_startup.init = FALSE;\r
+ break;\r
+ }\r
+\r
+ if (khm_startup.import) {\r
+ khm_cred_import();\r
+ khm_startup.import = FALSE;\r
+ break;\r
+ }\r
+\r
+ if (khm_startup.renew) {\r
+ if (defident)\r
+ khui_context_set(KHUI_SCOPE_IDENT,\r
+ defident,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL, NULL, 0,\r
+ NULL);\r
+ else\r
+ khui_context_reset();\r
+\r
+ khm_cred_renew_creds();\r
+ khm_startup.renew = FALSE;\r
+ break;\r
+ }\r
+\r
+ if (khm_startup.destroy) {\r
+ if (defident) {\r
+ khui_context_set(KHUI_SCOPE_IDENT,\r
+ defident,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL, NULL, 0,\r
+ NULL);\r
+\r
+ khm_cred_destroy_creds();\r
+ }\r
+\r
+ khm_startup.destroy = FALSE;\r
+ break;\r
+ }\r
+\r
+ if (khm_startup.autoinit) {\r
+ khm_size count;\r
+\r
+ kcdb_credset_get_size(NULL, &count);\r
+\r
+ if (count == 0) {\r
+ khm_cred_obtain_new_creds(NULL);\r
+ }\r
+ khm_startup.autoinit = FALSE;\r
+ break;\r
+ }\r
+\r
+ if (khm_startup.exit) {\r
+ PostMessage(khm_hwnd_main,\r
+ WM_COMMAND,\r
+ MAKEWPARAM(KHUI_ACTION_EXIT, 0), 0);\r
+ khm_startup.exit = FALSE;\r
+ break;\r
+ }\r
+\r
+ khm_startup.processing = FALSE;\r
+ } while(FALSE);\r
+\r
+ if (defident)\r
+ kcdb_identity_release(defident);\r
+}\r
+\r
+void\r
+khm_cred_begin_commandline(void) {\r
+ if (khm_startup.seen)\r
+ return;\r
+\r
+ khm_startup.seen = TRUE;\r
+ khm_startup.processing = TRUE;\r
+\r
+ khm_cred_process_commandline();\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_CREDFUNCS_H\r
+#define __KHIMAIRA_CREDFUNCS_H\r
+\r
+void KHMAPI \r
+kmsg_cred_completion(kmq_message *m);\r
+\r
+void \r
+khm_cred_destroy_creds(void);\r
+\r
+void \r
+khm_cred_renew_identity(khm_handle identity);\r
+\r
+void \r
+khm_cred_renew_cred(khm_handle cred);\r
+\r
+void \r
+khm_cred_renew_creds(void);\r
+\r
+void \r
+khm_cred_obtain_new_creds(wchar_t * window_title);\r
+\r
+void \r
+khm_cred_set_default(void);\r
+\r
+void \r
+khm_cred_change_password(wchar_t * window_title);\r
+\r
+void \r
+khm_cred_dispatch_process_message(khui_new_creds *nc);\r
+\r
+BOOL \r
+khm_cred_dispatch_process_level(khui_new_creds *nc);\r
+\r
+BOOL\r
+khm_cred_is_in_dialog(void);\r
+\r
+khm_int32\r
+khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result);\r
+\r
+void\r
+khm_cred_begin_commandline(void);\r
+\r
+void\r
+khm_cred_process_commandline(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<prsht.h>\r
+#include<assert.h>\r
+\r
+ATOM khui_credwnd_cls;\r
+khm_int32 khui_cw_flag_id;\r
+\r
+khm_int32 \r
+cw_get_custom_attr_id(wchar_t * s)\r
+{\r
+ if(!wcscmp(s, CW_CANAME_FLAGS))\r
+ return CW_CA_FLAGS;\r
+ if(!wcscmp(s, CW_CANAME_TYPEICON))\r
+ return CW_CA_TYPEICON;\r
+ return 0;\r
+}\r
+\r
+void \r
+cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) {\r
+ khm_handle hc_cw = NULL;\r
+ khm_handle hc_vs = NULL;\r
+ khm_handle hc_v = NULL;\r
+ khm_handle hc_cs = NULL;\r
+ khm_handle hc_c = NULL;\r
+ wchar_t buf[KCONF_MAXCCH_NAME];\r
+ wchar_t * clist = NULL;\r
+ khm_size cbsize;\r
+ wchar_t * cstr = NULL;\r
+ wchar_t * iter = NULL;\r
+ int i;\r
+ HDC hdc;\r
+\r
+ tbl->hwnd = hwnd;\r
+\r
+ if(KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &hc_cw)))\r
+ return;\r
+ if(KHM_FAILED(khc_open_space(hc_cw, L"Views", KHM_PERM_READ, &hc_vs)))\r
+ goto _exit;\r
+\r
+ if(!view) {\r
+ cbsize = sizeof(buf);\r
+ if(KHM_FAILED(khc_read_string(hc_cw, L"DefaultView", buf, &cbsize)))\r
+ goto _exit;\r
+ view = buf;\r
+ }\r
+\r
+ if(KHM_FAILED(khc_open_space(hc_vs, view, KHM_PERM_READ, &hc_v)))\r
+ goto _exit;\r
+\r
+ if(KHM_FAILED(khc_open_space(hc_v, L"Columns", KHM_PERM_READ, &hc_cs)))\r
+ goto _exit;\r
+\r
+ cbsize = 0;\r
+ if(khc_read_multi_string(hc_v, L"ColumnList", NULL, &cbsize) != KHM_ERROR_TOO_LONG)\r
+ goto _exit;\r
+\r
+ clist = malloc(cbsize);\r
+\r
+ if(KHM_FAILED(khc_read_multi_string(hc_v, L"ColumnList", clist, &cbsize)))\r
+ goto _exit;\r
+\r
+ tbl->n_cols = (int) multi_string_length_n(clist);\r
+ tbl->n_total_cols = UBOUNDSS(tbl->n_cols, KHUI_CW_COL_INITIAL, KHUI_CW_COL_INCREMENT);\r
+ tbl->cols = malloc(sizeof(khui_credwnd_col) * tbl->n_total_cols);\r
+ ZeroMemory(tbl->cols, sizeof(khui_credwnd_col) * tbl->n_total_cols);\r
+\r
+ iter = clist;\r
+ i = 0;\r
+ while(iter) {\r
+ khm_int32 attr_id;\r
+\r
+ attr_id = cw_get_custom_attr_id(iter);\r
+ if(!attr_id) {\r
+ /* a KCDB attribute */\r
+ if(KHM_FAILED(kcdb_attrib_get_id(iter, &attr_id)))\r
+ goto _skip_col;\r
+ if(kcdb_attrib_describe(attr_id, NULL, &cbsize, KCDB_TS_SHORT) != KHM_ERROR_TOO_LONG ||\r
+ cbsize == 0)\r
+ goto _skip_col;\r
+ tbl->cols[i].title = malloc(cbsize);\r
+ kcdb_attrib_describe(attr_id, tbl->cols[i].title, &cbsize, KCDB_TS_SHORT);\r
+ } else {\r
+ /* All current custom attributes are represented by icons,\r
+ not names */\r
+ tbl->cols[i].title = NULL;\r
+ }\r
+\r
+ tbl->cols[i].attr_id = attr_id;\r
+\r
+ if(KHM_SUCCEEDED(khc_open_space(hc_cs, iter, KHM_PERM_READ, &hc_c))) {\r
+ if(KHM_FAILED(khc_read_int32(hc_c, L"Flags", &(tbl->cols[i].flags))))\r
+ tbl->cols[i].flags = 0;\r
+ if(KHM_FAILED(khc_read_int32(hc_c, L"Width", &(tbl->cols[i].width))))\r
+ tbl->cols[i].width = -1;\r
+ if(KHM_FAILED(khc_read_int32(hc_c, L"SortIndex", &(tbl->cols[i].sort_index))))\r
+ tbl->cols[i].sort_index = -1;\r
+ khc_close_space(hc_c);\r
+ hc_c = NULL;\r
+ } else {\r
+ tbl->cols[i].flags = 0;\r
+ tbl->cols[i].width = -1;\r
+ tbl->cols[i].sort_index = -1;\r
+ }\r
+ i++;\r
+_skip_col:\r
+ iter = multi_string_next(iter);\r
+ }\r
+\r
+ /* adjust the number of columns. We may have skipped columns due to\r
+ inconsistencies above */\r
+ tbl->n_cols = i;\r
+\r
+ /* now that all the columns have been loaded, load the view\r
+ parameters */\r
+ if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHorizontal", &(tbl->hpad))))\r
+ khc_read_int32(hc_cw, L"PaddingHorizontal", &(tbl->hpad));\r
+ if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingVertical", &(tbl->vpad))))\r
+ khc_read_int32(hc_cw, L"PaddingVertical", &(tbl->vpad));\r
+ if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHeader", &(tbl->hpad_h))))\r
+ khc_read_int32(hc_cw, L"PaddingHeader", &(tbl->hpad_h));\r
+ if(KHM_FAILED(khc_read_int32(hc_v, L"WarnThreshold", &(tbl->threshold_warn))))\r
+ khc_read_int32(hc_cw, L"WarnThreshold", &(tbl->threshold_warn));\r
+ if(KHM_FAILED(khc_read_int32(hc_v, L"CriticalThreshold", &(tbl->threshold_critical))))\r
+ khc_read_int32(hc_cw, L"CriticalThreshold", &(tbl->threshold_critical));\r
+\r
+ /* and the font resources and stuff */\r
+\r
+ tbl->flags |= KHUI_CW_TBL_INITIALIZED | KHUI_CW_TBL_COL_DIRTY | KHUI_CW_TBL_ACTIVE;\r
+\r
+ /*TODO: the graphics objects should be customizable */\r
+\r
+ hdc = GetWindowDC(hwnd);\r
+\r
+ tbl->hf_header = CreateFont(\r
+ -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */\r
+ 0,0, /* escapement */\r
+ FW_THIN,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ DEFAULT_CHARSET,\r
+ OUT_DEFAULT_PRECIS,\r
+ CLIP_DEFAULT_PRECIS,\r
+ DEFAULT_QUALITY,\r
+ FF_SWISS,\r
+ L"MS Shell Dlg");\r
+\r
+ if(tbl->hf_header && tbl->hwnd_header)\r
+ SendMessage(tbl->hwnd_header, WM_SETFONT, (WPARAM) tbl->hf_header, 0);\r
+\r
+ tbl->hf_bold_header = CreateFont(\r
+ -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */\r
+ 0,0, /* escapement */\r
+ FW_BOLD,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ DEFAULT_CHARSET,\r
+ OUT_DEFAULT_PRECIS,\r
+ CLIP_DEFAULT_PRECIS,\r
+ DEFAULT_QUALITY,\r
+ FF_SWISS,\r
+ L"MS Shell Dlg");\r
+\r
+ tbl->hf_normal = CreateFont(\r
+ -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */\r
+ 0,0, /* escapement */\r
+ FW_THIN,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ DEFAULT_CHARSET,\r
+ OUT_DEFAULT_PRECIS,\r
+ CLIP_DEFAULT_PRECIS,\r
+ DEFAULT_QUALITY,\r
+ FF_SWISS,\r
+ L"MS Shell Dlg");\r
+\r
+ tbl->hf_bold = CreateFont(\r
+ -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */\r
+ 0,0, /* escapement */\r
+ FW_BOLD,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ DEFAULT_CHARSET,\r
+ OUT_DEFAULT_PRECIS,\r
+ CLIP_DEFAULT_PRECIS,\r
+ DEFAULT_QUALITY,\r
+ FF_SWISS,\r
+ L"MS Shell Dlg");\r
+\r
+ ReleaseDC(hwnd, hdc);\r
+\r
+ khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade),LoadImage(\r
+ khm_hInstance,\r
+ MAKEINTRESOURCE(IDB_LOGO_SHADE),\r
+ IMAGE_BITMAP,\r
+ 0,\r
+ 0,\r
+ LR_DEFAULTCOLOR));\r
+\r
+ tbl->hb_normal = CreateSolidBrush(RGB(255,255,255));\r
+ tbl->hb_grey = CreateSolidBrush(RGB(240,240,240));\r
+ tbl->hb_sel = CreateSolidBrush(RGB(230,230,255));\r
+ tbl->hb_hdr_bg = CreateSolidBrush(RGB(230,230,230));\r
+ tbl->hb_hdr_bg_sel = CreateSolidBrush(RGB(0,0,255));\r
+ tbl->hb_hdr_bg_crit = CreateSolidBrush(RGB(240,133,117));\r
+ tbl->hb_hdr_bg_warn = CreateSolidBrush(RGB(251,199,77));\r
+ tbl->hb_hdr_bg_exp = CreateSolidBrush(RGB(255,144,144));\r
+\r
+ tbl->cr_normal = RGB(0,0,0);\r
+ tbl->cr_sel = RGB(0,0,0);\r
+ tbl->cr_hdr_outline = RGB(0,0,0);\r
+ tbl->cr_hdr_normal = RGB(0,0,0);\r
+ tbl->cr_hdr_sel = RGB(255,255,255);\r
+\r
+ tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 16, 8, 0);\r
+ {\r
+ HBITMAP hbm;\r
+\r
+#define ADD_BITMAP(i) \\r
+ hbm = LoadImage(khm_hInstance, MAKEINTRESOURCE(i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); \\r
+ if(hbm) { \\r
+ khui_ilist_add_masked_id(tbl->ilist, hbm, KHUI_TOOLBAR_BGCOLOR, i); \\r
+ DeleteObject(hbm); \\r
+ }\r
+\r
+ ADD_BITMAP(IDB_WDG_COLLAPSE);\r
+ ADD_BITMAP(IDB_WDG_EXPAND);\r
+ ADD_BITMAP(IDB_ID_SM);\r
+ ADD_BITMAP(IDB_ID_DIS_SM);\r
+ ADD_BITMAP(IDB_TK_NEW_SM);\r
+ ADD_BITMAP(IDB_TK_REFRESH_SM);\r
+ ADD_BITMAP(IDB_WDG_COLLAPSE_HI);\r
+ ADD_BITMAP(IDB_WDG_EXPAND_HI);\r
+ ADD_BITMAP(IDB_WDG_FLAG);\r
+ ADD_BITMAP(IDB_WDG_CREDTYPE);\r
+ ADD_BITMAP(IDB_FLAG_WARN);\r
+ ADD_BITMAP(IDB_FLAG_EXPIRED);\r
+ ADD_BITMAP(IDB_FLAG_CRITICAL);\r
+\r
+#undef ADD_BITMAP\r
+ }\r
+\r
+ tbl->cursor_row = -1;\r
+ tbl->scr_left = 0;\r
+ tbl->scr_top = 0;\r
+ tbl->ext_height = 0;\r
+ tbl->ext_width = 0;\r
+\r
+_exit:\r
+ if(hc_cw)\r
+ khc_close_space(hc_cw);\r
+ if(hc_vs)\r
+ khc_close_space(hc_vs);\r
+ if(hc_v)\r
+ khc_close_space(hc_v);\r
+ if(hc_cs)\r
+ khc_close_space(hc_cs);\r
+ if(clist)\r
+ free(clist);\r
+}\r
+\r
+void \r
+cw_update_creds(khui_credwnd_tbl * tbl)\r
+{\r
+ kcdb_cred_comp_field * fields;\r
+ kcdb_cred_comp_order comp_order;\r
+ khm_size i;\r
+ khm_int32 n;\r
+ khm_int32 delta;\r
+ khm_handle hc;\r
+ khm_int32 flags;\r
+\r
+ if(!tbl->credset) {\r
+ if(KHM_FAILED(kcdb_credset_create(&(tbl->credset))))\r
+ return;\r
+ }\r
+\r
+ kcdb_credset_purge(tbl->credset);\r
+\r
+ kcdb_identity_refresh_all();\r
+\r
+ kcdb_credset_collect(\r
+ tbl->credset,\r
+ NULL,\r
+ NULL,\r
+ KCDB_CREDTYPE_ALL,\r
+ &delta);\r
+\r
+ /* now we need to figure out how to sort the credentials */\r
+ fields = malloc(sizeof(kcdb_cred_comp_field) * tbl->n_cols);\r
+ ZeroMemory(fields, sizeof(kcdb_cred_comp_field) * tbl->n_cols);\r
+\r
+ for(i=0, n=0; i<tbl->n_cols; i++) {\r
+ if((tbl->cols[i].flags & KHUI_CW_COL_SORT_INC) ||\r
+ (tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC) ||\r
+ (tbl->cols[i].flags & KHUI_CW_COL_GROUP))\r
+ {\r
+ int si;\r
+ /* we need to sort by this column */\r
+ si = tbl->cols[i].sort_index;\r
+\r
+ if(si < 0 || si >= (int) tbl->n_cols)\r
+ {\r
+ /* this shouldn't happen */\r
+ tbl->cols[i].flags &= ~(KHUI_CW_COL_SORT_INC | \r
+ KHUI_CW_COL_SORT_DEC | \r
+ KHUI_CW_COL_GROUP);\r
+ continue;\r
+ }\r
+\r
+ fields[si].attrib = tbl->cols[i].attr_id;\r
+ if(tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC)\r
+ fields[si].order = KCDB_CRED_COMP_DECREASING;\r
+ else\r
+ fields[si].order = KCDB_CRED_COMP_INCREASING;\r
+\r
+ /* special case. if we are sorting by name, we group\r
+ initial tickets before non-initial tickets.\r
+\r
+ Also, if we are sorting by credential type name, then\r
+ we allow the primary credential type first before\r
+ others.\r
+ */\r
+\r
+ if (fields[si].attrib == KCDB_ATTR_NAME ||\r
+ fields[si].attrib == KCDB_ATTR_TYPE_NAME)\r
+ fields[si].order |= KCDB_CRED_COMP_INITIAL_FIRST;\r
+\r
+ if(si >= n)\r
+ n = si+1;\r
+ }\r
+ }\r
+\r
+ /* we assume that the sort order is sane */\r
+ /*TODO: don't assume; check if the sort order is sane */\r
+\r
+ comp_order.nFields = n;\r
+ comp_order.fields = fields;\r
+\r
+ kcdb_credset_sort(tbl->credset, \r
+ kcdb_cred_comp_generic, \r
+ (void *) &comp_order);\r
+\r
+ /* also, if new credentials were added, initialize the UI flag\r
+ attribute to 0 */\r
+ if(delta & KCDB_DELTA_ADD) {\r
+ khm_size s;\r
+\r
+ kcdb_credset_get_size(tbl->credset, &s);\r
+ for(i=0;i<s;i++) {\r
+ if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, (khm_int32) i, &hc)))\r
+ continue; /* lost a race */\r
+ if(KHM_FAILED(kcdb_cred_get_attr(hc, khui_cw_flag_id, NULL, NULL, NULL))) {\r
+ flags = 0;\r
+ kcdb_cred_set_attr(hc, khui_cw_flag_id, &flags, sizeof(flags));\r
+ }\r
+ kcdb_cred_release(hc);\r
+ }\r
+ }\r
+}\r
+\r
+void \r
+cw_del_outline(khui_credwnd_outline *o) {\r
+ khui_credwnd_outline * c;\r
+ if(!o)\r
+ return;\r
+\r
+ /* the outline object is still in a list */\r
+ if(o->next || o->prev)\r
+ return;\r
+\r
+ if(o->header)\r
+ free(o->header);\r
+ if ((o->flags & KHUI_CW_O_DATAALLOC) &&\r
+ o->data)\r
+ free(o->data);\r
+\r
+ LPOP(&(o->children), &c);\r
+ while(c) {\r
+ cw_del_outline(c);\r
+ LPOP(&(o->children), &c);\r
+ }\r
+\r
+ free(o);\r
+}\r
+\r
+khui_credwnd_outline * \r
+cw_new_outline_node(wchar_t * heading) {\r
+ khui_credwnd_outline * o;\r
+ size_t cblen;\r
+\r
+ o = malloc(sizeof(khui_credwnd_outline));\r
+ ZeroMemory(o, sizeof(khui_credwnd_outline));\r
+ \r
+ if(SUCCEEDED(StringCbLength(heading, KHUI_MAXCB_HEADING, &cblen))) {\r
+ cblen += sizeof(wchar_t);\r
+ o->header = malloc(cblen);\r
+ StringCbCopy(o->header, cblen, heading);\r
+ }\r
+\r
+ return o;\r
+}\r
+\r
+khm_int32 \r
+cw_get_cred_exp_flags(khui_credwnd_tbl * tbl, khm_handle cred)\r
+{\r
+ khm_int32 flags;\r
+ long s;\r
+ FILETIME ft;\r
+ khm_size cbsize;\r
+\r
+ cbsize = sizeof(ft);\r
+ if(KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize)))\r
+ return 0;\r
+\r
+ s = FtIntervalToMilliseconds(&ft) / 1000;\r
+\r
+ flags = 0;\r
+ if(s < 0)\r
+ flags = CW_EXPSTATE_EXPIRED;\r
+ else if(s < tbl->threshold_critical)\r
+ flags = CW_EXPSTATE_CRITICAL;\r
+ else if(s < tbl->threshold_warn)\r
+ flags = CW_EXPSTATE_WARN;\r
+ else\r
+ flags = CW_EXPSTATE_NONE;\r
+\r
+ return flags;\r
+}\r
+\r
+void cw_update_outline(khui_credwnd_tbl * tbl);\r
+\r
+VOID CALLBACK \r
+cw_timer_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ UINT_PTR idEvent,\r
+ DWORD dwTime)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+ khui_credwnd_row * r;\r
+ khm_int32 nflags;\r
+ khm_size nr;\r
+ long ms;\r
+ FILETIME ft;\r
+ khm_size cbsize;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ r = (khui_credwnd_row *) idEvent;\r
+\r
+ nr = r - tbl->rows;\r
+\r
+ if(nr < 0 || nr >= tbl->n_rows)\r
+ return;\r
+\r
+ if(!(r->flags & KHUI_CW_ROW_CRED))\r
+ return; /* we only know what to do with cred rows */\r
+\r
+ nflags = cw_get_cred_exp_flags(tbl, (khm_handle) r->data);\r
+ if((r->flags & CW_EXPSTATE_MASK) != nflags) {\r
+ /* flags have changed */\r
+ /* the outline needs to be updated */\r
+ cw_update_outline(tbl);\r
+ InvalidateRect(tbl->hwnd, NULL, FALSE);\r
+ } else {\r
+ /* just invalidate the row */\r
+ RECT r,rr,ri;\r
+\r
+ GetClientRect(tbl->hwnd, &r);\r
+ r.top += tbl->header_height;\r
+ rr.top = r.top + (long)nr * tbl->cell_height - tbl->scr_top;\r
+ rr.bottom = rr.top + tbl->cell_height;\r
+ rr.left = r.left;\r
+ rr.right = r.right;\r
+\r
+ if(IntersectRect(&ri, &r, &rr))\r
+ InvalidateRect(tbl->hwnd, &ri, FALSE);\r
+ }\r
+\r
+ cbsize = sizeof(ft);\r
+ if(KHM_SUCCEEDED(kcdb_cred_get_attr((khm_handle) r->data, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize)))\r
+ {\r
+ ms = FtIntervalMsToRepChange(&ft);\r
+ if(ms > 0) {\r
+ SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc);\r
+ }\r
+ }\r
+}\r
+\r
+void \r
+cw_set_tbl_row_cred(khui_credwnd_tbl * tbl, \r
+ int row, \r
+ khm_handle cred, \r
+ int col)\r
+{\r
+ FILETIME ft;\r
+ long ms;\r
+ khm_size cbsize;\r
+\r
+ if((int) tbl->n_total_rows <= row) {\r
+ /* we need to resize the allocation */\r
+ khui_credwnd_row * newrows;\r
+ khm_size newsize;\r
+\r
+ newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT);\r
+ newrows = malloc(sizeof(khui_credwnd_row) * newsize);\r
+ memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows);\r
+ free(tbl->rows);\r
+ tbl->rows = newrows;\r
+ tbl->n_total_rows = newsize;\r
+ }\r
+\r
+ tbl->rows[row].col = col;\r
+ tbl->rows[row].data = cred;\r
+ tbl->rows[row].flags = KHUI_CW_ROW_CRED;\r
+\r
+ /* Set any required timer events */\r
+ cbsize = sizeof(ft);\r
+ if(KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) {\r
+ ms = FtIntervalMsToRepChange(&ft);\r
+ if(ms > 0) {\r
+ SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, cw_timer_proc);\r
+ tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET;\r
+ }\r
+ }\r
+}\r
+\r
+void \r
+cw_set_tbl_row_header(khui_credwnd_tbl * tbl, \r
+ int row, int col, \r
+ khui_credwnd_outline * o)\r
+{\r
+ if((int) tbl->n_total_rows <= row) {\r
+ /* we need to resize the allocation */\r
+ khui_credwnd_row * newrows;\r
+ khm_size newsize;\r
+\r
+ newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT);\r
+ newrows = malloc(sizeof(khui_credwnd_row) * newsize);\r
+ memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows);\r
+ free(tbl->rows);\r
+ tbl->rows = newrows;\r
+ tbl->n_total_rows = newsize;\r
+ }\r
+\r
+ tbl->rows[row].col = col;\r
+ tbl->rows[row].data = (khm_handle) o;\r
+ tbl->rows[row].flags = KHUI_CW_ROW_HEADER;\r
+ if(o->flags & KHUI_CW_O_SELECTED)\r
+ tbl->rows[row].flags |= KHUI_CW_ROW_SELECTED;\r
+}\r
+\r
+static int \r
+iwcscmp(const void * p1, const void * p2) {\r
+ const wchar_t * s1 = *(wchar_t **) p1;\r
+ const wchar_t * s2 = *(wchar_t **) p2;\r
+\r
+ return wcscmp(s1, s2);\r
+}\r
+\r
+void \r
+cw_update_outline(khui_credwnd_tbl * tbl)\r
+{\r
+ int i,j,n_rows;\r
+ int level;\r
+ int visible;\r
+ khm_size n_creds;\r
+ khm_handle prevcred = NULL;\r
+ khm_handle thiscred = NULL;\r
+ /* grouping[0..n_grouping-1] are the columns that we are going to\r
+ group the display by. Say we are grouping by identity and then\r
+ by type, then grouping[0]=col# of identity and grouping[1]=col#\r
+ of type */\r
+ khm_int32 * grouping = NULL;\r
+ khui_credwnd_outline * ol = NULL;\r
+ int n_grouping;\r
+ wchar_t buf[256];\r
+ khm_size cbbuf;\r
+ khm_int32 flags;\r
+ int selected;\r
+\r
+ /* this is called after calling cw_update_creds, so we assume\r
+ that the credentials are all loaded and sorted according to\r
+ grouping rules */\r
+\r
+ /* if the columns have changed, then any outline info we have\r
+ cached are unreliable */\r
+ if(tbl->flags & KHUI_CW_TBL_COL_DIRTY) {\r
+ khui_credwnd_outline * o;\r
+ LPOP(&(tbl->outline), &o);\r
+ while(o) {\r
+ cw_del_outline(o);\r
+ LPOP(&(tbl->outline), &o);\r
+ }\r
+ tbl->n_rows = 0;\r
+ }\r
+\r
+ /* Otherwise, we should reset the outline indices. Just the first\r
+ level is enough */\r
+ if (tbl->outline) {\r
+ khui_credwnd_outline * o;\r
+\r
+ o = tbl->outline;\r
+ while(o) {\r
+ o->start = -1;\r
+ o = LNEXT(o);\r
+ }\r
+ }\r
+\r
+\r
+ /* determine the grouping order */\r
+ grouping = malloc(sizeof(khm_int32) * tbl->n_cols);\r
+ for(i=0; i < (int) tbl->n_cols; i++)\r
+ grouping[i] = -1;\r
+ n_grouping = 0;\r
+\r
+ for(i=0; i < (int) tbl->n_cols; i++) {\r
+ /* since cw_update_creds has run, the KHUI_CW_COL_GROUP flag\r
+ only exists for columns that has a valid sort_index */\r
+ if(tbl->cols[i].flags & KHUI_CW_COL_GROUP) {\r
+ grouping[tbl->cols[i].sort_index] = i;\r
+ if(n_grouping <= tbl->cols[i].sort_index)\r
+ n_grouping = tbl->cols[i].sort_index + 1;\r
+ }\r
+ }\r
+\r
+ /* if we have sorted by an index without grouping by it, we can't\r
+ establish any grouping beyond that index. */\r
+ for(i=0; i < n_grouping; i++) {\r
+ if(grouping[i] == -1)\r
+ break;\r
+ }\r
+ n_grouping = i;\r
+\r
+ if(!tbl->rows) {\r
+ /* we haven't allocated memory yet */\r
+ tbl->n_total_rows = KHUI_CW_ROW_INITIAL;\r
+ tbl->n_rows = 0;\r
+ tbl->rows = malloc(sizeof(khui_credwnd_row) * tbl->n_total_rows);\r
+ } else {\r
+ /* kill any pending timers */\r
+ for(i=0; i < (int) tbl->n_rows; i++) \r
+ if(tbl->rows[i].flags & KHUI_CW_ROW_TIMERSET)\r
+ {\r
+ KillTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[i]));\r
+ tbl->rows[i].flags &= ~KHUI_CW_ROW_TIMERSET;\r
+ }\r
+ }\r
+\r
+ if(KHM_FAILED(kcdb_credset_get_size(tbl->credset, &n_creds)))\r
+ goto _exit;\r
+\r
+ n_rows = 0;\r
+ prevcred = NULL;\r
+ ol = NULL;\r
+\r
+ for(i=0; i < (int) n_creds; i++) {\r
+ if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, i, &thiscred)))\r
+ continue;\r
+\r
+ /* if this credential appears to be the same as another for\r
+ this view, we skip it */\r
+ if(prevcred) {\r
+ for(j=0; j < (int) tbl->n_cols; j++) {\r
+ if(kcdb_creds_comp_attr(prevcred, thiscred, tbl->cols[j].attr_id))\r
+ break;\r
+ }\r
+\r
+ if(j >= (int) tbl->n_cols) {\r
+ if (n_rows > 0) {\r
+ tbl->rows[n_rows - 1].idx_end = i;\r
+ }\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if(!prevcred)\r
+ level = 0;\r
+ else {\r
+ for(j=0; j < n_grouping; j++) {\r
+ /* determine the grouping level at which thiscred\r
+ differs from prevcred */\r
+ if(kcdb_creds_comp_attr(prevcred,thiscred,tbl->cols[grouping[j]].attr_id))\r
+ break;\r
+ }\r
+ level = j;\r
+ }\r
+\r
+ /* now we have to walk up until we get to the parent of the\r
+ outline level we should be in */\r
+ while(ol && ol->level >= level) {\r
+ ol->length = n_rows - ol->start;\r
+ ol->idx_end = i - 1;\r
+ ol = TPARENT(ol);\r
+ }\r
+\r
+ if(ol) {\r
+ visible = (ol->flags & KHUI_CW_O_VISIBLE) && \r
+ (ol->flags & KHUI_CW_O_EXPAND);\r
+ selected = (ol->flags & KHUI_CW_O_SELECTED);\r
+ } else {\r
+ visible = TRUE;\r
+ selected = FALSE;\r
+ }\r
+\r
+ /* now ol points to an outline node at the next highest level\r
+ or is NULL if level = 0 */\r
+\r
+ for(j=level; j < n_grouping; j++) {\r
+ khui_credwnd_outline * to;\r
+ /* now we search for an outline object at the next level\r
+ which matches the heading */\r
+ cbbuf = sizeof(buf);\r
+ buf[0] = L'\0';\r
+ if(KHM_FAILED\r
+ (kcdb_cred_get_attr_string(thiscred, \r
+ tbl->cols[grouping[j]].attr_id, \r
+ buf, &cbbuf, 0))) {\r
+ cbbuf = sizeof(wchar_t);\r
+ buf[0] = L'\0';\r
+ }\r
+\r
+ if(ol)\r
+ to = TFIRSTCHILD(ol);\r
+ else\r
+ to = tbl->outline;\r
+\r
+ while(to) {\r
+ if(!wcscmp(buf, to->header))\r
+ break;\r
+ to = LNEXT(to);\r
+ }\r
+\r
+ if(to) {\r
+ /* found it */\r
+ ol = to;\r
+ } else {\r
+ /* not found. create */\r
+ to = cw_new_outline_node(buf);\r
+ if(ol) {\r
+ TADDCHILD(ol, to);\r
+ } else {\r
+ LPUSH(&(tbl->outline), to);\r
+ }\r
+ ol = to;\r
+ ol->flags = KHUI_CW_O_EXPAND;\r
+ ol->level = j;\r
+ ol->col = grouping[j];\r
+\r
+ if(tbl->cols[grouping[j]].attr_id == KCDB_ATTR_ID_NAME) {\r
+ khm_handle h;\r
+ if(KHM_SUCCEEDED(kcdb_identity_create(buf, 0, &h))) {\r
+ ol->attr_id = KCDB_ATTR_ID;\r
+ ol->data = (void *) h;\r
+\r
+ /* the outline only lasts as long as the\r
+ credential, and the credential has a hold\r
+ on the identity. */\r
+ kcdb_identity_release(h);\r
+ }\r
+ else\r
+ ol->data = 0;\r
+ } else if(tbl->cols[grouping[j]].attr_id == \r
+ KCDB_ATTR_TYPE_NAME) {\r
+ khm_int32 t;\r
+ ol->attr_id = KCDB_ATTR_TYPE;\r
+ if(KHM_SUCCEEDED(kcdb_cred_get_type(thiscred, &t)))\r
+ ol->data = (void *)(ssize_t) t;\r
+ else\r
+ ol->data = (void *)(ssize_t) KCDB_CREDTYPE_INVALID;\r
+ } else {\r
+ khm_int32 rv;\r
+ khm_int32 alt_id;\r
+ kcdb_attrib * attrib;\r
+\r
+ rv = \r
+ kcdb_attrib_get_info(tbl->cols[grouping[j]].attr_id,\r
+ &attrib);\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ if (attrib->flags & KCDB_ATTR_FLAG_ALTVIEW)\r
+ alt_id = attrib->alt_id;\r
+ else\r
+ alt_id = tbl->cols[grouping[j]].attr_id;\r
+\r
+ ol->attr_id = alt_id;\r
+\r
+ kcdb_attrib_release_info(attrib);\r
+\r
+ rv = kcdb_cred_get_attr(thiscred,\r
+ alt_id,\r
+ NULL,\r
+ NULL,\r
+ &cbbuf);\r
+ if (rv != KHM_ERROR_TOO_LONG || cbbuf == 0) {\r
+ ol->data = NULL;\r
+ } else {\r
+ ol->data = malloc(cbbuf);\r
+ assert(ol->data);\r
+ rv = kcdb_cred_get_attr(thiscred,\r
+ alt_id,\r
+ NULL,\r
+ ol->data,\r
+ &cbbuf);\r
+ assert(KHM_SUCCEEDED(rv));\r
+ ol->cb_data = cbbuf;\r
+ ol->flags |= KHUI_CW_O_DATAALLOC;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* now ol points at the node at level j we want to be\r
+ in */\r
+ ol->start = n_rows;\r
+ ol->idx_start = i;\r
+ ol->length = 0;\r
+ ol->flags &= ~CW_EXPSTATE_MASK;\r
+ ol->flags &= ~KHUI_CW_O_SHOWFLAG;\r
+ ol->flags &= ~KHUI_CW_O_STICKY;\r
+\r
+ if(selected) {\r
+ ol->flags |= KHUI_CW_O_SELECTED;\r
+ }\r
+ if(visible) {\r
+ cw_set_tbl_row_header(tbl, n_rows, grouping[j], ol);\r
+ n_rows ++;\r
+ ol->flags |= KHUI_CW_O_VISIBLE;\r
+ } else {\r
+ ol->flags &= ~KHUI_CW_O_VISIBLE;\r
+ }\r
+ visible = visible && (ol->flags & KHUI_CW_O_EXPAND);\r
+ selected = (selected || (ol->flags & KHUI_CW_O_SELECTED));\r
+ }\r
+ \r
+ /* we need to do this here too just in case we were already at\r
+ the level we were supposed to be in */\r
+ visible = visible && (ol->flags & KHUI_CW_O_EXPAND);\r
+\r
+ flags = cw_get_cred_exp_flags(tbl, thiscred);\r
+\r
+ if(visible) {\r
+ khm_int32 c_flags;\r
+\r
+ cw_set_tbl_row_cred(tbl, n_rows, thiscred, \r
+ grouping[n_grouping-1]);\r
+ kcdb_cred_get_flags(thiscred, &c_flags);\r
+ if(flags) {\r
+ tbl->rows[n_rows].flags |= flags;\r
+ }\r
+ if(selected ||\r
+ (c_flags & KCDB_CRED_FLAG_SELECTED))\r
+ tbl->rows[n_rows].flags |= KHUI_CW_ROW_SELECTED;\r
+ tbl->rows[n_rows].idx_start = i;\r
+ tbl->rows[n_rows].idx_end = i;\r
+\r
+ n_rows++;\r
+ } else if(flags) {\r
+ khui_credwnd_outline *to;\r
+ /* the row that is flagged is not visible. We need to send\r
+ the flag upstream until we hit a visible outline node */\r
+ to = ol;\r
+ while(to && !(to->flags & KHUI_CW_O_VISIBLE)) {\r
+ to = TPARENT(to);\r
+ }\r
+ if(to) {\r
+ to->flags |= KHUI_CW_O_SHOWFLAG;\r
+ }\r
+ }\r
+\r
+ /* and we propagate the flags upstream */\r
+ if(flags) {\r
+ khui_credwnd_outline *to;\r
+\r
+ to = ol;\r
+ while(to) {\r
+ if((to->flags & CW_EXPSTATE_MASK) < flags) {\r
+ to->flags = (to->flags & ~CW_EXPSTATE_MASK) | flags;\r
+ }\r
+ to = TPARENT(to);\r
+ }\r
+ }\r
+\r
+ if(prevcred)\r
+ kcdb_cred_release(prevcred);\r
+ prevcred = thiscred;\r
+ }\r
+\r
+ while(ol) {\r
+ ol->length = n_rows - ol->start;\r
+ ol->idx_end = i - 1;\r
+ ol = TPARENT(ol);\r
+ }\r
+\r
+ if(prevcred) {\r
+ kcdb_cred_release(prevcred);\r
+ prevcred = NULL;\r
+ }\r
+\r
+ /* Add any sticky identities that we haven't seen yet */\r
+ if (n_grouping > 0 && \r
+ tbl->cols[grouping[0]].attr_id == KCDB_ATTR_ID_NAME) {\r
+\r
+ khui_credwnd_outline * o;\r
+ wchar_t * idnames = NULL;\r
+ wchar_t * t;\r
+ khm_size n_idents;\r
+ khm_size cb_names;\r
+ wchar_t ** idarray = NULL;\r
+ int i;\r
+\r
+ if (kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY,\r
+ KCDB_IDENT_FLAG_STICKY,\r
+ NULL,\r
+ &cb_names,\r
+ &n_idents) != KHM_ERROR_TOO_LONG ||\r
+ n_idents == 0 ||\r
+ cb_names == 0)\r
+ goto _cleanup_sticky;\r
+\r
+ idnames = malloc(cb_names);\r
+ idarray = malloc(n_idents * sizeof(*idarray));\r
+#ifdef DEBUG\r
+ assert(idnames);\r
+ assert(idarray);\r
+#endif\r
+\r
+ if (KHM_FAILED(kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY,\r
+ KCDB_IDENT_FLAG_STICKY,\r
+ idnames,\r
+ &cb_names,\r
+ &n_idents)))\r
+ goto _cleanup_sticky;\r
+\r
+ for (i=0, t=idnames; t && *t; t = multi_string_next(t), i++) {\r
+ idarray[i] = t;\r
+ }\r
+\r
+ qsort(idarray, n_idents, sizeof(*idarray), iwcscmp);\r
+\r
+ for (i=0; i < (int) n_idents; i++) {\r
+ for (o = tbl->outline; o; o = LNEXT(o)) {\r
+ if (!wcscmp(idarray[i], o->header))\r
+ break;\r
+ }\r
+\r
+ if (o) {\r
+ /* found it */\r
+ if (o->start != -1) /* already visible? */\r
+ continue;\r
+ } else {\r
+ /* not found. create */\r
+ o = cw_new_outline_node(idarray[i]);\r
+ o->flags = KHUI_CW_O_VISIBLE;\r
+ o->level = 0;\r
+ o->col = grouping[0];\r
+ }\r
+\r
+ o->flags |= KHUI_CW_O_STICKY;\r
+ o->flags &= ~KHUI_CW_O_EXPAND;\r
+ o->start = n_rows;\r
+ o->length = 1;\r
+ o->idx_start = -1;\r
+\r
+ cw_set_tbl_row_header(tbl, n_rows, grouping[0], o);\r
+\r
+ n_rows ++;\r
+ }\r
+\r
+ _cleanup_sticky:\r
+ if (idnames)\r
+ free(idnames);\r
+ if (idarray)\r
+ free(idarray);\r
+ }\r
+\r
+ tbl->n_rows = n_rows;\r
+ tbl->flags |= KHUI_CW_TBL_ROW_DIRTY;\r
+\r
+ tbl->flags &= ~KHUI_CW_TBL_COL_DIRTY;\r
+_exit:\r
+ if(grouping)\r
+ free(grouping);\r
+}\r
+\r
+void \r
+cw_unload_view(khui_credwnd_tbl * tbl)\r
+{\r
+#define SafeDeleteObject(o) \\r
+ do { \\r
+ if(o) { \\r
+ DeleteObject(o); \\r
+ o = NULL; \\r
+ } \\r
+ } while(0)\r
+\r
+ SafeDeleteObject(tbl->hf_header);\r
+ SafeDeleteObject(tbl->hf_normal);\r
+ SafeDeleteObject(tbl->hf_bold);\r
+ SafeDeleteObject(tbl->hf_bold_header);\r
+ SafeDeleteObject(tbl->hb_grey);\r
+ SafeDeleteObject(tbl->hb_normal);\r
+ SafeDeleteObject(tbl->hb_sel);\r
+ SafeDeleteObject(tbl->hb_hdr_bg);\r
+ SafeDeleteObject(tbl->hb_hdr_bg_sel);\r
+ SafeDeleteObject(tbl->hb_hdr_bg_crit);\r
+ SafeDeleteObject(tbl->hb_hdr_bg_exp);\r
+ SafeDeleteObject(tbl->hb_hdr_bg_warn);\r
+\r
+#undef SafeDeleteObject\r
+\r
+ if(tbl->credset) {\r
+ kcdb_credset_delete(tbl->credset);\r
+ tbl->credset = NULL;\r
+ }\r
+ if(tbl->ilist) {\r
+ khui_delete_ilist(tbl->ilist);\r
+ tbl->ilist = NULL;\r
+ }\r
+\r
+ if(tbl->cols) {\r
+ khm_size i;\r
+ for(i=0; i < tbl->n_cols; i++) {\r
+ if(tbl->cols[i].title)\r
+ free(tbl->cols[i].title);\r
+ Header_DeleteItem(tbl->hwnd_header, 0);\r
+ }\r
+ free(tbl->cols);\r
+ tbl->cols = NULL;\r
+ tbl->n_cols = 0;\r
+ tbl->n_total_cols = 0;\r
+ }\r
+\r
+ if(tbl->rows) {\r
+ free(tbl->rows);\r
+ tbl->rows = NULL;\r
+ tbl->n_rows = 0;\r
+ tbl->n_total_rows = 0;\r
+ }\r
+\r
+ khui_delete_bitmap(&tbl->kbm_logo_shade);\r
+}\r
+\r
+void \r
+cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi)\r
+{\r
+ size_t cchsize;\r
+\r
+ phi->mask = HDI_FORMAT | HDI_LPARAM | HDI_WIDTH;\r
+ if(cw_is_custom_attr(col->attr_id)) {\r
+ if(col->attr_id == CW_CA_FLAGS) {\r
+ phi->fmt = 0;\r
+ } else if(col->attr_id == CW_CA_TYPEICON) {\r
+ phi->fmt = 0;\r
+ } else {\r
+ /* what the? */\r
+ /*TODO: throw up and die */\r
+ }\r
+ } else {\r
+ phi->mask |= HDI_TEXT;\r
+ phi->pszText = col->title;\r
+ StringCchLength(col->title, KCDB_MAXCCH_SHORT_DESC, &cchsize);\r
+ phi->cchTextMax = (int) cchsize;\r
+ phi->fmt = HDF_CENTER | HDF_STRING;\r
+ }\r
+ phi->lParam = col->attr_id;\r
+ if(col->flags & KHUI_CW_COL_SORT_INC) {\r
+ phi->fmt |= HDF_SORTUP;\r
+ } else if(col->flags & KHUI_CW_COL_SORT_DEC) {\r
+ phi->fmt |= HDF_SORTDOWN;\r
+ }\r
+ if(col->width < 0) {\r
+ /*TODO: come up with a better way to handle this case */\r
+ col->width = 200;\r
+ }\r
+ phi->cxy = col->width;\r
+}\r
+\r
+/* returns a bitmask indicating which measures were changed */\r
+int \r
+cw_update_extents(khui_credwnd_tbl * tbl, \r
+ khm_boolean update_scroll) {\r
+ int ext_x, ext_y;\r
+ int i;\r
+\r
+ ext_x = 0;\r
+ for(i=0; i < (int) tbl->n_cols; i++) {\r
+ tbl->cols[i].x = ext_x;\r
+ ext_x += tbl->cols[i].width;\r
+ }\r
+\r
+ if(!tbl->cell_height) {\r
+ HDC dc;\r
+ HFONT hfold;\r
+ SIZE size;\r
+ size_t cbbuf;\r
+ wchar_t buf[64];\r
+\r
+ dc = GetWindowDC(tbl->hwnd);\r
+ if(tbl->hf_normal)\r
+ hfold = SelectFont(dc, tbl->hf_normal);\r
+\r
+ LoadString(khm_hInstance, IDS_SAMPLE_STRING, buf, sizeof(buf)/sizeof(buf[0]));\r
+ StringCchLength(buf, sizeof(buf)/sizeof(buf[0]), &cbbuf);\r
+ GetTextExtentPoint32(dc, buf, (int) cbbuf, &size);\r
+\r
+ if(tbl->hf_normal)\r
+ SelectFont(dc,hfold);\r
+ ReleaseDC(tbl->hwnd, dc);\r
+\r
+ tbl->cell_height = size.cy + tbl->vpad * 2;\r
+ }\r
+\r
+ ext_y = (int) tbl->n_rows * tbl->cell_height;\r
+\r
+ tbl->ext_width = ext_x;\r
+ tbl->ext_height = ext_y;\r
+\r
+ /* useful in the future when implementing variable height rows.\r
+ The KHUI_CW_TBL_ROW_DIRTY bit indicates that the rows have\r
+ changed and that the y extent has to be recalculated. */\r
+ tbl->flags &= ~KHUI_CW_TBL_ROW_DIRTY;\r
+\r
+ if(update_scroll) {\r
+ RECT r;\r
+ int cl_w;\r
+ int cl_h;\r
+ SCROLLINFO si;\r
+ WINDOWPOS pw;\r
+ HDLAYOUT hdl;\r
+\r
+ /* update the header control first */\r
+\r
+retry_update_scroll:\r
+ GetClientRect(tbl->hwnd, &r);\r
+\r
+ cl_w = r.right - r.left;\r
+ cl_h = (r.bottom - r.top);\r
+ cl_h -= tbl->header_height;\r
+\r
+ if(tbl->scr_top < 0 || tbl->ext_height < cl_h)\r
+ tbl->scr_top = 0;\r
+ else if(tbl->scr_top > tbl->ext_height - cl_h)\r
+ tbl->scr_top = tbl->ext_height - cl_h;\r
+ if(tbl->scr_left < 0 || tbl->ext_width < cl_w)\r
+ tbl->scr_left = 0;\r
+ else if(tbl->scr_left > tbl->ext_width - cl_w)\r
+ tbl->scr_left = tbl->ext_width - cl_w;\r
+\r
+ /* adjustments for scrolling */\r
+ r.left -= tbl->scr_left;\r
+ r.right = max(tbl->ext_width + r.left, r.right);\r
+\r
+ hdl.prc = &r;\r
+ hdl.pwpos = &pw;\r
+\r
+ Header_Layout(tbl->hwnd_header, &hdl);\r
+\r
+ if(tbl->header_height == 0) {\r
+ tbl->header_height = pw.cy;\r
+ goto retry_update_scroll;\r
+ } else\r
+ tbl->header_height = pw.cy;\r
+\r
+ SetWindowPos(\r
+ tbl->hwnd_header, \r
+ pw.hwndInsertAfter, \r
+ pw.x, \r
+ pw.y, \r
+ pw.cx, \r
+ pw.cy, \r
+ pw.flags);\r
+\r
+ si.cbSize = sizeof(si);\r
+ si.nMin = 0;\r
+ si.nMax = tbl->ext_height;\r
+ si.nPage = cl_h;\r
+ si.nPos = tbl->scr_top;\r
+ si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;\r
+ SetScrollInfo(tbl->hwnd, SB_VERT, &si, TRUE);\r
+\r
+ si.cbSize = sizeof(si);\r
+ si.nMin = 0;\r
+ si.nMax = tbl->ext_width;\r
+ si.nPage = cl_w;\r
+ si.nPos = tbl->scr_left;\r
+ si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;\r
+ SetScrollInfo(tbl->hwnd, SB_HORZ, &si, TRUE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+void \r
+cw_insert_header_cols(khui_credwnd_tbl * tbl) {\r
+ HWND hdr;\r
+ HDITEM hi;\r
+ int i;\r
+\r
+ hdr = tbl->hwnd_header;\r
+ \r
+ for(i=0; i < (int) tbl->n_cols; i++) {\r
+ cw_hditem_from_tbl_col(&(tbl->cols[i]), &hi);\r
+ Header_InsertItem(hdr, 512, &hi);\r
+ }\r
+}\r
+\r
+#define CW_ER_BLANK 0\r
+#define CW_ER_GREY 1\r
+#define CW_ER_SEL 2\r
+\r
+void \r
+cw_erase_rect(HDC hdc, \r
+ khui_credwnd_tbl * tbl, \r
+ RECT * r_wnd, \r
+ RECT * r_erase, \r
+ int type)\r
+{\r
+ RECT rlogo;\r
+ RECT ri;\r
+ RECT t;\r
+ BOOL rie;\r
+ HBRUSH hbr;\r
+\r
+ if(RectVisible(hdc, r_erase)) {\r
+\r
+ switch(type) {\r
+ case CW_ER_BLANK:\r
+ hbr = tbl->hb_normal;\r
+ break;\r
+\r
+ case CW_ER_GREY:\r
+ hbr = tbl->hb_grey;\r
+ break;\r
+\r
+ case CW_ER_SEL:\r
+ hbr = tbl->hb_sel;\r
+ break;\r
+\r
+ default:\r
+ return;\r
+ }\r
+\r
+ if(tbl->kbm_logo_shade.cx != -1 && type == CW_ER_BLANK) {\r
+ rlogo.left = r_wnd->right - tbl->kbm_logo_shade.cx;\r
+ rlogo.right = r_wnd->right;\r
+ rlogo.top = r_wnd->bottom - tbl->kbm_logo_shade.cy;\r
+ rlogo.bottom = r_wnd->bottom;\r
+ rie = IntersectRect(&ri, r_erase, &rlogo);\r
+ } else {\r
+ rie = FALSE;\r
+ }\r
+\r
+ if(!rie) {\r
+ FillRect(hdc, r_erase, hbr);\r
+ } else {\r
+ HDC hdcb = CreateCompatibleDC(hdc);\r
+ HBITMAP hbmold = SelectObject(hdcb, tbl->kbm_logo_shade.hbmp);\r
+\r
+ BitBlt(hdc, ri.left, ri.top, ri.right - ri.left, ri.bottom - ri.top,\r
+ hdcb, ri.left - rlogo.left, ri.top - rlogo.top, SRCCOPY);\r
+ \r
+ SelectObject(hdcb, hbmold);\r
+ DeleteDC(hdcb);\r
+\r
+ if(r_erase->top < ri.top && r_erase->left < ri.left) {\r
+ t.left = r_erase->left;\r
+ t.top = r_erase->top;\r
+ t.right = ri.left;\r
+ t.bottom = ri.top;\r
+ FillRect(hdc, &t, hbr);\r
+ }\r
+\r
+ if(r_erase->left < ri.left) {\r
+ t.left = r_erase->left;\r
+ t.top = ri.top;\r
+ t.right = ri.left;\r
+ t.bottom = ri.bottom;\r
+ FillRect(hdc, &t, hbr);\r
+ }\r
+\r
+ if(r_erase->top < ri.top) {\r
+ t.left = ri.left;\r
+ t.top = r_erase->top;\r
+ t.right = ri.right;\r
+ t.bottom = ri.top;\r
+ FillRect(hdc, &t, hbr);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void \r
+cw_draw_header(HDC hdc, \r
+ khui_credwnd_tbl * tbl, \r
+ int row, \r
+ RECT * r)\r
+{\r
+ int colattr;\r
+ HPEN pl, pold;\r
+ khui_credwnd_row * cr;\r
+ khui_credwnd_outline * o;\r
+ int selected = 0;\r
+ \r
+ /* each header consists of a 'expose' widget and some text */\r
+ /* we need to figure out the background color first */\r
+ \r
+ cr = &(tbl->rows[row]);\r
+ o = (khui_credwnd_outline *) cr->data;\r
+\r
+ colattr = tbl->cols[cr->col].attr_id;\r
+\r
+ selected = o->flags & KHUI_CW_O_SELECTED;\r
+\r
+ {\r
+ HBRUSH hbr;\r
+ if(selected)\r
+ hbr = tbl->hb_hdr_bg_sel;\r
+ else if((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED)\r
+ hbr = tbl->hb_hdr_bg_exp;\r
+ else if((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL)\r
+ hbr = tbl->hb_hdr_bg_crit;\r
+ else if((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN)\r
+ hbr = tbl->hb_hdr_bg_warn;\r
+ else\r
+ hbr = tbl->hb_hdr_bg;\r
+\r
+ FillRect(hdc, r, hbr);\r
+ }\r
+\r
+ pl = CreatePen(PS_SOLID, 0, tbl->cr_hdr_outline);\r
+ pold = SelectObject(hdc, pl);\r
+ MoveToEx(hdc, r->left, r->bottom - 1, NULL);\r
+ LineTo(hdc,r->right,r->bottom - 1);\r
+ SelectObject(hdc, pold);\r
+ DeleteObject(pl);\r
+\r
+ if (o->flags & KHUI_CW_O_STICKY) {\r
+ /* khui_ilist_draw_id(tbl->ilist, IDB_TK_NEW_SM, hdc, \r
+ r->left, r->bottom - KHUI_SMICON_CY, 0); */\r
+ } else if((tbl->mouse_state & CW_MOUSE_OUTLINE) && tbl->mouse_row == row) {\r
+ if(o->flags & KHUI_CW_O_EXPAND) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
+ } else {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
+ }\r
+ } else {\r
+ if(o->flags & KHUI_CW_O_EXPAND) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
+ } else {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
+ }\r
+ }\r
+\r
+ r->left += KHUI_SMICON_CX * 2;\r
+\r
+ /* try to draw the icon, if there is one */\r
+ if(colattr == KCDB_ATTR_ID_NAME) {\r
+ khui_ilist_draw_id(tbl->ilist, \r
+ ((o->flags & KHUI_CW_O_STICKY)?\r
+ IDB_ID_DIS_SM:\r
+ IDB_ID_SM), \r
+ hdc, \r
+ r->left, r->bottom - KHUI_SMICON_CY, \r
+ 0);\r
+ r->left += KHUI_SMICON_CX ;\r
+ }\r
+\r
+ /* ok, now o->header contains the string representation of the\r
+ outline value */\r
+ /* for now just write out the value */\r
+ SetTextAlign(hdc, TA_BOTTOM | TA_LEFT);\r
+\r
+ if(selected)\r
+ SetTextColor(hdc, tbl->cr_hdr_sel);\r
+ else\r
+ SetTextColor(hdc, tbl->cr_hdr_normal);\r
+\r
+ TextOut(hdc, r->left, r->bottom - tbl->vpad, o->header, (int) wcslen(o->header));\r
+}\r
+\r
+LRESULT \r
+cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) {\r
+ RECT r;\r
+ HDITEM hi;\r
+\r
+ switch(ph->hdr.code) {\r
+ /*TODO:Make it track smoother */\r
+ case HDN_BEGINTRACK:\r
+ {\r
+ if(tbl->cols[ph->iItem].flags & KHUI_CW_COL_FIXED_WIDTH)\r
+ return TRUE;\r
+ else\r
+ return FALSE;\r
+ }\r
+\r
+ case HDN_TRACK:\r
+ case HDN_ENDTRACK:\r
+ {\r
+ int width;\r
+ hi.mask = HDI_ORDER;\r
+ Header_GetItem(ph->hdr.hwndFrom, ph->iItem, &hi);\r
+ Header_GetItemRect(ph->hdr.hwndFrom, ph->iItem, &r);\r
+ width = r.right - r.left;\r
+ if(width != tbl->cols[hi.iOrder].width) {\r
+ tbl->cols[hi.iOrder].width = width;\r
+ cw_update_extents(tbl, TRUE);\r
+ InvalidateRect(tbl->hwnd, NULL, FALSE);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case NM_CUSTOMDRAW:\r
+ {\r
+ LPNMCUSTOMDRAW cd;\r
+ int idx;\r
+\r
+ cd = (LPNMCUSTOMDRAW) ph;\r
+ switch(cd->dwDrawStage)\r
+ {\r
+ case CDDS_PREPAINT:\r
+ return CDRF_NOTIFYITEMDRAW;\r
+\r
+ case CDDS_ITEMPREPAINT:\r
+ return CDRF_NOTIFYPOSTPAINT;\r
+\r
+ case CDDS_ITEMPOSTPAINT:\r
+ if(cd->lItemlParam == CW_CA_FLAGS)\r
+ idx = IDB_WDG_FLAG;\r
+ else if(cd->lItemlParam == CW_CA_TYPEICON)\r
+ idx = IDB_WDG_CREDTYPE;\r
+ else\r
+ idx = -1;\r
+\r
+ khui_ilist_draw_id(tbl->ilist, idx, cd->hdc, cd->rc.left, cd->rc.top, 0);\r
+ return 0;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+LRESULT \r
+cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ kmq_subscribe_hwnd(KMSG_CRED, hwnd);\r
+\r
+ tbl = malloc(sizeof(*tbl));\r
+ ZeroMemory(tbl, sizeof(*tbl));\r
+\r
+ /* some versions of VC generate portability warnings for\r
+ SetWindowLongPtr */\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) tbl);\r
+#pragma warning(pop)\r
+\r
+ tbl->hwnd_header = CreateWindowEx(\r
+ 0,\r
+ WC_HEADER,\r
+ (LPWSTR) NULL,\r
+ WS_CHILD | HDS_BUTTONS |\r
+ HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK | HDS_FLAT,\r
+ 0,0,0,0,hwnd, (HMENU) 0, khm_hInstance, NULL);\r
+\r
+ cw_load_view(tbl, NULL /* default view */, hwnd);\r
+ cw_insert_header_cols(tbl);\r
+\r
+ cw_update_creds(tbl);\r
+ cw_update_outline(tbl);\r
+ cw_update_extents(tbl, FALSE);\r
+\r
+ {\r
+ RECT rect;\r
+ WINDOWPOS pw;\r
+ HDLAYOUT hdl;\r
+\r
+ hdl.prc = ▭\r
+ hdl.pwpos = &pw;\r
+ GetClientRect(hwnd, &rect);\r
+\r
+ Header_Layout(tbl->hwnd_header, &hdl);\r
+\r
+ SetWindowPos(\r
+ tbl->hwnd_header, \r
+ pw.hwndInsertAfter, \r
+ pw.x, \r
+ pw.y, \r
+ pw.cx, \r
+ pw.cy, \r
+ pw.flags | SWP_SHOWWINDOW);\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT \r
+cw_wm_destroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ cw_unload_view(tbl);\r
+\r
+ free(tbl);\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT \r
+cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+ HDC hdc;\r
+ PAINTSTRUCT ps;\r
+ RECT r,rh;\r
+ HFONT hf_old;\r
+ int row_s, row_e;\r
+ int col_s, col_e;\r
+ int i,j,x,y,xs,xe,ys,ye;\r
+ int flag_col = -1;\r
+ int d_x = -1;\r
+ int selected = 0;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(!GetUpdateRect(hwnd, &r, FALSE))\r
+ goto _exit;\r
+\r
+ hdc = BeginPaint(hwnd, &ps);\r
+ if(tbl->hf_normal)\r
+ hf_old = SelectFont(hdc, tbl->hf_normal);\r
+ SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP);\r
+ SetBkMode(hdc, TRANSPARENT);\r
+\r
+ GetClientRect(hwnd,&r);\r
+ r.top += tbl->header_height;\r
+\r
+ if(tbl->n_rows) {\r
+ /* remove the notification window if there is one */\r
+ if(tbl->hwnd_notif) {\r
+ DestroyWindow(tbl->hwnd_notif);\r
+ tbl->hwnd_notif = NULL;\r
+ }\r
+ /* we compute the visible area in terms of rows and columns */\r
+ /* row_s : first visible row */\r
+ /* col_s : first visible column */\r
+ /* row_e : last visible row */\r
+ /* col_e : last visible column */\r
+ /* ys : top edge of first visible row */\r
+ /* xs : left edge of first visible column */\r
+\r
+ /* We *NEED* all the meta columns to be on the left */\r
+\r
+ row_s = tbl->scr_top / tbl->cell_height;\r
+ ys = row_s * tbl->cell_height;\r
+ row_e = (tbl->scr_top + (r.bottom - r.top)) / tbl->cell_height + 1;\r
+ if(row_e > (int) tbl->n_rows)\r
+ row_e = (int) tbl->n_rows;\r
+ x = 0;\r
+ col_s = -1;\r
+ col_e = -1;\r
+ xs = 0;\r
+ for(i=0; i < (int) tbl->n_cols; i++) {\r
+ if(col_e == -1 && x >= tbl->scr_left + (r.right - r.left)) {\r
+ col_e = i;\r
+ }\r
+ if(tbl->cols[i].attr_id == CW_CA_FLAGS)\r
+ flag_col = i;\r
+ if(d_x == -1 && !cw_is_custom_attr(tbl->cols[i].attr_id))\r
+ d_x = x;\r
+ x += tbl->cols[i].width;\r
+ if(col_s == -1 && x > tbl->scr_left) {\r
+ col_s = i;\r
+ xs = tbl->cols[i].x;\r
+ }\r
+ }\r
+\r
+ if(col_e == -1)\r
+ col_e = i;\r
+\r
+ if(col_s == -1)\r
+ col_s = i;\r
+\r
+ if(d_x != -1)\r
+ d_x += r.left - tbl->scr_left;\r
+\r
+ xs += r.left - tbl->scr_left;\r
+ ys += r.top - tbl->scr_top;\r
+ xe = r.left + tbl->ext_width - tbl->scr_left;\r
+ ye = r.top + tbl->ext_height - tbl->scr_top;\r
+\r
+ /* now draw */\r
+ y = ys;\r
+ for(i=row_s; i < row_e; i++) {\r
+ selected = tbl->rows[i].flags & KHUI_CW_ROW_SELECTED;\r
+\r
+ if(tbl->cursor_row == i)\r
+ SelectFont(hdc, tbl->hf_bold);\r
+\r
+ x = xs;\r
+ if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) {\r
+ rh.left = xs;\r
+ rh.right = xs;\r
+ for(j=col_s; j < tbl->rows[i].col; j++)\r
+ rh.right += tbl->cols[j].width;\r
+ rh.top = y;\r
+ rh.bottom = y + tbl->cell_height;\r
+ if(rh.right > rh.left) {\r
+ cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK);\r
+ }\r
+ rh.left = rh.right;\r
+ rh.right = xe;\r
+\r
+ cw_draw_header(hdc, tbl, i, &rh);\r
+ }\r
+ \r
+ if(selected)\r
+ SetTextColor(hdc, tbl->cr_sel);\r
+ else\r
+ SetTextColor(hdc, tbl->cr_normal);\r
+\r
+ x = xs;\r
+ rh.top = y;\r
+ rh.bottom = y + tbl->cell_height;\r
+ for(j=col_s; j < col_e; x += tbl->cols[j++].width) {\r
+ wchar_t buf[256];\r
+ khm_size cbbuf;\r
+\r
+ rh.left = x;\r
+ rh.right = x + tbl->cols[j].width;\r
+\r
+ if(!RectVisible(hdc, &rh))\r
+ continue;\r
+\r
+ if(!cw_is_custom_attr(tbl->cols[j].attr_id)) {\r
+ if(!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) {\r
+ cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK);\r
+\r
+ if(j > tbl->rows[i].col) {\r
+ cbbuf = sizeof(buf);\r
+ if(KHM_FAILED(kcdb_cred_get_attr_string((khm_handle) tbl->rows[i].data, tbl->cols[j].attr_id, buf, &cbbuf, KCDB_TS_SHORT)))\r
+ continue;\r
+\r
+ rh.left += tbl->hpad;\r
+ rh.right -= tbl->hpad;\r
+\r
+ SetTextAlign(hdc, 0);\r
+ DrawText(hdc, buf, (int)((cbbuf / sizeof(wchar_t)) - 1), &rh, DT_LEFT | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE | DT_END_ELLIPSIS);\r
+ //TextOut(hdc, x, y + tbl->vpad, buf, (cbbuf / sizeof(wchar_t)) - 1);\r
+ }\r
+ }\r
+ } else {\r
+ cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK);\r
+\r
+ if(tbl->cols[j].attr_id == CW_CA_FLAGS) {\r
+ khui_credwnd_outline * o;\r
+ khm_int32 flag;\r
+\r
+ if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) {\r
+ o = ((khui_credwnd_outline *) tbl->rows[i].data);\r
+ if(o->flags & KHUI_CW_O_SHOWFLAG)\r
+ flag = o->flags;\r
+ else\r
+ flag = 0;\r
+ }\r
+ else\r
+ flag = tbl->rows[i].flags;\r
+\r
+ flag &= CW_EXPSTATE_MASK;\r
+\r
+ if(flag == CW_EXPSTATE_WARN) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_FLAG_WARN, hdc, x, y, 0);\r
+ } else if(flag == CW_EXPSTATE_CRITICAL) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_FLAG_CRITICAL, hdc, x, y, 0);\r
+ } else if(flag == CW_EXPSTATE_EXPIRED) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_FLAG_EXPIRED, hdc, x, y, 0);\r
+ } else {\r
+ khm_int32 flags;\r
+\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_flags((khm_handle) tbl->rows[i].data, &flags)) &&\r
+ (flags & KCDB_CRED_FLAG_RENEWABLE)) {\r
+ khui_ilist_draw_id(tbl->ilist,\r
+ IDB_TK_REFRESH_SM,\r
+ hdc,\r
+ x, y, 0);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if(tbl->cursor_row == i) {\r
+ rh.left = tbl->scr_left;\r
+ rh.right = tbl->scr_left + tbl->ext_width;\r
+\r
+ DrawFocusRect(hdc, &rh);\r
+\r
+ SelectFont(hdc, tbl->hf_normal);\r
+ }\r
+\r
+ y += tbl->cell_height;\r
+\r
+ }\r
+\r
+ if(xe < r.right) {\r
+ rh.left = xe;\r
+ rh.right = r.right;\r
+ rh.top = r.top;\r
+ rh.bottom = r.bottom;\r
+\r
+ cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK);\r
+ }\r
+\r
+ if(ye < r.bottom) {\r
+ rh.left = r.left;\r
+ rh.right = (xe < r.right)?xe:r.right;\r
+ rh.top = ye;\r
+ rh.bottom = r.bottom;\r
+\r
+ cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK);\r
+ }\r
+\r
+ } else {\r
+ wchar_t buf[512];\r
+ cw_erase_rect(hdc, tbl, &r, &r, CW_ER_BLANK);\r
+\r
+ if(tbl->hwnd_notif == NULL) {\r
+ LoadString(khm_hInstance, IDS_NO_CREDS, buf, sizeof(buf)/sizeof(buf[0]));\r
+ tbl->hwnd_notif = khm_create_htwnd(\r
+ tbl->hwnd,\r
+ buf,\r
+ r.left,r.top,r.right - r.left,(r.bottom - r.top) /2,\r
+ WS_EX_TRANSPARENT,\r
+ WS_VISIBLE);\r
+ if(tbl->hwnd_notif) {\r
+ SendMessage(tbl->hwnd_notif, WM_SETFONT, (WPARAM) tbl->hf_normal, (LPARAM) FALSE);\r
+ ShowWindow(tbl->hwnd_notif, SW_SHOW);\r
+ }\r
+ }\r
+ }\r
+\r
+ if(tbl->hf_normal)\r
+ SelectFont(hdc, hf_old);\r
+\r
+ EndPaint(hwnd,&ps);\r
+_exit:\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT \r
+cw_wm_size(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ RECT rect;\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ cw_update_extents(tbl, TRUE);\r
+\r
+ GetClientRect(hwnd, &rect);\r
+\r
+ if(tbl->hwnd_notif) {\r
+ SetWindowPos(\r
+ tbl->hwnd_notif,\r
+ tbl->hwnd_header,\r
+ rect.left,\r
+ tbl->header_height,\r
+ rect.right - rect.left,\r
+ (rect.bottom - tbl->header_height) / 2,\r
+ 0);\r
+ }\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT \r
+cw_wm_notify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+ LPNMHDR pnmh;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ pnmh = (LPNMHDR) lParam;\r
+ if(pnmh->hwndFrom == tbl->hwnd_header) {\r
+ LPNMHEADER ph;\r
+ ph = (LPNMHEADER) lParam;\r
+ return cw_handle_header_msg(tbl, ph);\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+static void cw_pp_begin(khui_property_sheet * s);\r
+static void cw_pp_precreate(khui_property_sheet * s);\r
+static void cw_pp_end(khui_property_sheet * s);\r
+static void cw_pp_destroy(khui_property_sheet *ps);\r
+\r
+LRESULT \r
+cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ kmq_message * m;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); \r
+\r
+ kmq_wm_begin(lParam, &m);\r
+ if(m->type == KMSG_CRED) {\r
+ if(m->subtype == KMSG_CRED_ROOTDELTA) {\r
+ cw_update_creds(tbl);\r
+ cw_update_outline(tbl);\r
+ cw_update_extents(tbl, TRUE);\r
+ InvalidateRect(hwnd, NULL, FALSE);\r
+ } else if(m->subtype == KMSG_CRED_PP_BEGIN) {\r
+ cw_pp_begin((khui_property_sheet *) m->vparam);\r
+ } else if(m->subtype == KMSG_CRED_PP_PRECREATE) {\r
+ cw_pp_precreate((khui_property_sheet *) m->vparam);\r
+ } else if(m->subtype == KMSG_CRED_PP_END) {\r
+ cw_pp_end((khui_property_sheet *) m->vparam);\r
+ } else if(m->subtype == KMSG_CRED_PP_DESTROY) {\r
+ cw_pp_destroy((khui_property_sheet *) m->vparam);\r
+ }\r
+ }\r
+ return kmq_wm_end(m, rv);\r
+}\r
+\r
+static void \r
+cw_select_outline_level(khui_credwnd_outline * o,\r
+ BOOL select)\r
+{\r
+ while(o) {\r
+ if (select)\r
+ o->flags |= KHUI_CW_O_SELECTED;\r
+ else\r
+ o->flags &= ~KHUI_CW_O_SELECTED;\r
+ cw_select_outline_level(TFIRSTCHILD(o), select);\r
+ o = LNEXT(o);\r
+ }\r
+}\r
+\r
+static void\r
+cw_select_outline(khui_credwnd_outline * o,\r
+ BOOL select)\r
+{\r
+ if (select)\r
+ o->flags |= KHUI_CW_O_SELECTED;\r
+ else\r
+ o->flags &= ~KHUI_CW_O_SELECTED;\r
+}\r
+\r
+static void \r
+cw_unselect_all(khui_credwnd_tbl * tbl)\r
+{\r
+ khm_size i;\r
+\r
+ for(i=0; i<tbl->n_rows; i++) {\r
+ tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED;\r
+ if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER))\r
+ kcdb_cred_set_flags((khm_handle) tbl->rows[i].data,\r
+ 0,\r
+ KCDB_CRED_FLAG_SELECTED);\r
+ }\r
+\r
+ cw_select_outline_level(tbl->outline, FALSE);\r
+}\r
+\r
+static void\r
+cw_update_outline_selection_state(khui_credwnd_tbl * tbl,\r
+ khui_credwnd_outline * o)\r
+{\r
+ BOOL select = TRUE;\r
+ int j;\r
+\r
+ for (j = o->start + 1; j < o->start + o->length; j++) {\r
+ if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) {\r
+ cw_update_outline_selection_state(tbl,\r
+ (khui_credwnd_outline *)\r
+ tbl->rows[j].data);\r
+ }\r
+\r
+ if (!(tbl->rows[j].flags & KHUI_CW_ROW_SELECTED)) {\r
+ select = FALSE;\r
+ }\r
+\r
+ if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) {\r
+ j += ((khui_credwnd_outline *) tbl->rows[j].data)->length - 1;\r
+ }\r
+ }\r
+\r
+ /* special case : the header has been collapsed and we are just\r
+ using one row. In this case, the for loop above will do\r
+ nothing. */\r
+\r
+ if (o->length == 1) {\r
+ select = (tbl->rows[o->start].flags & KHUI_CW_ROW_SELECTED);\r
+ }\r
+\r
+ cw_select_outline(o, select);\r
+\r
+ if (select) {\r
+ tbl->rows[o->start].flags |= KHUI_CW_ROW_SELECTED;\r
+ } else {\r
+ tbl->rows[o->start].flags &= ~KHUI_CW_ROW_SELECTED;\r
+ }\r
+}\r
+\r
+static void \r
+cw_update_selection_state(khui_credwnd_tbl * tbl)\r
+{\r
+ khm_size i;\r
+\r
+ cw_select_outline_level(tbl->outline, FALSE);\r
+\r
+ for (i=0; i < tbl->n_rows; i++) {\r
+ if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) {\r
+ khui_credwnd_outline * o;\r
+\r
+ o = (khui_credwnd_outline *) tbl->rows[i].data;\r
+\r
+ cw_update_outline_selection_state(tbl, o);\r
+\r
+ i += o->length - 1;\r
+ }\r
+ }\r
+}\r
+\r
+/* Examine the current row and set the UI context */\r
+static void \r
+cw_set_row_context(khui_credwnd_tbl * tbl, int row)\r
+{\r
+ khui_credwnd_outline * o;\r
+ BOOL set_context = TRUE;\r
+\r
+ if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) {\r
+\r
+ o = (khui_credwnd_outline *) tbl->rows[row].data;\r
+\r
+ if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) {\r
+ if (TPARENT(o) == NULL) { /* selected an identity */\r
+ khui_context_set(KHUI_SCOPE_IDENT,\r
+ (khm_handle) o->data,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ tbl->credset);\r
+ } else {\r
+ khui_credwnd_outline * op;\r
+\r
+ op = TPARENT(o);\r
+\r
+ if (tbl->cols[op->col].attr_id == KCDB_ATTR_TYPE_NAME &&\r
+ TPARENT(op) == NULL) {\r
+ /* selected a credential type */\r
+ khui_context_set(KHUI_SCOPE_CREDTYPE,\r
+ (khm_handle) o->data,\r
+ (khm_int32) (DWORD_PTR) op->data,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ tbl->credset);\r
+ } else {\r
+ set_context = FALSE;\r
+ }\r
+ }\r
+ } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_TYPE_NAME) {\r
+ if (TPARENT(o) == NULL) {\r
+ /* selected an entire cred type */\r
+ khui_context_set(KHUI_SCOPE_CREDTYPE,\r
+ NULL,\r
+ (khm_int32) (DWORD_PTR) o->data,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ tbl->credset);\r
+ } else {\r
+ khui_credwnd_outline * op;\r
+\r
+ op = TPARENT(o);\r
+ if (tbl->cols[op->col].attr_id == KCDB_ATTR_ID_NAME &&\r
+ TPARENT(op) == NULL) {\r
+ /* credtype under an identity */\r
+ khui_context_set(KHUI_SCOPE_CREDTYPE,\r
+ (khm_handle) op->data,\r
+ (khm_int32) (DWORD_PTR) o->data,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ tbl->credset);\r
+ } else {\r
+ set_context = FALSE;\r
+ }\r
+ }\r
+ } else {\r
+ set_context = FALSE;\r
+ }\r
+\r
+ if (!set_context) {\r
+ /* woohoo. cred group. yay. */\r
+ khui_header headers[KHUI_MAX_HEADERS];\r
+ khm_size n_headers = 0;\r
+\r
+ do {\r
+ headers[n_headers].attr_id =\r
+ o->attr_id;\r
+ if (tbl->cols[o->col].attr_id == \r
+ KCDB_ATTR_ID_NAME) {\r
+ headers[n_headers].data = &(o->data);\r
+ headers[n_headers].cb_data = sizeof(khm_handle);\r
+ } else if (tbl->cols[o->col].attr_id == \r
+ KCDB_ATTR_TYPE_NAME) {\r
+ headers[n_headers].data = &(o->data);\r
+ headers[n_headers].cb_data = sizeof(khm_int32);\r
+ } else {\r
+ headers[n_headers].data = o->data;\r
+ headers[n_headers].cb_data = o->cb_data;\r
+ }\r
+\r
+ n_headers++;\r
+\r
+ o = TPARENT(o);\r
+ } while(o);\r
+\r
+ khui_context_set(KHUI_SCOPE_GROUP,\r
+ NULL,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL,\r
+ headers,\r
+ n_headers,\r
+ tbl->credset);\r
+ }\r
+\r
+ } else {\r
+ khm_handle cred;\r
+\r
+ cred = (khm_handle) tbl->rows[row].data;\r
+\r
+ khui_context_set(KHUI_SCOPE_CRED,\r
+ NULL,\r
+ KCDB_CREDTYPE_INVALID,\r
+ cred,\r
+ NULL,\r
+ 0,\r
+ tbl->credset);\r
+ }\r
+}\r
+\r
+static void \r
+cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam)\r
+{\r
+ int i;\r
+ BOOL toggle;\r
+ BOOL extend;\r
+ int group_begin;\r
+ int group_end;\r
+\r
+ if (wParam & MK_CONTROL) {\r
+ toggle = TRUE;\r
+ extend = FALSE;\r
+ } else if (wParam & MK_SHIFT) {\r
+ toggle = FALSE;\r
+ extend = TRUE;\r
+ } else {\r
+ toggle = FALSE;\r
+ extend = FALSE;\r
+ }\r
+\r
+ if (row < 0 || row >= (int) tbl->n_rows)\r
+ return;\r
+\r
+ if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) {\r
+ khui_credwnd_outline * o;\r
+\r
+ o = (khui_credwnd_outline *) tbl->rows[row].data;\r
+\r
+ group_begin = o->start;\r
+ group_end = o->start + o->length - 1;\r
+ } else {\r
+ group_begin = row;\r
+ group_end = row;\r
+ }\r
+\r
+ if (!toggle && !extend) {\r
+ /* selecting a single row */\r
+ cw_unselect_all(tbl);\r
+\r
+ tbl->cursor_row = row;\r
+ tbl->anchor_row = row;\r
+\r
+ for (i = group_begin; i <= group_end; i++) {\r
+ tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED;\r
+ if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) {\r
+ kcdb_cred_set_flags((khm_handle) tbl->rows[i].data,\r
+ KCDB_CRED_FLAG_SELECTED,\r
+ KCDB_CRED_FLAG_SELECTED);\r
+ }\r
+ }\r
+ } else if (toggle) {\r
+ BOOL select;\r
+\r
+ tbl->cursor_row = row;\r
+ tbl->anchor_row = row;\r
+\r
+ select = !(tbl->rows[row].flags & KHUI_CW_ROW_SELECTED);\r
+\r
+ for (i = group_begin; i <= group_end; i++) {\r
+ if (select)\r
+ tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED;\r
+ else\r
+ tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED;\r
+\r
+ if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) {\r
+ kcdb_cred_set_flags((khm_handle) tbl->rows[i].data,\r
+ (select)?KCDB_CRED_FLAG_SELECTED:0,\r
+ KCDB_CRED_FLAG_SELECTED);\r
+ }\r
+\r
+ }\r
+ } else if (extend) {\r
+ int range_begin;\r
+ int range_end;\r
+\r
+ cw_unselect_all(tbl);\r
+\r
+ range_begin = min(row, tbl->anchor_row);\r
+ range_end = max(row, tbl->anchor_row);\r
+\r
+ for (i = range_begin; i <= range_end; i++) {\r
+ tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED;\r
+\r
+ if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) {\r
+ kcdb_cred_set_flags((khm_handle) tbl->rows[i].data,\r
+ KCDB_CRED_FLAG_SELECTED,\r
+ KCDB_CRED_FLAG_SELECTED);\r
+ }\r
+ }\r
+\r
+ tbl->cursor_row = row;\r
+ }\r
+\r
+ cw_update_selection_state(tbl);\r
+\r
+ cw_set_row_context(tbl, tbl->cursor_row);\r
+\r
+ InvalidateRect(tbl->hwnd, NULL, FALSE);\r
+}\r
+\r
+static void\r
+cw_toggle_outline_state(khui_credwnd_tbl * tbl,\r
+ khui_credwnd_outline * o) {\r
+\r
+ int old_range_begin;\r
+ int old_range_end;\r
+ int new_range_begin;\r
+ int new_range_end;\r
+\r
+ old_range_begin = o->start;\r
+ old_range_end = o->start + o->length - 1;\r
+ \r
+ o->flags ^= KHUI_CW_O_EXPAND;\r
+\r
+ cw_update_outline(tbl);\r
+ cw_update_extents(tbl, TRUE);\r
+\r
+ new_range_begin = o->start;\r
+ new_range_end = o->start + o->length - 1;\r
+\r
+ if (tbl->cursor_row > old_range_end) {\r
+ tbl->cursor_row -= old_range_end - new_range_end;\r
+ } else if (tbl->cursor_row >= old_range_begin &&\r
+ tbl->cursor_row <= old_range_end) {\r
+ tbl->cursor_row = new_range_begin;\r
+ }\r
+\r
+ if (tbl->anchor_row > old_range_end) {\r
+ tbl->anchor_row -= old_range_end - new_range_end;\r
+ } else if (tbl->anchor_row >= old_range_begin &&\r
+ tbl->anchor_row <= old_range_end) {\r
+ tbl->anchor_row = new_range_begin;\r
+ }\r
+\r
+ InvalidateRect(tbl->hwnd, NULL, TRUE);\r
+\r
+}\r
+\r
+LRESULT cw_properties(HWND hwnd);\r
+\r
+LRESULT \r
+cw_wm_mouse(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+ int x,y;\r
+ RECT r;\r
+ int row;\r
+ int col;\r
+ int i;\r
+ int nm_state,nm_row,nm_col;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ /* we are basically trying to capture events where the mouse is\r
+ hovering over one of the 'hotspots'. There are two kinds of\r
+ hotspots one is the little widget thinggy that you click on to\r
+ expand or collapse an outline. The other is a text cell that is\r
+ partially concealed.\r
+ */\r
+\r
+ x = GET_X_LPARAM(lParam);\r
+ y = GET_Y_LPARAM(lParam);\r
+ x += tbl->scr_left;\r
+ y += tbl->scr_top - tbl->header_height;\r
+\r
+ row = y / tbl->cell_height;\r
+ col = -1;\r
+ nm_state = CW_MOUSE_NONE;\r
+ nm_row = nm_col = -1;\r
+ for(i=0; i < (int) tbl->n_cols; i++) {\r
+ if(x >= tbl->cols[i].x &&\r
+ x < tbl->cols[i].x + tbl->cols[i].width) \r
+ {\r
+ col = i;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(wParam & MK_LBUTTON)\r
+ nm_state = CW_MOUSE_LDOWN;\r
+\r
+ if(row >= 0 && row < (int) tbl->n_rows) {\r
+ nm_state |= CW_MOUSE_ROW;\r
+ nm_row = row;\r
+ nm_col = col;\r
+ if(tbl->rows[row].flags & KHUI_CW_ROW_HEADER) {\r
+ /* are we on a widget then? */\r
+ x -= tbl->cols[tbl->rows[row].col].x;\r
+ if(x >= 0 && x < KHUI_SMICON_CX) /* hit */ {\r
+ nm_state |= CW_MOUSE_OUTLINE;\r
+ }\r
+ }\r
+ }\r
+\r
+ if((tbl->mouse_state & CW_MOUSE_LDOWN) && \r
+ (tbl->mouse_state & CW_MOUSE_OUTLINE) && \r
+ (nm_row != tbl->mouse_row))\r
+ {\r
+ nm_state &= ~CW_MOUSE_OUTLINE;\r
+ }\r
+ \r
+ if(!(nm_state & CW_MOUSE_LDOWN) && \r
+ (tbl->mouse_state & CW_MOUSE_LDOWN)) {\r
+\r
+ if((nm_state & CW_MOUSE_OUTLINE) &&\r
+ (tbl->mouse_state & CW_MOUSE_OUTLINE)) {\r
+ /* click on a widget */\r
+ khui_credwnd_outline * o;\r
+\r
+ o = (khui_credwnd_outline *) tbl->rows[nm_row].data;\r
+ tbl->mouse_state = CW_MOUSE_OUTLINE;\r
+\r
+ cw_toggle_outline_state(tbl, o);\r
+\r
+ return 0;\r
+ } else if(nm_row == tbl->mouse_row) {\r
+ /* click on a row */\r
+ cw_select_row(tbl, nm_row, wParam);\r
+ }\r
+\r
+ }\r
+\r
+ /*TODO: if a user clicks somewhere and drags on to an exand widget, it activates the widet. should not */\r
+\r
+ /* ok, now if we are changing state, we need to invalidate a few\r
+ regions */\r
+ if((tbl->mouse_state ^ nm_state) & CW_MOUSE_OUTLINE) {\r
+ if(tbl->mouse_state & CW_MOUSE_OUTLINE) {\r
+ r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ r.top = tbl->mouse_row * tbl->cell_height + tbl->header_height - tbl->scr_top;\r
+ r.right = r.left + KHUI_SMICON_CX;\r
+ r.bottom = r.top + tbl->cell_height;\r
+ InvalidateRect(tbl->hwnd, &r, TRUE);\r
+ }\r
+\r
+ tbl->mouse_col = nm_col;\r
+ tbl->mouse_row = nm_row;\r
+ tbl->mouse_state = nm_state;\r
+\r
+ /* same code block as above */\r
+ if(tbl->mouse_state & CW_MOUSE_OUTLINE) {\r
+ r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ r.top = tbl->mouse_row * tbl->cell_height + tbl->header_height - tbl->scr_top;\r
+ r.right = r.left + KHUI_SMICON_CX;\r
+ r.bottom = r.top + tbl->cell_height;\r
+ InvalidateRect(tbl->hwnd, &r, TRUE);\r
+ }\r
+ } else if(tbl->mouse_state != nm_state) {\r
+ tbl->mouse_col = nm_col;\r
+ tbl->mouse_row = nm_row;\r
+ tbl->mouse_state = nm_state;\r
+ }\r
+\r
+ /* if it was a double click, also show the property\r
+ window */\r
+ if (uMsg == WM_LBUTTONDBLCLK) {\r
+ cw_properties(hwnd);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+LRESULT \r
+cw_wm_hscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+ SCROLLINFO si;\r
+ RECT cr;\r
+ RECT lr;\r
+ RECT sr;\r
+ int dx;\r
+ int newpos;\r
+\r
+ tbl = (khui_credwnd_tbl *) (LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ GetClientRect(hwnd, &cr);\r
+ dx = tbl->scr_left;\r
+\r
+ switch(LOWORD(wParam)) {\r
+ case SB_LEFT:\r
+ newpos = 0;\r
+ break;\r
+\r
+ case SB_RIGHT:\r
+ newpos = tbl->ext_width;\r
+ break;\r
+\r
+ case SB_LINELEFT:\r
+ newpos = tbl->scr_left - (tbl->ext_width / 12);\r
+ break;\r
+\r
+ case SB_LINERIGHT:\r
+ newpos = tbl->scr_left + (tbl->ext_width / 12);\r
+ break;\r
+\r
+ case SB_PAGELEFT:\r
+ newpos = tbl->scr_left - (cr.right - cr.left);\r
+ break;\r
+\r
+ case SB_PAGERIGHT:\r
+ newpos = tbl->scr_left + (cr.right - cr.left);\r
+ break;\r
+\r
+ case SB_THUMBTRACK:\r
+ case SB_THUMBPOSITION:\r
+ ZeroMemory(&si, sizeof(si));\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_TRACKPOS;\r
+ GetScrollInfo(hwnd, SB_HORZ, &si);\r
+\r
+ newpos = si.nTrackPos;\r
+ break;\r
+\r
+ default:\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+ }\r
+\r
+ //cr.top += tbl->header_height;\r
+ tbl->scr_left = newpos;\r
+ cw_update_extents(tbl, TRUE);\r
+\r
+ dx -= tbl->scr_left;\r
+\r
+ /* exclude the watermark */\r
+ lr.bottom = cr.bottom;\r
+ lr.right = cr.right;\r
+ lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top);\r
+ lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left);\r
+\r
+ if(cr.top < lr.top && cr.left < cr.right) {\r
+ sr.left = cr.left;\r
+ sr.right = cr.right;\r
+ sr.top = cr.top;\r
+ sr.bottom = lr.top;\r
+ ScrollWindowEx(\r
+ hwnd, \r
+ dx, \r
+ 0, \r
+ &sr, \r
+ &sr, \r
+ NULL, \r
+ NULL, \r
+ SW_INVALIDATE | SW_SCROLLCHILDREN);\r
+ }\r
+\r
+ if(cr.left < lr.left && lr.top < lr.bottom) {\r
+ sr.left = cr.left;\r
+ sr.right = lr.left;\r
+ sr.top = lr.top;\r
+ sr.bottom = lr.bottom;\r
+ ScrollWindowEx(\r
+ hwnd, \r
+ dx, \r
+ 0, \r
+ &sr, \r
+ &sr, \r
+ NULL, \r
+ NULL, \r
+ SW_INVALIDATE | SW_SCROLLCHILDREN);\r
+ }\r
+\r
+ if(lr.top < lr.bottom && lr.left < lr.right) {\r
+ InvalidateRect(hwnd, &lr, FALSE);\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT \r
+cw_wm_vscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+ SCROLLINFO si;\r
+ RECT cr;\r
+ RECT sr;\r
+ RECT lr;\r
+ int dy;\r
+ int newpos;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ GetClientRect(hwnd, &cr);\r
+ cr.top += tbl->header_height;\r
+ dy = tbl->scr_top;\r
+\r
+ switch(LOWORD(wParam)) {\r
+ case SB_LEFT:\r
+ newpos = 0;\r
+ break;\r
+\r
+ case SB_BOTTOM:\r
+ newpos = tbl->ext_height;\r
+ break;\r
+\r
+ case SB_LINEUP:\r
+ newpos = tbl->scr_top - (tbl->ext_height / 12);\r
+ break;\r
+\r
+ case SB_LINEDOWN:\r
+ newpos = tbl->scr_top + (tbl->ext_height / 12);\r
+ break;\r
+\r
+ case SB_PAGEUP:\r
+ newpos = tbl->scr_top - (cr.bottom - cr.top);\r
+ break;\r
+\r
+ case SB_PAGEDOWN:\r
+ newpos = tbl->scr_top + (cr.bottom - cr.top);\r
+ break;\r
+\r
+ case SB_THUMBTRACK:\r
+ case SB_THUMBPOSITION:\r
+ ZeroMemory(&si, sizeof(si));\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_TRACKPOS;\r
+ GetScrollInfo(hwnd, SB_VERT, &si);\r
+\r
+ newpos = si.nTrackPos;\r
+ break;\r
+\r
+ default:\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+ }\r
+\r
+ tbl->scr_top = newpos;\r
+ cw_update_extents(tbl, TRUE);\r
+\r
+ dy -= tbl->scr_top;\r
+\r
+ /* exclude watermark */\r
+ lr.bottom = cr.bottom;\r
+ lr.right = cr.right;\r
+ lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top);\r
+ lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left);\r
+\r
+ if(cr.left < lr.left && cr.top < cr.bottom) {\r
+ sr.left = cr.left;\r
+ sr.right = lr.left;\r
+ sr.top = cr.top;\r
+ sr.bottom = cr.bottom;\r
+ ScrollWindowEx(\r
+ hwnd, \r
+ 0, \r
+ dy, \r
+ &sr, \r
+ &sr, \r
+ NULL, \r
+ NULL, \r
+ SW_INVALIDATE);\r
+ }\r
+\r
+ if(lr.left < lr.right && cr.top < lr.top) {\r
+ sr.left = lr.left;\r
+ sr.right = lr.right;\r
+ sr.top = cr.top;\r
+ sr.bottom = lr.top;\r
+ ScrollWindowEx(\r
+ hwnd, \r
+ 0, \r
+ dy, \r
+ &sr, \r
+ &sr, \r
+ NULL, \r
+ NULL, \r
+ SW_INVALIDATE);\r
+ }\r
+\r
+ if(lr.top < lr.bottom && lr.left < lr.right) {\r
+ InvalidateRect(hwnd, &lr, FALSE);\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+static INT_PTR CALLBACK \r
+cw_pp_ident_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ )\r
+{\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ khui_property_sheet * s;\r
+ PROPSHEETPAGE * p;\r
+ khm_handle ident;\r
+ wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
+ khm_size t;\r
+ khm_int32 i;\r
+\r
+ p = (PROPSHEETPAGE *) lParam;\r
+ s = (khui_property_sheet *) p->lParam;\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s);\r
+#pragma warning(pop)\r
+\r
+ ident = s->identity;\r
+\r
+ t = sizeof(idname);\r
+ kcdb_identity_get_name(ident, idname, &t);\r
+ SetDlgItemText(hwnd, IDC_PP_IDNAME, idname);\r
+\r
+ kcdb_identity_get_flags(ident, &i);\r
+\r
+ SendDlgItemMessage(hwnd, \r
+ IDC_PP_IDDEF, \r
+ BM_SETCHECK, \r
+ (WPARAM) ((i & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED:BST_UNCHECKED),\r
+ 0);\r
+\r
+ SendDlgItemMessage(\r
+ hwnd,\r
+ IDC_PP_IDSEARCH,\r
+ BM_SETCHECK,\r
+ (WPARAM) ((i & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED:BST_UNCHECKED),\r
+ 0);\r
+\r
+ khui_property_wnd_set_record(GetDlgItem(hwnd, IDC_PP_PROPLIST),\r
+ ident);\r
+ }\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+static INT_PTR CALLBACK \r
+cw_pp_cred_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ )\r
+{\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+ {\r
+ khui_property_sheet * s;\r
+ PROPSHEETPAGE * p;\r
+ khm_handle cred;\r
+\r
+ p = (PROPSHEETPAGE *) lParam;\r
+ s = (khui_property_sheet *) p->lParam;\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s);\r
+#pragma warning(pop)\r
+\r
+ cred = s->cred;\r
+\r
+ khui_property_wnd_set_record(\r
+ GetDlgItem(hwnd, IDC_PP_CPROPLIST),\r
+ cred);\r
+ }\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+static void \r
+cw_pp_begin(khui_property_sheet * s)\r
+{\r
+ PROPSHEETPAGE *p;\r
+\r
+ if(s->identity) {\r
+ p = malloc(sizeof(*p));\r
+ ZeroMemory(p, sizeof(*p));\r
+\r
+ p->dwSize = sizeof(*p);\r
+ p->dwFlags = 0;\r
+ p->hInstance = khm_hInstance;\r
+ p->pszTemplate = MAKEINTRESOURCE(IDD_PP_IDENT);\r
+ p->pfnDlgProc = cw_pp_ident_proc;\r
+ p->lParam = (LPARAM) s;\r
+ khui_ps_add_page(s, KHUI_PPCT_IDENTITY, 0, p, NULL);\r
+ }\r
+\r
+ if(s->cred) {\r
+ p = malloc(sizeof(*p));\r
+ ZeroMemory(p, sizeof(*p));\r
+\r
+ p->dwSize = sizeof(*p);\r
+ p->dwFlags = 0;\r
+ p->hInstance = khm_hInstance;\r
+ p->pszTemplate = MAKEINTRESOURCE(IDD_PP_CRED);\r
+ p->pfnDlgProc = cw_pp_cred_proc;\r
+ p->lParam = (LPARAM) s;\r
+ khui_ps_add_page(s, KHUI_PPCT_CREDENTIAL, 0, p, NULL);\r
+ }\r
+}\r
+\r
+static void \r
+cw_pp_precreate(khui_property_sheet * s)\r
+{\r
+ khui_ps_show_sheet(khm_hwnd_main, s);\r
+\r
+ khm_add_property_sheet(s);\r
+}\r
+\r
+static void \r
+cw_pp_end(khui_property_sheet * s)\r
+{\r
+ khui_property_page * p = NULL;\r
+\r
+ khui_ps_find_page(s, KHUI_PPCT_IDENTITY, &p);\r
+ if(p) {\r
+ free(p->p_page);\r
+ p->p_page = NULL;\r
+ }\r
+\r
+ p = NULL;\r
+\r
+ khui_ps_find_page(s, KHUI_PPCT_CREDENTIAL, &p);\r
+ if(p) {\r
+ free(p->p_page);\r
+ p->p_page = NULL;\r
+ }\r
+}\r
+\r
+static void \r
+cw_pp_destroy(khui_property_sheet *ps)\r
+{\r
+ if(ps->ctx.scope == KHUI_SCOPE_CRED) {\r
+ if(ps->header.pszCaption)\r
+ free((LPWSTR) ps->header.pszCaption);\r
+ }\r
+\r
+ khui_ps_destroy_sheet(ps);\r
+\r
+ /* this is pretty weird because ps gets freed when\r
+ khui_ps_destroy_sheet() is called. However, since destroying ps\r
+ involves sending a WM_DESTROY message to the property sheet, we\r
+ still need to keep it on the property sheet chain (or else the\r
+ messages will not be delivered). This is only safe because we are\r
+ not relinquishing the thread in-between destroying ps and removing\r
+ it from the chain. */\r
+\r
+ /*TODO: fix this */\r
+ khm_del_property_sheet(ps);\r
+}\r
+\r
+LRESULT \r
+cw_properties(HWND hwnd)\r
+{\r
+ /* show a property sheet of some sort */\r
+ khui_action_context ctx;\r
+ khui_property_sheet * ps;\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ khui_context_get(&ctx);\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(ctx.scope == KHUI_SCOPE_NONE) {\r
+\r
+ return FALSE;\r
+\r
+ /* While it seems like a good idea, doing this is not */\r
+#if 0\r
+ /* try to establish a context based on the current cursor\r
+ position */\r
+ if(tbl->cursor_row >= 0 && tbl->cursor_row < (int) tbl->n_rows) {\r
+ if(tbl->rows[tbl->cursor_row].flags & KHUI_CW_ROW_HEADER) {\r
+ if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_ID_NAME) {\r
+ /* identity context */\r
+ ctx.ctx = KHUI_SCOPE_IDENT;\r
+ ctx.identity = (khm_handle) \r
+ ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data;\r
+ } else if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_TYPE_NAME) {\r
+ ctx.ctx = KHUI_SCOPE_CREDTYPE;\r
+ ctx.cred_type = (khm_int32) (DWORD_PTR) \r
+ ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data;\r
+ } else {\r
+ ctx.ctx = KHUI_SCOPE_GROUP;\r
+ //ctx.parm = (khm_lparm) tbl->rows[tbl->cursor_row].data;\r
+ /* TODO: Figure out method of establishing a credgroup */\r
+ }\r
+ } else {\r
+ /* a credential context */\r
+ ctx.ctx = KHUI_SCOPE_CRED;\r
+ ctx.cred = (khm_handle) tbl->rows[tbl->cursor_row].data;\r
+ }\r
+ }\r
+#endif\r
+ }\r
+\r
+ /* if still no context, then we can't show a property sheet */\r
+ if(ctx.scope == KHUI_SCOPE_NONE) {\r
+ return FALSE;\r
+ }\r
+\r
+ khui_ps_create_sheet(&ps);\r
+\r
+ if(ctx.scope == KHUI_SCOPE_IDENT) {\r
+ khm_handle ident;\r
+ khm_size t;\r
+\r
+ ident = ctx.identity;\r
+\r
+ ps->header.hInstance = khm_hInstance;\r
+ ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP);\r
+\r
+ kcdb_identity_get_name(ident, NULL, &t);\r
+\r
+ if(t > 0) {\r
+ ps->header.pszCaption = malloc(t);\r
+ kcdb_identity_get_name(ident, (wchar_t *) ps->header.pszCaption, &t);\r
+ } else {\r
+ ps->header.pszCaption = NULL;\r
+ }\r
+\r
+ ps->ctx = ctx;\r
+ ps->identity = ident;\r
+ ps->credtype = KCDB_CREDTYPE_INVALID;\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps);\r
+\r
+ } else if(ctx.scope == KHUI_SCOPE_CREDTYPE) {\r
+ khm_size t = 0;\r
+ khm_int32 cred_type;\r
+\r
+ cred_type = ctx.cred_type;\r
+\r
+ ps->header.hInstance = khm_hInstance;\r
+ ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP);\r
+\r
+ ps->ctx = ctx;\r
+ ps->credtype = cred_type;\r
+\r
+ if(ctx.identity) {\r
+ ps->identity = ctx.identity;\r
+ /* also, if there is an associated identity, we assume that\r
+ the properties are for the specified credentials type\r
+ specific to the identity. Hence we change the title to\r
+ something else */\r
+ kcdb_identity_get_name(ctx.identity, NULL, &t);\r
+ if (t > 0) {\r
+ ps->header.pszCaption = malloc(t);\r
+ kcdb_identity_get_name(ctx.identity, (wchar_t *) ps->header.pszCaption, &t);\r
+ } else {\r
+ ps->header.pszCaption = NULL;\r
+ }\r
+ } else {\r
+ kcdb_credtype_describe(cred_type, NULL, &t, KCDB_TS_LONG);\r
+ if(t > 0) {\r
+ ps->header.pszCaption = malloc(t);\r
+ kcdb_credtype_describe(cred_type, (wchar_t *) ps->header.pszCaption, &t, KCDB_TS_LONG);\r
+ } else {\r
+ ps->header.pszCaption = NULL;\r
+ }\r
+ }\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps);\r
+ } else if(ctx.scope == KHUI_SCOPE_CRED) {\r
+ khm_handle cred;\r
+ khm_size t;\r
+\r
+ cred = ctx.cred;\r
+\r
+ ps->header.hInstance = khm_hInstance;\r
+ ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP);\r
+ ps->ctx = ctx;\r
+\r
+ kcdb_cred_get_name(cred, NULL, &t);\r
+ ps->header.pszCaption = malloc(t);\r
+ kcdb_cred_get_name(cred, (LPWSTR) ps->header.pszCaption, &t);\r
+\r
+ kcdb_cred_get_identity(cred, &ps->identity);\r
+ kcdb_cred_get_type(cred, &ps->credtype);\r
+ ps->cred = cred;\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps);\r
+ } else {\r
+ khui_ps_destroy_sheet(ps);\r
+ }\r
+\r
+ khui_context_reset();\r
+\r
+ return TRUE;\r
+}\r
+\r
+LRESULT \r
+cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(HIWORD(wParam) == BN_CLICKED && \r
+ LOWORD(wParam) == KHUI_HTWND_CTLID) {\r
+\r
+ wchar_t wid[256];\r
+ /* a hyperlink was activated */\r
+ khui_htwnd_link * l;\r
+ l = (khui_htwnd_link *) lParam;\r
+ wcsncpy(wid, l->id, l->id_len);\r
+ wid[l->id_len] = 0;\r
+\r
+ if(!wcscmp(wid, L"NewCreds")) {\r
+ PostMessage(khm_hwnd_main, WM_COMMAND, \r
+ MAKEWPARAM(KHUI_ACTION_NEW_CRED,0), 0);\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ switch(LOWORD(wParam)) \r
+ {\r
+ case KHUI_PACTION_ENTER:\r
+ /* enter key is a synonym for the default action, on the\r
+ context, which is to lauch a property sheet */\r
+ /* fallthrough */\r
+ case KHUI_ACTION_PROPERTIES:\r
+ {\r
+ return cw_properties(hwnd);\r
+ }\r
+ break;\r
+\r
+ case KHUI_ACTION_LAYOUT_ID:\r
+ {\r
+ cw_unload_view(tbl);\r
+\r
+ cw_load_view(tbl, L"ByIdentity", hwnd);\r
+ cw_insert_header_cols(tbl);\r
+\r
+ cw_update_creds(tbl);\r
+ cw_update_outline(tbl);\r
+ cw_update_extents(tbl, FALSE);\r
+\r
+ InvalidateRect(tbl->hwnd, NULL, TRUE);\r
+\r
+ khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), KHUI_ACTION_LAYOUT_ID);\r
+ }\r
+ break;\r
+\r
+ case KHUI_ACTION_LAYOUT_LOC:\r
+ {\r
+ cw_unload_view(tbl);\r
+\r
+ cw_load_view(tbl, L"ByLocation", hwnd);\r
+ cw_insert_header_cols(tbl);\r
+\r
+ cw_update_creds(tbl);\r
+ cw_update_outline(tbl);\r
+ cw_update_extents(tbl, FALSE);\r
+\r
+ InvalidateRect(tbl->hwnd, NULL, TRUE);\r
+\r
+ khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), \r
+ KHUI_ACTION_LAYOUT_LOC);\r
+ }\r
+ break;\r
+\r
+ case KHUI_PACTION_UP:\r
+ case KHUI_PACTION_UP_EXTEND:\r
+ case KHUI_PACTION_UP_TOGGLE:\r
+ { /* cursor up */\r
+ khm_int32 new_row;\r
+ WPARAM wp;\r
+\r
+ new_row = tbl->cursor_row - 1;\r
+\r
+ /* checking both bounds. we make no assumption about the\r
+ value of cursor_row before this message */\r
+ if(new_row < 0)\r
+ new_row = 0;\r
+ if(new_row >= (int) tbl->n_rows)\r
+ new_row = (int) tbl->n_rows;\r
+\r
+ if (LOWORD(wParam) == KHUI_PACTION_UP)\r
+ wp = 0;\r
+ else if (LOWORD(wParam) == KHUI_PACTION_UP_EXTEND)\r
+ wp = MK_SHIFT;\r
+ else if (LOWORD(wParam) == KHUI_PACTION_UP_TOGGLE)\r
+ wp = 0; //MK_CONTROL;\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+\r
+ cw_select_row(tbl, new_row, wp);\r
+ }\r
+ break;\r
+\r
+ case KHUI_PACTION_DOWN:\r
+ case KHUI_PACTION_DOWN_EXTEND:\r
+ case KHUI_PACTION_DOWN_TOGGLE:\r
+ { /* cursor down */\r
+ khm_int32 new_row;\r
+ WPARAM wp;\r
+\r
+ new_row = tbl->cursor_row + 1;\r
+\r
+ /* checking both bounds. we make no assumption about the\r
+ value of cursor_row before this message */\r
+ if(new_row < 0)\r
+ new_row = 0;\r
+ if(new_row >= (int) tbl->n_rows)\r
+ new_row = (int) tbl->n_rows;\r
+\r
+ if (LOWORD(wParam) == KHUI_PACTION_DOWN)\r
+ wp = 0;\r
+ else if (LOWORD(wParam) == KHUI_PACTION_DOWN_EXTEND)\r
+ wp = MK_SHIFT;\r
+ else if (LOWORD(wParam) == KHUI_PACTION_DOWN_TOGGLE)\r
+ wp = 0; //MK_CONTROL;\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+ cw_select_row(tbl, new_row, wp);\r
+ }\r
+ break;\r
+\r
+ case KHUI_PACTION_LEFT:\r
+ { /* collapse and up*/\r
+ khui_credwnd_outline * o;\r
+ int r;\r
+\r
+ if(tbl->cursor_row < 0 || tbl->cursor_row >= (int) tbl->n_rows) {\r
+ cw_select_row(tbl, 0, 0);\r
+ break;\r
+ }\r
+\r
+ for(r = tbl->cursor_row; \r
+ (r >= 0 && !(tbl->rows[r].flags & KHUI_CW_ROW_HEADER));\r
+ r--);\r
+ \r
+ if(r < 0)\r
+ break;\r
+\r
+ /* If we were not on a header, we collapse the innermost\r
+ outline. Otherwise, we collpase up to the parent\r
+ outline level */\r
+\r
+ if(r != tbl->cursor_row) {\r
+ o = (khui_credwnd_outline *) tbl->rows[r].data;\r
+\r
+ cw_toggle_outline_state(tbl, o);\r
+ } else {\r
+ o = (khui_credwnd_outline *) tbl->rows[r].data;\r
+\r
+ if(o->flags & KHUI_CW_O_EXPAND) {\r
+ cw_toggle_outline_state(tbl, o);\r
+ } else {\r
+ o = TPARENT(o);\r
+ if(o) {\r
+ cw_toggle_outline_state(tbl, o);\r
+ r = o->start;\r
+ } else if(r > 0)\r
+ r--;\r
+ }\r
+ }\r
+\r
+ cw_select_row(tbl, r, 0);\r
+ }\r
+ break;\r
+\r
+ case KHUI_PACTION_RIGHT:\r
+ { /* expand and down*/\r
+ khui_credwnd_outline * o;\r
+ int r;\r
+\r
+ if(tbl->cursor_row < 0 || \r
+ tbl->cursor_row >= (int) tbl->n_rows) {\r
+ cw_select_row(tbl, 0, 0);\r
+ break;\r
+ }\r
+\r
+ r = tbl->cursor_row;\r
+\r
+ if(tbl->rows[r].flags & KHUI_CW_ROW_HEADER) {\r
+ o = (khui_credwnd_outline *) tbl->rows[r].data;\r
+ if(!(o->flags & KHUI_CW_O_EXPAND)) {\r
+ cw_toggle_outline_state(tbl, o);\r
+ }\r
+ }\r
+\r
+ r++;\r
+\r
+ cw_select_row(tbl, r, 0);\r
+ }\r
+ break;\r
+ }\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT \r
+cw_wm_contextmenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ RECT r;\r
+ int x,y;\r
+ int row;\r
+ khui_credwnd_tbl * tbl;\r
+\r
+ tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ GetWindowRect(hwnd, &r);\r
+\r
+ x = GET_X_LPARAM(lParam);\r
+ y = GET_Y_LPARAM(lParam);\r
+\r
+ x += tbl->scr_left - r.left;\r
+ y += tbl->scr_top - tbl->header_height - r.top;\r
+\r
+ row = y / tbl->cell_height;\r
+\r
+ if(row < 0 || row >= (int) tbl->n_rows)\r
+ return FALSE;\r
+\r
+ cw_set_row_context(tbl, row);\r
+\r
+ if((tbl->rows[row].flags & KHUI_CW_ROW_HEADER) &&\r
+ (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME))\r
+ {\r
+ khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\r
+ //khui_context_reset();\r
+ } else {\r
+ khm_menu_show_panel(KHUI_MENU_TOK_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\r
+ //khui_context_reset();\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+/* copy and paste template */\r
+#if 0\r
+LRESULT \r
+cw_wm_msg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+#endif\r
+\r
+LRESULT CALLBACK \r
+khm_credwnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) \r
+{\r
+ switch(uMsg) {\r
+ case WM_COMMAND:\r
+ return cw_wm_command(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_CREATE:\r
+ return cw_wm_create(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_DESTROY:\r
+ return cw_wm_destroy(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_ERASEBKGND:\r
+ /* we don't bother wasting cycles erasing the background\r
+ because the foreground elements completely cover the\r
+ client area */\r
+ return TRUE;\r
+\r
+ case WM_PAINT:\r
+ return cw_wm_paint(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_SIZE:\r
+ return cw_wm_size(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_NOTIFY:\r
+ return cw_wm_notify(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_HSCROLL:\r
+ return cw_wm_hscroll(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_VSCROLL:\r
+ return cw_wm_vscroll(hwnd, uMsg, wParam, lParam);\r
+\r
+ case KMQ_WM_DISPATCH:\r
+ return cw_kmq_wm_dispatch(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_LBUTTONDBLCLK:\r
+ case WM_LBUTTONDOWN:\r
+ case WM_MOUSEMOVE:\r
+ case WM_LBUTTONUP:\r
+ return cw_wm_mouse(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_CONTEXTMENU:\r
+ return cw_wm_contextmenu(hwnd, uMsg, wParam, lParam);\r
+ }\r
+\r
+ return DefWindowProc(hwnd,uMsg,wParam,lParam);\r
+}\r
+\r
+void \r
+khm_register_credwnd_class(void) {\r
+ WNDCLASSEX wcx;\r
+ kcdb_attrib attrib;\r
+ khm_int32 attr_id;\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = CS_DBLCLKS | CS_OWNDC;\r
+ wcx.lpfnWndProc = khm_credwnd_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = sizeof(LONG_PTR);\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = NULL;\r
+ wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);\r
+ wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_CREDWND_CLASS_NAME;\r
+ wcx.hIconSm = NULL;\r
+\r
+ khui_credwnd_cls = RegisterClassEx(&wcx);\r
+\r
+ /* while we are at it, register the credwnd attribute type as well, and\r
+ obtain the type ID */\r
+ if(KHM_FAILED(kcdb_attrib_get_id(KHUI_CREDWND_FLAG_ATTRNAME, &attr_id))) {\r
+ ZeroMemory(&attrib, sizeof(attrib));\r
+ attrib.id = KCDB_ATTR_INVALID;\r
+ attrib.flags = KCDB_ATTR_FLAG_HIDDEN;\r
+ attrib.type = KCDB_TYPE_INT32;\r
+ attrib.name = KHUI_CREDWND_FLAG_ATTRNAME;\r
+\r
+ kcdb_attrib_register(&attrib, &attr_id);\r
+ }\r
+\r
+ khui_cw_flag_id = attr_id;\r
+}\r
+\r
+void \r
+khm_unregister_credwnd_class(void) {\r
+ UnregisterClass(MAKEINTATOM(khui_credwnd_cls), khm_hInstance);\r
+}\r
+\r
+HWND \r
+khm_create_credwnd(HWND parent) {\r
+ RECT r;\r
+ GetClientRect(parent, &r);\r
+ return CreateWindowEx(\r
+ 0,\r
+ MAKEINTATOM(khui_credwnd_cls),\r
+ L"",\r
+ WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,\r
+ r.left,\r
+ r.top,\r
+ r.right - r.left,\r
+ r.bottom - r.top,\r
+ parent,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_CREDWND_H\r
+#define __KHIMAIRA_CREDWND_H\r
+\r
+#define KHUI_CREDWND_CLASS_NAME L"NetIDMgrCredWnd"\r
+\r
+#define KHUI_CREDWND_FLAG_ATTRNAME L"CredWndFlags"\r
+\r
+extern khm_int32 khui_cw_flag_id;\r
+\r
+/* The expiration states */\r
+#define CW_EXPSTATE_NONE 0\r
+#define CW_EXPSTATE_WARN 1024\r
+#define CW_EXPSTATE_CRITICAL 2048\r
+#define CW_EXPSTATE_EXPIRED 3072\r
+\r
+#define CW_EXPSTATE_MASK 3072\r
+\r
+typedef struct khui_credwnd_outline_t {\r
+ khm_int32 flags; /* combination of KHUI_CW_O_* */\r
+ khm_int32 start; /* first row of outline */\r
+ khm_int32 length; /* number of rows in outline */\r
+ khm_int32 level; /* outline level */\r
+ khm_int32 col; /* outline column */\r
+ wchar_t *header; /* character string associated with header */\r
+ khm_int32 attr_id;\r
+ void * data; /* level specific data :\r
+ Identity -> handle to identity\r
+ Type -> type ID\r
+ otherwise -> canonical data buffer\r
+ */\r
+ khm_size cb_data;\r
+\r
+ khm_size idx_start; /* index of the first cred in the credset */\r
+ khm_size idx_end; /* index of the last cred in the credset */\r
+ TDCL(struct khui_credwnd_outline_t);\r
+} khui_credwnd_outline;\r
+\r
+#define KHUI_CW_O_EXPAND 0x00000001\r
+#define KHUI_CW_O_STICKY 0x00000002\r
+#define KHUI_CW_O_VISIBLE 0x00000004\r
+#define KHUI_CW_O_SHOWFLAG 0x00000008\r
+#define KHUI_CW_O_SELECTED 0x00000010\r
+#define KHUI_CW_O_DATAALLOC 0x00000020\r
+\r
+typedef struct khui_credwnd_row_t {\r
+ khm_int32 flags;\r
+ khm_int32 col;\r
+ khm_handle data;\r
+ khm_size idx_start;\r
+ khm_size idx_end;\r
+} khui_credwnd_row;\r
+\r
+#define KHUI_CW_ROW_CRED 2\r
+#define KHUI_CW_ROW_HEADER 4\r
+#define KHUI_CW_ROW_TIMERSET 8\r
+#define KHUI_CW_ROW_SELECTED 16\r
+\r
+/* row allocation */\r
+/* initial number of rows to be allocated */\r
+#define KHUI_CW_ROW_INITIAL 512\r
+/* allocation increment, if we run out of space */\r
+#define KHUI_CW_ROW_INCREMENT 512\r
+\r
+typedef struct khui_credwnd_col_t {\r
+ khm_int32 attr_id;\r
+ khm_int32 width; /* width of the column (screen units) */\r
+ khm_int32 x; /* starting x coordinate (screen units) */\r
+ khm_int32 flags; /* combination of KHUI_CW_COL_* */\r
+ khm_int32 sort_index;\r
+ wchar_t * title;\r
+} khui_credwnd_col;\r
+\r
+/* column allocation */\r
+/* initial number of columns to be allocated */\r
+#define KHUI_CW_COL_INITIAL 16\r
+/* allocation increment, if we run out of space */\r
+#define KHUI_CW_COL_INCREMENT 16\r
+\r
+#define KHUI_CW_COL_AUTOSIZE 1\r
+#define KHUI_CW_COL_SORT_INC 2\r
+#define KHUI_CW_COL_SORT_DEC 4\r
+#define KHUI_CW_COL_GROUP 8\r
+#define KHUI_CW_COL_FIXED_WIDTH 16\r
+#define KHUI_CW_COL_FIXED_POS 32\r
+#define KHUI_CW_COL_META 64\r
+\r
+/* Custom column attributes (are not kcdb attributes) */\r
+#define CW_CA_FLAGS -1\r
+#define CW_CANAME_FLAGS L"_CWFlags"\r
+\r
+#define CW_CA_TYPEICON -2\r
+#define CW_CANAME_TYPEICON L"_CWTypeIcon"\r
+\r
+#define cw_is_custom_attr(i) ((i)<0)\r
+\r
+typedef struct khui_credwnd_tbl_t {\r
+ HWND hwnd; /* the window that this table belongs to */\r
+\r
+ khm_int32 scr_top; /* screen units */\r
+ khm_int32 scr_left; /* screen units */\r
+ khm_int32 ext_width; /* screen units */\r
+ khm_int32 ext_height; /* screen units */\r
+ khm_int32 cell_height; /* screen units */\r
+\r
+ HWND hwnd_header; /* header control */\r
+ khm_int32 header_height; /* height of the header */\r
+ HWND hwnd_notif; /* notification control */\r
+\r
+ khui_credwnd_col * cols; /* n_cols elements */\r
+ khui_credwnd_row * rows; /* n_rows elements */\r
+ khm_size n_cols;\r
+ khm_size n_total_cols; /* number of columns actually\r
+ allocated in cols */\r
+ khm_size n_rows;\r
+ khm_size n_total_rows; /* number of rows actually allocated\r
+ in rows */\r
+\r
+ khui_credwnd_outline * outline;\r
+\r
+ khm_int32 flags; /* combo of KHUI_CW_TBL_* */\r
+\r
+ khm_int32 cursor_row; /* cursor and selection */\r
+ khm_int32 anchor_row; /* anchor, for range selections */\r
+\r
+ /* view parameters */\r
+ khm_int32 hpad;\r
+ khm_int32 vpad;\r
+ khm_int32 hpad_h; /* horizontal padding correction for headers */\r
+ khm_int32 threshold_warn; /* Warning threshold, in seconds*/\r
+ khm_int32 threshold_critical; /* Critical threshold, in seconds */\r
+\r
+ /* graphics objects we are going to need. */\r
+ HFONT hf_normal; /* normal text */\r
+ HFONT hf_header; /* header text */\r
+ HFONT hf_bold; /* bold text */\r
+ HFONT hf_bold_header; /* bold header text */\r
+ HBRUSH hb_normal; /* normal background brush */\r
+ HBRUSH hb_grey; /* normal grey background brush */\r
+ HBRUSH hb_sel; /* selected background brush */\r
+ COLORREF cr_hdr_outline;/* header outline color */\r
+ COLORREF cr_normal; /* normal text color */\r
+ COLORREF cr_sel; /* selected text color */\r
+ COLORREF cr_hdr_normal; /* normal header text color */\r
+ COLORREF cr_hdr_sel; /* selected header text color */\r
+ HBRUSH hb_hdr_bg; /* header background color (normal) */\r
+ HBRUSH hb_hdr_bg_exp; /* header background color (expired) */\r
+ HBRUSH hb_hdr_bg_warn; /* header background color (warn) */\r
+ HBRUSH hb_hdr_bg_crit; /* header background color (critical) */\r
+ HBRUSH hb_hdr_bg_sel; /* header background color (selected) */\r
+ HCURSOR hc_hand; /* the HAND cursor */\r
+ khui_ilist * ilist; /* image list */\r
+\r
+#if 0\r
+ /* icon indices */\r
+ int idx_expand; /* index of 'expanded' icon in image list */\r
+ int idx_expand_hi; /* index of 'expanded' icon (highlighted) in image list */\r
+ int idx_collapse; /* index of 'collapsed' icon in image list */\r
+ int idx_collapse_hi; /* index of 'collapsed' icon (highlighted) in image list */\r
+ int idx_ident; /* index of 'identity' icon in image list */\r
+#endif\r
+\r
+ /* mouse state */\r
+ khm_int32 mouse_state; /* state of the mouse can be combo of CW_MOUSE_* values */\r
+ khm_int32 mouse_row; /* row that the mouse state applies to */\r
+ khm_int32 mouse_col; /* col that the mouse state applies to */\r
+\r
+ khui_bitmap kbm_logo_shade;\r
+\r
+ /* the credentials set */\r
+ khm_handle credset;\r
+} khui_credwnd_tbl;\r
+\r
+#define KHUI_MAXCB_HEADING 256\r
+\r
+/* table flags */\r
+#define KHUI_CW_TBL_INITIALIZED 0x00000001\r
+#define KHUI_CW_TBL_COL_DIRTY 0x00000002\r
+#define KHUI_CW_TBL_ROW_DIRTY 0x00000004\r
+#define KHUI_CW_TBL_ACTIVE 0x00000100\r
+\r
+/* mouse_state constants */\r
+#define CW_MOUSE_NONE 0 /* nothing interesting */\r
+#define CW_MOUSE_OUTLINE 1 /* mouse is highlighting an outline widget */\r
+#define CW_MOUSE_LDOWN 2 /* left button is down */\r
+#define CW_MOUSE_ROW 4 /* mouse is acive over a valid row */\r
+\r
+void khm_unregister_credwnd_class(void);\r
+\r
+void khm_register_credwnd_class(void);\r
+\r
+HWND khm_create_credwnd(HWND parent);\r
+\r
+LRESULT CALLBACK khm_credwnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ );\r
+\r
+void cw_load_view(khui_credwnd_tbl * tbl, wchar_t * viewname, HWND hwnd);\r
+\r
+void cw_update_creds(khui_credwnd_tbl * tbl);\r
+\r
+void cw_unload_view(khui_credwnd_tbl * tbl);\r
+\r
+void cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi);\r
+\r
+int cw_update_extents(khui_credwnd_tbl * tbl, khm_boolean update_scroll);\r
+\r
+void cw_insert_header_cols(khui_credwnd_tbl * tbl);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2004 Massachusetts Institute of Technology\r
+*\r
+* Permission is hereby granted, free of charge, to any person\r
+* obtaining a copy of this software and associated documentation\r
+* files (the "Software"), to deal in the Software without\r
+* restriction, including without limitation the rights to use, copy,\r
+* modify, merge, publish, distribute, sublicense, and/or sell copies\r
+* of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be\r
+* included in all copies or substantial portions of the Software.\r
+*\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+* SOFTWARE.\r
+*/\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<crtdbg.h>\r
+\r
+ATOM khui_htwnd_cls;\r
+\r
+#define HTW_STYLE_NORMAL 0\r
+\r
+/* There are currently 4 style "bits" and 3 sizes, which means\r
+ there can be 2^4*3=48 possible styles max. If someone is\r
+ feeling adventurous you can slightly improve performance of\r
+ the parser using this little fact. For now, I don't care.\r
+ (hint: combine size and style bits to form a single number\r
+ and use it as an index into the styles array)\r
+*/\r
+#define HTW_STYLE_MAX 48\r
+\r
+#define HTW_FORMAT_MAX 128\r
+\r
+#define HTW_TAB_MAX 8\r
+\r
+#define HTW_DEFAULT (-1)\r
+\r
+#define HTW_NORMAL_SIZE 8\r
+#define HTW_LARGE_SIZE 12\r
+#define HTW_HUGE_SIZE 20\r
+\r
+/* font variant */\r
+#define FV_ABSOLUTE 0x10000000\r
+\r
+#define FV_ITALIC 0x00000002\r
+#define FV_UNDERLINE 0x00000004\r
+#define FV_STRIKEOUT 0x00000008\r
+#define FV_BOLD 0x00000010\r
+\r
+#define FV_NOITALIC 0x00020000\r
+#define FV_NOUNDERLINE 0x00040000\r
+#define FV_NOSTRIKEOUT 0x00080000\r
+#define FV_NOBOLD 0x00100000\r
+\r
+#define FV_NONE 0x00000000\r
+#define FV_MASK 0x0000001f\r
+\r
+#define HTW_LINK_ALLOC 8\r
+\r
+#define ALIGN_LEFT 0\r
+#define ALIGN_CENTER 1\r
+#define ALIGN_RIGHT 2\r
+\r
+struct tx_tbl_t {\r
+ wchar_t * string;\r
+ LONG value;\r
+} \r
+\r
+htw_color_table[] = {\r
+ {L"black", RGB(0,0,0)},\r
+ {L"white", RGB(255,255,255)},\r
+ {L"red", RGB(255,0,0)},\r
+ {L"green", RGB(0,255,0)},\r
+ {L"blue", RGB(0,0,255)},\r
+ {L"grey", RGB(128,128,128)}\r
+},\r
+\r
+htw_size_table[] = {\r
+ {L"normal", HTW_NORMAL_SIZE},\r
+ {L"large", HTW_LARGE_SIZE},\r
+ {L"huge", HTW_HUGE_SIZE}\r
+},\r
+\r
+htw_align_table[] = {\r
+ {L"left", ALIGN_LEFT},\r
+ {L"center", ALIGN_LEFT},\r
+ {L"right", ALIGN_RIGHT}\r
+};\r
+\r
+typedef struct khui_htwnd_style_t {\r
+ LONG height;\r
+ LONG variation; /* combination of FV_* */\r
+\r
+ HFONT font;\r
+} khui_htwnd_style;\r
+\r
+typedef struct khui_format_t {\r
+ int style_idx;\r
+ COLORREF color;\r
+} khui_format;\r
+\r
+typedef struct format_stack_t {\r
+ khui_format stack[HTW_FORMAT_MAX];\r
+ int stack_top;\r
+} format_stack;\r
+\r
+typedef struct khui_htwnd_data_t {\r
+ int id; /* control ID */\r
+ int flags;\r
+ wchar_t * text;\r
+ int scroll_left;\r
+ int scroll_top;\r
+ COLORREF bk_color;\r
+ HCURSOR hc_hand;\r
+ int l_pixel_y;\r
+\r
+ khui_htwnd_style styles[HTW_STYLE_MAX];\r
+ int n_styles;\r
+\r
+ khui_htwnd_link ** links;\r
+ int n_links;\r
+ int max_links;\r
+ int active_link;\r
+ int md_link;\r
+\r
+ int tabs[HTW_TAB_MAX];\r
+ int n_tabs;\r
+} khui_htwnd_data;\r
+\r
+static LONG table_lookup(struct tx_tbl_t * tbl, int n, wchar_t * v, int len)\r
+{\r
+ int i;\r
+\r
+ for(i=0; i<n; i++) {\r
+ if(!wcsnicmp(tbl[i].string, v, len))\r
+ return tbl[i].value;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+static void clear_styles(khui_htwnd_data * d)\r
+{\r
+ int i;\r
+\r
+ for(i=0; i<d->n_styles; i++) {\r
+ if(d->styles[i].font != NULL) {\r
+ DeleteObject(d->styles[i].font);\r
+ d->styles[i].font = NULL;\r
+ }\r
+ }\r
+\r
+ d->n_styles = 0;\r
+}\r
+\r
+static void format_init(format_stack * s)\r
+{\r
+ s->stack_top = -1;\r
+ ZeroMemory(s->stack, sizeof(s->stack));\r
+}\r
+\r
+static khui_format * format_current(format_stack * s)\r
+{\r
+ if(s->stack_top >= 0)\r
+ return &(s->stack[s->stack_top]);\r
+ else\r
+ return NULL;\r
+}\r
+\r
+static int format_style(format_stack * s)\r
+{\r
+ if(s->stack_top >= 0)\r
+ return s->stack[s->stack_top].style_idx;\r
+ else\r
+ return 0;\r
+}\r
+\r
+static COLORREF format_color(format_stack * s)\r
+{\r
+ if(s->stack_top >= 0)\r
+ return s->stack[s->stack_top].color;\r
+ else\r
+ return 0;\r
+}\r
+\r
+static int format_level(format_stack * s)\r
+{\r
+ return s->stack_top;\r
+}\r
+\r
+static void format_unwind(format_stack * s, int level)\r
+{\r
+ s->stack_top = level;\r
+}\r
+\r
+static void format_push(format_stack * s, khui_htwnd_data * d, LONG height, LONG variation, COLORREF color)\r
+{\r
+ int i;\r
+ khui_format * top;\r
+ khui_htwnd_style * style;\r
+\r
+ _ASSERT(s->stack_top < (HTW_FORMAT_MAX-1));\r
+\r
+ /* formatting is additive unless FV_NORMAL is set in variation */\r
+ top = format_current(s);\r
+ if(top) {\r
+ style = &(d->styles[top->style_idx]);\r
+ if(height == HTW_DEFAULT)\r
+ height = style->height;\r
+\r
+ if(variation == HTW_DEFAULT)\r
+ variation = style->variation;\r
+ else if(!(variation & FV_ABSOLUTE))\r
+ variation |= style->variation;\r
+\r
+ if(color == HTW_DEFAULT)\r
+ color = top->color;\r
+ }\r
+\r
+ variation &= ~FV_ABSOLUTE;\r
+ variation ^= variation & (variation>>16);\r
+ variation &= FV_MASK;\r
+\r
+ /* now look for an existing style that matches the requested one */\r
+ for(i=0; i<d->n_styles; i++) {\r
+ style = &(d->styles[i]);\r
+\r
+ if(style->height == height &&\r
+ style->variation == variation)\r
+ break;\r
+ }\r
+\r
+ s->stack_top++;\r
+\r
+ if(i<d->n_styles) {\r
+ s->stack[s->stack_top].style_idx = i;\r
+ } else {\r
+ if(d->n_styles == HTW_STYLE_MAX) {\r
+ s->stack[s->stack_top].style_idx = 0;\r
+ } else {\r
+ s->stack[s->stack_top].style_idx = d->n_styles;\r
+ d->styles[d->n_styles].font = NULL;\r
+ d->styles[d->n_styles].height = height;\r
+ d->styles[d->n_styles].variation = variation;\r
+ d->n_styles++;\r
+ }\r
+ }\r
+ s->stack[s->stack_top].color = color;\r
+}\r
+\r
+static void format_pop(format_stack * s) {\r
+ if(s->stack_top >= 0)\r
+ s->stack_top--;\r
+}\r
+\r
+static wchar_t * token_end(wchar_t * s) {\r
+ while(iswalnum(*s) || *s == L'/')\r
+ s++;\r
+ return s;\r
+}\r
+\r
+static wchar_t * skip_ws(wchar_t * s) {\r
+ while(iswspace(*s))\r
+ s++;\r
+ return s;\r
+}\r
+\r
+/* s points to something like " = \"value\"" \r
+ start and len will point to the start and\r
+ length of value. return value will point to the\r
+ character following the last double quote. */\r
+static wchar_t * read_attr(wchar_t * s, wchar_t ** start, int * len)\r
+{\r
+ wchar_t *e;\r
+\r
+ *start = NULL;\r
+ *len = 0;\r
+\r
+ do {\r
+ s = skip_ws(s);\r
+ if(*s != L'=')\r
+ break;\r
+ s = skip_ws(++s);\r
+ if(*s != L'"')\r
+ break;\r
+ e = wcschr(++s, L'"');\r
+ if(!e)\r
+ break;\r
+\r
+ *start = s;\r
+ *len = (int) (e - s);\r
+\r
+ s = e + 1;\r
+ } while(FALSE);\r
+\r
+ return s;\r
+}\r
+\r
+/*\r
+We currently support the following tags:\r
+\r
+<a [id="string"] [param="paramstring"]>link text</a>\r
+<b>foo</b>\r
+<u>foo</u>\r
+\r
+<center>foo</center>\r
+<left>foo</left>\r
+<right>foo</right>\r
+\r
+<font [color="color"] [size="normal|large|huge"]>foo</font>\r
+<large>foo</large>\r
+<huge>foo</huge>\r
+\r
+<p [align="left|center|right"]>foo</p>\r
+<settab pos="">\r
+<tab>\r
+*/\r
+\r
+static int htw_parse_tag(\r
+ wchar_t * start, \r
+ wchar_t ** end, \r
+ int * align, \r
+ khui_htwnd_data * d, \r
+ format_stack * s, \r
+ PPOINT p_abs,\r
+ PPOINT p_rel,\r
+ int lh, \r
+ BOOL dry_run)\r
+{\r
+ wchar_t * c;\r
+ int n = 0;\r
+\r
+ /* start initially points to the starting '<' */\r
+ c = token_end(++start);\r
+\r
+ if(!wcsnicmp(start,L"a",c-start)) {\r
+ /* start of an 'a' tag */\r
+ wchar_t * id_start = NULL;\r
+ int id_len = 0;\r
+ wchar_t * param_start = NULL;\r
+ int param_len = 0;\r
+\r
+ /* We don't need to parse the link\r
+ if it is just a dry run */\r
+ if(dry_run) {\r
+ format_push(s, d, HTW_DEFAULT, HTW_DEFAULT, RGB(0,0,255));\r
+ *end = wcschr(start, L'>');\r
+ return FALSE;\r
+ }\r
+\r
+ while(c && *c && *c != L'>') {\r
+ wchar_t * e;\r
+\r
+ c = skip_ws(c);\r
+ e = token_end(c);\r
+\r
+ if(c==e)\r
+ break;\r
+\r
+ if(!wcsnicmp(c,L"id",e-c)) {\r
+ c = read_attr(e, &id_start, &id_len);\r
+ } else if(!wcsnicmp(c,L"param",e-c)) {\r
+ c = read_attr(e, ¶m_start, ¶m_len);\r
+ }\r
+ }\r
+\r
+ if(d->active_link == d->n_links)\r
+ format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, RGB(0,0,255));\r
+ else\r
+ format_push(s,d, HTW_DEFAULT, FV_NONE, RGB(0,0,255));\r
+\r
+ {\r
+ khui_htwnd_link * l;\r
+\r
+ if(!d->links) {\r
+ d->links = malloc(sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC);\r
+ ZeroMemory(d->links, sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC);\r
+ d->max_links = HTW_LINK_ALLOC;\r
+ d->n_links = 0;\r
+ }\r
+\r
+ if(d->n_links >= d->max_links) {\r
+ khui_htwnd_link ** ll;\r
+ int n_new;\r
+\r
+ n_new = UBOUNDSS(d->n_links + 1, HTW_LINK_ALLOC, HTW_LINK_ALLOC);\r
+\r
+ ll = malloc(sizeof(khui_htwnd_link *) * n_new);\r
+ ZeroMemory(ll, sizeof(khui_htwnd_link *) * n_new);\r
+ memcpy(ll, d->links, sizeof(khui_htwnd_link *) * d->max_links);\r
+ free(d->links);\r
+ d->links = ll;\r
+ d->max_links = n_new;\r
+ }\r
+\r
+ l = d->links[d->n_links];\r
+ if(!l) {\r
+ l = malloc(sizeof(khui_htwnd_link));\r
+ d->links[d->n_links] = l;\r
+ }\r
+\r
+ l->id = id_start;\r
+ l->id_len = id_len;\r
+ l->param = param_start;\r
+ l->param_len = param_len;\r
+\r
+ l->r.left = p_abs->x;\r
+ l->r.top = p_abs->y;\r
+\r
+ d->n_links++;\r
+ }\r
+\r
+ } else if(!wcsnicmp(start, L"/a", c - start)) {\r
+ khui_htwnd_link * l;\r
+\r
+ c = wcschr(c,L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+\r
+ format_pop(s);\r
+\r
+ if(!dry_run) {\r
+ l = d->links[d->n_links - 1]; /* last link */\r
+ l->r.right = p_abs->x;\r
+ l->r.bottom = p_abs->y + lh;\r
+ }\r
+ } else if(!wcsnicmp(start, L"p", c - start)) {\r
+ wchar_t * e;\r
+ wchar_t * align_s = NULL;\r
+ int align_len;\r
+\r
+ c = skip_ws(c);\r
+ e = token_end(c);\r
+\r
+ if(c != e && !wcsnicmp(c,L"align",e-c)) {\r
+ c = read_attr(e, &align_s, &align_len);\r
+ }\r
+\r
+ c = wcschr(c, L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+ \r
+\r
+ if(align_s)\r
+ *align = table_lookup(htw_align_table, ARRAYLENGTH(htw_align_table), align_s, align_len);\r
+ else\r
+ *align = ALIGN_LEFT;\r
+\r
+ n = 1;\r
+ } else if(!wcsnicmp(start, L"b", c - start)) {\r
+ format_push(s,d, HTW_DEFAULT, FV_BOLD, HTW_DEFAULT);\r
+ } else if(!wcsnicmp(start, L"/b", c - start)) {\r
+ format_pop(s);\r
+ } else if(!wcsnicmp(start, L"u", c - start)) {\r
+ format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, HTW_DEFAULT);\r
+ } else if(!wcsnicmp(start, L"/u", c - start)) {\r
+ format_pop(s);\r
+ } else if(!wcsnicmp(start, L"large", c - start)) {\r
+ format_push(s,d,-MulDiv(HTW_LARGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT);\r
+ } else if(!wcsnicmp(start, L"/large", c - start)) {\r
+ format_pop(s);\r
+ } else if(!wcsnicmp(start, L"huge", c - start)) {\r
+ format_push(s,d,-MulDiv(HTW_HUGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT);\r
+ } else if(!wcsnicmp(start, L"/huge", c - start)) {\r
+ format_pop(s);\r
+ } else if(!wcsnicmp(start, L"center", c - start)) {\r
+ c = wcschr(c, L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+ *align = ALIGN_CENTER;\r
+ n = 1;\r
+ } else if(!wcsnicmp(start, L"left", c - start) ||\r
+ !wcsnicmp(start, L"p", c - start)) \r
+ {\r
+ c = wcschr(c, L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+ *align = ALIGN_LEFT;\r
+ n = 1;\r
+ } else if(!wcsnicmp(start, L"right", c - start)) {\r
+ c = wcschr(c, L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+ *align = ALIGN_RIGHT;\r
+ n = 1;\r
+ } else if(!wcsnicmp(start, L"/center", c - start) ||\r
+ !wcsnicmp(start, L"/left", c - start) ||\r
+ !wcsnicmp(start, L"/right", c - start) ||\r
+ !wcsnicmp(start, L"/p", c - start))\r
+ {\r
+ c = wcschr(c, L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+ *align = ALIGN_LEFT;\r
+ n = 1;\r
+ } else if(!wcsnicmp(start, L"font", c - start)) {\r
+ wchar_t * color_s = NULL;\r
+ int color_len;\r
+ wchar_t * size_s = NULL;\r
+ int size_len;\r
+ LONG color = HTW_DEFAULT;\r
+ LONG h = HTW_DEFAULT;\r
+\r
+ while(c && *c && *c != L'>') {\r
+ wchar_t * e;\r
+\r
+ c = skip_ws(c);\r
+ e = token_end(c);\r
+\r
+ if(c==e)\r
+ break;\r
+\r
+ if(!wcsnicmp(c,L"color",e-c)) {\r
+ c = read_attr(e, &color_s, &color_len);\r
+ } else if(!wcsnicmp(c,L"size",e-c)) {\r
+ c = read_attr(e, &size_s, &size_len);\r
+ }\r
+ }\r
+\r
+ if(color_s)\r
+ color = table_lookup(htw_color_table, ARRAYLENGTH(htw_color_table), color_s, color_len);\r
+ if(size_s) {\r
+ h = table_lookup(htw_size_table, ARRAYLENGTH(htw_size_table), size_s, size_len);\r
+ if(h)\r
+ h = -MulDiv(h, d->l_pixel_y, 72);\r
+ else\r
+ h = -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72);\r
+ }\r
+\r
+ format_push(s,d,h,HTW_DEFAULT,color);\r
+ } else if(!wcsnicmp(start, L"/font", c - start)) {\r
+ format_pop(s);\r
+ } else if(!wcsnicmp(start, L"settab", c - start)) {\r
+ wchar_t * e;\r
+ wchar_t * pos_s = NULL;\r
+ int pos_len;\r
+\r
+ c = skip_ws(c);\r
+ e = token_end(c);\r
+\r
+ if(c != e && !wcsnicmp(c,L"pos",e-c)) {\r
+ c = read_attr(e, &pos_s, &pos_len);\r
+ }\r
+\r
+ c = wcschr(c, L'>');\r
+ if(!c)\r
+ c = c + wcslen(c);\r
+\r
+ if(pos_s && d->n_tabs < HTW_TAB_MAX && !dry_run) {\r
+ wchar_t * dummy;\r
+ LONG bu;\r
+ int bx;\r
+ int dx;\r
+\r
+ bu = GetDialogBaseUnits();\r
+ bx = LOWORD(bu);\r
+\r
+ dx = wcstol(pos_s, &dummy, 10);\r
+\r
+ d->tabs[d->n_tabs++] = MulDiv(dx, bx, 4);\r
+ }\r
+ } else if(!wcsnicmp(start, L"tab", c - start)) {\r
+ int i;\r
+\r
+ if(!dry_run) {\r
+ for(i=0; i < d->n_tabs; i++) {\r
+ if(d->tabs[i] > p_rel->x) {\r
+ p_rel->x = d->tabs[i];\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if(*c)\r
+ c++;\r
+ *end = c;\r
+\r
+ return n;\r
+}\r
+\r
+static void htw_assert_style(HDC hdc, khui_htwnd_data * d, int style)\r
+{\r
+ LOGFONT lf;\r
+\r
+ if(d->styles[style].font)\r
+ return;\r
+\r
+ /*TODO: we need select different fonts depending on system locale */\r
+ lf.lfHeight = d->styles[style].height; //-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72);\r
+ lf.lfWidth = 0;\r
+ lf.lfEscapement = 0;\r
+ lf.lfOrientation = 0;\r
+ lf.lfWeight = (d->styles[style].variation & FV_BOLD)? FW_BOLD: FW_NORMAL;\r
+ lf.lfItalic = !!(d->styles[style].variation & FV_ITALIC);\r
+ lf.lfUnderline = !!(d->styles[style].variation & FV_UNDERLINE);\r
+ lf.lfStrikeOut = !!(d->styles[style].variation & FV_STRIKEOUT);\r
+ lf.lfCharSet = DEFAULT_CHARSET;\r
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
+ lf.lfQuality = DEFAULT_QUALITY;\r
+ lf.lfPitchAndFamily = DEFAULT_PITCH;\r
+\r
+ LoadString(khm_hInstance, IDS_DEFAULT_FONT, lf.lfFaceName, ARRAYLENGTH(lf.lfFaceName));\r
+\r
+ d->styles[style].font = CreateFontIndirect(&lf);\r
+}\r
+\r
+static LRESULT htw_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ PAINTSTRUCT ps;\r
+ HBRUSH hbk;\r
+ khui_htwnd_data * d;\r
+ RECT r;\r
+ SIZE s;\r
+ HDC hdc;\r
+ wchar_t * text;\r
+ format_stack s_stack;\r
+\r
+ int align;\r
+ int y;\r
+ wchar_t * par_start;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(!GetUpdateRect(hwnd, &r, !(d->flags & KHUI_HTWND_TRANSPARENT)))\r
+ return 0;\r
+\r
+ if(d->text == NULL)\r
+ return 0;\r
+\r
+ text = d->text;\r
+\r
+ hdc = BeginPaint(hwnd, &ps);\r
+\r
+ GetClientRect(hwnd, &r);\r
+\r
+ if(d->flags & KHUI_HTWND_CLIENTEDGE)\r
+ DrawEdge(hdc, &r, EDGE_SUNKEN, BF_ADJUST | BF_RECT | BF_FLAT);\r
+\r
+ hbk = CreateSolidBrush(RGB(255,255,255));\r
+ FillRect(hdc, &r, hbk);\r
+ DeleteObject(hbk);\r
+\r
+ /* push the default format */\r
+ format_init(&s_stack);\r
+\r
+ d->l_pixel_y = GetDeviceCaps(hdc, LOGPIXELSY);\r
+ format_push(&s_stack,d, -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72), FV_NONE, RGB(0,0,0));\r
+\r
+ y = d->scroll_top + r.top;\r
+\r
+ par_start = text;\r
+\r
+ align = ALIGN_LEFT;\r
+\r
+ SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP);\r
+ if(d->flags & KHUI_HTWND_TRANSPARENT)\r
+ SetBkMode(hdc, TRANSPARENT);\r
+\r
+ d->n_links = 0;\r
+ d->n_tabs = 0;\r
+\r
+ while(*par_start) {\r
+ wchar_t * p = par_start;\r
+ wchar_t * c = NULL;\r
+ int p_width = 0;\r
+ int s_start;\r
+ int l_height = 0;\r
+ int x = 0;\r
+ POINT pt;\r
+ POINT pt_rel;\r
+\r
+ s_start = format_level(&s_stack);\r
+\r
+ /* begin dry run */\r
+ while(*p) {\r
+ if(*p == L'<') {\r
+ int talign = -1;\r
+ int n = htw_parse_tag(p,&c,&talign,d,&s_stack,NULL,NULL,0,TRUE);\r
+\r
+ if(n && p_width)\r
+ break;\r
+\r
+ p = c;\r
+\r
+ if(n && talign >= 0)\r
+ align = talign;\r
+ } else {\r
+ HFONT hfold;\r
+ c = wcschr(p, L'<');\r
+ if(!c)\r
+ c = p + wcslen(p);\r
+\r
+ htw_assert_style(hdc, d, format_style(&s_stack));\r
+ hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font);\r
+ GetTextExtentPoint32(hdc, p, (int)(c - p), &s);\r
+ SelectFont(hdc, hfold);\r
+\r
+ p_width += s.cx;\r
+ if(s.cy > l_height)\r
+ l_height = s.cy;\r
+\r
+ p = c;\r
+ }\r
+ }\r
+\r
+ /* dry run ends */\r
+\r
+ x = r.left - d->scroll_left;\r
+\r
+ if(align == ALIGN_CENTER)\r
+ x += (r.right - r.left)/2 - p_width / 2;\r
+ else if(align == ALIGN_RIGHT)\r
+ x += (r.right - r.left) - p_width;\r
+\r
+ /* begin wet run */\r
+ p = par_start;\r
+ format_unwind(&s_stack, s_start); /* unwind format stack */\r
+\r
+ //MoveToEx(hdc, x, y + l_height, NULL);\r
+\r
+ p_width = 0;\r
+\r
+ while(*p) {\r
+ if(*p == L'<') {\r
+ int talign = -1;\r
+ int n;\r
+\r
+ pt.x = x + p_width;\r
+ pt.y = y;\r
+ pt_rel.x = p_width;\r
+ pt_rel.y = 0;\r
+\r
+ n = htw_parse_tag(p, &c, &talign, d, &s_stack, &pt, &pt_rel, l_height, FALSE);\r
+\r
+ if(n && p_width) {\r
+ break;\r
+ }\r
+\r
+ p_width = pt_rel.x;\r
+\r
+ p = c;\r
+ if(n && talign >= 0)\r
+ align = talign;\r
+ } else {\r
+ HFONT hfold;\r
+ RECT rd,rt;\r
+\r
+ c = wcschr(p, L'<');\r
+ if(!c)\r
+ c = p + wcslen(p);\r
+\r
+ htw_assert_style(hdc, d, format_style(&s_stack));\r
+ hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font);\r
+ SetTextColor(hdc, format_color(&s_stack));\r
+\r
+ GetTextExtentPoint32(hdc, p, (int)(c - p), &s);\r
+ rd.left = x + p_width;\r
+ rd.top = y;\r
+ rd.right = x + p_width + s.cx;\r
+ rd.bottom = y + l_height;\r
+\r
+ if(IntersectRect(&rt, &rd, &r)) {\r
+ DrawText(hdc, p, (int)(c - p), &rt, DT_BOTTOM | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX);\r
+ }\r
+\r
+ p_width += s.cx;\r
+\r
+ SelectFont(hdc, hfold);\r
+ p = c;\r
+ }\r
+ }\r
+\r
+ y += l_height;\r
+ par_start = p;\r
+ }\r
+\r
+ EndPaint(hwnd, &ps);\r
+\r
+ return 0;\r
+}\r
+\r
+LRESULT CALLBACK khui_htwnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ )\r
+{\r
+ switch(uMsg) {\r
+ case WM_CREATE:\r
+ {\r
+ CREATESTRUCT * cs;\r
+ khui_htwnd_data * d;\r
+ size_t cbsize;\r
+\r
+ cs = (CREATESTRUCT *) lParam;\r
+\r
+ d = malloc(sizeof(*d));\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ if(cs->dwExStyle & WS_EX_TRANSPARENT) {\r
+ d->flags |= KHUI_HTWND_TRANSPARENT;\r
+ }\r
+ if(cs->dwExStyle & WS_EX_CLIENTEDGE) {\r
+ d->flags |= KHUI_HTWND_CLIENTEDGE;\r
+ }\r
+ d->id = (int)(INT_PTR) cs->hMenu;\r
+\r
+ d->active_link = -1;\r
+ d->bk_color = RGB(255,255,255);\r
+ d->hc_hand = LoadCursor(NULL, IDC_HAND);\r
+\r
+ if(SUCCEEDED(StringCbLength(cs->lpszName, KHUI_HTWND_MAXCB_TEXT, &cbsize))) {\r
+ cbsize += sizeof(wchar_t);\r
+ d->text = malloc(cbsize);\r
+ StringCbCopy(d->text, cbsize, cs->lpszName);\r
+ }\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ return 0;\r
+ }\r
+ break;\r
+\r
+ case WM_SETTEXT:\r
+ {\r
+ wchar_t * newtext;\r
+ size_t cbsize;\r
+ khui_htwnd_data * d;\r
+ BOOL rv;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ newtext = (wchar_t *) lParam;\r
+\r
+ if(d->text) {\r
+ free(d->text);\r
+ d->text = NULL;\r
+ }\r
+\r
+ if(SUCCEEDED(StringCbLength(newtext, KHUI_HTWND_MAXCB_TEXT, &cbsize))) {\r
+ cbsize += sizeof(wchar_t);\r
+ d->text = malloc(cbsize);\r
+ StringCbCopy(d->text, cbsize, newtext);\r
+ rv = TRUE;\r
+ } else\r
+ rv = FALSE;\r
+\r
+ clear_styles(d);\r
+\r
+ InvalidateRect(hwnd, NULL, TRUE);\r
+\r
+ return rv;\r
+ }\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ {\r
+ khui_htwnd_data * d;\r
+ int i;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ if(d->text)\r
+ free(d->text);\r
+ d->text = 0;\r
+\r
+ if(d->links) {\r
+ for(i=0;i<d->max_links;i++) {\r
+ if(d->links[i])\r
+ free(d->links[i]);\r
+ }\r
+ free(d->links);\r
+ }\r
+\r
+ clear_styles(d);\r
+\r
+ free(d);\r
+ }\r
+ break;\r
+\r
+ case WM_ERASEBKGND:\r
+ {\r
+ khui_htwnd_data * d;\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(d->flags & KHUI_HTWND_TRANSPARENT)\r
+ return TRUE;\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ case WM_PAINT:\r
+ htw_paint(hwnd, uMsg, wParam, lParam);\r
+ break;\r
+\r
+ case WM_SETCURSOR:\r
+ {\r
+ khui_htwnd_data * d;\r
+\r
+ if(hwnd != (HWND)wParam)\r
+ break;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(d->active_link >= 0) {\r
+ SetCursor(d->hc_hand);\r
+ return TRUE;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WM_SETFOCUS:\r
+ {\r
+ khui_htwnd_data * d;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ d->flags |= KHUI_HTWND_FOCUS;\r
+\r
+ InvalidateRect(hwnd, NULL, TRUE);\r
+ }\r
+ break;\r
+\r
+ case WM_KILLFOCUS:\r
+ {\r
+ khui_htwnd_data * d;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ d->flags &= ~KHUI_HTWND_FOCUS;\r
+\r
+ InvalidateRect(hwnd, NULL, TRUE);\r
+ }\r
+ break;\r
+\r
+ case WM_LBUTTONDOWN:\r
+ {\r
+ khui_htwnd_data * d;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ d->md_link = d->active_link;\r
+\r
+ SetCapture(hwnd);\r
+ }\r
+ break;\r
+\r
+ case WM_LBUTTONUP:\r
+ {\r
+ khui_htwnd_data * d;\r
+\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+\r
+ if(d->md_link == d->active_link && d->md_link >= 0) {\r
+ /* clicked */\r
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(d->id, BN_CLICKED), (LPARAM) d->links[d->md_link]);\r
+ }\r
+\r
+ ReleaseCapture();\r
+ }\r
+ break;\r
+\r
+ case WM_MOUSEMOVE:\r
+ {\r
+ khui_htwnd_data * d;\r
+ int i;\r
+ POINT p;\r
+ int nl;\r
+\r
+ p.x = GET_X_LPARAM(lParam);\r
+ p.y = GET_Y_LPARAM(lParam);\r
+ d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ \r
+ for(i=0; i<d->n_links; i++) {\r
+ if(d->links && d->links[i] && PtInRect(&(d->links[i]->r), p))\r
+ break;\r
+ }\r
+\r
+ if(i == d->n_links)\r
+ nl = -1;\r
+ else\r
+ nl = i;\r
+\r
+ if(d->active_link != nl) {\r
+ if(d->active_link >= 0) {\r
+ if(d->flags & KHUI_HTWND_TRANSPARENT)\r
+ {\r
+ HWND parent = GetParent(hwnd);\r
+ if(parent) {\r
+ InvalidateRect(parent, NULL, TRUE);\r
+ }\r
+ }\r
+ /* although we are invalidating the rect before setting active_link,\r
+ WM_PAINT will not be issued until wndproc returns */\r
+ InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE);\r
+ }\r
+ d->active_link = nl;\r
+ if(d->active_link >= 0) {\r
+ /* although we are invalidating the rect before setting active_link,\r
+ WM_PAINT will not be issued until wndproc returns */\r
+ if(d->flags & KHUI_HTWND_TRANSPARENT)\r
+ {\r
+ HWND parent = GetParent(hwnd);\r
+ if(parent) {\r
+ InvalidateRect(parent, NULL, TRUE);\r
+ }\r
+ }\r
+ InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg,wParam,lParam);\r
+}\r
+\r
+void khm_register_htwnd_class(void)\r
+{\r
+ WNDCLASSEX wcx;\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;\r
+ wcx.lpfnWndProc = khui_htwnd_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = sizeof(LONG_PTR);\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = NULL;\r
+ wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);\r
+ wcx.hbrBackground = CreateSolidBrush(RGB(255,255,255));\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_HTWND_CLASS;\r
+ wcx.hIconSm = NULL;\r
+\r
+ khui_htwnd_cls = RegisterClassEx(&wcx);\r
+}\r
+\r
+void khm_unregister_htwnd_class(void)\r
+{\r
+ UnregisterClass((LPWSTR) khui_htwnd_cls, khm_hInstance);\r
+}\r
+\r
+HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style)\r
+{\r
+\r
+ return CreateWindowEx(\r
+ ex_style,\r
+ (LPWSTR) khui_htwnd_cls,\r
+ text,\r
+ style | WS_CHILD,\r
+ x,y,width,height,\r
+ parent,\r
+ (HMENU) KHUI_HTWND_CTLID,\r
+ khm_hInstance,\r
+ NULL);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_HTWND_H\r
+#define __KHIMAIRA_HTWND_H\r
+\r
+#include<khuidefs.h>\r
+\r
+/*\r
+We currently support the following tags:\r
+\r
+<a [id="string"] [param="paramstring"]>link text</a>\r
+<center>foo</center>\r
+<left>foo</left>\r
+<right>foo</right>\r
+*/\r
+\r
+#define KHUI_HTWND_TRANSPARENT 1\r
+#define KHUI_HTWND_CLIENTEDGE 2\r
+#define KHUI_HTWND_FOCUS 2048\r
+\r
+#define KHUI_HTWND_CLASS L"KhmHtWnd"\r
+#define KHUI_HTWND_CTLID 2040\r
+\r
+#define KHUI_HTWND_MAXCCH_TEXT 2048\r
+#define KHUI_HTWND_MAXCB_TEXT (sizeof(wchar_t) * KHUI_HTWND_MAXCCH_TEXT)\r
+\r
+HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style);\r
+void khm_unregister_htwnd_class(void);\r
+void khm_register_htwnd_class(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHIMAIRA_H\r
+#define __KHIMAIRA_KHIMAIRA_H\r
+\r
+#include<windows.h>\r
+#include<windowsx.h>\r
+#include<strsafe.h>\r
+#include<commctrl.h>\r
+\r
+#define KHERR_HMODULE khm_hInstance\r
+#define KHERR_FACILITY khm_facility\r
+#define KHERR_FACILITY_ID 3\r
+\r
+#include<khdefs.h>\r
+#include<khlist.h>\r
+#include<kherror.h>\r
+#include<kconfig.h>\r
+#include<kcreddb.h>\r
+#include<kmq.h>\r
+#include<khmsgtypes.h>\r
+#include<kmm.h>\r
+#include<khhelp.h>\r
+#include<khuidefs.h>\r
+\r
+#include<resource.h>\r
+#include<credfuncs.h>\r
+#include<appglobal.h>\r
+#include<mainwnd.h>\r
+#include<mainmenu.h>\r
+#include<toolbar.h>\r
+#include<statusbar.h>\r
+#include<credwnd.h>\r
+#include<htwnd.h>\r
+#include<passwnd.h>\r
+#include<newcredwnd.h>\r
+#include<propertywnd.h>\r
+#include<configwnd.h>\r
+#include<aboutwnd.h>\r
+\r
+#include<reqdaemon.h>\r
+#include<notifier.h>\r
+#include<timer.h>\r
+\r
+#endif\r
--- /dev/null
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "..\..\resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include <khimaira_version.h>\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "..\\..\\resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "#include <khimaira_version.h>\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+IDI_MAIN_APP ICON "..\\..\\images\\main_app.ico"\r
+IDI_WGT_COLLAPSE ICON "..\\..\\images\\wgt_arrow_collapse.ico"\r
+IDI_WGT_EXPAND ICON "..\\..\\images\\wgt_arrow_expand.ico"\r
+IDI_ENABLED ICON "..\\..\\images\\enabled.ico"\r
+IDI_DISABLED ICON "..\\..\\images\\disabled.ico"\r
+IDI_NOTIFY_NONE ICON "..\\..\\images\\app_notify_none.ico"\r
+IDI_NOTIFY_INFO ICON "..\\..\\images\\app_notify_info.ico"\r
+IDI_NOTIFY_WARN ICON "..\\..\\images\\app_notify_warn.ico"\r
+IDI_NOTIFY_ERROR ICON "..\\..\\images\\app_notify_error.ico"\r
+IDI_CFG_DEFAULT ICON "..\\..\\images\\cfg_default.ico"\r
+IDI_CFG_MODIFIED ICON "..\\..\\images\\cfg_mod.ico"\r
+IDI_CFG_APPLIED ICON "..\\..\\images\\cfg_applied.ico"\r
+IDI_CFG_DELETED ICON "..\\..\\images\\cfg_deleted.ico"\r
+IDI_ID ICON "..\\..\\images\\id.ico"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION 0,1,1,0\r
+ PRODUCTVERSION 0,1,1,0\r
+ FILEFLAGSMASK 0x17L\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x0L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+ BLOCK "StringFileInfo"\r
+ BEGIN\r
+ BLOCK "040904b0"\r
+ BEGIN\r
+ VALUE "CompanyName", "Massachusetts Institute of Technology"\r
+ VALUE "FileDescription", "Network Identity Manager"\r
+ VALUE "FileVersion", "0.1.1.0"\r
+ VALUE "InternalName", "NetIDMgr"\r
+ VALUE "LegalCopyright", "Copyright (C) 2005 Massachusetts Institute of Technology"\r
+ VALUE "OriginalFilename", "netidmgr.exe"\r
+ VALUE "ProductName", "NetIDMgr"\r
+ VALUE "ProductVersion", "0.1.1.0"\r
+ END\r
+ END\r
+ BLOCK "VarFileInfo"\r
+ BEGIN\r
+ VALUE "Translation", 0x409, 1200\r
+ END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Bitmap\r
+//\r
+\r
+IDB_TK_REFRESH BITMAP "..\\..\\images\\tk-refresh.bmp"\r
+IDB_ID BITMAP "..\\..\\images\\id.bmp"\r
+IDB_ID_DELETE BITMAP "..\\..\\images\\id-delete.bmp"\r
+IDB_ID_NEW BITMAP "..\\..\\images\\id-new.bmp"\r
+IDB_ID_REFRESH BITMAP "..\\..\\images\\id-refresh.bmp"\r
+IDB_TK BITMAP "..\\..\\images\\tk.bmp"\r
+IDB_TK_DELETE BITMAP "..\\..\\images\\tk-delete.bmp"\r
+IDB_TK_NEW BITMAP "..\\..\\images\\tk-new.bmp"\r
+IDB_VW_REFRESH_SM BITMAP "..\\..\\images\\vw-refresh-sm.bmp"\r
+IDB_TB_BLANK BITMAP "..\\..\\images\\tb-blank.bmp"\r
+IDB_TB_BLANK_SM BITMAP "..\\..\\images\\tb-blank-small.bmp"\r
+IDB_VW_REFRESH BITMAP "..\\..\\images\\vw-refresh.bmp"\r
+IDB_ID_DELETE_DIS BITMAP "..\\..\\images\\id-delete-dis.bmp"\r
+IDB_ID_DELETE_DIS_SM BITMAP "..\\..\\images\\id-delete-dis-sm.bmp"\r
+IDB_ID_DELETE_SM BITMAP "..\\..\\images\\id-delete-sm.bmp"\r
+IDB_ID_DIS BITMAP "..\\..\\images\\id-dis.bmp"\r
+IDB_ID_DIS_SM BITMAP "..\\..\\images\\id-dis-sm.bmp"\r
+IDB_ID_NEW_DIS BITMAP "..\\..\\images\\id-new-dis.bmp"\r
+IDB_ID_NEW_DIS_SM BITMAP "..\\..\\images\\id-new-dis-sm.bmp"\r
+IDB_ID_NEW_SM BITMAP "..\\..\\images\\id-new-sm.bmp"\r
+IDB_ID_REFRESH_DIS BITMAP "..\\..\\images\\id-refresh-dis.bmp"\r
+IDB_ID_REFRESH_SM BITMAP "..\\..\\images\\id-refresh-sm.bmp"\r
+IDB_ID_REFRESH_DIS_SM BITMAP "..\\..\\images\\id-refresh-sm-dis.bmp"\r
+IDB_TK_DELETE_DIS BITMAP "..\\..\\images\\tk-delete-dis.bmp"\r
+IDB_TK_DELETE_DIS_SM BITMAP "..\\..\\images\\tk-delete-dis-sm.bmp"\r
+IDB_TK_DELETE_SM BITMAP "..\\..\\images\\tk-delete-sm.bmp"\r
+IDB_TK_DIS_SM BITMAP "..\\..\\images\\tk-dis-sm.bmp"\r
+IDB_TK_NEW_DIS BITMAP "..\\..\\images\\tk-new-dis.bmp"\r
+IDB_TK_NEW_DIS_SM BITMAP "..\\..\\images\\tk-new-dis-sm.bmp"\r
+IDB_TK_NEW_SM BITMAP "..\\..\\images\\tk-new-sm.bmp"\r
+IDB_TK_REFRESH_DIS BITMAP "..\\..\\images\\tk-refresh-dis.bmp"\r
+IDB_TK_REFRESH_DIS_SM BITMAP "..\\..\\images\\tk-refresh-dis-sm.bmp"\r
+IDB_TK_REFRESH_SM BITMAP "..\\..\\images\\tk-refresh-sm.bmp"\r
+IDB_TK_SM BITMAP "..\\..\\images\\tk-sm.bmp"\r
+IDB_HELP_SM BITMAP "..\\..\\images\\help-sm.bmp"\r
+IDB_HELP BITMAP "..\\..\\images\\help.bmp"\r
+IDB_LOGO_SHADE BITMAP "..\\..\\images\\logo_shade.bmp"\r
+IDB_WDG_EXPAND BITMAP "..\\..\\images\\wdg_expanded.bmp"\r
+IDB_WDG_COLLAPSE BITMAP "..\\..\\images\\wdg_collapsed.bmp"\r
+IDB_ID_SM BITMAP "..\\..\\images\\id-sm.bmp"\r
+IDB_WDG_EXPAND_HI BITMAP "..\\..\\images\\wdg_expanded_hi.bmp"\r
+IDB_WDG_COLLAPSE_HI BITMAP "..\\..\\images\\wdg_collapsed_hi.bmp"\r
+IDB_WDG_CREDTYPE BITMAP "..\\..\\images\\wdg_credtype.bmp"\r
+IDB_WDG_FLAG BITMAP "..\\..\\images\\wdg_flag.bmp"\r
+IDB_FLAG_WARN BITMAP "..\\..\\images\\flag-warning.bmp"\r
+IDB_FLAG_EXPIRED BITMAP "..\\..\\images\\flag_expired.bmp"\r
+IDB_FLAG_CRITICAL BITMAP "..\\..\\images\\flag-critical.bmp"\r
+IDB_LOGO_OPAQUE BITMAP "..\\..\\images\\khimaira-cfg.bmp"\r
+IDB_IMPORT_SM_DIS BITMAP "..\\..\\images\\import-sm-dis.bmp"\r
+IDB_IMPORT BITMAP "..\\..\\images\\import.bmp"\r
+IDB_IMPORT_DIS BITMAP "..\\..\\images\\import-dis.bmp"\r
+IDB_IMPORT_SM BITMAP "..\\..\\images\\import-sm.bmp"\r
+IDB_CHPW_SM BITMAP "..\\..\\images\\chpw-sm.bmp"\r
+IDB_CHPW BITMAP "..\\..\\images\\chpw.bmp"\r
+IDB_CHPW_DIS BITMAP "..\\..\\images\\chpw-dis.bmp"\r
+IDB_CHPW_DIS_SM BITMAP "..\\..\\images\\chpw-dis-sm.bmp"\r
+IDB_TB_SPACE BITMAP "..\\..\\images\\tb-space.bmp"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Accelerator\r
+//\r
+\r
+IDR_MENU_BAR ACCELERATORS \r
+BEGIN\r
+ VK_F10, IDA_ACTIVATE_MENU, VIRTKEY, NOINVERT\r
+ VK_UP, IDA_UP, VIRTKEY, NOINVERT\r
+ VK_DOWN, IDA_DOWN, VIRTKEY, NOINVERT\r
+ VK_LEFT, IDA_LEFT, VIRTKEY, NOINVERT\r
+ VK_RIGHT, IDA_RIGHT, VIRTKEY, NOINVERT\r
+ VK_ESCAPE, IDA_ESC, VIRTKEY, NOINVERT\r
+ VK_EXECUTE, IDA_ENTER, VIRTKEY, NOINVERT\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_NC_NEWCRED DIALOGEX 0, 0, 301, 167\r
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "UI Row2",IDC_NC_TPL_ROW_LG,7,31,287,18,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+ LTEXT "TplPanel",IDC_NC_TPL_PANEL,7,7,287,153,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+ LTEXT "UI Row",IDC_NC_TPL_ROW,7,7,287,18,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+ LTEXT "TplLabel",IDC_NC_TPL_LABEL,7,8,45,10,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+ LTEXT "TplInput",IDC_NC_TPL_INPUT,54,7,240,13,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+ LTEXT "TplLabelLg",IDC_NC_TPL_LABEL_LG,7,33,146,10,NOT \r
+ WS_VISIBLE | WS_BORDER\r
+ LTEXT "TplInputLg",IDC_NC_TPL_INPUT_LG,155,31,139,13,NOT \r
+ WS_VISIBLE | WS_BORDER\r
+ LTEXT "&Credentials",IDC_NC_CREDTEXT_LABEL,7,66,41,10,NOT \r
+ WS_GROUP\r
+ CONTROL "",IDC_NC_CREDTEXT,"KhmHtWnd",WS_TABSTOP,54,65,240,73,\r
+ WS_EX_CLIENTEDGE\r
+ PUSHBUTTON "&Ok",IDOK,57,142,89,18,WS_DISABLED\r
+ PUSHBUTTON "&Cancel",IDCANCEL,158,142,54,18\r
+ PUSHBUTTON "&Options >>",IDC_NC_OPTIONS,223,142,71,18\r
+END\r
+\r
+IDD_NC_BBAR DIALOGEX 0, 0, 60, 181\r
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ DEFPUSHBUTTON "&Ok",IDOK,0,7,53,41,WS_DISABLED\r
+ PUSHBUTTON "&Cancel",IDCANCEL,0,58,53,19\r
+ PUSHBUTTON "&Help",IDC_NC_HELP,0,155,53,19\r
+END\r
+\r
+IDD_NC_TS DIALOGEX 0, 0, 300, 15\r
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+END\r
+\r
+IDD_PP_IDENT DIALOGEX 0, 0, 235, 156\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+CAPTION "Identity"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+ LTEXT "Name",IDC_STATIC,7,8,19,12\r
+ LTEXT "IdentityName",IDC_PP_IDNAME,34,7,194,12,NOT WS_GROUP,\r
+ WS_EX_CLIENTEDGE\r
+ CONTROL "Default identity",IDC_PP_IDDEF,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,34,25,71,12\r
+ CONTROL "Searchable",IDC_PP_IDSEARCH,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,34,43,74,12\r
+ CONTROL "Custom1",IDC_PP_PROPLIST,"NetIDMgrPropertyWnd",\r
+ WS_TABSTOP,7,61,221,88\r
+ CONTROL "Always visible (sticky)",IDC_PP_STICKY,"Button",\r
+ BS_AUTOCHECKBOX | WS_TABSTOP,117,25,85,10\r
+END\r
+\r
+IDD_PP_CRED DIALOGEX 0, 0, 236, 158\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION\r
+CAPTION "Credential"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+ CONTROL "Check1",IDC_PP_DUMMY,"Button",BS_AUTOCHECKBOX | NOT \r
+ WS_VISIBLE | WS_TABSTOP,0,1,39,10\r
+ CONTROL "Custom1",IDC_PP_CPROPLIST,"NetIDMgrPropertyWnd",\r
+ WS_TABSTOP,7,7,222,144\r
+END\r
+\r
+IDD_CFG_MAIN DIALOGEX 0, 0, 357, 222\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+ WS_SYSMENU\r
+EXSTYLE WS_EX_CONTEXTHELP\r
+CAPTION "Khimaira Configuration"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ LTEXT "Title",IDC_CFG_TITLE,0,0,357,20,SS_CENTERIMAGE\r
+ CONTROL "",IDC_CFG_NODELIST,"SysTreeView32",TVS_HASBUTTONS | \r
+ TVS_HASLINES | TVS_LINESATROOT | WS_TABSTOP,0,20,100,182\r
+ LTEXT "Static",IDC_CFG_PANE,102,20,255,182,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+ PUSHBUTTON "&Ok",IDOK,162,205,78,16\r
+ PUSHBUTTON "&Cancel",IDCANCEL,246,205,51,16\r
+ PUSHBUTTON "&Apply",IDAPPLY,303,205,51,16,WS_DISABLED\r
+ PUSHBUTTON "C&hange Summary ...",IDC_CFG_SUMMARY,3,205,76,16,\r
+ WS_DISABLED\r
+END\r
+\r
+IDD_CFG_GENERIC DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CTEXT "Please select one of the configuration categories on the left.",\r
+ IDC_STATIC,21,17,212,18,SS_CENTERIMAGE,WS_EX_TRANSPARENT\r
+END\r
+\r
+IDD_CFG_GENERAL DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ GROUPBOX "Startup",IDC_CFG_STARTUP_GROUP,7,7,241,50\r
+ CONTROL "&Prompt for new credentials if there aren't any at startup",\r
+ IDC_CFG_AUTOINIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,\r
+ 16,22,196,10\r
+ CONTROL "&Start NetIDMgr when Windows starts",IDC_CFG_AUTOSTART,\r
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16,\r
+ 38,135,10\r
+ GROUPBOX "Other",IDC_CFG_OTHER,7,63,241,70\r
+ CONTROL "&Keep NetIDMgr running after closing window",\r
+ IDC_CFG_KEEPRUNNING,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,16,78,158,10\r
+ CONTROL "Detect network connectivity",IDC_CFG_NETDETECT,"Button",\r
+ BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16,96,106,10\r
+ CONTROL "A&utomatically import credentials from Windows",\r
+ IDC_CFG_AUTOIMPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,\r
+ 16,113,165,10\r
+END\r
+\r
+IDD_CFG_IDENTITIES DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "",IDC_CFG_TAB,"SysTabControl32",WS_TABSTOP,7,7,241,168\r
+ LTEXT "Static",IDC_CFG_TARGET,10,21,235,151,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+END\r
+\r
+IDD_CFG_NOTIF DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "&Monitor credentials expiration",IDC_NOTIF_MONITOR,\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,139,10\r
+ CONTROL "&Renew automatically",IDC_NOTIF_RENEW,"Button",\r
+ BS_AUTOCHECKBOX | WS_TABSTOP,22,32,82,10\r
+ EDITTEXT IDC_NOTIF_RENEW_THR,122,30,126,14,ES_AUTOHSCROLL\r
+ CONTROL "Warn",IDC_NOTIF_WARN1,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,22,57,33,10\r
+ EDITTEXT IDC_NOTIF_WARN1_THR,122,55,126,14,ES_AUTOHSCROLL\r
+ CONTROL "Warn again",IDC_NOTIF_WARN2,"Button",BS_AUTOCHECKBOX | \r
+ WS_TABSTOP,22,82,67,10\r
+ EDITTEXT IDC_NOTIF_WARN2_THR,122,80,126,14,ES_AUTOHSCROLL\r
+END\r
+\r
+IDD_CFG_PLUGINS DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "",IDC_CFG_PLUGINS,"SysListView32",LVS_ALIGNLEFT | \r
+ WS_BORDER | WS_TABSTOP,7,7,75,168\r
+ GROUPBOX "Plugin",IDC_CFG_PLUGINGRP,86,7,162,103\r
+ LTEXT "Description",IDC_CFG_LBL_DESC,90,20,36,8\r
+ EDITTEXT IDC_CFG_DESC,134,17,109,14,ES_AUTOHSCROLL | ES_READONLY\r
+ LTEXT "Status",IDC_CFG_LBL_STATE,90,38,22,8\r
+ EDITTEXT IDC_CFG_STATE,134,35,109,14,ES_AUTOHSCROLL | ES_READONLY\r
+ LTEXT "Depends on",IDC_CFG_LBL_DEPS,90,52,39,8\r
+ LISTBOX IDC_CFG_DEPS,134,52,109,34,LBS_SORT | \r
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP\r
+ PUSHBUTTON "Enable",IDC_CFG_ENABLE,134,90,50,14\r
+ PUSHBUTTON "Disable",IDC_CFG_DISABLE,193,90,50,14\r
+ GROUPBOX "Provided by",IDC_CFG_PROVGRP,86,111,162,47\r
+ LTEXT "Module",IDC_CFG_LBL_MOD,90,124,24,8\r
+ EDITTEXT IDC_CFG_MODULE,134,121,109,14,ES_AUTOHSCROLL | \r
+ ES_READONLY\r
+ LTEXT "Vendor",IDC_CFG_LBL_VEN,90,142,24,8\r
+ EDITTEXT IDC_CFG_VENDOR,133,139,110,14,ES_AUTOHSCROLL | \r
+ ES_READONLY\r
+ PUSHBUTTON "Register new plugin ...",IDC_CFG_REGISTER,163,161,85,14,\r
+ WS_DISABLED\r
+END\r
+\r
+IDD_CFG_IDENTITY DIALOGEX 0, 0, 255, 182\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "",IDC_CFG_TAB,"SysTabControl32",WS_TABSTOP,7,7,241,168\r
+ LTEXT "Static",IDC_CFG_TARGET,10,21,235,151,NOT WS_VISIBLE | \r
+ WS_BORDER\r
+END\r
+\r
+IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+EXSTYLE WS_EX_CONTROLPARENT\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "",IDC_CFG_IDENTS,"SysListView32",LVS_SHAREIMAGELISTS | \r
+ LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,221,72\r
+ GROUPBOX "Selected identity",IDC_CFG_IDENTITY,7,81,221,63\r
+ CONTROL "Monitor credential expiration",IDC_CFG_MONITOR,"Button",\r
+ BS_3STATE | WS_TABSTOP,13,92,107,10\r
+ CONTROL "Automatically renew",IDC_CFG_RENEW,"Button",BS_3STATE | \r
+ WS_TABSTOP,13,106,81,10\r
+ CONTROL "Always show in the credentials list (Sticky)",\r
+ IDC_CFG_STICKY,"Button",BS_3STATE | WS_TABSTOP,13,120,\r
+ 151,10\r
+ PUSHBUTTON "&Remove",IDC_CFG_REMOVE,174,126,50,14,WS_DISABLED\r
+END\r
+\r
+IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ CONTROL "Always show in the credentials list (Sticky)",\r
+ IDC_CFG_STICKY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,\r
+ 34,151,10\r
+ CONTROL "Monitor credential expiration",IDC_CFG_MONITOR,"Button",\r
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,7,107,10\r
+ CONTROL "Automatically renew",IDC_CFG_RENEW,"Button",\r
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,20,81,10\r
+END\r
+\r
+IDD_ABOUT DIALOGEX 0, 0, 268, 170\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+ WS_SYSMENU\r
+CAPTION "About Network Identity Manager"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+ DEFPUSHBUTTON "OK",IDOK,211,7,50,14\r
+ LTEXT "Productname",IDC_PRODUCT,41,7,163,13,NOT WS_GROUP\r
+ LTEXT "© 2005 Massachusetts Institute of Technology",\r
+ IDC_COPYRIGHT,41,23,220,18,NOT WS_GROUP\r
+ LTEXT "BuildInfo",IDC_BUILDINFO,41,41,220,17,NOT WS_GROUP\r
+ ICON IDI_MAIN_APP,IDC_STATIC,6,7,21,20\r
+ CONTROL "",IDC_MODULES,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | \r
+ WS_TABSTOP,41,72,220,91\r
+ LTEXT "Loaded modules",IDC_STATIC,41,60,52,8\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO \r
+BEGIN\r
+ IDD_NC_NEWCRED, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 294\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 160\r
+ END\r
+\r
+ IDD_NC_BBAR, DIALOG\r
+ BEGIN\r
+ RIGHTMARGIN, 53\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 174\r
+ END\r
+\r
+ IDD_PP_IDENT, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ VERTGUIDE, 34\r
+ VERTGUIDE, 117\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 149\r
+ END\r
+\r
+ IDD_PP_CRED, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 229\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 151\r
+ END\r
+\r
+ IDD_CFG_GENERIC, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+\r
+ IDD_CFG_GENERAL, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 16\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+\r
+ IDD_CFG_IDENTITIES, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 10\r
+ VERTGUIDE, 244\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ HORZGUIDE, 22\r
+ HORZGUIDE, 171\r
+ END\r
+\r
+ IDD_CFG_NOTIF, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 22\r
+ VERTGUIDE, 122\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+\r
+ IDD_CFG_PLUGINS, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ VERTGUIDE, 86\r
+ VERTGUIDE, 90\r
+ VERTGUIDE, 134\r
+ VERTGUIDE, 243\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+\r
+ IDD_CFG_IDENTITY, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 248\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 175\r
+ END\r
+\r
+ IDD_CFG_IDS_TAB, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 144\r
+ END\r
+\r
+ IDD_CFG_ID_TAB, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 7\r
+ RIGHTMARGIN, 228\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 144\r
+ END\r
+\r
+ IDD_ABOUT, DIALOG\r
+ BEGIN\r
+ LEFTMARGIN, 6\r
+ RIGHTMARGIN, 261\r
+ VERTGUIDE, 41\r
+ VERTGUIDE, 204\r
+ TOPMARGIN, 7\r
+ BOTTOMMARGIN, 163\r
+ END\r
+END\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_MAIN_WINDOW_TITLE "Network Identity Manager"\r
+ IDS_MENU_FILE "&File"\r
+ IDS_MENU_CRED "&Credential"\r
+ IDS_MENU_VIEW "&View"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_MENU_OPTIONS "&Options"\r
+ IDS_MENU_HELP "&Help"\r
+ IDS_ACTION_PROPERTIES "&Properties ..."\r
+ IDS_ACTION_EXIT "E&xit"\r
+ IDS_CFG_ROOT_NAME "NetIDMgr"\r
+ IDS_ACTION_SET_DEF_ID "Set as &default"\r
+ IDS_ACTION_SET_SRCH_ID "Allow applications to &search"\r
+ IDS_CFG_ROOT_TITLE "NetIDMgr Configuration"\r
+ IDS_CFG_GENERAL_SHORT "General"\r
+ IDS_ACTION_NEW_CRED "&New credentials ..."\r
+ IDS_ACTION_PASSWD_ID "Change &password ..."\r
+ IDS_ACTION_CHOOSE_COLS "Choose columns ..."\r
+ IDS_ACTION_DEBUG_WINDOW "Debug window ..."\r
+ IDS_ACTION_VIEW_REFRESH "Refresh"\r
+ IDS_MENU_LAYOUT "Layout"\r
+ IDS_MENU_TOOLBARS "Toolbars"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_ACTION_LAYOUT_ID "By identity"\r
+ IDS_ACTION_LAYOUT_TYPE "By type"\r
+ IDS_ACTION_LAYOUT_LOC "By location"\r
+ IDS_ACTION_TB_STANDARD "Standard"\r
+ IDS_ACTION_OPT_KHIM "General ..."\r
+ IDS_ACTION_OPT_IDENTS "Identities ..."\r
+ IDS_ACTION_OPT_NOTIF "Notifications ..."\r
+ IDS_ACTION_HELP_CTX "Context"\r
+ IDS_ACTION_HELP_CONTENTS "Contents ..."\r
+ IDS_ACTION_HELP_INDEX "Index ..."\r
+ IDS_ACTION_HELP_ABOUT "About NetIDMgr ..."\r
+ IDS_CFG_GENERAL_LONG "General options for NetIDMgr"\r
+ IDS_SAMPLE_STRING "Wxy"\r
+ IDS_NO_CREDS "<large><center>You currently have no credentials.Click <a id=""NewCreds"">here</a> to obtain new credentials.</center></large>"\r
+ IDS_WT_INIT_CREDS "Obtain initial credentials"\r
+ IDS_WT_NEW_CREDS "Obtain new credentials"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_NC_IDENTITY "&Identity"\r
+ IDS_NC_IDENTS "&Identities"\r
+ IDS_NC_CREDTEXT_ID_NONE "<p><b>(No identities specified)</b></p>"\r
+ IDS_NC_CREDTEXT_ID_ONE "<p>Selected identity: <b>%s</b></p>"\r
+ IDS_NC_CREDTEXT_ID_MANY "<p>Primary identity: <b>%s</b></p><p>Additional identities: <b>%s</b></p>"\r
+ IDS_NC_CREDTEXT_ID_INVALID "<font color=""red"">%s (invalid)</font>"\r
+ IDS_WTPOST_INIT_CREDS " - Initial credentials"\r
+ IDS_WTPOST_NEW_CREDS " - New credentials"\r
+ IDS_ACTION_RENEW_CRED "R&enew credentials"\r
+ IDS_ACTION_DESTROY_CRED "De&stroy credentials ..."\r
+ IDS_DEFAULT_FONT "MS Shell Dlg"\r
+ IDS_NC_CREDTEXT_TABS "<settab pos=""15""><settab pos=""30""><settab pos=""45"">"\r
+ IDS_NOTIFY_PREFIX "NetIDMgr - "\r
+ IDS_NOTIFY_READY "Ready"\r
+ IDS_NOTIFY_ATTENTION "Attention"\r
+ IDS_ALERT_DEFAULT "Alert"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_PACTION_OK "&Ok"\r
+ IDS_PACTION_CANCEL "&Cancel"\r
+ IDS_PACTION_CLOSE "&Close"\r
+ IDS_ALERT_NOSEL_TITLE "No credentials selected"\r
+ IDS_ALERT_NOSEL "Please select a credential, a credential type or an identity."\r
+ IDS_NC_CREDTEXT_ID_VALID "<font color=""blue"">%s</font>"\r
+ IDS_NC_CREDTEXT_ID_UNCHECKED "<font color=""grey"">%s (Unverified)</font>"\r
+ IDS_PROP_COL_PROPERTY "Property"\r
+ IDS_PROP_COL_VALUE "Value"\r
+ IDS_NC_NEW_IDENT "( New identity ... )"\r
+ IDS_NC_CREDTEXT_ID_CHECKING "<font color=""grey"">%s (Checking...)</font>"\r
+ IDS_ACTION_OPEN_APP "Open NetIDMgr ..."\r
+ IDS_CTX_NEW_IDENT "Obaining new identity"\r
+ IDS_CTX_NEW_CREDS "Obtaining new credentials"\r
+ IDS_CTX_RENEW_CREDS "Renewing credentials"\r
+ IDS_CTX_PROC_NEW_IDENT "Obtaining initial credentials for %1!s!"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_CTX_PROC_NEW_CREDS "Obtaining new credentials for %1!s!"\r
+ IDS_CTX_PROC_RENEW_CREDS "Renewing credentials for %1!s!"\r
+ IDS_ACTION_CLOSE_APP "Close NetIDMgr window"\r
+ IDS_NC_FAILED_TITLE "Failed to acquire credentials"\r
+ IDS_CFG_IDENTITIES_SHORT "Identities"\r
+ IDS_CFG_IDENTITIES_LONG "Options for all identities"\r
+ IDS_CFG_NOTIF_SHORT "Notifications"\r
+ IDS_CFG_NOTIF_LONG "Notifications"\r
+ IDS_CFG_PLUGINS_SHORT "Plugins"\r
+ IDS_CFG_PLUGINS_LONG "Plugins and Modules"\r
+ IDS_CFG_IDENTITY_SHORT "%s"\r
+ IDS_CFG_IDENTITY_LONG "Options for %s"\r
+ IDS_CTX_DESTROY_CREDS "Destroying credentials"\r
+ IDS_WARN_EXPIRE "Some of your credentials will expire in %s"\r
+ IDS_WARN_TITLE "Credentials expiration warning"\r
+ IDS_ALERT_MOREINFO "...\nClick here for more..."\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_WARN_EXPIRED "Some of your credentials have expired."\r
+ IDS_WARN_EXPIRE_ID "Credentials for %.180s will expire in %s"\r
+ IDS_WARN_EXPIRED_ID "Credentials for %.220s have expired"\r
+ IDS_WARN_WM_TITLE "NetIDMgr is still running"\r
+ IDS_WARN_WM_MSG "Click the NetIDMgr icon below to open the application.\n\nOr right click the icon to access the NetIDMgr menu."\r
+ IDS_CFG_ID_TAB_SHORT "General"\r
+ IDS_CFG_ID_TAB_LONG "General options for this identity"\r
+ IDS_CFG_IDS_TAB_SHORT "General"\r
+ IDS_CFG_IDS_TAB_LONG "General options for all identities"\r
+ IDS_CFG_IDS_IDENTITY "Identity"\r
+ IDS_ACTION_IMPORT "Import Credentials"\r
+ IDS_CTX_IMPORT "Importing credentials from Windows"\r
+ IDS_CFG_PI_COL_PLUGINS "Plugins"\r
+ IDS_PISTATE_FAILUNK "Unknown failure"\r
+ IDS_PISTATE_FAILMAX "Maximum failure count reached"\r
+ IDS_PISTATE_FAILREG "Not properly registered"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_PISTATE_FAILDIS "Disabled"\r
+ IDS_PISTATE_FAILLOD "Failed to initialize"\r
+ IDS_PISTATE_PLACEHOLD "Not loaded"\r
+ IDS_PISTATE_REG "Not initialized"\r
+ IDS_PISTATE_HOLD "Waiting for dependencies"\r
+ IDS_PISTATE_INIT "Initializing"\r
+ IDS_PISTATE_RUN "Running"\r
+ IDS_PISTATE_EXIT "Stopped"\r
+ IDS_CTX_PASSWORD "Changing password"\r
+ IDS_WT_PASSWORD "Changing password"\r
+ IDS_WTPOST_PASSWORD " - Changing password"\r
+ IDS_CTX_PROC_PASSWORD "Changing password for %1!s!"\r
+ IDS_NC_PWD_FAILED_TITLE "Failed to change password"\r
+ IDS_CMDLINE_HELP "Command line options for NetIDMgr are :\n\n-a or --autoinit: Auto initialize credentials\n-i or --kinit: Obtain new credentials\n-d or --destroy: Destroy default identity\n-r or --renew: Renew all credentials"\r
+END\r
+\r
+#endif // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+\r
+#if DEBUG\r
+#include<assert.h>\r
+#endif\r
+\r
+HINSTANCE khm_hInstance;\r
+const wchar_t * khm_facility = L"NetIDMgr";\r
+int khm_nCmdShow;\r
+\r
+khm_startup_options khm_startup;\r
+\r
+void khm_init_gui(void) {\r
+ khui_init_actions();\r
+ khui_init_rescache();\r
+ khui_init_menu();\r
+ khui_init_toolbar();\r
+ khui_init_notifier();\r
+ khm_init_config();\r
+}\r
+\r
+void khm_exit_gui(void) {\r
+ khm_exit_config();\r
+ khui_exit_notifier();\r
+ khui_exit_toolbar();\r
+ khui_exit_menu();\r
+ khui_exit_rescache();\r
+ khui_exit_actions();\r
+}\r
+\r
+void khm_parse_commandline(void) {\r
+ LPWSTR wcmdline;\r
+ LPWSTR * wargs;\r
+ int wargc;\r
+ int i;\r
+\r
+ ZeroMemory(&khm_startup, sizeof(khm_startup));\r
+\r
+ wcmdline = GetCommandLine();\r
+ wargs = CommandLineToArgvW(wcmdline, &wargc);\r
+\r
+ for (i=1; i<wargc; i++) {\r
+ if (!wcscmp(wargs[i], L"-i") ||\r
+ !wcscmp(wargs[i], L"--kinit")) {\r
+ khm_startup.init = TRUE;\r
+ khm_startup.exit = TRUE;\r
+ khm_startup.no_main_window = TRUE;\r
+ }\r
+ else if (!wcscmp(wargs[i], L"-m") ||\r
+ !wcscmp(wargs[i], L"--import")) {\r
+ khm_startup.import = TRUE;\r
+ khm_startup.exit = TRUE;\r
+ khm_startup.no_main_window = TRUE;\r
+ }\r
+ else if (!wcscmp(wargs[i], L"-r") ||\r
+ !wcscmp(wargs[i], L"--renew")) {\r
+ khm_startup.renew = TRUE;\r
+ khm_startup.exit = TRUE;\r
+ khm_startup.no_main_window = TRUE;\r
+ }\r
+ else if (!wcscmp(wargs[i], L"-d") ||\r
+ !wcscmp(wargs[i], L"--destroy")) {\r
+ khm_startup.destroy = TRUE;\r
+ khm_startup.exit = TRUE;\r
+ khm_startup.no_main_window = TRUE;\r
+ }\r
+ else if (!wcscmp(wargs[i], L"-a") ||\r
+ !wcscmp(wargs[i], L"--autoinit")) {\r
+ khm_startup.autoinit = TRUE;\r
+ }\r
+ else {\r
+ wchar_t help[2048];\r
+\r
+ LoadString(khm_hInstance, IDS_CMDLINE_HELP,\r
+ help, ARRAYLENGTH(help));\r
+\r
+ MessageBox(NULL, help, L"NetIDMgr", MB_OK);\r
+\r
+ khm_startup.error_exit = TRUE;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+void khm_register_window_classes(void) {\r
+ INITCOMMONCONTROLSEX ics;\r
+\r
+ ZeroMemory(&ics, sizeof(ics));\r
+ ics.dwSize = sizeof(ics);\r
+ ics.dwICC = \r
+ ICC_COOL_CLASSES |\r
+ ICC_BAR_CLASSES |\r
+ ICC_DATE_CLASSES |\r
+ ICC_HOTKEY_CLASS |\r
+ ICC_LINK_CLASS |\r
+ ICC_LISTVIEW_CLASSES |\r
+ ICC_STANDARD_CLASSES |\r
+ ICC_TAB_CLASSES;\r
+ InitCommonControlsEx(&ics);\r
+\r
+ khm_register_main_wnd_class();\r
+ khm_register_credwnd_class();\r
+ khm_register_htwnd_class();\r
+ khm_register_passwnd_class();\r
+ khm_register_newcredwnd_class();\r
+ khm_register_propertywnd_class();\r
+}\r
+\r
+void khm_unregister_window_classes(void) {\r
+ khm_unregister_main_wnd_class();\r
+ khm_unregister_credwnd_class();\r
+ khm_unregister_htwnd_class();\r
+ khm_unregister_passwnd_class();\r
+ khm_unregister_newcredwnd_class();\r
+ khm_unregister_propertywnd_class();\r
+}\r
+\r
+\r
+/* we support up to 16 simutaneous dialogs. In reality, more than two\r
+ is pretty unlikely. Property sheets are special and are handled\r
+ separately. */\r
+#define MAX_UI_DIALOGS 16\r
+\r
+typedef struct tag_khui_dialog {\r
+ HWND hwnd;\r
+ BOOL active;\r
+} khui_dialog;\r
+\r
+static khui_dialog khui_dialogs[MAX_UI_DIALOGS];\r
+static int n_khui_dialogs = 0;\r
+static HWND khui_modal_dialog = NULL;\r
+static BOOL khui_main_window_active;\r
+\r
+/* should only be called from the UI thread */\r
+void khm_add_dialog(HWND dlg) {\r
+ if(n_khui_dialogs < MAX_UI_DIALOGS - 1) {\r
+ khui_dialogs[n_khui_dialogs].hwnd = dlg;\r
+ /* we set .active=FALSE for now. We don't need this to have a\r
+ meaningful value until we enter a modal loop */\r
+ khui_dialogs[n_khui_dialogs].active = FALSE;\r
+ n_khui_dialogs++;\r
+ }\r
+#if DEBUG\r
+ else {\r
+ assert(FALSE);\r
+ }\r
+#endif\r
+}\r
+\r
+/* should only be called from the UI thread */\r
+void khm_enter_modal(HWND hwnd) {\r
+ int i;\r
+\r
+ for(i=0; i < n_khui_dialogs; i++) {\r
+ if(khui_dialogs[i].hwnd != hwnd) {\r
+ khui_dialogs[i].active = IsWindowEnabled(khui_dialogs[i].hwnd);\r
+ EnableWindow(khui_dialogs[i].hwnd, FALSE);\r
+ }\r
+ }\r
+\r
+ khui_main_window_active = IsWindowEnabled(khm_hwnd_main);\r
+ EnableWindow(khm_hwnd_main, FALSE);\r
+\r
+ khui_modal_dialog = hwnd;\r
+}\r
+\r
+/* should only be called from the UI thread */\r
+void khm_leave_modal(void) {\r
+ int i;\r
+\r
+ for(i=0; i < n_khui_dialogs; i++) {\r
+ if(khui_dialogs[i].hwnd != khui_modal_dialog) {\r
+ EnableWindow(khui_dialogs[i].hwnd, khui_dialogs[i].active);\r
+ }\r
+ }\r
+\r
+ EnableWindow(khm_hwnd_main, khui_main_window_active);\r
+\r
+ khui_modal_dialog = NULL;\r
+}\r
+\r
+/* should only be called from the UI thread */\r
+void khm_del_dialog(HWND dlg) {\r
+ int i;\r
+ for(i=0;i < n_khui_dialogs; i++) {\r
+ if(khui_dialogs[i].hwnd == dlg)\r
+ break;\r
+ }\r
+ \r
+ if(i < n_khui_dialogs)\r
+ n_khui_dialogs--;\r
+ else\r
+ return;\r
+\r
+ for(;i < n_khui_dialogs; i++) {\r
+ khui_dialogs[i] = khui_dialogs[i+1];\r
+ }\r
+}\r
+\r
+BOOL khm_check_dlg_message(LPMSG pmsg) {\r
+ int i;\r
+ for(i=0;i<n_khui_dialogs;i++) {\r
+ if(IsDialogMessage(khui_dialogs[i].hwnd, pmsg))\r
+ break;\r
+ }\r
+\r
+ if(i<n_khui_dialogs)\r
+ return TRUE;\r
+ else\r
+ return FALSE;\r
+}\r
+\r
+BOOL khm_is_dialog_active(void) {\r
+ HWND hwnd;\r
+ int i;\r
+\r
+ hwnd = GetForegroundWindow();\r
+\r
+ for (i=0; i<n_khui_dialogs; i++) {\r
+ if (khui_dialogs[i].hwnd == hwnd)\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* We support at most 256 property sheets simultaneously. 256\r
+ property sheets should be enough for everybody. */\r
+#define MAX_UI_PROPSHEETS 256\r
+\r
+khui_property_sheet *_ui_propsheets[MAX_UI_PROPSHEETS];\r
+int _n_ui_propsheets = 0;\r
+\r
+void khm_add_property_sheet(khui_property_sheet * s) {\r
+ if(_n_ui_propsheets < MAX_UI_PROPSHEETS)\r
+ _ui_propsheets[_n_ui_propsheets++] = s;\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+}\r
+\r
+void khm_del_property_sheet(khui_property_sheet * s) {\r
+ int i;\r
+\r
+ for(i=0;i < _n_ui_propsheets; i++) {\r
+ if(_ui_propsheets[i] == s)\r
+ break;\r
+ }\r
+\r
+ if(i < _n_ui_propsheets)\r
+ _n_ui_propsheets--;\r
+ else\r
+ return;\r
+\r
+ for(;i < _n_ui_propsheets; i++) {\r
+ _ui_propsheets[i] = _ui_propsheets[i+1];\r
+ }\r
+}\r
+\r
+BOOL khm_check_ps_message(LPMSG pmsg) {\r
+ int i;\r
+ khui_property_sheet * ps;\r
+ for(i=0;i<_n_ui_propsheets;i++) {\r
+ if(khui_ps_check_message(_ui_propsheets[i], pmsg)) {\r
+ if(_ui_propsheets[i]->status == KHUI_PS_STATUS_DONE) {\r
+ ps = _ui_propsheets[i];\r
+\r
+ ps->status = KHUI_PS_STATUS_DESTROY;\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_END, 0, (void *) ps);\r
+\r
+ return TRUE;\r
+ }\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+WPARAM khm_message_loop(void) {\r
+ int r;\r
+ MSG msg;\r
+ HACCEL ha_menu;\r
+\r
+ ha_menu = khui_create_global_accel_table();\r
+ while(r = GetMessage(&msg, NULL, 0,0)) {\r
+ if(r == -1)\r
+ break;\r
+ if(!khm_check_dlg_message(&msg) &&\r
+ !khm_check_ps_message(&msg) &&\r
+ !TranslateAccelerator(khm_hwnd_main, ha_menu, &msg)) {\r
+ TranslateMessage(&msg);\r
+ DispatchMessage(&msg);\r
+ }\r
+ }\r
+ DestroyAcceleratorTable(ha_menu);\r
+ return msg.wParam;\r
+}\r
+\r
+int WINAPI WinMain(HINSTANCE hInstance,\r
+ HINSTANCE hPrevInstance,\r
+ LPSTR lpCmdLine,\r
+ int nCmdShow) \r
+{\r
+ int rv = 0;\r
+ HANDLE h_appmutex;\r
+ BOOL slave = FALSE;\r
+\r
+ khm_hInstance = hInstance;\r
+ khm_nCmdShow = nCmdShow;\r
+\r
+ khm_parse_commandline();\r
+\r
+ if (khm_startup.error_exit)\r
+ return 0;\r
+\r
+ h_appmutex = CreateMutex(NULL, FALSE, L"Local\\NetIDMgr_GlobalAppMutex");\r
+ if (h_appmutex == NULL)\r
+ return 5;\r
+ if (GetLastError() == ERROR_ALREADY_EXISTS)\r
+ slave = TRUE;\r
+\r
+ khc_load_schema(NULL, schema_uiconfig);\r
+\r
+ if(!slave) {\r
+ /* we only open a main window if this is the only instance \r
+ of the application that is running. */\r
+ kmq_init();\r
+ kmm_init();\r
+ khm_init_gui();\r
+\r
+ kmq_set_completion_handler(KMSG_CRED, kmsg_cred_completion);\r
+\r
+ /* load the standard plugins */\r
+ kmm_load_default_modules();\r
+\r
+ khm_register_window_classes();\r
+\r
+ khm_init_request_daemon();\r
+\r
+ khm_create_main_window();\r
+\r
+ if (!khm_startup.no_main_window)\r
+ khm_show_main_window();\r
+\r
+ rv = (int) khm_message_loop();\r
+\r
+ kmq_set_completion_handler(KMSG_CRED, NULL);\r
+\r
+ khm_exit_request_daemon();\r
+\r
+ khm_exit_gui();\r
+ khm_unregister_window_classes();\r
+ kmm_exit();\r
+ kmq_exit();\r
+\r
+ CloseHandle(h_appmutex);\r
+ } else {\r
+ HWND hwnd = NULL;\r
+ int retries = 5;\r
+ HANDLE hmap;\r
+ wchar_t mapname[256];\r
+ DWORD tid;\r
+ void * xfer;\r
+\r
+ CloseHandle(h_appmutex);\r
+\r
+ while (hwnd == NULL && retries) {\r
+ hwnd = FindWindowEx(NULL, NULL, KHUI_MAIN_WINDOW_CLASS, NULL);\r
+\r
+ if (hwnd)\r
+ break;\r
+\r
+ retries--;\r
+ Sleep(1000);\r
+ }\r
+\r
+ if (!hwnd)\r
+ return 2;\r
+\r
+ StringCbPrintf(mapname, sizeof(mapname),\r
+ COMMANDLINE_MAP_FMT,\r
+ (tid = GetCurrentThreadId()));\r
+\r
+ hmap = CreateFileMapping(INVALID_HANDLE_VALUE,\r
+ NULL,\r
+ PAGE_READWRITE,\r
+ 0,\r
+ 4096,\r
+ mapname);\r
+\r
+ if (hmap == NULL)\r
+ return 3;\r
+\r
+ xfer = MapViewOfFile(hmap,\r
+ FILE_MAP_WRITE,\r
+ 0, 0,\r
+ sizeof(khm_startup));\r
+\r
+ if (xfer) {\r
+ memcpy(xfer, &khm_startup, sizeof(khm_startup));\r
+\r
+ SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE,\r
+ 0, (LPARAM) tid);\r
+ }\r
+\r
+ if (xfer)\r
+ UnmapViewOfFile(xfer);\r
+\r
+ if (hmap)\r
+ CloseHandle(hmap);\r
+ }\r
+\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+HWND khui_main_menu_toolbar;\r
+int mm_last_hot_item = -1;\r
+int mm_next_hot_item = -1;\r
+BOOL mm_hot_track = FALSE;\r
+\r
+#define MAX_ILIST 256\r
+/* not the same as MENU_SIZE_ICON_* */\r
+#define ILIST_ICON_X 16\r
+#define ILIST_ICON_Y 15\r
+\r
+khui_ilist * il_icon;\r
+int il_icon_id[MAX_ILIST];\r
+\r
+void khui_init_menu(void) {\r
+ int i;\r
+\r
+ il_icon = khui_create_ilist(ILIST_ICON_X, \r
+ ILIST_ICON_Y, \r
+ MAX_ILIST, 5, 0);\r
+ for(i=0;i<MAX_ILIST;i++)\r
+ il_icon_id[i] = -1;\r
+}\r
+\r
+void khui_exit_menu(void) {\r
+ khui_delete_ilist(il_icon);\r
+}\r
+\r
+int khui_get_icon_index(int id) {\r
+ int i;\r
+ HBITMAP hbm;\r
+\r
+ for(i=0;i<MAX_ILIST;i++)\r
+ if(il_icon_id[i] == id) {\r
+ return i;\r
+ }\r
+\r
+ hbm = LoadImage(khm_hInstance, \r
+ MAKEINTRESOURCE(id), \r
+ IMAGE_BITMAP, \r
+ ILIST_ICON_X, ILIST_ICON_Y, \r
+ LR_DEFAULTCOLOR);\r
+ i = khui_ilist_add_masked(il_icon, hbm, KHUI_TOOLBAR_BGCOLOR);\r
+ il_icon_id[i] = id;\r
+ DeleteObject(hbm);\r
+\r
+ return i;\r
+}\r
+\r
+void add_action_to_menu(HMENU hm, khui_action * act, \r
+ int idx, int flags) {\r
+ MENUITEMINFO mii;\r
+ wchar_t buf[MAX_RES_STRING] = L"";\r
+ wchar_t accel[MAX_RES_STRING] = L"";\r
+\r
+ mii.cbSize = sizeof(mii);\r
+ mii.fMask = 0;\r
+\r
+ if(act == NULL) {\r
+ mii.fMask = MIIM_FTYPE;\r
+ mii.fType = MFT_SEPARATOR;\r
+ } else {\r
+ khui_menu_def * def;\r
+\r
+ LoadString(khm_hInstance, \r
+ act->is_caption, \r
+ buf, ARRAYLENGTH(buf));\r
+\r
+ if(khui_get_cmd_accel_string(act->cmd, accel, \r
+ ARRAYLENGTH(accel))) {\r
+ StringCbCat(buf, sizeof(buf), L"\t");\r
+ StringCbCat(buf, sizeof(buf), accel);\r
+ }\r
+\r
+ mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;\r
+ mii.fType = MFT_STRING;\r
+\r
+ mii.dwTypeData = buf;\r
+ mii.cch = (int) wcslen(buf);\r
+\r
+ mii.wID = act->cmd;\r
+\r
+ if(act->state & KHUI_ACTIONSTATE_DISABLED) {\r
+ mii.fMask |= MIIM_STATE;\r
+ mii.fState = MFS_DISABLED;\r
+ } else {\r
+ mii.fState = 0;\r
+ }\r
+\r
+ if((act->type & KHUI_ACTIONTYPE_TOGGLE) && \r
+ (act->state & KHUI_ACTIONSTATE_CHECKED)) {\r
+ mii.fMask |= MIIM_STATE;\r
+ mii.fState |= MFS_CHECKED;\r
+ }\r
+\r
+ if(act->ib_icon) {\r
+ mii.fMask |= MIIM_BITMAP;\r
+ mii.hbmpItem = HBMMENU_CALLBACK;\r
+ }\r
+\r
+ def = khui_find_menu(act->cmd);\r
+ if(def) {\r
+ mii.fMask |= MIIM_SUBMENU;\r
+ mii.hSubMenu = mm_create_menu_from_def(def);\r
+ }\r
+\r
+ if(flags & KHUI_ACTIONREF_DEFAULT)\r
+ mii.fState |= MFS_DEFAULT;\r
+ }\r
+\r
+ InsertMenuItem(hm,idx,TRUE,&mii);\r
+}\r
+\r
+static HMENU mm_create_menu_from_def(khui_menu_def * def) {\r
+ HMENU hm;\r
+ khui_action_ref * act;\r
+ int i;\r
+\r
+ hm = CreatePopupMenu();\r
+ act = def->items;\r
+ i = 0;\r
+ while(act->action != KHUI_MENU_END) {\r
+ add_action_to_menu(hm,khui_find_action(act->action),i,act->flags);\r
+ act++; i++;\r
+ }\r
+\r
+ return hm;\r
+}\r
+\r
+void mm_begin_hot_track(void);\r
+void mm_end_hot_track(void);\r
+\r
+static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y)\r
+{\r
+ HMENU hm;\r
+\r
+ hm = mm_create_menu_from_def(def);\r
+\r
+ mm_hot_track = (mm_last_hot_item >= 0);\r
+\r
+ if (mm_hot_track)\r
+ mm_begin_hot_track();\r
+\r
+ TrackPopupMenuEx(hm, \r
+ TPM_LEFTALIGN | TPM_TOPALIGN | \r
+ TPM_VERPOSANIMATION, \r
+ x, y, khm_hwnd_main, NULL);\r
+\r
+ mm_last_hot_item = -1;\r
+\r
+ if (mm_hot_track)\r
+ mm_end_hot_track();\r
+\r
+ mm_hot_track = FALSE;\r
+\r
+ DestroyMenu(hm);\r
+}\r
+\r
+void khm_menu_show_panel(int id, LONG x, LONG y) {\r
+ khui_menu_def * def;\r
+\r
+ def = khui_find_menu(id);\r
+ if(!def)\r
+ return;\r
+\r
+ mm_show_panel_def(def, x, y);\r
+}\r
+\r
+LRESULT khm_menu_activate(int menu_id) {\r
+ khui_menu_def * mmdef;\r
+ int nmm;\r
+\r
+ mmdef = khui_find_menu(KHUI_MENU_MAIN);\r
+ nmm = (int) khui_action_list_length(mmdef->items);\r
+\r
+ if(menu_id == MENU_ACTIVATE_DEFAULT) {\r
+ if (mm_last_hot_item != -1)\r
+ menu_id = mm_last_hot_item;\r
+ else\r
+ menu_id = 0;\r
+ } else if(menu_id == MENU_ACTIVATE_LEFT) {\r
+ menu_id = (mm_last_hot_item > 0)? \r
+ mm_last_hot_item - 1: \r
+ ((mm_last_hot_item == 0)? nmm - 1: 0);\r
+ } else if(menu_id == MENU_ACTIVATE_RIGHT) {\r
+ menu_id = (mm_last_hot_item >=0 && mm_last_hot_item < nmm - 1)? \r
+ mm_last_hot_item + 1: \r
+ 0;\r
+ } else if(menu_id == MENU_ACTIVATE_NONE) {\r
+ menu_id = -1;\r
+ }\r
+\r
+ \r
+ SendMessage(khui_main_menu_toolbar,\r
+ TB_SETHOTITEM,\r
+ menu_id,\r
+ 0);\r
+ \r
+\r
+ khm_menu_track_current();\r
+\r
+ return TRUE;\r
+}\r
+\r
+LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lParam) {\r
+ /* all menu icons have a fixed size */\r
+ LPMEASUREITEMSTRUCT lpm = (LPMEASUREITEMSTRUCT) lParam;\r
+ lpm->itemWidth = MENU_SIZE_ICON_X;\r
+ lpm->itemHeight = MENU_SIZE_ICON_Y;\r
+ return TRUE;\r
+}\r
+\r
+LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lParam) {\r
+ LPDRAWITEMSTRUCT lpd;\r
+ khui_action * act;\r
+ int resid;\r
+ int iidx;\r
+ UINT style;\r
+\r
+ lpd = (LPDRAWITEMSTRUCT) lParam;\r
+ act = khui_find_action(lpd->itemID);\r
+\r
+ resid = 0;\r
+ if((lpd->itemState & ODS_DISABLED) || (lpd->itemState & ODS_GRAYED)) {\r
+ resid = act->ib_icon_dis;\r
+ }\r
+ if(!resid)\r
+ resid = act->ib_icon;\r
+\r
+ if(!resid) /* nothing to draw */\r
+ return TRUE;\r
+\r
+ \r
+ iidx = khui_get_icon_index(resid);\r
+ if(iidx == -1)\r
+ return TRUE;\r
+\r
+\r
+ style = ILD_TRANSPARENT;\r
+ if(lpd->itemState & ODS_HOTLIGHT || lpd->itemState & ODS_SELECTED) {\r
+ style |= ILD_SELECTED;\r
+ }\r
+ \r
+ khui_ilist_draw(il_icon, \r
+ iidx, \r
+ lpd->hDC, \r
+ lpd->rcItem.left, lpd->rcItem.top, style);\r
+\r
+ return TRUE;\r
+}\r
+\r
+void khm_track_menu(int menu) {\r
+ TBBUTTON bi;\r
+ RECT r;\r
+ RECT wr;\r
+\r
+ if (menu != -1)\r
+ mm_last_hot_item = menu;\r
+\r
+ if (mm_last_hot_item != -1) {\r
+ SendMessage(khui_main_menu_toolbar,\r
+ TB_GETBUTTON,\r
+ mm_last_hot_item,\r
+ (LPARAM) &bi);\r
+\r
+ SendMessage(khui_main_menu_toolbar,\r
+ TB_GETITEMRECT,\r
+ mm_last_hot_item,\r
+ (LPARAM) &r);\r
+\r
+ GetWindowRect(khui_main_menu_toolbar, &wr);\r
+\r
+ khm_menu_show_panel(bi.idCommand, wr.left + r.left, wr.top + r.bottom);\r
+\r
+ r.left = 0;\r
+\r
+ if (mm_next_hot_item != -1) {\r
+ mm_last_hot_item = mm_next_hot_item;\r
+ mm_next_hot_item = -1;\r
+\r
+ PostMessage(khm_hwnd_main, WM_COMMAND, \r
+ MAKEWPARAM(KHUI_PACTION_MENU,0),\r
+ MAKELPARAM(mm_last_hot_item,1));\r
+ }\r
+ }\r
+}\r
+\r
+void khm_menu_track_current(void) {\r
+ khm_track_menu(-1);\r
+}\r
+\r
+LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam) {\r
+ if((HIWORD(wParam) == 0xffff && lParam == 0) || \r
+ (HIWORD(wParam) & MF_POPUP)) {\r
+ /* the menu was closed */\r
+ khui_statusbar_set_text(KHUI_SBPART_INFO, NULL);\r
+ } else {\r
+ khui_action * act;\r
+ int id;\r
+ wchar_t buf[MAX_RES_STRING] = L"";\r
+\r
+ id = LOWORD(wParam);\r
+ act = khui_find_action(id);\r
+ if(act == NULL || act->is_tooltip == 0)\r
+ khui_statusbar_set_text(KHUI_SBPART_INFO, NULL);\r
+ else {\r
+ LoadString(khm_hInstance, \r
+ act->is_tooltip, \r
+ buf, ARRAYLENGTH(buf));\r
+ khui_statusbar_set_text(KHUI_SBPART_INFO, buf);\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+HHOOK mm_hevt_hook = NULL;\r
+HWND mm_hwnd_menu_panel = NULL;\r
+\r
+LRESULT CALLBACK mm_event_filter(int code,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+ MSG * m;\r
+ RECT r;\r
+ int x,y;\r
+\r
+ if (code == MSGF_MENU) {\r
+ /* do stuff */\r
+ m = (MSG *) lParam;\r
+ GetWindowRect(khui_main_menu_toolbar, &r);\r
+\r
+ if (m->hwnd != khm_hwnd_main)\r
+ mm_hwnd_menu_panel = m->hwnd;\r
+\r
+ switch(m->message) {\r
+ case WM_MOUSEMOVE:\r
+\r
+ x = GET_X_LPARAM(m->lParam);\r
+ y = GET_Y_LPARAM(m->lParam);\r
+ x -= r.left;\r
+ y -= r.top;\r
+\r
+ SendMessage(khui_main_menu_toolbar,\r
+ m->message,\r
+ m->wParam,\r
+ MAKELPARAM(x,y));\r
+ break;\r
+ }\r
+ }\r
+\r
+ return CallNextHookEx(mm_hevt_hook, code, wParam, lParam);\r
+}\r
+\r
+\r
+void mm_begin_hot_track(void) {\r
+\r
+ if (mm_hevt_hook)\r
+ UnhookWindowsHookEx(mm_hevt_hook);\r
+\r
+ mm_hevt_hook = SetWindowsHookEx(WH_MSGFILTER,\r
+ mm_event_filter,\r
+ NULL,\r
+ GetCurrentThreadId());\r
+}\r
+\r
+void mm_end_hot_track(void) {\r
+ if (mm_hevt_hook)\r
+ UnhookWindowsHookEx(mm_hevt_hook);\r
+\r
+ mm_hevt_hook = NULL;\r
+ mm_hwnd_menu_panel = NULL;\r
+}\r
+\r
+void mm_cancel_menu(void) {\r
+ if (mm_hwnd_menu_panel)\r
+ SendMessage(mm_hwnd_menu_panel, WM_CANCELMODE, 0, 0);\r
+}\r
+\r
+LRESULT khm_menu_notify_main(LPNMHDR notice) {\r
+ LPNMTOOLBAR nmt;\r
+ LRESULT ret = FALSE;\r
+ RECT r;\r
+ khui_menu_def * mmdef;\r
+ khui_action_ref * mm;\r
+ int nmm;\r
+\r
+ mmdef = khui_find_menu(KHUI_MENU_MAIN);\r
+ mm = mmdef->items;\r
+ nmm = (int) khui_action_list_length(mm);\r
+\r
+ GetWindowRect(khui_main_menu_toolbar, &r);\r
+\r
+ nmt = (LPNMTOOLBAR) notice;\r
+ switch(notice->code) {\r
+ case TBN_DROPDOWN:\r
+ khm_track_menu(-1);\r
+ /*\r
+ khm_menu_show_panel(nmt->iItem, \r
+ r.left + nmt->rcButton.left, \r
+ r.top + nmt->rcButton.bottom);\r
+ */\r
+ ret = TBDDRET_DEFAULT;\r
+ break;\r
+\r
+ case TBN_HOTITEMCHANGE: \r
+ {\r
+ LPNMTBHOTITEM nmhi;\r
+ int new_item = -1;\r
+\r
+ nmhi = (LPNMTBHOTITEM) notice;\r
+\r
+ if(nmhi->dwFlags & HICF_LEAVING)\r
+ new_item = -1;\r
+ else {\r
+ int i;\r
+ for(i=0; i < nmm; i++) {\r
+ if(mm[i].action == nmhi->idNew) {\r
+ new_item = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (mm_hot_track && \r
+ new_item != mm_last_hot_item &&\r
+ new_item != -1 &&\r
+ mm_last_hot_item != -1) {\r
+\r
+ EndMenu();\r
+ mm_next_hot_item = new_item;\r
+\r
+ }\r
+\r
+ ret = 0;\r
+\r
+ if (!mm_hot_track || new_item != -1)\r
+ mm_last_hot_item = new_item;\r
+\r
+ } break;\r
+\r
+ default:\r
+ /* hmm. what to do */\r
+ ret = FALSE;\r
+ }\r
+ return ret;\r
+}\r
+\r
+void khm_menu_create_main(HWND rebar) {\r
+ HWND hwtb;\r
+ REBARBANDINFO rbi;\r
+ SIZE sz;\r
+ int i;\r
+ khui_menu_def * mmdef;\r
+ khui_action_ref * mm;\r
+ int nmm;\r
+\r
+ mmdef = khui_find_menu(KHUI_MENU_MAIN);\r
+ mm = mmdef->items;\r
+ nmm = (int) khui_action_list_length(mm);\r
+\r
+ hwtb = CreateWindowEx(\r
+ TBSTYLE_EX_MIXEDBUTTONS,\r
+ TOOLBARCLASSNAME,\r
+ (LPWSTR) NULL,\r
+ WS_CHILD | \r
+ CCS_ADJUSTABLE | \r
+ TBSTYLE_FLAT |\r
+ TBSTYLE_AUTOSIZE |\r
+ TBSTYLE_LIST |\r
+ CCS_NORESIZE |\r
+ CCS_NOPARENTALIGN |\r
+ CCS_NODIVIDER,\r
+ 0, 0, 0, 0, rebar,\r
+ (HMENU) NULL, khm_hInstance,\r
+ NULL);\r
+\r
+ if(!hwtb) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return;\r
+#endif\r
+ }\r
+\r
+ khui_main_menu_toolbar = hwtb;\r
+\r
+ SendMessage(hwtb,\r
+ TB_BUTTONSTRUCTSIZE,\r
+ (WPARAM) sizeof(TBBUTTON),\r
+ 0);\r
+\r
+ for(i=0; i<nmm; i++) {\r
+ khui_add_action_to_toolbar(hwtb, \r
+ khui_find_action(mm[i].action), \r
+ KHUI_TOOLBAR_ADD_TEXT | \r
+ KHUI_TOOLBAR_ADD_DROPDOWN | \r
+ KHUI_TOOLBAR_VARSIZE, \r
+ NULL);\r
+ }\r
+\r
+ SendMessage(hwtb,\r
+ TB_AUTOSIZE,\r
+ 0,0);\r
+\r
+ SendMessage(hwtb,\r
+ TB_GETMAXSIZE,\r
+ 0,\r
+ (LPARAM) &sz);\r
+\r
+ ZeroMemory(&rbi, sizeof(rbi));\r
+\r
+ rbi.cbSize = sizeof(rbi);\r
+\r
+ rbi.fMask = \r
+ RBBIM_ID |\r
+ RBBIM_STYLE | \r
+ RBBIM_CHILD | \r
+ RBBIM_CHILDSIZE | \r
+ RBBIM_SIZE | \r
+ RBBIM_IDEALSIZE; \r
+\r
+ rbi.fStyle = \r
+ RBBS_USECHEVRON;\r
+\r
+ rbi.hwndChild = hwtb;\r
+ rbi.wID = KHUI_MENU_MAIN;\r
+ rbi.cx = sz.cx;\r
+ rbi.cxMinChild = rbi.cx;\r
+ rbi.cxIdeal = rbi.cx;\r
+ rbi.cyMinChild = sz.cy;\r
+ rbi.cyChild = rbi.cyMinChild;\r
+ rbi.cyIntegral = rbi.cyMinChild;\r
+ rbi.cyMaxChild = rbi.cyMinChild;\r
+\r
+ SendMessage(rebar,\r
+ RB_INSERTBAND,\r
+ 0,\r
+ (LPARAM) &rbi);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_MAINMENU_H\r
+#define __KHIMAIRA_MAINMENU_H\r
+\r
+extern HWND khui_main_menu_toolbar;\r
+\r
+#define MENU_ACTIVATE_DEFAULT -1\r
+#define MENU_ACTIVATE_LEFT -2\r
+#define MENU_ACTIVATE_RIGHT -3\r
+#define MENU_ACTIVATE_NONE -4\r
+\r
+extern int mm_last_hot_item;\r
+extern BOOL mm_hot_track;\r
+\r
+void khm_menu_create_main(HWND rebar);\r
+LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam);\r
+LRESULT khm_menu_notify_main(LPNMHDR notice);\r
+LRESULT khm_menu_activate(int menu_id);\r
+void khm_menu_show_panel(int id, LONG x, LONG y);\r
+void khm_menu_track_current(void);\r
+LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lparam);\r
+LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lparam);\r
+\r
+static HMENU mm_create_menu_from_def(khui_menu_def * def);\r
+static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y);\r
+\r
+void khui_init_menu(void);\r
+void khui_exit_menu(void);\r
+\r
+#define MENU_SIZE_ICON_X 16\r
+#define MENU_SIZE_ICON_Y 16\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+ATOM khm_main_window_class;\r
+ATOM khm_null_window_class;\r
+HWND khm_hwnd_null;\r
+HWND khm_hwnd_main;\r
+HWND khm_hwnd_rebar;\r
+HWND khm_hwnd_main_cred;\r
+\r
+#define MW_RESIZE_TIMER 1\r
+#define MW_RESIZE_TIMEOUT 2000\r
+#define MW_REFRESH_TIMER 2\r
+#define MW_REFRESH_TIMEOUT 600\r
+\r
+void\r
+khm_set_dialog_result(HWND hwnd, LRESULT lr) {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWL_MSGRESULT, lr);\r
+#pragma warning(pop)\r
+}\r
+\r
+static void\r
+mw_restart_refresh_timer(HWND hwnd) {\r
+ khm_handle csp_cw;\r
+ khm_int32 timeout;\r
+\r
+ KillTimer(hwnd, MW_REFRESH_TIMER);\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL,\r
+ L"CredWindow",\r
+ KHM_PERM_READ,\r
+ &csp_cw))) {\r
+ if (KHM_FAILED(khc_read_int32(csp_cw,\r
+ L"RefreshTimeout",\r
+ &timeout)))\r
+ timeout = MW_REFRESH_TIMEOUT;\r
+ khc_close_space(csp_cw);\r
+ } else\r
+ timeout = MW_REFRESH_TIMEOUT;\r
+\r
+ timeout *= 1000; /* convert to milliseconds */\r
+\r
+ SetTimer(hwnd, MW_REFRESH_TIMER, timeout, NULL);\r
+}\r
+\r
+LRESULT CALLBACK khm_main_wnd_proc(\r
+ HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ ) \r
+{\r
+ LPNMHDR lpnm;\r
+\r
+ switch(uMsg) {\r
+ case WM_CREATE:\r
+ khm_create_main_window_controls(hwnd);\r
+ kmq_subscribe_hwnd(KMSG_CRED, hwnd);\r
+ kmq_subscribe_hwnd(KMSG_ACT, hwnd);\r
+ kmq_subscribe_hwnd(KMSG_KMM, hwnd);\r
+ mw_restart_refresh_timer(hwnd);\r
+\r
+ if (!kmm_load_pending())\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0);\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ kmq_unsubscribe_hwnd(KMSG_ACT, hwnd);\r
+ kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);\r
+ PostQuitMessage(0);\r
+ break;\r
+\r
+ case WM_NOTIFY:\r
+ lpnm = (LPNMHDR) lParam;\r
+ if(lpnm->hwndFrom == khui_main_menu_toolbar) {\r
+ return khm_menu_notify_main(lpnm);\r
+ } else if(lpnm->hwndFrom == khui_hwnd_standard_toolbar) {\r
+ return khm_toolbar_notify(lpnm);\r
+ } else if(lpnm->hwndFrom == khm_hwnd_rebar) {\r
+ return khm_rebar_notify(lpnm);\r
+ }\r
+ break;\r
+\r
+ case WM_COMMAND:\r
+ switch(LOWORD(wParam)) {\r
+ /* general actions */\r
+ case KHUI_ACTION_VIEW_REFRESH:\r
+ InvalidateRect(khm_hwnd_main_cred, NULL, FALSE);\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, NULL);\r
+ return 0;\r
+\r
+ case KHUI_ACTION_PASSWD_ID:\r
+ khm_cred_change_password(NULL);\r
+ return 0;\r
+\r
+ case KHUI_ACTION_NEW_CRED:\r
+ khm_cred_obtain_new_creds(NULL);\r
+ return 0;\r
+\r
+ case KHUI_ACTION_RENEW_CRED:\r
+ khm_cred_renew_creds();\r
+ return 0;\r
+\r
+ case KHUI_ACTION_DESTROY_CRED:\r
+ khm_cred_destroy_creds();\r
+ return 0;\r
+\r
+ case KHUI_ACTION_SET_DEF_ID:\r
+ khm_cred_set_default();\r
+ return 0;\r
+\r
+ case KHUI_ACTION_EXIT:\r
+ DestroyWindow(hwnd);\r
+ break;\r
+\r
+ case KHUI_ACTION_OPEN_APP:\r
+ khm_show_main_window();\r
+ break;\r
+\r
+ case KHUI_ACTION_CLOSE_APP:\r
+ khm_hide_main_window();\r
+ break;\r
+\r
+ case KHUI_ACTION_OPT_KHIM:\r
+ khm_show_config_pane(NULL);\r
+ break;\r
+\r
+ case KHUI_ACTION_OPT_IDENTS: {\r
+ khui_config_node node;\r
+\r
+ khui_cfg_open(NULL, L"KhmIdentities", &node);\r
+ khm_show_config_pane(node);\r
+ }\r
+ break;\r
+\r
+ case KHUI_ACTION_OPT_NOTIF: {\r
+ khui_config_node node;\r
+\r
+ khui_cfg_open(NULL, L"KhmNotifications", &node);\r
+ khm_show_config_pane(node);\r
+ }\r
+ break;\r
+\r
+ case KHUI_ACTION_HELP_ABOUT:\r
+ khm_create_about_window();\r
+ break;\r
+\r
+ case KHUI_ACTION_PROPERTIES:\r
+ /* properties are not handled by the main window.\r
+ Just bounce it to credwnd. However, use SendMessage\r
+ instead of PostMessage so we don't lose context */\r
+ return SendMessage(khm_hwnd_main_cred, uMsg, \r
+ wParam, lParam);\r
+\r
+ /* menu commands */\r
+ case KHUI_PACTION_MENU:\r
+ if(HIWORD(lParam) == 1)\r
+ mm_last_hot_item = LOWORD(lParam);\r
+ return khm_menu_activate(MENU_ACTIVATE_DEFAULT);\r
+\r
+ /* generic, retargetting */\r
+ case KHUI_PACTION_UP:\r
+ case KHUI_PACTION_UP_TOGGLE:\r
+ case KHUI_PACTION_UP_EXTEND:\r
+ case KHUI_PACTION_DOWN:\r
+ case KHUI_PACTION_DOWN_TOGGLE:\r
+ case KHUI_PACTION_DOWN_EXTEND:\r
+ case KHUI_PACTION_LEFT:\r
+ case KHUI_PACTION_RIGHT:\r
+ case KHUI_PACTION_ESC:\r
+ case KHUI_PACTION_ENTER:\r
+ /* menu tracking */\r
+ if(mm_last_hot_item != -1) {\r
+ switch(LOWORD(wParam)) {\r
+ case KHUI_PACTION_LEFT:\r
+ khm_menu_activate(MENU_ACTIVATE_LEFT);\r
+ break;\r
+\r
+ case KHUI_PACTION_RIGHT:\r
+ khm_menu_activate(MENU_ACTIVATE_RIGHT);\r
+ break;\r
+\r
+ case KHUI_PACTION_ESC:\r
+ case KHUI_PACTION_ENTER:\r
+ khm_menu_activate(MENU_ACTIVATE_NONE);\r
+ break;\r
+\r
+ case KHUI_PACTION_DOWN:\r
+ khm_menu_track_current();\r
+ break;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ /*FALLTHROUGH*/\r
+\r
+ case KHUI_PACTION_DELETE:\r
+\r
+ case KHUI_ACTION_LAYOUT_ID:\r
+ case KHUI_ACTION_LAYOUT_TYPE:\r
+ case KHUI_ACTION_LAYOUT_LOC:\r
+ /* otherwise fallthrough and bounce to the creds window */\r
+ return SendMessage(khm_hwnd_main_cred, uMsg, \r
+ wParam, lParam);\r
+ }\r
+ break; /* WM_COMMAND */\r
+\r
+ case WM_SYSCOMMAND:\r
+ switch(wParam & 0xfff0) {\r
+ case SC_MINIMIZE:\r
+ khm_hide_main_window();\r
+ return 0;\r
+\r
+ case SC_CLOSE:\r
+ {\r
+ khm_handle csp_cw;\r
+ BOOL keep_running = FALSE;\r
+\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow",\r
+ KHM_PERM_READ, &csp_cw))) {\r
+ khm_int32 t;\r
+\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"KeepRunning", \r
+ &t)))\r
+ keep_running = t;\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+\r
+ khc_close_space(csp_cw);\r
+ }\r
+#ifdef DEBUG\r
+ else\r
+ assert(FALSE);\r
+#endif\r
+\r
+ if (keep_running)\r
+ khm_hide_main_window();\r
+ else\r
+ DestroyWindow(hwnd);\r
+ }\r
+ return 0;\r
+ }\r
+ break;\r
+\r
+ case WM_MEASUREITEM:\r
+ /* sent to measure the bitmaps associated with a menu item */\r
+ if(!wParam) /* sent by menu */\r
+ return khm_menu_measure_item(wParam, lParam);\r
+ break;\r
+\r
+ case WM_DRAWITEM:\r
+ /* sent to draw a menu item */\r
+ if(!wParam) \r
+ return khm_menu_draw_item(wParam, lParam);\r
+ break;\r
+\r
+ case WM_ERASEBKGND:\r
+ /* Don't erase the background. The whole client area is\r
+ covered with children. It doesn't need to be erased */\r
+ return TRUE;\r
+ break;\r
+\r
+ case WM_SIZE: \r
+ if(hwnd == khm_hwnd_main && \r
+ (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) {\r
+ int cwidth, cheight;\r
+ RECT r_rebar, r_status;\r
+\r
+ cwidth = LOWORD(lParam);\r
+ cheight = HIWORD(lParam);\r
+\r
+ /* resize the rebar control */\r
+ SendMessage(khm_hwnd_rebar, WM_SIZE, 0, 0);\r
+\r
+ khui_update_statusbar(hwnd);\r
+ \r
+ GetWindowRect(khm_hwnd_rebar, &r_rebar);\r
+ GetWindowRect(khui_hwnd_statusbar, &r_status);\r
+\r
+ /* the cred window fills the area between the rebar\r
+ and the status bar */\r
+ MoveWindow(khm_hwnd_main_cred, 0, \r
+ r_rebar.bottom - r_rebar.top, \r
+ r_status.right - r_status.left, \r
+ r_status.top - r_rebar.bottom, TRUE);\r
+\r
+ SetTimer(hwnd,\r
+ MW_RESIZE_TIMER,\r
+ MW_RESIZE_TIMEOUT,\r
+ NULL);\r
+ return 0;\r
+ }\r
+ break;\r
+\r
+ case WM_MOVE:\r
+ {\r
+ SetTimer(hwnd,\r
+ MW_RESIZE_TIMER,\r
+ MW_RESIZE_TIMEOUT,\r
+ NULL);\r
+ }\r
+ break;\r
+\r
+ case WM_TIMER:\r
+ if (wParam == MW_RESIZE_TIMER) {\r
+ RECT r;\r
+ khm_handle csp_cw;\r
+ khm_handle csp_mw;\r
+\r
+ KillTimer(hwnd, wParam);\r
+\r
+ GetWindowRect(hwnd, &r);\r
+\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL,\r
+ L"CredWindow",\r
+ KHM_PERM_WRITE,\r
+ &csp_cw))) {\r
+ if (KHM_SUCCEEDED(khc_open_space(csp_cw,\r
+ L"Windows\\Main",\r
+ KHM_PERM_WRITE,\r
+ &csp_mw))) {\r
+ khc_write_int32(csp_mw, L"XPos", r.left);\r
+ khc_write_int32(csp_mw, L"YPos", r.top);\r
+ khc_write_int32(csp_mw, L"Width",\r
+ r.right - r.left);\r
+ khc_write_int32(csp_mw, L"Height",\r
+ r.bottom - r.top);\r
+\r
+ khc_close_space(csp_mw);\r
+ }\r
+ khc_close_space(csp_cw);\r
+ }\r
+ } else if (wParam == MW_REFRESH_TIMER) {\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0);\r
+ }\r
+ break;\r
+\r
+ case WM_MENUSELECT:\r
+ return khm_menu_handle_select(wParam, lParam);\r
+ break;\r
+\r
+ case KMQ_WM_DISPATCH:\r
+ {\r
+ kmq_message * m;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ kmq_wm_begin(lParam, &m);\r
+ if (m->type == KMSG_ACT &&\r
+ m->subtype == KMSG_ACT_REFRESH) {\r
+ khm_update_standard_toolbar();\r
+ } else if (m->type == KMSG_ACT &&\r
+ m->subtype == KMSG_ACT_BEGIN_CMDLINE) {\r
+ khm_cred_begin_commandline();\r
+ } else if (m->type == KMSG_CRED &&\r
+ m->subtype == KMSG_CRED_REFRESH) {\r
+ mw_restart_refresh_timer(hwnd);\r
+ } else if (m->type == KMSG_KMM &&\r
+ m->subtype == KMSG_KMM_I_DONE) {\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0);\r
+ }\r
+ return kmq_wm_end(m, rv);\r
+ }\r
+ break;\r
+\r
+ case WM_KHUI_ASSIGN_COMMANDLINE:\r
+ {\r
+ HANDLE hmap;\r
+ void * xfer;\r
+ wchar_t mapname[256];\r
+\r
+ StringCbPrintf(mapname, sizeof(mapname),\r
+ COMMANDLINE_MAP_FMT, (DWORD) lParam);\r
+\r
+ hmap = OpenFileMapping(FILE_MAP_READ, FALSE, mapname);\r
+\r
+ if (hmap == NULL)\r
+ return 1;\r
+\r
+ xfer = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0,\r
+ sizeof(khm_startup));\r
+\r
+ if (xfer) {\r
+ memcpy(&khm_startup, xfer, sizeof(khm_startup));\r
+\r
+ UnmapViewOfFile(xfer);\r
+ }\r
+\r
+ CloseHandle(hmap);\r
+\r
+ if(InSendMessage())\r
+ ReplyMessage(0);\r
+\r
+ khm_startup.exit = FALSE;\r
+\r
+ khm_startup.seen = FALSE;\r
+ khm_startup.processing = FALSE;\r
+\r
+ khm_cred_begin_commandline();\r
+ }\r
+ break;\r
+ }\r
+ return DefWindowProc(hwnd,uMsg,wParam,lParam);\r
+}\r
+\r
+LRESULT CALLBACK khm_null_wnd_proc(\r
+ HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ ) {\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+LRESULT khm_rebar_notify(LPNMHDR lpnm) {\r
+ switch(lpnm->code) {\r
+ case RBN_AUTOBREAK:\r
+ {\r
+ LPNMREBARAUTOBREAK lpra = (LPNMREBARAUTOBREAK) lpnm;\r
+ lpra->fAutoBreak = TRUE;\r
+ }\r
+ break;\r
+\r
+ case RBN_BEGINDRAG:\r
+ {\r
+ LPNMREBAR lprb = (LPNMREBAR) lpnm;\r
+ if ((lprb->dwMask & RBNM_ID) &&\r
+ lprb->wID == 0)\r
+ return 1;\r
+ else\r
+ return 0;\r
+ }\r
+ break;\r
+\r
+ case NM_CUSTOMDRAW:\r
+ return CDRF_DODEFAULT;\r
+ break;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+void khm_create_main_window_controls(HWND hwnd_main) {\r
+ REBARINFO rbi;\r
+ HWND hwRebar;\r
+\r
+ hwRebar = \r
+ CreateWindowEx(WS_EX_TOOLWINDOW,\r
+ REBARCLASSNAME,\r
+ L"Rebar",\r
+ WS_CHILD | \r
+ WS_VISIBLE| \r
+ WS_CLIPSIBLINGS | \r
+ WS_CLIPCHILDREN |\r
+ CCS_NODIVIDER |\r
+ RBS_VARHEIGHT |\r
+ RBS_FIXEDORDER,\r
+ 0,0,0,0,\r
+ hwnd_main,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+ if(!hwRebar) {\r
+ DWORD dwe = GetLastError();\r
+ return;\r
+ }\r
+\r
+ khm_hwnd_rebar = hwRebar;\r
+\r
+ rbi.cbSize = sizeof(rbi);\r
+ rbi.fMask = 0;\r
+ rbi.himl = (HIMAGELIST) NULL;\r
+ if(!SendMessage(hwRebar, RB_SETBARINFO, 0, (LPARAM) &rbi))\r
+ return;\r
+\r
+ /* self attach */\r
+ khm_menu_create_main(hwRebar);\r
+ khm_create_standard_toolbar(hwRebar);\r
+ khui_create_statusbar(hwnd_main);\r
+\r
+ /* manual attach */\r
+ khm_hwnd_main_cred = khm_create_credwnd(hwnd_main);\r
+}\r
+\r
+void khm_create_main_window(void) {\r
+ wchar_t buf[1024];\r
+ khm_handle csp_cw = NULL;\r
+ khm_handle csp_mw = NULL;\r
+ int x,y,width,height;\r
+\r
+ LoadString(khm_hInstance, IDS_MAIN_WINDOW_TITLE, buf, sizeof(buf)/sizeof(buf[0]));\r
+\r
+ khm_hwnd_null =\r
+ CreateWindow(MAKEINTATOM(khm_null_window_class),\r
+ buf,\r
+ 0, /* Style */\r
+ 0, 0, /* x, y */\r
+ 100, 100, /* width, height */\r
+ NULL, /* parent */\r
+ NULL, /* menu */\r
+ NULL, /* HINSTANCE */\r
+ 0); /* lparam */\r
+\r
+ if (!khm_hwnd_null)\r
+ return;\r
+\r
+ x = CW_USEDEFAULT;\r
+ y = CW_USEDEFAULT;\r
+ width = CW_USEDEFAULT;\r
+ height = CW_USEDEFAULT;\r
+\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow",\r
+ KHM_PERM_READ,\r
+ &csp_cw))) {\r
+ if (KHM_SUCCEEDED(khc_open_space(csp_cw,\r
+ L"Windows\\Main",\r
+ KHM_PERM_READ,\r
+ &csp_mw))) {\r
+ khm_int32 t;\r
+\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"XPos", &t)))\r
+ x = t;\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"YPos", &t)))\r
+ y = t;\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Width", &t)))\r
+ width = t;\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Height", &t)))\r
+ height = t;\r
+\r
+ khc_close_space(csp_mw);\r
+ }\r
+ khc_close_space(csp_cw);\r
+ }\r
+\r
+ khm_hwnd_main = \r
+ CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,\r
+ MAKEINTATOM(khm_main_window_class),\r
+ buf,\r
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | \r
+ WS_CLIPSIBLINGS,\r
+ x, y, width, height,\r
+ khm_hwnd_null,\r
+ NULL,\r
+ NULL,\r
+ NULL);\r
+\r
+ if (!khm_hwnd_main)\r
+ return;\r
+}\r
+\r
+void khm_show_main_window(void) {\r
+\r
+ if (khm_nCmdShow == SW_RESTORE) {\r
+ HWND hw;\r
+\r
+ hw = GetForegroundWindow();\r
+ if (hw != khm_hwnd_main)\r
+ SetForegroundWindow(khm_hwnd_main);\r
+ }\r
+\r
+ ShowWindow(khm_hwnd_main, khm_nCmdShow);\r
+ UpdateWindow(khm_hwnd_main);\r
+\r
+ khm_nCmdShow = SW_RESTORE;\r
+}\r
+\r
+void khm_hide_main_window(void) {\r
+ khm_handle csp_notices = NULL;\r
+ khm_int32 show_warning = FALSE;\r
+\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow\\Notices",\r
+ KHM_PERM_WRITE, &csp_notices)) &&\r
+ KHM_SUCCEEDED(khc_read_int32(csp_notices, L"MinimizeWarning",\r
+ &show_warning)) &&\r
+ show_warning != 0) {\r
+ khui_alert * alert;\r
+ wchar_t title[KHUI_MAXCCH_TITLE];\r
+ wchar_t msg[KHUI_MAXCCH_MESSAGE];\r
+\r
+ LoadString(khm_hInstance, IDS_WARN_WM_TITLE,\r
+ title, ARRAYLENGTH(title));\r
+ LoadString(khm_hInstance, IDS_WARN_WM_MSG,\r
+ msg, ARRAYLENGTH(msg));\r
+\r
+ khui_alert_create_simple(title, msg, KHERR_INFO, &alert);\r
+ khui_alert_set_flags(alert, KHUI_ALERT_FLAG_REQUEST_BALLOON,\r
+ KHUI_ALERT_FLAG_REQUEST_BALLOON);\r
+\r
+ khui_alert_show(alert);\r
+\r
+ khc_write_int32(csp_notices, L"MinimizeWarning", 0);\r
+ }\r
+\r
+ if (csp_notices != NULL)\r
+ khc_close_space(csp_notices);\r
+\r
+ ShowWindow(khm_hwnd_main, SW_HIDE);\r
+}\r
+\r
+BOOL khm_is_main_window_visible(void) {\r
+ return IsWindowVisible(khm_hwnd_main);\r
+}\r
+\r
+BOOL khm_is_main_window_active(void) {\r
+ if (!IsWindowVisible(khm_hwnd_main))\r
+ return FALSE;\r
+ if (GetForegroundWindow() == khm_hwnd_main)\r
+ return TRUE;\r
+ return khm_is_dialog_active();\r
+}\r
+\r
+void khm_register_main_wnd_class(void) {\r
+ WNDCLASSEX wc;\r
+\r
+ wc.cbSize = sizeof(WNDCLASSEX);\r
+ wc.style = 0;\r
+ wc.lpfnWndProc = khm_null_wnd_proc;\r
+ wc.cbClsExtra = 0;\r
+ wc.cbWndExtra = 0;\r
+ wc.hInstance = khm_hInstance;\r
+ wc.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP));\r
+ wc.hCursor = LoadCursor((HINSTANCE) NULL, MAKEINTRESOURCE(IDC_ARROW));\r
+ wc.hIconSm = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
+ wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE);\r
+ wc.lpszMenuName = NULL;\r
+ wc.lpszClassName = KHUI_NULL_WINDOW_CLASS;\r
+\r
+ khm_null_window_class = RegisterClassEx(&wc);\r
+\r
+\r
+ wc.cbSize = sizeof(WNDCLASSEX);\r
+ wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;\r
+ wc.lpfnWndProc = khm_main_wnd_proc;\r
+ wc.cbClsExtra = 0;\r
+ wc.cbWndExtra = 0;\r
+ wc.hInstance = khm_hInstance;\r
+ wc.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP));\r
+ wc.hCursor = LoadCursor((HINSTANCE) NULL, MAKEINTRESOURCE(IDC_ARROW));\r
+ wc.hIconSm = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
+ wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE);\r
+ wc.lpszMenuName = NULL;\r
+ wc.lpszClassName = KHUI_MAIN_WINDOW_CLASS;\r
+\r
+ khm_main_window_class = RegisterClassEx(&wc);\r
+}\r
+\r
+void khm_unregister_main_wnd_class(void) {\r
+ UnregisterClass(MAKEINTATOM(khm_main_window_class),khm_hInstance);\r
+ UnregisterClass(MAKEINTATOM(khm_null_window_class),khm_hInstance);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_MAINWND_H\r
+#define __KHIMAIRA_MAINWND_H\r
+\r
+#define KHUI_MAIN_WINDOW_CLASS L"KhmMainWindowClass"\r
+#define KHUI_NULL_WINDOW_CLASS L"KhmNullWindowClass"\r
+\r
+extern ATOM khm_main_window_class;\r
+extern HWND khm_hwnd_main;\r
+extern HWND khm_hwnd_rebar;\r
+\r
+void khm_register_main_wnd_class(void);\r
+void khm_unregister_main_wnd_class(void);\r
+void khm_create_main_window_controls(HWND);\r
+void khm_create_main_window(void);\r
+void khm_show_main_window(void);\r
+void khm_hide_main_window(void);\r
+BOOL khm_is_main_window_visible(void);\r
+BOOL khm_is_main_window_active(void);\r
+LRESULT khm_rebar_notify(LPNMHDR lpnm);\r
+\r
+void\r
+khm_set_dialog_result(HWND hwnd, LRESULT lr);\r
+\r
+LRESULT CALLBACK \r
+khm_main_wnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+#define WM_KHUI_ASSIGN_COMMANDLINE 32808\r
+\r
+#define COMMANDLINE_MAP_FMT L"Local\\NetIDMgr_Cmdline_%lu"\r
+\r
+#endif\r
--- /dev/null
+#\r
+\r
+die "Please specify input and output filenames" if($#ARGV != 1);\r
+\r
+open INF, '<', $ARGV[0] or die "Can't open input file";\r
+open OUF, '>', $ARGV[1] or die "Can't open output file";\r
+\r
+print OUF <<EOS;\r
+#include<khimaira.h>\r
+\r
+ khui_accel_def khui_accel_global[] = {\r
+EOS\r
+\r
+# skip first line\r
+ <INF>;\r
+\r
+while(<INF>) {\r
+ print OUF "{".$_."},\n";\r
+}\r
+\r
+print OUF <<EOS;\r
+};\r
+\r
+int khui_n_accel_global = sizeof(khui_accel_global) / sizeof(khui_accel_def);\r
+\r
+EOS\r
+\r
+close INF;\r
+close OUF;\r
--- /dev/null
+#\r
+\r
+die "Please specify input and output filenames" if($#ARGV != 1);\r
+\r
+open INF, '<', $ARGV[0] or die "Can't open input file";\r
+open OUF, '>', $ARGV[1] or die "Can't open output file";\r
+\r
+print OUF <<EOS;\r
+#include<khimaira.h>\r
+\r
+ khui_action khui_actions[] = {\r
+EOS\r
+\r
+# skip first line\r
+ <INF>;\r
+\r
+while(<INF>) {\r
+ print OUF "{".$_."},\n";\r
+}\r
+\r
+print OUF <<EOS;\r
+};\r
+\r
+int khui_n_actions = sizeof(khui_actions) / sizeof(khui_action);\r
+\r
+EOS\r
+\r
+close INF;\r
+close OUF;\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+<assemblyIdentity\r
+ version="1.0.0.0"\r
+ processorArchitecture="X86"\r
+ name="MIT.NetIDMgr.UI"\r
+ type="win32"\r
+/>\r
+<description>Khimaira Credentials Manager</description>\r
+<dependency>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.Windows.Common-Controls"\r
+ version="6.0.0.0"\r
+ processorArchitecture="X86"\r
+ publicKeyToken="6595b64144ccf1df"\r
+ language="*"\r
+ />\r
+ </dependentAssembly>\r
+</dependency>\r
+</assembly>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+<assemblyIdentity\r
+ version="1.0.0.0"\r
+ processorArchitecture="X86"\r
+ name="MIT.NetIDMgr.UI"\r
+ type="win32"\r
+/>\r
+<description>Khimaira Credentials Manager</description>\r
+<dependency>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.Windows.Common-Controls"\r
+ version="6.0.0.0"\r
+ processorArchitecture="X86"\r
+ publicKeyToken="6595b64144ccf1df"\r
+ language="*"\r
+ />\r
+ </dependentAssembly>\r
+</dependency>\r
+</assembly>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+<assemblyIdentity\r
+ version="1.0.0.0"\r
+ processorArchitecture="X86"\r
+ name="MIT.NetIDMgr.UI"\r
+ type="win32"\r
+/>\r
+<description>Khimaira Credentials Manager</description>\r
+<dependency>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.Windows.Common-Controls"\r
+ version="6.0.0.0"\r
+ processorArchitecture="X86"\r
+ publicKeyToken="6595b64144ccf1df"\r
+ language="*"\r
+ />\r
+ </dependentAssembly>\r
+</dependency>\r
+</assembly>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+<assemblyIdentity\r
+ version="1.0.0.0"\r
+ processorArchitecture="X86"\r
+ name="MIT.NetIDMgr.UI"\r
+ type="win32"\r
+/>\r
+<description>Khimaira Credentials Manager</description>\r
+<dependency>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.Windows.Common-Controls"\r
+ version="6.0.0.0"\r
+ processorArchitecture="X86"\r
+ publicKeyToken="6595b64144ccf1df"\r
+ language="*"\r
+ />\r
+ </dependentAssembly>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.VC80.DebugCRT"\r
+ version="8.0.50215.4652"\r
+ processorArchitecture="x86"\r
+ publicKeyToken="1fc8b3b9a1e18e3b"\r
+ />\r
+ </dependentAssembly>\r
+</dependency>\r
+</assembly>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+<assemblyIdentity\r
+ version="1.0.0.0"\r
+ processorArchitecture="X86"\r
+ name="MIT.NetIDMgr.UI"\r
+ type="win32"\r
+/>\r
+<description>Khimaira Credentials Manager</description>\r
+<dependency>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.Windows.Common-Controls"\r
+ version="6.0.0.0"\r
+ processorArchitecture="X86"\r
+ publicKeyToken="6595b64144ccf1df"\r
+ language="*"\r
+ />\r
+ </dependentAssembly>\r
+ <dependentAssembly>\r
+ <assemblyIdentity\r
+ type="win32"\r
+ name="Microsoft.VC80.DebugCRT"\r
+ version="8.0.50215.4652"\r
+ processorArchitecture="x86"\r
+ publicKeyToken="1fc8b3b9a1e18e3b"\r
+ />\r
+ </dependentAssembly>\r
+</dependency>\r
+</assembly>\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+ATOM khui_newcredwnd_cls;\r
+\r
+/* forward dcl */\r
+static void\r
+nc_position_credtext(khui_nc_wnd_data * d);\r
+\r
+/* Common dialog procedure. Be careful. This is used by more than\r
+ one dialog. */\r
+static INT_PTR CALLBACK \r
+nc_common_dlg_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ switch(uMsg) {\r
+ case WM_INITDIALOG:\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, DWLP_USER, lParam);\r
+#pragma warning(pop)\r
+\r
+ return TRUE;\r
+\r
+ case WM_COMMAND:\r
+ {\r
+ int ctrl_id;\r
+\r
+ ctrl_id = LOWORD(wParam);\r
+ if (ctrl_id < KHUI_CW_ID_MIN ||\r
+ ctrl_id > KHUI_CW_ID_MAX) {\r
+ /* pump it to the parent */\r
+ PostMessage(GetParent(hwnd), WM_COMMAND, wParam, lParam);\r
+ return TRUE;\r
+ } /* else we allow the message to fall through and get\r
+ passed into the identity provider's message\r
+ handler. */\r
+ }\r
+ break;\r
+\r
+#if 0\r
+ /* someday this will be used to draw custom tab buttons. But\r
+ that's not today */\r
+ case WM_DRAWITEM:\r
+ {\r
+ khui_nc_wnd_data * d;\r
+ int id;\r
+ LPDRAWITEMSTRUCT ds;\r
+\r
+ d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);\r
+ id = wParam;\r
+ ds = (LPDRAWITEMSTRUCT) lParam;\r
+\r
+ if(id >= NC_TS_CTRL_ID_MIN && id <= NC_TS_CTRL_ID_MAX) {\r
+ /*TODO: custom draw the buttons */\r
+ }\r
+ else\r
+ return FALSE;\r
+ }\r
+ break;\r
+#endif\r
+\r
+ case KHUI_WM_NC_NOTIFY:\r
+ {\r
+ khui_nc_wnd_data * d;\r
+ d = (khui_nc_wnd_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ /* message sent by parent to notify us of something */\r
+ switch(HIWORD(wParam)) {\r
+ case WMNC_DIALOG_EXPAND:\r
+ if(hwnd == d->dlg_main) {\r
+ HWND hw;\r
+ \r
+ if(hw = GetDlgItem(hwnd, IDOK))\r
+ ShowWindow(hw, SW_HIDE);\r
+ if(hw = GetDlgItem(hwnd, IDCANCEL))\r
+ ShowWindow(hw, SW_HIDE);\r
+ if(hw = GetDlgItem(hwnd, IDC_NC_OPTIONS))\r
+ ShowWindow(hw, SW_HIDE);\r
+\r
+ d->r_credtext.bottom = d->r_area.bottom;\r
+\r
+ nc_position_credtext(d);\r
+\r
+ return TRUE;\r
+ }\r
+ }\r
+ }\r
+ return TRUE;\r
+ }\r
+\r
+ /* check if we have a wnd_data, and if so pass the message on to\r
+ the identity provider callback. */\r
+ {\r
+ khui_nc_wnd_data * d;\r
+\r
+ d = (khui_nc_wnd_data *) (LONG_PTR)\r
+ GetWindowLongPtr(hwnd, DWLP_USER);\r
+\r
+ if (d && d->nc && d->nc->ident_cb) {\r
+ return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, hwnd, uMsg, \r
+ wParam, lParam);\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+static void\r
+nc_position_credtext(khui_nc_wnd_data * d)\r
+{\r
+ HWND hw;\r
+\r
+ hw = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+\r
+ if (d->r_credtext.bottom < d->r_credtext.top + d->r_row.bottom * 2) {\r
+ /* not enough room */\r
+ if (d->nc->mode == KHUI_NC_MODE_MINI &&\r
+ d->nc->subtype != KMSG_CRED_PASSWORD) {\r
+ PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY,\r
+ MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0);\r
+ return;\r
+ } else {\r
+ ShowWindow(hw, SW_HIDE);\r
+ return;\r
+ }\r
+ } else {\r
+ ShowWindow(hw, SW_SHOW);\r
+ }\r
+\r
+ SetWindowPos(hw, NULL,\r
+ d->r_credtext.left + d->r_n_input.left, /* x */\r
+ d->r_credtext.top, /* y */\r
+ d->r_n_input.right - d->r_n_input.left, /* width */\r
+ d->r_credtext.bottom - d->r_credtext.top, /* height */\r
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | \r
+ SWP_NOZORDER);\r
+\r
+ hw = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT_LABEL);\r
+\r
+ SetWindowPos(hw, NULL,\r
+ d->r_credtext.left + d->r_n_label.left, /* x */\r
+ d->r_credtext.top, /* y */\r
+ d->r_n_label.right - d->r_n_label.left, /* width */\r
+ d->r_n_label.bottom - d->r_n_label.top, /* height */\r
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER |\r
+ SWP_NOZORDER);\r
+}\r
+\r
+/* sorts tab buttons */\r
+static int __cdecl \r
+nc_tab_sort_func(const void * v1, const void * v2)\r
+{\r
+ /* v1 and v2 and of type : khui_new_creds_by_type ** */\r
+ khui_new_creds_by_type *t1, *t2;\r
+\r
+ t1 = *((khui_new_creds_by_type **) v1);\r
+ t2 = *((khui_new_creds_by_type **) v2);\r
+\r
+ if(t1->ordinal > 0) {\r
+ if(t2->ordinal > 0) {\r
+ if(t1->ordinal == t2->ordinal)\r
+ return wcscmp(t1->name, t2->name);\r
+ else\r
+ /* safe to convert to an int here */\r
+ return (int) (t1->ordinal - t2->ordinal);\r
+ } else\r
+ return -1;\r
+ } else {\r
+ if(t2->ordinal > 0)\r
+ return 1;\r
+ else if (t1->name && t2->name)\r
+ return wcscmp(t1->name, t2->name);\r
+ else\r
+ return 0;\r
+ }\r
+}\r
+\r
+static void \r
+nc_notify_types_async(khui_new_creds * c, UINT uMsg,\r
+ WPARAM wParam, LPARAM lParam)\r
+{\r
+ khm_size i;\r
+\r
+ for(i=0; i<c->n_types; i++) {\r
+ PostMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam);\r
+ }\r
+}\r
+\r
+static void \r
+nc_notify_types(khui_new_creds * c, UINT uMsg,\r
+ WPARAM wParam, LPARAM lParam)\r
+{\r
+ khm_size i;\r
+\r
+ for(i=0; i<c->n_types; i++) {\r
+ SendMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam);\r
+ }\r
+}\r
+\r
+#define NC_MAXCCH_CREDTEXT 16384\r
+#define NC_MAXCB_CREDTEXT (NC_MAXCCH_CREDTEXT * sizeof(wchar_t))\r
+\r
+static void \r
+nc_update_credtext(khui_nc_wnd_data * d) \r
+{\r
+ wchar_t * ctbuf = NULL;\r
+ wchar_t * buf;\r
+ BOOL okEnable = FALSE;\r
+ BOOL validId = FALSE;\r
+ HWND hw = NULL;\r
+ size_t cch = 0;\r
+\r
+ ctbuf = malloc(NC_MAXCB_CREDTEXT);\r
+\r
+ assert(ctbuf != NULL);\r
+\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_TABS, ctbuf, NC_MAXCCH_CREDTEXT);\r
+ StringCchLength(ctbuf, NC_MAXCCH_CREDTEXT, &cch);\r
+ buf = ctbuf + cch;\r
+ nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);\r
+\r
+ /* hopefully all the types have updated their credential texts */\r
+ if(d->nc->n_identities == 1) {\r
+ wchar_t main_fmt[256];\r
+ wchar_t id_fmt[256];\r
+ wchar_t id_name[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256];\r
+ khm_size cbbuf;\r
+ khm_int32 flags;\r
+\r
+\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_ONE, \r
+ main_fmt, (int) ARRAYLENGTH(main_fmt));\r
+\r
+ cbbuf = sizeof(id_name);\r
+ kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf);\r
+\r
+ kcdb_identity_get_flags(d->nc->identities[0], &flags);\r
+ if (flags & KCDB_IDENT_FLAG_INVALID) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else if(flags & KCDB_IDENT_FLAG_VALID) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else if(d->nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_CHECKING, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ }\r
+\r
+ StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name);\r
+\r
+ StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), \r
+ main_fmt, id_string);\r
+\r
+ } else if(d->nc->n_identities > 1) {\r
+ wchar_t *ids_string;\r
+ khm_size cb_ids_string;\r
+\r
+ wchar_t id_name[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t id_fmt[256];\r
+ wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256];\r
+\r
+ wchar_t main_fmt[256];\r
+ khm_size cbbuf;\r
+\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_MANY, \r
+ main_fmt, (int) ARRAYLENGTH(main_fmt));\r
+\r
+ /* we are going to concatenate all the identity names into\r
+ a comma separated string */\r
+\r
+ /* d->nc->n_identities is at least 2 */\r
+ ids_string = malloc((KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * \r
+ (d->nc->n_identities - 1));\r
+ cb_ids_string = \r
+ (KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * \r
+ (d->nc->n_identities - 1);\r
+\r
+ assert(ids_string != NULL);\r
+\r
+ ids_string[0] = 0;\r
+\r
+ {\r
+ khm_size i;\r
+ khm_int32 flags;\r
+\r
+ for(i=1; i<d->nc->n_identities; i++) {\r
+ if(i>1) {\r
+ StringCbCat(ids_string, cb_ids_string, L",");\r
+ }\r
+\r
+ flags = 0;\r
+\r
+ cbbuf = sizeof(id_name);\r
+ kcdb_identity_get_name(d->nc->identities[i], id_name, &cbbuf);\r
+ kcdb_identity_get_flags(d->nc->identities[i], &flags);\r
+ if(flags & KCDB_IDENT_FLAG_INVALID) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else if(flags & KCDB_IDENT_FLAG_VALID) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ }\r
+\r
+ StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name);\r
+ StringCbCat(ids_string, cb_ids_string, id_string);\r
+ }\r
+\r
+ cbbuf = sizeof(id_name);\r
+ kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf);\r
+ kcdb_identity_get_flags(d->nc->identities[0], &flags);\r
+ if(flags & KCDB_IDENT_FLAG_INVALID) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else if(flags & KCDB_IDENT_FLAG_VALID) {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, \r
+ id_fmt, (int) ARRAYLENGTH(id_fmt));\r
+ }\r
+ StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name);\r
+\r
+ StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), \r
+ main_fmt, id_string, ids_string);\r
+\r
+ free(ids_string);\r
+ }\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_NONE, \r
+ buf, (int)(NC_MAXCCH_CREDTEXT - cch));\r
+ }\r
+\r
+ /* now, append the credtext string from each of the cred types */\r
+ {\r
+ khm_size i;\r
+ size_t cb;\r
+ wchar_t * buf;\r
+\r
+ cb = NC_MAXCB_CREDTEXT;\r
+ buf = ctbuf;\r
+\r
+ for(i=0; i<d->nc->n_types; i++) {\r
+ if(d->nc->types[i]->credtext != NULL) {\r
+ StringCbCatEx(buf, cb, \r
+ d->nc->types[i]->credtext,\r
+ &buf, &cb,\r
+ 0);\r
+ }\r
+ }\r
+ }\r
+\r
+ SetDlgItemText(d->dlg_main, IDC_NC_CREDTEXT, ctbuf);\r
+\r
+ free(ctbuf);\r
+\r
+ /* so depending on whether the primary identity was found to be\r
+ invalid, we need to disable the Ok button and set the title to\r
+ reflect this */\r
+\r
+ if(d->nc->n_identities > 0) {\r
+ khm_int32 flags = 0;\r
+\r
+ if(KHM_SUCCEEDED(kcdb_identity_get_flags(d->nc->identities[0], \r
+ &flags)) &&\r
+ (flags & KCDB_IDENT_FLAG_VALID)) {\r
+ validId = TRUE;\r
+ }\r
+ }\r
+\r
+ if (d->nc->window_title == NULL) {\r
+ if(validId) {\r
+ wchar_t wpostfix[256];\r
+ wchar_t wtitle[KCDB_IDENT_MAXCCH_NAME + 256];\r
+ khm_size cbsize;\r
+\r
+ cbsize = sizeof(wtitle);\r
+ kcdb_identity_get_name(d->nc->identities[0], wtitle, &cbsize);\r
+\r
+ if (d->nc->subtype == KMSG_CRED_PASSWORD)\r
+ LoadString(khm_hInstance, IDS_WTPOST_PASSWORD,\r
+ wpostfix, (int) ARRAYLENGTH(wpostfix));\r
+ else\r
+ LoadString(khm_hInstance, IDS_WTPOST_NEW_CREDS, \r
+ wpostfix, (int) ARRAYLENGTH(wpostfix));\r
+\r
+ StringCbCat(wtitle, sizeof(wtitle), wpostfix);\r
+\r
+ SetWindowText(d->nc->hwnd, wtitle);\r
+ } else {\r
+ wchar_t wtitle[256];\r
+\r
+ if (d->nc->subtype == KMSG_CRED_PASSWORD)\r
+ LoadString(khm_hInstance, IDS_WT_PASSWORD,\r
+ wtitle, (int) ARRAYLENGTH(wtitle));\r
+ else\r
+ LoadString(khm_hInstance, IDS_WT_NEW_CREDS, \r
+ wtitle, (int) ARRAYLENGTH(wtitle));\r
+\r
+ SetWindowText(d->nc->hwnd, wtitle);\r
+ }\r
+ }\r
+\r
+ if(validId || d->nc->subtype == KMSG_CRED_PASSWORD) {\r
+ /* TODO: check if all the required fields have valid values\r
+ before enabling the Ok button */\r
+ okEnable = TRUE;\r
+ }\r
+\r
+ hw = GetDlgItem(d->dlg_main, IDOK);\r
+ EnableWindow(hw, okEnable);\r
+ hw = GetDlgItem(d->dlg_bb, IDOK);\r
+ EnableWindow(hw, okEnable);\r
+}\r
+\r
+#define CW_PARAM DWLP_USER\r
+\r
+static LRESULT \r
+nc_handle_wm_create(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ LPCREATESTRUCT lpc;\r
+ khui_new_creds * c;\r
+ khui_nc_wnd_data * ncd;\r
+ int x, y;\r
+ int width, height;\r
+ RECT r;\r
+\r
+ lpc = (LPCREATESTRUCT) lParam;\r
+\r
+ ncd = malloc(sizeof(*ncd));\r
+ ZeroMemory(ncd, sizeof(*ncd));\r
+\r
+ c = (khui_new_creds *) lpc->lpCreateParams;\r
+ ncd->nc = c;\r
+ c->hwnd = hwnd;\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, CW_PARAM, (LONG_PTR) ncd);\r
+#pragma warning(pop)\r
+\r
+ /* first try to create the main dialog panel */\r
+ \r
+ assert(c->subtype == KMSG_CRED_NEW_CREDS ||\r
+ c->subtype == KMSG_CRED_PASSWORD);\r
+\r
+ ncd->dlg_main = CreateDialogParam(khm_hInstance,\r
+ MAKEINTRESOURCE(IDD_NC_PASSWORD),\r
+ hwnd,\r
+ nc_common_dlg_proc,\r
+ (LPARAM) ncd);\r
+#ifdef DEBUG\r
+ assert(ncd->dlg_main);\r
+#endif\r
+\r
+ {\r
+ RECT r_main;\r
+ RECT r_area;\r
+ RECT r_row;\r
+ HWND hw;\r
+ \r
+ /* pick out metrics for use by the custom prompter stuff */\r
+ GetWindowRect(ncd->dlg_main, &r_main);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_PANEL);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r_area);\r
+ OffsetRect(&r_area,-r_main.left, -r_main.top);\r
+ CopyRect(&ncd->r_area, &r_area);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r);\r
+ CopyRect(&r_row, &r);\r
+ OffsetRect(&r,-r.left, -r.top);\r
+ CopyRect(&ncd->r_row, &r);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r);\r
+ OffsetRect(&r,-r_row.left, -r_row.top);\r
+ CopyRect(&ncd->r_n_label, &r);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r);\r
+ OffsetRect(&r, -r_row.left, -r_row.top);\r
+ CopyRect(&ncd->r_n_input, &r);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW_LG);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r_row);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL_LG);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r);\r
+ OffsetRect(&r, -r_row.left, -r_row.top);\r
+ CopyRect(&ncd->r_e_label, &r);\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT_LG);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r);\r
+ OffsetRect(&r, -r_row.left, -r_row.top);\r
+ CopyRect(&ncd->r_e_input, &r);\r
+\r
+ CopyRect(&ncd->r_credtext, &ncd->r_area);\r
+ CopyRect(&ncd->r_idspec, &ncd->r_area);\r
+\r
+ ncd->r_idspec.bottom = ncd->r_idspec.top;\r
+\r
+ hw = GetDlgItem(ncd->dlg_main, IDC_NC_CREDTEXT);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ GetWindowRect(hw, &r);\r
+ OffsetRect(&r, -r_main.left, -r_main.top);\r
+ ncd->r_credtext.bottom = r.bottom;\r
+ }\r
+\r
+ /* if the mode is 'mini'*/\r
+ r.left = 0;\r
+ r.top = 0;\r
+ if(c->mode == KHUI_NC_MODE_MINI) {\r
+ r.right = NCDLG_WIDTH;\r
+ r.bottom = NCDLG_HEIGHT;\r
+ } else {\r
+ r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH;\r
+ r.bottom = NCDLG_HEIGHT + NCDLG_TAB_HEIGHT;\r
+ }\r
+\r
+ MapDialogRect(ncd->dlg_main, &r);\r
+\r
+ ncd->r_main.left = 0;\r
+ ncd->r_main.top = 0;\r
+ ncd->r_main.right = NCDLG_WIDTH;\r
+ ncd->r_main.bottom = NCDLG_HEIGHT;\r
+\r
+ ncd->r_ts.left = 0;\r
+ ncd->r_ts.top = ncd->r_main.bottom;\r
+ ncd->r_ts.right = ncd->r_main.right;\r
+ ncd->r_ts.bottom = ncd->r_ts.top + NCDLG_TAB_HEIGHT;\r
+\r
+ ncd->r_bb.left = ncd->r_main.right;\r
+ ncd->r_bb.top = 0;\r
+ ncd->r_bb.right = ncd->r_bb.left + NCDLG_BBAR_WIDTH;\r
+ ncd->r_bb.bottom = ncd->r_ts.bottom;\r
+\r
+ MapDialogRect(ncd->dlg_main, &(ncd->r_main));\r
+ MapDialogRect(ncd->dlg_main, &(ncd->r_ts));\r
+ MapDialogRect(ncd->dlg_main, &(ncd->r_bb));\r
+\r
+ /* center the new creds window over the main NetIDMgr window */\r
+ width = r.right - r.left;\r
+ height = r.bottom - r.top;\r
+\r
+ /* adjust width and height to accomodate NC area */\r
+ {\r
+ RECT wr,cr;\r
+\r
+ GetWindowRect(hwnd, &wr);\r
+ GetClientRect(hwnd, &cr);\r
+\r
+ /* the non-client and client areas have already been calculated\r
+ at this point. We just use the difference to adjust the width\r
+ and height */\r
+ width += (wr.right - wr.left) - (cr.right - cr.left);\r
+ height += (wr.bottom - wr.top) - (cr.bottom - cr.top);\r
+ }\r
+\r
+ GetWindowRect(lpc->hwndParent, &r);\r
+ x = (r.right + r.left)/2 - width / 2;\r
+ y = (r.top + r.bottom)/2 - height / 2;\r
+\r
+ MoveWindow(hwnd, x, y, width, height, FALSE);\r
+\r
+ SetWindowPos(ncd->dlg_main, \r
+ NULL, \r
+ ncd->r_main.left, \r
+ ncd->r_main.top,\r
+ ncd->r_main.right - ncd->r_main.left,\r
+ ncd->r_main.bottom - ncd->r_main.top,\r
+ SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | \r
+ SWP_NOREDRAW | SWP_NOZORDER);\r
+\r
+ /* IDD_NC_BBAR is the button bar that sits on the right of the\r
+ dialog when the new creds window is in 'expanded' mode. */\r
+\r
+ ncd->dlg_bb = CreateDialogParam(khm_hInstance,\r
+ MAKEINTRESOURCE(IDD_NC_BBAR),\r
+ hwnd,\r
+ nc_common_dlg_proc,\r
+ (LPARAM) ncd);\r
+\r
+#ifdef DEBUG\r
+ assert(ncd->dlg_bb);\r
+#endif\r
+\r
+ SetWindowPos(ncd->dlg_bb, \r
+ NULL, \r
+ ncd->r_bb.left, \r
+ ncd->r_bb.top,\r
+ ncd->r_bb.right - ncd->r_bb.left,\r
+ ncd->r_bb.bottom - ncd->r_bb.top,\r
+ SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | \r
+ SWP_NOREDRAW | SWP_NOZORDER);\r
+\r
+ /* IDD_NC_TS is the tab strip that sits below the main panel when\r
+ the new creds window is in 'expanded' mode */\r
+\r
+ ncd->dlg_ts = CreateDialogParam(khm_hInstance,\r
+ MAKEINTRESOURCE(IDD_NC_TS),\r
+ hwnd,\r
+ nc_common_dlg_proc,\r
+ (LPARAM) ncd);\r
+\r
+#ifdef DEBUG\r
+ assert(ncd->dlg_ts);\r
+#endif\r
+\r
+ SetWindowPos(ncd->dlg_ts, \r
+ NULL, \r
+ ncd->r_ts.left, \r
+ ncd->r_ts.top,\r
+ ncd->r_ts.right - ncd->r_ts.left,\r
+ ncd->r_ts.bottom - ncd->r_ts.top,\r
+ SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | \r
+ SWP_NOREDRAW | SWP_NOZORDER);\r
+\r
+ if(c->mode == KHUI_NC_MODE_MINI) {\r
+ /* hide and show stuff */\r
+ ShowWindow(ncd->dlg_main, SW_SHOW);\r
+ ShowWindow(ncd->dlg_bb, SW_HIDE);\r
+ ShowWindow(ncd->dlg_ts, SW_HIDE);\r
+\r
+ nc_position_credtext(ncd);\r
+ } else {\r
+ /* hide and show stuff */\r
+ ShowWindow(ncd->dlg_main, SW_SHOW);\r
+ ShowWindow(ncd->dlg_bb, SW_SHOW);\r
+ ShowWindow(ncd->dlg_ts, SW_SHOW);\r
+\r
+ PostMessage(ncd->dlg_main, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0);\r
+ }\r
+\r
+ /* Call the identity provider callback to set the identity\r
+ selector controls */\r
+ c->ident_cb(c, WMNC_IDENT_INIT, NULL, 0, 0, (LPARAM) ncd->dlg_main);\r
+\r
+ /* we defer the creation of the tab buttons for later */\r
+\r
+ /* add this to the dialog chain */\r
+ khm_add_dialog(hwnd);\r
+\r
+ return TRUE;\r
+}\r
+\r
+static void\r
+nc_add_control_row(khui_nc_wnd_data * d, \r
+ HWND label,\r
+ HWND input,\r
+ khui_control_size size)\r
+{\r
+ RECT r_row;\r
+ RECT r_label;\r
+ RECT r_input;\r
+ HFONT hf;\r
+\r
+ hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);\r
+ SendMessage(label, WM_SETFONT, (WPARAM) hf, FALSE);\r
+ SendMessage(input, WM_SETFONT, (WPARAM) hf, FALSE);\r
+\r
+ CopyRect(&r_row, &d->r_row);\r
+ OffsetRect(&r_row, d->r_idspec.left, d->r_idspec.bottom);\r
+\r
+ if (size == KHUI_CTRLSIZE_SMALL) {\r
+ CopyRect(&r_label, &d->r_n_label);\r
+ CopyRect(&r_input, &d->r_n_input);\r
+ OffsetRect(&r_label, r_row.left, r_row.top);\r
+ OffsetRect(&r_input, r_row.left, r_row.top);\r
+ } else if (size == KHUI_CTRLSIZE_HALF) {\r
+ CopyRect(&r_label, &d->r_e_label);\r
+ CopyRect(&r_input, &d->r_e_input);\r
+ OffsetRect(&r_label, r_row.left, r_row.top);\r
+ OffsetRect(&r_input, r_row.left, r_row.top);\r
+ } else if (size == KHUI_CTRLSIZE_FULL) {\r
+ CopyRect(&r_label, &d->r_n_label);\r
+ r_label.right = d->r_row.right;\r
+ CopyRect(&r_input, &d->r_n_input);\r
+ OffsetRect(&r_input, r_row.left, r_row.top);\r
+ OffsetRect(&r_input, 0, r_input.bottom);\r
+ r_row.bottom += r_input.bottom;\r
+ OffsetRect(&r_label, r_row.left, r_row.top);\r
+ } else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return;\r
+#endif\r
+ }\r
+\r
+ SetWindowPos(label,\r
+ ((d->hwnd_last_idspec != NULL)?\r
+ d->hwnd_last_idspec:\r
+ HWND_TOP),\r
+ r_label.left, r_label.top,\r
+ r_label.right - r_label.left,\r
+ r_label.bottom - r_label.top,\r
+ SWP_DEFERERASE | SWP_NOACTIVATE |\r
+ SWP_NOOWNERZORDER);\r
+\r
+ SetWindowPos(input,\r
+ label,\r
+ r_input.left, r_input.top,\r
+ r_input.right - r_input.left,\r
+ r_input.bottom - r_input.top,\r
+ SWP_DEFERERASE | SWP_NOACTIVATE |\r
+ SWP_NOOWNERZORDER);\r
+\r
+ d->hwnd_last_idspec = input;\r
+\r
+ d->r_idspec.bottom = r_row.bottom;\r
+\r
+ d->r_credtext.top = r_row.bottom;\r
+\r
+ nc_position_credtext(d);\r
+}\r
+\r
+\r
+static LRESULT \r
+nc_handle_wm_destroy(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ khui_nc_wnd_data * d;\r
+ khm_size i;\r
+\r
+ /* remove self from dialog chain */\r
+ khm_del_dialog(hwnd);\r
+\r
+ d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);\r
+\r
+ d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0);\r
+\r
+ if(d->hwnd_tc_main)\r
+ DestroyWindow(d->hwnd_tc_main);\r
+ for(i=0;i<d->nc->n_types;i++) {\r
+ if(d->nc->types[i]->hwnd_tc) {\r
+ DestroyWindow(d->nc->types[i]->hwnd_tc);\r
+ d->nc->types[i]->hwnd_tc = NULL;\r
+ }\r
+ }\r
+\r
+ if(d->dlg_bb)\r
+ DestroyWindow(d->dlg_bb);\r
+ if(d->dlg_main)\r
+ DestroyWindow(d->dlg_main);\r
+ if(d->dlg_ts)\r
+ DestroyWindow(d->dlg_ts);\r
+\r
+ d->dlg_bb = NULL;\r
+ d->dlg_main = NULL;\r
+ d->dlg_ts = NULL;\r
+\r
+ free(d);\r
+\r
+ return TRUE;\r
+}\r
+\r
+static LRESULT \r
+nc_handle_wm_command(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ khui_nc_wnd_data * d;\r
+ int id;\r
+\r
+ d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);\r
+\r
+ switch(HIWORD(wParam)) {\r
+ case BN_CLICKED:\r
+ switch(LOWORD(wParam)) {\r
+\r
+ case IDOK:\r
+ d->nc->result = KHUI_NC_RESULT_GET_CREDS;\r
+\r
+ /* fallthrough */\r
+\r
+ case IDCANCEL:\r
+ /* the default value for d->nc->result is set to\r
+ KHUI_NC_RESULT_CANCEL */\r
+ d->nc->response = 0;\r
+\r
+ nc_notify_types(d->nc, \r
+ KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_DIALOG_PREPROCESS), \r
+ 0);\r
+\r
+ khui_cw_sync_prompt_values(d->nc);\r
+\r
+ khm_cred_dispatch_process_message(d->nc);\r
+\r
+ /* we won't know whether to abort or not until we get\r
+ feedback from the plugins, even if the command was\r
+ to cancel */\r
+ {\r
+ HWND hw;\r
+\r
+ hw = GetDlgItem(d->dlg_main, IDOK);\r
+ EnableWindow(hw, FALSE);\r
+ hw = GetDlgItem(d->dlg_main, IDCANCEL);\r
+ EnableWindow(hw, FALSE);\r
+ hw = GetDlgItem(d->dlg_bb, IDOK);\r
+ EnableWindow(hw, FALSE);\r
+ hw = GetDlgItem(d->dlg_bb, IDCANCEL);\r
+ EnableWindow(hw, FALSE);\r
+ }\r
+ return FALSE;\r
+\r
+ case IDC_NC_OPTIONS: \r
+ /* the Options button in the main window was clicked. we\r
+ respond by expanding the dialog. */\r
+ PostMessage(hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0);\r
+ return FALSE;\r
+\r
+ case IDC_NC_CREDTEXT: /* credtext link activated */\r
+ {\r
+ khui_htwnd_link * l;\r
+ wchar_t sid[KHUI_MAXCCH_HTLINK_FIELD];\r
+ wchar_t sparam[KHUI_MAXCCH_HTLINK_FIELD];\r
+ wchar_t * colon;\r
+\r
+ l = (khui_htwnd_link *) lParam;\r
+\r
+ /* do we have a valid link? */\r
+ if(l->id == NULL || l->id_len >= ARRAYLENGTH(sid))\r
+ return TRUE; /* nope */\r
+\r
+ StringCchCopyN(sid, ARRAYLENGTH(sid), l->id, l->id_len);\r
+ sid[l->id_len] = L'\0'; /* just make sure */\r
+\r
+ if(l->param != NULL && \r
+ l->param_len < ARRAYLENGTH(sparam) &&\r
+ l->param_len > 0) {\r
+\r
+ wcsncpy(sparam, l->param, l->param_len);\r
+ sparam[l->param_len] = L'\0';\r
+\r
+ } else {\r
+ sparam[0] = L'\0';\r
+ }\r
+\r
+ /* If the ID is of the form '<credtype>:<link_tag>'\r
+ and <credtype> is a valid name of a credentials\r
+ type that is participating in the credentials\r
+ acquisition process, then we forward the message to\r
+ the panel that is providing the UI for that cred\r
+ type. We also switch to that panel first. */\r
+\r
+ colon = wcschr(sid, L':');\r
+ if (colon != NULL) {\r
+ khm_int32 credtype;\r
+ khui_new_creds_by_type * t;\r
+\r
+ *colon = L'\0';\r
+ if (KHM_SUCCEEDED(kcdb_credtype_get_id(sid, &credtype)) &&\r
+ KHM_SUCCEEDED(khui_cw_find_type(d->nc, credtype, &t))){\r
+ *colon = L':';\r
+\r
+ if (t->ordinal != d->ctab)\r
+ PostMessage(hwnd,\r
+ KHUI_WM_NC_NOTIFY,\r
+ MAKEWPARAM(t->ordinal,\r
+ WMNC_DIALOG_SWITCH_PANEL),\r
+ 0);\r
+\r
+ return SendMessage(t->hwnd_panel,\r
+ KHUI_WM_NC_NOTIFY,\r
+ MAKEWPARAM(0, WMNC_CREDTEXT_LINK),\r
+ lParam);\r
+ }\r
+ }\r
+\r
+ /* if it was for us, then we need to process the message */\r
+ if(!wcsicmp(sid, CTLINKID_SWITCH_PANEL)) {\r
+ khm_int32 credtype;\r
+ khui_new_creds_by_type * t;\r
+\r
+ if (KHM_SUCCEEDED(kcdb_credtype_get_id(sparam, \r
+ &credtype)) &&\r
+ KHM_SUCCEEDED(khui_cw_find_type(d->nc,\r
+ credtype, &t))) {\r
+ if (t->ordinal != d->ctab)\r
+ PostMessage(hwnd,\r
+ KHUI_WM_NC_NOTIFY,\r
+ MAKEWPARAM(t->ordinal,\r
+ WMNC_DIALOG_SWITCH_PANEL),\r
+ 0);\r
+ }\r
+ }\r
+ }\r
+ return FALSE;\r
+\r
+ default:\r
+ /* if one of the tab strip buttons were pressed, then\r
+ we should switch to that panel */\r
+ id = LOWORD(wParam);\r
+ if(id >= NC_TS_CTRL_ID_MIN && id <= NC_TS_CTRL_ID_MAX) {\r
+ id -= NC_TS_CTRL_ID_MIN;\r
+ PostMessage(hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(id, WMNC_DIALOG_SWITCH_PANEL),0);\r
+ return FALSE;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+static LRESULT nc_handle_wm_moving(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ khui_nc_wnd_data * d;\r
+\r
+ d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);\r
+\r
+ nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_MOVE), 0);\r
+\r
+ return FALSE;\r
+}\r
+\r
+static LRESULT nc_handle_wm_nc_notify(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ khui_nc_wnd_data * d;\r
+ RECT r;\r
+ int width, height;\r
+ khm_size id;\r
+\r
+ d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM);\r
+\r
+ switch(HIWORD(wParam)) {\r
+\r
+ case WMNC_DIALOG_SWITCH_PANEL:\r
+ id = LOWORD(wParam);\r
+ if(id >= 0 && id <= d->nc->n_types) {\r
+ /* one of the tab buttons were pressed */\r
+ if(d->ctab == id) {\r
+ return TRUE; /* nothign to do */\r
+ }\r
+\r
+ if(d->ctab == 0) {\r
+ ShowWindow(d->dlg_main, SW_HIDE);\r
+ SendMessage(d->hwnd_tc_main, \r
+ BM_SETCHECK, BST_UNCHECKED, 0);\r
+ } else {\r
+ ShowWindow(d->nc->types[d->ctab - 1]->hwnd_panel, SW_HIDE);\r
+ SendMessage(d->nc->types[d->ctab - 1]->hwnd_tc, \r
+ BM_SETCHECK, BST_UNCHECKED, 0);\r
+ }\r
+\r
+ d->ctab = id;\r
+\r
+ if(d->ctab == 0) {\r
+ ShowWindow(d->dlg_main, SW_SHOW);\r
+ SendMessage(d->hwnd_tc_main, \r
+ BM_SETCHECK, BST_CHECKED, 0);\r
+ } else {\r
+ ShowWindow(d->nc->types[id - 1]->hwnd_panel, SW_SHOW);\r
+ SendMessage(d->nc->types[id - 1]->hwnd_tc, \r
+ BM_SETCHECK, BST_CHECKED, 0);\r
+ }\r
+ }\r
+\r
+ if(d->nc->mode == KHUI_NC_MODE_EXPANDED)\r
+ return TRUE;\r
+ /*else*/\r
+ /* fallthrough */\r
+\r
+ case WMNC_DIALOG_EXPAND:\r
+ /* we are expanding the dialog box */\r
+\r
+ /* nothing to do? */\r
+ if (d->nc->mode == KHUI_NC_MODE_EXPANDED)\r
+ break;\r
+\r
+ d->nc->mode = KHUI_NC_MODE_EXPANDED;\r
+\r
+ r.top = 0;\r
+ r.left = 0;\r
+ r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH;\r
+ r.bottom = NCDLG_HEIGHT + NCDLG_TAB_HEIGHT;\r
+\r
+ MapDialogRect(d->dlg_main, &r);\r
+\r
+ width = r.right - r.left;\r
+ height = r.bottom - r.top;\r
+\r
+ /* adjust width and height to accomodate NC area */\r
+ {\r
+ RECT wr,cr;\r
+\r
+ GetWindowRect(hwnd, &wr);\r
+ GetClientRect(hwnd, &cr);\r
+\r
+ /* the non-client and client areas have already been\r
+ calculated at this point. We just use the difference\r
+ to adjust the width and height */\r
+ width += (wr.right - wr.left) - (cr.right - cr.left);\r
+ height += (wr.bottom - wr.top) - (cr.bottom - cr.top);\r
+ }\r
+\r
+ SendMessage(d->dlg_main, \r
+ KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_DIALOG_EXPAND), \r
+ 0);\r
+\r
+ SetWindowPos(hwnd, \r
+ NULL, \r
+ 0, 0, \r
+ width, height, \r
+ SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | \r
+ SWP_NOZORDER);\r
+\r
+ ShowWindow(d->dlg_bb, SW_SHOW);\r
+ ShowWindow(d->dlg_ts, SW_SHOW);\r
+ break;\r
+\r
+ case WMNC_DIALOG_SETUP:\r
+ if(d->nc->n_types > 0) {\r
+ khm_size i;\r
+ for(i=0; i < d->nc->n_types;i++) {\r
+\r
+ if (d->nc->types[i]->dlg_proc == NULL) {\r
+ d->nc->types[i]->hwnd_panel = NULL;\r
+ } else {\r
+ /* Create the dialog panel */ \r
+ d->nc->types[i]->hwnd_panel = \r
+ CreateDialogParam(d->nc->types[i]->h_module,\r
+ d->nc->types[i]->dlg_template,\r
+ d->nc->hwnd,\r
+ d->nc->types[i]->dlg_proc,\r
+ (LPARAM) d->nc);\r
+\r
+#ifdef DEBUG\r
+ assert(d->nc->types[i]->hwnd_panel);\r
+#endif\r
+ }\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WMNC_DIALOG_ACTIVATE:\r
+ {\r
+ int x,y,width,height;\r
+ RECT r;\r
+ int id;\r
+ wchar_t wbuf[256];\r
+ HFONT hf;\r
+\r
+ /* now we create all the tab strip controls */\r
+ r.left = 0;\r
+ r.top = 0;\r
+ r.right = NCDLG_TAB_WIDTH;\r
+ r.bottom = NCDLG_TAB_HEIGHT;\r
+ MapDialogRect(d->dlg_main, &r);\r
+\r
+ width = r.right - r.left;\r
+ height = r.bottom - r.top;\r
+\r
+ x = 0;\r
+ y = 0;\r
+\r
+ id = NC_TS_CTRL_ID_MIN;\r
+\r
+ khui_cw_lock_nc(d->nc);\r
+\r
+ /* first, the control for the main panel */\r
+ LoadString(khm_hInstance, IDS_NC_IDENTITY, \r
+ wbuf, ARRAYLENGTH(wbuf));\r
+\r
+ d->hwnd_tc_main = \r
+ CreateWindow(L"BUTTON",\r
+ wbuf,\r
+ WS_VISIBLE | WS_CHILD | WS_TABSTOP |\r
+ BS_PUSHLIKE | BS_CHECKBOX | BS_TEXT,\r
+ x,y,width,height,\r
+ d->dlg_ts,\r
+ (HMENU)(INT_PTR) id,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+ hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);\r
+ SendMessage(d->hwnd_tc_main, WM_SETFONT, (WPARAM) hf, 0);\r
+ SendMessage(d->hwnd_tc_main, BM_SETCHECK, BST_CHECKED, 0);\r
+\r
+ id++;\r
+ x += width;\r
+\r
+ if(d->nc->n_types > 0) {\r
+ khm_size i;\r
+ /* we should sort the tabs first */\r
+ qsort(d->nc->types, \r
+ d->nc->n_types, \r
+ sizeof(*(d->nc->types)), \r
+ nc_tab_sort_func);\r
+\r
+ for(i=0; i < d->nc->n_types;i++) {\r
+ wchar_t * name;\r
+\r
+ d->nc->types[i]->ordinal = i + 1;\r
+\r
+ if(d->nc->types[i]->name)\r
+ name = d->nc->types[i]->name;\r
+ else {\r
+ khm_size cbsize;\r
+\r
+ if(kcdb_credtype_describe\r
+ (d->nc->types[i]->type, \r
+ NULL, \r
+ &cbsize, \r
+ KCDB_TS_SHORT) == KHM_ERROR_TOO_LONG) {\r
+\r
+ name = malloc(cbsize);\r
+ kcdb_credtype_describe(d->nc->types[i]->type, \r
+ name, \r
+ &cbsize, \r
+ KCDB_TS_SHORT);\r
+ } else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ continue;\r
+#endif\r
+ }\r
+ }\r
+\r
+ d->nc->types[i]->hwnd_tc = \r
+ CreateWindow(L"BUTTON",\r
+ name,\r
+ WS_VISIBLE | WS_CHILD | WS_TABSTOP |\r
+ BS_PUSHLIKE | BS_CHECKBOX | BS_TEXT |\r
+ ((d->nc->types[i]->hwnd_panel == NULL)? \r
+ WS_DISABLED : 0),\r
+ x,y,width,height,\r
+ d->dlg_ts,\r
+ (HMENU)(INT_PTR) id,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+ SendMessage(d->nc->types[i]->hwnd_tc, WM_SETFONT, \r
+ (WPARAM)hf, 0);\r
+\r
+#if 0\r
+ if(d->nc->types[i]->flags & KHUI_NCT_FLAG_DISABLED)\r
+ SendMessage(d->nc->types[i]->hwnd_tc, \r
+ BM_SETIMAGE, \r
+ IMAGE_ICON, \r
+ LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_DISABLED)));\r
+ else\r
+ SendMessage(d->nc->types[i]->hwnd_tc, \r
+ BM_SETIMAGE, \r
+ IMAGE_ICON, \r
+ LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_ENABLED)));\r
+#endif\r
+\r
+ id++;\r
+ x += width;\r
+\r
+ if(!(d->nc->types[i]->name))\r
+ free(name);\r
+\r
+ /* Now set the position of the type panel */\r
+ ShowWindow(d->nc->types[i]->hwnd_panel, SW_HIDE);\r
+ SetWindowPos(d->nc->types[i]->hwnd_panel, \r
+ NULL,\r
+ d->r_main.left, \r
+ d->r_main.top,\r
+ d->r_main.right - d->r_main.left,\r
+ d->r_main.bottom - d->r_main.top,\r
+ SWP_DEFERERASE | SWP_NOACTIVATE | \r
+ SWP_NOOWNERZORDER | SWP_NOREDRAW | \r
+ SWP_NOZORDER);\r
+\r
+ }\r
+ }\r
+\r
+ khui_cw_unlock_nc(d->nc);\r
+\r
+ nc_update_credtext(d);\r
+\r
+ ShowWindow(hwnd, SW_SHOW);\r
+ SetFocus(hwnd);\r
+\r
+ if (d->nc->n_identities == 0)\r
+ break;\r
+ /* else */\r
+ /* fallthrough */\r
+ }\r
+\r
+ case WMNC_IDENTITY_CHANGE:\r
+ {\r
+ BOOL okEnable = FALSE;\r
+\r
+ nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY,\r
+ MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0);\r
+ nc_update_credtext(d);\r
+ }\r
+ break;\r
+\r
+ case WMNC_TYPE_STATE:\r
+ /* fallthrough */\r
+ case WMNC_UPDATE_CREDTEXT:\r
+ nc_update_credtext(d);\r
+ break;\r
+\r
+ case WMNC_CLEAR_PROMPTS:\r
+ {\r
+ khm_size i;\r
+\r
+ khui_cw_lock_nc(d->nc);\r
+\r
+ if(d->hwnd_banner != NULL) {\r
+ DestroyWindow(d->hwnd_banner);\r
+ d->hwnd_banner = NULL;\r
+ }\r
+\r
+ if(d->hwnd_name != NULL) {\r
+ DestroyWindow(d->hwnd_name);\r
+ d->hwnd_name = NULL;\r
+ }\r
+\r
+ for(i=0;i<d->nc->n_prompts;i++) {\r
+ if(!(d->nc->prompts[i]->flags & \r
+ KHUI_NCPROMPT_FLAG_STOCK)) {\r
+ if(d->nc->prompts[i]->hwnd_static != NULL)\r
+ DestroyWindow(d->nc->prompts[i]->hwnd_static);\r
+\r
+ if(d->nc->prompts[i]->hwnd_edit != NULL)\r
+ DestroyWindow(d->nc->prompts[i]->hwnd_edit);\r
+ }\r
+\r
+ d->nc->prompts[i]->hwnd_static = NULL;\r
+ d->nc->prompts[i]->hwnd_edit = NULL;\r
+ }\r
+\r
+ khui_cw_unlock_nc(d->nc);\r
+\r
+ d->r_credtext.top = d->r_idspec.bottom;\r
+\r
+ nc_position_credtext(d);\r
+ }\r
+ break;\r
+\r
+ case WMNC_SET_PROMPTS:\r
+ {\r
+ khm_size i;\r
+ int y;\r
+ HWND hw, hw_prev;\r
+ HFONT hf, hfold;\r
+ HDC hdc;\r
+\r
+ /* we assume that WMNC_CLEAR_PROMPTS has already been\r
+ received */\r
+\r
+ khui_cw_lock_nc(d->nc);\r
+\r
+#if 0\r
+ /* special case, we have one prompt and it is a password\r
+ prompt. very common */\r
+ if(d->nc->n_prompts == 1 && \r
+ d->nc->prompts[0]->type == KHUI_NCPROMPT_TYPE_PASSWORD) {\r
+\r
+ hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD);\r
+ EnableWindow(hw, TRUE);\r
+\r
+ d->nc->prompts[0]->flags |= KHUI_NCPROMPT_FLAG_STOCK;\r
+ d->nc->prompts[0]->hwnd_edit = hw;\r
+ d->nc->prompts[0]->hwnd_static = NULL; /* don't care */\r
+\r
+ khui_cw_unlock_nc(d->nc);\r
+ break;\r
+ }\r
+#endif\r
+ /* for everything else */\r
+\r
+ /* hide the stock password controls */\r
+#if 0\r
+ /* TAGREMOVE */\r
+ hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD);\r
+ ShowWindow(hw, SW_HIDE);\r
+ hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD_LABEL);\r
+ ShowWindow(hw, SW_HIDE);\r
+#endif\r
+\r
+ y = d->r_idspec.bottom;\r
+\r
+ hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0);\r
+\r
+ if (d->nc->pname != NULL) {\r
+ hw =\r
+ CreateWindowEx\r
+ (0,\r
+ L"STATIC",\r
+ d->nc->pname,\r
+ SS_SUNKEN | WS_CHILD,\r
+ d->r_area.left, y,\r
+ d->r_row.right, \r
+ d->r_n_label.bottom - d->r_n_label.top,\r
+ d->dlg_main,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ d->hwnd_name = hw;\r
+ SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM) TRUE);\r
+ ShowWindow(hw, SW_SHOW);\r
+\r
+ y += d->r_n_label.bottom - d->r_n_label.top;\r
+ }\r
+\r
+ if (d->nc->banner != NULL) {\r
+ hw = \r
+ CreateWindowEx\r
+ (0,\r
+ L"STATIC",\r
+ d->nc->banner,\r
+ WS_CHILD,\r
+ d->r_area.left, y,\r
+ d->r_row.right, d->r_row.bottom,\r
+ d->dlg_main,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+ d->hwnd_banner = hw;\r
+ SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE);\r
+ ShowWindow(hw, SW_SHOW);\r
+ y += d->r_row.bottom;\r
+ }\r
+\r
+ hw_prev = d->hwnd_last_idspec;\r
+\r
+ hdc = GetWindowDC(d->dlg_main);\r
+ hfold = SelectObject(hdc,hf);\r
+\r
+ for(i=0; i<d->nc->n_prompts; i++) {\r
+ RECT pr, er;\r
+ SIZE s;\r
+ int dy;\r
+\r
+ if(d->nc->prompts[i]->prompt != NULL) {\r
+ GetTextExtentPoint32(hdc, \r
+ d->nc->prompts[i]->prompt, \r
+ (int) wcslen(d->nc->prompts[i]->prompt),\r
+ &s);\r
+ if(s.cx < d->r_n_label.right - d->r_n_label.left) {\r
+ CopyRect(&pr, &d->r_n_label);\r
+ CopyRect(&er, &d->r_n_input);\r
+ dy = d->r_row.bottom;\r
+ } else if(s.cx < \r
+ d->r_e_label.right - d->r_e_label.left) {\r
+ CopyRect(&pr, &d->r_e_label);\r
+ CopyRect(&er, &d->r_e_input);\r
+ dy = d->r_row.bottom;\r
+ } else {\r
+ /* oops. the prompt doesn't fit in our\r
+ controls. we need to use up two lines */\r
+ pr.left = 0;\r
+ pr.right = d->r_row.right;\r
+ pr.top = 0;\r
+ pr.bottom = d->r_n_label.bottom - \r
+ d->r_n_label.top;\r
+ CopyRect(&er, &d->r_n_input);\r
+ OffsetRect(&er, 0, pr.bottom);\r
+ dy = er.bottom + (d->r_row.bottom - \r
+ d->r_n_input.bottom);\r
+ }\r
+ } else {\r
+ SetRectEmpty(&pr);\r
+ CopyRect(&er, &d->r_n_input);\r
+ dy = d->r_row.bottom;\r
+ }\r
+\r
+ if(IsRectEmpty(&pr)) {\r
+ d->nc->prompts[i]->hwnd_static = NULL;\r
+ } else {\r
+ OffsetRect(&pr, d->r_area.left, y);\r
+\r
+ hw = CreateWindowEx\r
+ (0,\r
+ L"STATIC",\r
+ d->nc->prompts[i]->prompt,\r
+ WS_CHILD,\r
+ pr.left, pr.top,\r
+ pr.right - pr.left, pr.bottom - pr.top,\r
+ d->dlg_main,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+\r
+ SendMessage(hw, WM_SETFONT, \r
+ (WPARAM) hf, (LPARAM) TRUE);\r
+\r
+ SetWindowPos(hw, hw_prev,\r
+ 0, 0, 0, 0,\r
+ SWP_NOACTIVATE | SWP_NOMOVE |\r
+ SWP_NOOWNERZORDER | SWP_NOSIZE |\r
+ SWP_SHOWWINDOW);\r
+\r
+ d->nc->prompts[i]->hwnd_static = hw;\r
+ hw_prev = hw;\r
+ }\r
+\r
+ OffsetRect(&er, d->r_area.left, y);\r
+\r
+ hw = CreateWindowEx\r
+ (0,\r
+ L"EDIT",\r
+ (d->nc->prompts[i]->def ? \r
+ d->nc->prompts[i]->def : L""),\r
+ WS_CHILD | WS_TABSTOP |\r
+ WS_BORDER |\r
+ ((d->nc->prompts[i]->flags & \r
+ KHUI_NCPROMPT_FLAG_HIDDEN)? ES_PASSWORD:0),\r
+ er.left, er.top,\r
+ er.right - er.left, er.bottom - er.top,\r
+ d->dlg_main,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+#ifdef DEBUG\r
+ assert(hw);\r
+#endif\r
+\r
+ SendMessage(hw, WM_SETFONT, \r
+ (WPARAM) hf, (LPARAM) TRUE);\r
+\r
+ SetWindowPos(hw, hw_prev,\r
+ 0, 0, 0, 0, \r
+ SWP_NOACTIVATE | SWP_NOMOVE | \r
+ SWP_NOOWNERZORDER | SWP_NOSIZE | \r
+ SWP_SHOWWINDOW);\r
+ \r
+ d->nc->prompts[i]->hwnd_edit = hw;\r
+\r
+ hw_prev = hw;\r
+\r
+ y += dy;\r
+ }\r
+\r
+ SelectObject(hdc, hfold);\r
+ ReleaseDC(d->dlg_main, hdc);\r
+\r
+ khui_cw_unlock_nc(d->nc);\r
+\r
+ d->r_credtext.top = y;\r
+\r
+ nc_position_credtext(d);\r
+ }\r
+ break;\r
+\r
+ case WMNC_DIALOG_PROCESS_COMPLETE:\r
+ {\r
+ khui_new_creds * nc;\r
+\r
+ nc = d->nc;\r
+\r
+ /* reset state */\r
+ nc->result = KHUI_NC_RESULT_CANCEL;\r
+\r
+ if(nc->response & KHUI_NC_RESPONSE_NOEXIT) {\r
+ HWND hw;\r
+\r
+ hw = GetDlgItem(d->dlg_main, IDOK);\r
+ EnableWindow(hw, TRUE);\r
+ hw = GetDlgItem(d->dlg_main, IDCANCEL);\r
+ EnableWindow(hw, TRUE);\r
+ hw = GetDlgItem(d->dlg_bb, IDOK);\r
+ EnableWindow(hw, TRUE);\r
+ hw = GetDlgItem(d->dlg_bb, IDCANCEL);\r
+ EnableWindow(hw, TRUE);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ DestroyWindow(hwnd);\r
+\r
+ kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc);\r
+ }\r
+ break;\r
+\r
+ /* MUST be called with SendMessage */\r
+ case WMNC_ADD_CONTROL_ROW:\r
+ {\r
+ khui_control_row * row;\r
+\r
+ row = (khui_control_row *) lParam;\r
+\r
+#ifdef DEBUG\r
+ assert(row->label);\r
+ assert(row->input);\r
+#endif\r
+\r
+ nc_add_control_row(d, row->label, row->input, row->size);\r
+ }\r
+ break;\r
+ } /* switch(HIWORD(wParam)) */\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+static LRESULT CALLBACK nc_window_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ switch(uMsg) {\r
+ case WM_CREATE:\r
+ return nc_handle_wm_create(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_DESTROY:\r
+ return nc_handle_wm_destroy(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_COMMAND:\r
+ return nc_handle_wm_command(hwnd, uMsg, wParam, lParam);\r
+\r
+ case WM_MOVE:\r
+ case WM_MOVING:\r
+ return nc_handle_wm_moving(hwnd, uMsg, wParam, lParam);\r
+\r
+ case KHUI_WM_NC_NOTIFY:\r
+ return nc_handle_wm_nc_notify(hwnd, uMsg, wParam, lParam);\r
+ }\r
+\r
+ /* Note that this is technically a dialog box */\r
+ return DefDlgProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+void khm_register_newcredwnd_class(void)\r
+{\r
+ WNDCLASSEX wcx;\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = CS_DBLCLKS | CS_OWNDC;\r
+ wcx.lpfnWndProc = nc_window_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR);\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP));\r
+ wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);\r
+ wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_NEWCREDWND_CLASS;\r
+ wcx.hIconSm = NULL;\r
+\r
+ khui_newcredwnd_cls = RegisterClassEx(&wcx);\r
+}\r
+\r
+void khm_unregister_newcredwnd_class(void)\r
+{\r
+ UnregisterClass((LPWSTR) khui_newcredwnd_cls, khm_hInstance);\r
+}\r
+\r
+HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c)\r
+{\r
+ wchar_t wtitle[256];\r
+ HWND hwnd;\r
+\r
+ if (c->window_title == NULL) {\r
+ if (c->subtype == KMSG_CRED_PASSWORD)\r
+ LoadString(khm_hInstance, \r
+ IDS_WT_PASSWORD,\r
+ wtitle,\r
+ ARRAYLENGTH(wtitle));\r
+ else\r
+ LoadString(khm_hInstance, \r
+ IDS_WT_NEW_CREDS,\r
+ wtitle,\r
+ ARRAYLENGTH(wtitle));\r
+ }\r
+\r
+ hwnd = CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP,\r
+ MAKEINTATOM(khui_newcredwnd_cls),\r
+ ((c->window_title)?c->window_title: wtitle),\r
+ WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN,\r
+ 0,0,400,400, /* bogus values. the window\r
+ is going to resize and\r
+ reposition itself\r
+ anyway */\r
+ parent,\r
+ NULL,\r
+ khm_hInstance,\r
+ (LPVOID) c);\r
+\r
+#ifdef DEBUG\r
+ assert(hwnd != NULL);\r
+#endif\r
+\r
+ /* note that the window is not visible yet. That's because, at\r
+ this point we don't know what the panels are */\r
+\r
+ return hwnd;\r
+}\r
+\r
+void khm_prep_newcredwnd(HWND hwnd)\r
+{\r
+ SendMessage(hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_SETUP), 0);\r
+}\r
+\r
+void khm_show_newcredwnd(HWND hwnd)\r
+{\r
+ /* add all the panels in and prep UI */\r
+ SendMessage(hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_ACTIVATE), 0);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_NEWCREDWND_H\r
+#define __KHIMAIRA_NEWCREDWND_H\r
+\r
+#include<khuidefs.h>\r
+\r
+#define KHUI_NEWCREDWND_CLASS L"KhmNewCredWnd"\r
+\r
+typedef struct khui_nc_wnd_data_t {\r
+ khui_new_creds * nc;\r
+\r
+ HWND dlg_main; /* main dialog */\r
+ RECT r_main;\r
+ HWND dlg_bb; /* button bar */\r
+ RECT r_bb;\r
+ HWND dlg_ts; /* tab strip */\r
+ RECT r_ts;\r
+\r
+ khm_size ctab; /* current tab */\r
+\r
+ HWND hwnd_tc_main; /* tab control button for main dialog */\r
+\r
+ HWND hwnd_banner; /* static control for banner */\r
+ HWND hwnd_name; /* static control for name */\r
+\r
+ HWND hwnd_last_idspec; /* last identity specifier control */\r
+\r
+ /* metrics for custom prompts and identity specifiers */\r
+\r
+ RECT r_idspec; /* Area used by identity specifiers\r
+ (relative to client) */\r
+ RECT r_row; /* Metrics for a control row\r
+ (top=0,left=0,right=width,\r
+ bottom=height) */\r
+ RECT r_area; /* Area available for controls (relative\r
+ to client) */\r
+ RECT r_n_label; /* coords of the static control (relative\r
+ to row) */\r
+ RECT r_n_input; /* coords of the edit control (relative to\r
+ row) */\r
+ RECT r_e_label; /* coords of the extended edit control\r
+ (relative to row) */\r
+ RECT r_e_input; /* coords of the extended edit control\r
+ (relative to row) */\r
+ RECT r_credtext; /* Area for credtext window (relative to\r
+ row) */\r
+} khui_nc_wnd_data;\r
+\r
+void khm_register_newcredwnd_class(void);\r
+void khm_unregister_newcredwnd_class(void);\r
+HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c);\r
+void khm_prep_newcredwnd(HWND hwnd);\r
+void khm_show_newcredwnd(HWND hwnd);\r
+\r
+/* This is the first control ID that is created in the custom tabstrip\r
+ control buttons. Subsequent buttons get consecutive IDs starting\r
+ from this one. */\r
+#define NC_TS_CTRL_ID_MIN 8001\r
+\r
+/* Maximum number of controls */\r
+#define NC_TS_MAX_CTRLS 8\r
+\r
+/* Maximum control ID */\r
+#define NC_TS_CTRL_ID_MAX (NC_TS_CTRL_ID_MIN + NC_TS_MAX_CTRLS - 1)\r
+\r
+/* the first control ID that may be used by an identity provider */\r
+#define NC_IS_CTRL_ID_MIN 8016\r
+\r
+/* the maximum number of controls that may be created by an identity\r
+ provider*/\r
+#define NC_IS_CTRL_MAX_CTRLS 8\r
+\r
+/* the maximum control ID that may be used by an identity provider */\r
+#define NC_IS_CTRL_ID_MAX (NC_IS_CTRL_ID_MIN + NC_IS_MAX_CTRLS - 1)\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#define OEMRESOURCE\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+#define KHUI_NOTIFIER_CLASS L"KhuiNotifierMsgWindowClass"\r
+#define KHUI_ALERTER_CLASS L"KhuiAlerterWindowClass"\r
+\r
+#define KHUI_NOTIFIER_WINDOW L"KhuiNotifierMsgWindow"\r
+\r
+/* notifier message for notification icon */\r
+#define KHUI_WM_NOTIFIER WM_COMMAND\r
+\r
+/* window class registration atom for message only notifier window\r
+ class */\r
+ATOM atom_notifier = 0;\r
+\r
+/* window class registration atom for alert windows */\r
+ATOM atom_alerter = 0;\r
+\r
+/* notifier message window */\r
+HWND hwnd_notifier = NULL;\r
+\r
+BOOL notifier_ready = FALSE;\r
+\r
+khui_alert * current_alert = NULL;\r
+\r
+\r
+/* forward dcls */\r
+static khm_int32 \r
+alert_show(khui_alert * a);\r
+\r
+static khm_int32 \r
+alert_show_minimized(khui_alert * a);\r
+\r
+static khm_int32\r
+alert_show_normal(khui_alert * a);\r
+\r
+/**********************************************************************\r
+ Notifier\r
+***********************************************************************\r
+\r
+The notifier is a message only window that listens for notifier\r
+messages. This window will exist for the lifetime of the application\r
+and will use alerter windows as needed to show application alerts.\r
+*/\r
+\r
+static LRESULT CALLBACK \r
+notifier_wnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ kmq_message * m;\r
+ khm_int32 rv;\r
+\r
+ if(uMsg == KMQ_WM_DISPATCH) {\r
+ kmq_wm_begin(lParam, &m);\r
+ rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(m->type == KMSG_ALERT) {\r
+ /* handle notifier messages */\r
+ switch(m->subtype) {\r
+ case KMSG_ALERT_SHOW:\r
+ rv = alert_show((khui_alert *) m->vparam);\r
+ khui_alert_release((khui_alert *) m->vparam);\r
+ break;\r
+ }\r
+ } else if (m->type == KMSG_CRED &&\r
+ m->subtype == KMSG_CRED_ROOTDELTA) {\r
+ KillTimer(hwnd, KHUI_REFRESH_TIMER_ID);\r
+ SetTimer(hwnd, KHUI_REFRESH_TIMER_ID,\r
+ KHUI_REFRESH_TIMEOUT,\r
+ NULL);\r
+ }\r
+\r
+ return kmq_wm_end(m, rv);\r
+ } else if (uMsg == KHUI_WM_NOTIFIER) {\r
+ /* Handle events generated from the notification icon */\r
+\r
+ /* wParam is the identifier of the notify icon, but we only\r
+ have one. */\r
+ switch(lParam) {\r
+ case WM_CONTEXTMENU: \r
+ {\r
+ POINT pt;\r
+ int menu_id;\r
+\r
+ GetCursorPos(&pt);\r
+\r
+ if (khm_is_main_window_visible())\r
+ menu_id = KHUI_MENU_ICO_CTX_NORMAL;\r
+ else\r
+ menu_id = KHUI_MENU_ICO_CTX_MIN;\r
+\r
+ SetForegroundWindow(khm_hwnd_main);\r
+\r
+ khm_menu_show_panel(menu_id, pt.x, pt.y);\r
+\r
+ PostMessage(khm_hwnd_main, WM_NULL, 0, 0);\r
+ }\r
+ break;\r
+\r
+ case WM_LBUTTONDOWN:\r
+ /* we actually wait for the WM_LBUTTONUP before doing\r
+ anything */\r
+ break;\r
+\r
+ case WM_LBUTTONUP:\r
+ /* fall through */\r
+\r
+ case NIN_SELECT:\r
+ case NIN_KEYSELECT:\r
+ khm_show_main_window();\r
+ break;\r
+\r
+ case NIN_BALLOONUSERCLICK:\r
+ if (current_alert) {\r
+ if ((current_alert->flags & KHUI_ALERT_FLAG_DEFACTION) &&\r
+ current_alert->n_alert_commands > 0) {\r
+ PostMessage(khm_hwnd_main, WM_COMMAND,\r
+ MAKEWPARAM(current_alert->alert_commands[0], 0),\r
+ 0);\r
+ } else if (current_alert->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) {\r
+ khm_show_main_window();\r
+ alert_show_normal(current_alert);\r
+ }\r
+ }\r
+ /* fallthrough */\r
+ case NIN_BALLOONTIMEOUT:\r
+ khui_notify_icon_change(KHERR_NONE);\r
+ if (current_alert) {\r
+ khui_alert_release(current_alert);\r
+ current_alert = NULL;\r
+ }\r
+ break;\r
+ }\r
+ } else if (uMsg == WM_TIMER) {\r
+ if (wParam == KHUI_TRIGGER_TIMER_ID) {\r
+ KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID);\r
+ khm_timer_fire(hwnd);\r
+ } else if (wParam == KHUI_REFRESH_TIMER_ID) {\r
+ KillTimer(hwnd, KHUI_REFRESH_TIMER_ID);\r
+ khm_timer_refresh(hwnd);\r
+ }\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+ATOM \r
+khui_register_notifier_wnd_class(void)\r
+{\r
+ WNDCLASSEX wcx;\r
+\r
+ ZeroMemory(&wcx, sizeof(wcx));\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = 0;\r
+ wcx.lpfnWndProc = notifier_wnd_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = 0;\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = NULL;\r
+ wcx.hCursor = NULL;\r
+ wcx.hbrBackground = NULL;\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_NOTIFIER_CLASS;\r
+ wcx.hIconSm = NULL;\r
+\r
+ atom_notifier = RegisterClassEx(&wcx);\r
+\r
+ return atom_notifier;\r
+}\r
+\r
+/*********************************************************************\r
+ Alerter\r
+**********************************************************************/\r
+\r
+typedef struct tag_alerter_wnd_data {\r
+ khui_alert * alert;\r
+\r
+ HWND hwnd;\r
+ HFONT hfont;\r
+\r
+ BOOL metrics_done;\r
+\r
+ HWND hwnd_buttons[KHUI_MAX_ALERT_COMMANDS];\r
+\r
+ /* various metrics */\r
+\r
+ /* calculated during WM_CREATE and adjusted during WM_PAINT */\r
+ int dy_message;\r
+ int dy_suggestion;\r
+\r
+ /* calculated during WM_CREATE */\r
+ int dx_button;\r
+ int dy_button;\r
+ int dx_button_incr;\r
+ int dx_margin;\r
+ int dy_margin;\r
+ int dy_bb;\r
+ int x_message;\r
+ int dx_message;\r
+ int dx_icon;\r
+ int dy_icon;\r
+ int dx_suggest_pad;\r
+\r
+ /* calculated during WM_CREATE and adjusted during WM_PAINT */\r
+ int dx_client;\r
+ int dy_client;\r
+\r
+ /* calculated during WM_PAINT */\r
+ int y_message;\r
+ int y_suggestion;\r
+\r
+ LDCL(struct tag_alerter_wnd_data);\r
+} alerter_wnd_data;\r
+\r
+alerter_wnd_data * khui_alerts = NULL;\r
+\r
+#define NTF_PARAM DWLP_USER\r
+\r
+/* dialog sizes in base dialog units */\r
+\r
+#define NTF_MARGIN 5\r
+#define NTF_WIDTH 200\r
+\r
+#define NTF_BB_HEIGHT 15\r
+\r
+#define NTF_ICON_X NTF_MARGIN\r
+#define NTF_ICON_WIDTH 20\r
+#define NTF_ICON_HEIGHT 20\r
+\r
+#define NTF_MSG_X (NTF_ICON_X + NTF_ICON_WIDTH + NTF_MARGIN)\r
+#define NTF_MSG_WIDTH ((NTF_WIDTH - NTF_MARGIN) - NTF_MSG_X)\r
+#define NTF_MSG_HEIGHT 15\r
+\r
+#define NTF_SUG_X NTF_MSG_X\r
+#define NTF_SUG_WIDTH NTF_MSG_WIDTH\r
+#define NTF_SUG_HEIGHT NTF_MSG_HEIGHT\r
+#define NTF_SUG_PAD 2\r
+\r
+#define NTF_BUTTON_X NTF_MSG_X\r
+\r
+#define NTF_BUTTON_WIDTH ((NTF_MSG_WIDTH - 3*NTF_MARGIN) / 4)\r
+#define NTF_BUTTON_XINCR (NTF_BUTTON_WIDTH + NTF_MARGIN)\r
+#define NTF_BUTTON_HEIGHT (NTF_BB_HEIGHT - NTF_MARGIN)\r
+\r
+#define NTF_TIMEOUT 20000\r
+\r
+static khm_int32 \r
+alert_show_minimized(khui_alert * a) {\r
+ wchar_t tbuf[64];\r
+ wchar_t mbuf[256];\r
+\r
+ if (a->message == NULL)\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if (a->title == NULL) {\r
+ LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
+ tbuf, ARRAYLENGTH(tbuf));\r
+ } else {\r
+ StringCbCopy(tbuf, sizeof(tbuf), a->title);\r
+ }\r
+\r
+ if (FAILED(StringCbCopy(mbuf, sizeof(mbuf), a->message)) ||\r
+ (!(a->flags & KHUI_ALERT_FLAG_DEFACTION) &&\r
+ (a->n_alert_commands > 0 ||\r
+ a->suggestion ||\r
+ (a->flags & KHUI_ALERT_FLAG_VALID_ERROR)))) {\r
+ /* if mbuf wasn't big enough, this should have copied a\r
+ truncated version of it */\r
+ size_t cch_m, cch_p;\r
+ wchar_t postfix[256];\r
+\r
+ cch_p = LoadString(khm_hInstance, IDS_ALERT_MOREINFO, postfix,\r
+ ARRAYLENGTH(postfix));\r
+ cch_p++; /* account for NULL */\r
+\r
+ StringCchLength(mbuf, ARRAYLENGTH(mbuf), &cch_m);\r
+ cch_m = min(cch_m, ARRAYLENGTH(mbuf) - cch_p);\r
+\r
+ StringCchCopy(mbuf + cch_m, ARRAYLENGTH(mbuf) - cch_m,\r
+ postfix);\r
+\r
+ a->flags |= KHUI_ALERT_FLAG_REQUEST_WINDOW;\r
+ }\r
+\r
+ a->flags |= KHUI_ALERT_FLAG_DISPLAY_BALLOON;\r
+\r
+ current_alert = a;\r
+ khui_alert_hold(a);\r
+\r
+ khui_notify_icon_balloon(a->severity,\r
+ tbuf,\r
+ mbuf,\r
+ NTF_TIMEOUT);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32 \r
+alert_show_normal(khui_alert * a) {\r
+ HWND hwa;\r
+ wchar_t buf[256];\r
+ wchar_t * title;\r
+\r
+ if(a->title == NULL) {\r
+ LoadString(khm_hInstance, IDS_ALERT_DEFAULT, \r
+ buf, ARRAYLENGTH(buf));\r
+ title = buf;\r
+ } else\r
+ title = a->title;\r
+\r
+ /* if we don't have any commands, we just add a "close" button */\r
+ if(a->n_alert_commands == 0) {\r
+ khui_alert_add_command(a, KHUI_PACTION_CLOSE);\r
+ }\r
+\r
+ /* we don't need to keep track of the window handle\r
+ because the window procedure adds it to the dialog\r
+ list automatically */\r
+\r
+ hwa = \r
+ CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP,\r
+ MAKEINTATOM(atom_alerter),\r
+ title,\r
+ WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN |\r
+ WS_VISIBLE,\r
+ 0, 0, 300, 300, // bogus values\r
+ khm_hwnd_main,\r
+ (HMENU) NULL,\r
+ khm_hInstance,\r
+ (LPVOID) a);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+static khm_int32 \r
+alert_show(khui_alert * a) {\r
+ /* the window has already been shown */\r
+ if((a->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW) ||\r
+ ((a->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) &&\r
+ !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW)))\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ if(a->err_context != NULL ||\r
+ a->err_event != NULL) {\r
+ khui_alert_lock(a);\r
+ a->flags |= KHUI_ALERT_FLAG_VALID_ERROR;\r
+ khui_alert_unlock(a);\r
+ }\r
+\r
+ /* depending on the state of the main window, we\r
+ need to either show a window or a balloon */\r
+ if(khm_is_main_window_active() &&\r
+ !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON))\r
+ return alert_show_normal(a);\r
+ else\r
+ return alert_show_minimized(a);\r
+}\r
+\r
+/* the alerter window is actually a dialog */\r
+static LRESULT CALLBACK \r
+alerter_wnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ switch(uMsg) {\r
+ case WM_CREATE:\r
+ {\r
+ LONG dlgb;\r
+ HWND hwnd_parent;\r
+ RECT r_parent;\r
+ POINT pos;\r
+ SIZE s;\r
+ LPCREATESTRUCT lpcs;\r
+ khui_alert * a;\r
+ alerter_wnd_data * d;\r
+\r
+ lpcs = (LPCREATESTRUCT) lParam;\r
+ a = (khui_alert *) lpcs->lpCreateParams;\r
+ khui_alert_hold(a);\r
+\r
+ d = malloc(sizeof(*d));\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ d->alert = a;\r
+ d->hwnd = hwnd;\r
+\r
+ khui_alert_lock(a);\r
+\r
+ a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW;\r
+ LPUSH(&khui_alerts, d);\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd, NTF_PARAM, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ khm_add_dialog(hwnd);\r
+ khm_enter_modal(hwnd);\r
+\r
+ /* now figure out the size and position of the window */\r
+\r
+ hwnd_parent = GetWindow(hwnd, GW_OWNER);\r
+ GetWindowRect(hwnd_parent, &r_parent);\r
+\r
+ dlgb = GetDialogBaseUnits();\r
+\r
+#define DLG2SCNX(x) MulDiv((x), LOWORD(dlgb), 4)\r
+#define DLG2SCNY(y) MulDiv((y), HIWORD(dlgb), 8)\r
+\r
+ d->dx_margin = DLG2SCNX(NTF_MARGIN);\r
+ d->dy_margin = DLG2SCNY(NTF_MARGIN);\r
+\r
+ d->x_message = DLG2SCNX(NTF_MSG_X);\r
+ d->dx_message = DLG2SCNX(NTF_MSG_WIDTH);\r
+\r
+ if (a->message) {\r
+ d->dy_message = DLG2SCNY(NTF_MSG_HEIGHT);\r
+ }\r
+\r
+ if (a->suggestion) {\r
+ d->dy_suggestion = DLG2SCNY(NTF_SUG_HEIGHT);\r
+ d->dx_suggest_pad = DLG2SCNX(NTF_SUG_PAD);\r
+ }\r
+\r
+ d->dy_bb = DLG2SCNY(NTF_BB_HEIGHT);\r
+ d->dx_button = DLG2SCNX(NTF_BUTTON_WIDTH);\r
+ d->dy_button = DLG2SCNY(NTF_BUTTON_HEIGHT);\r
+ d->dx_button_incr = DLG2SCNX(NTF_BUTTON_XINCR);\r
+\r
+ d->dx_icon = DLG2SCNX(NTF_ICON_WIDTH);\r
+ d->dy_icon = DLG2SCNY(NTF_ICON_HEIGHT);\r
+\r
+ d->dx_client = DLG2SCNX(NTF_WIDTH);\r
+ d->dy_client = max(d->dy_icon,\r
+ d->dy_message +\r
+ ((d->dy_suggestion > 0)?\r
+ (d->dy_suggestion + d->dy_margin):\r
+ 0)) +\r
+ d->dy_margin * 3 + d->dy_bb;\r
+\r
+ /* adjust for client rect */\r
+ s.cx = d->dx_client;\r
+ s.cy = d->dy_client;\r
+\r
+ {\r
+ RECT c_r;\r
+ RECT w_r;\r
+\r
+ GetWindowRect(hwnd, &w_r);\r
+ GetClientRect(hwnd, &c_r);\r
+\r
+ s.cx += (w_r.right - w_r.left) - (c_r.right - c_r.left);\r
+ s.cy += (w_r.bottom - w_r.top) - (c_r.bottom - c_r.top);\r
+ }\r
+\r
+ pos.x = (r_parent.left + r_parent.right - s.cx) / 2;\r
+ pos.y = (r_parent.top + r_parent.bottom - s.cy) / 2;\r
+\r
+ SetWindowPos(hwnd,\r
+ HWND_TOP,\r
+ pos.x, pos.y,\r
+ s.cx, s.cy,\r
+ SWP_SHOWWINDOW);\r
+\r
+ {\r
+ LOGFONT lf;\r
+ HDC hdc_dt;\r
+\r
+ hdc_dt = GetDC(NULL);\r
+\r
+ lf.lfHeight = -MulDiv(8, \r
+ GetDeviceCaps(hdc_dt, LOGPIXELSY), \r
+ 72);\r
+ lf.lfWidth = 0;\r
+ lf.lfEscapement = 0;\r
+ lf.lfOrientation = 0;\r
+ lf.lfWeight = FW_NORMAL;\r
+ lf.lfItalic = FALSE;\r
+ lf.lfUnderline = FALSE;\r
+ lf.lfStrikeOut = FALSE;\r
+ lf.lfCharSet = DEFAULT_CHARSET;\r
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
+ lf.lfQuality = DEFAULT_QUALITY;\r
+ lf.lfPitchAndFamily = DEFAULT_PITCH;\r
+\r
+ LoadString(khm_hInstance, IDS_DEFAULT_FONT, \r
+ lf.lfFaceName, ARRAYLENGTH(lf.lfFaceName));\r
+\r
+ d->hfont = CreateFontIndirect(&lf);\r
+\r
+ ReleaseDC(NULL, hdc_dt);\r
+ }\r
+\r
+ /* create dialog controls now */\r
+ {\r
+ int x,y;\r
+ int width, height;\r
+ int i;\r
+\r
+ x = d->x_message;\r
+ y = d->dy_client - d->dy_bb;\r
+ width = d->dx_button;\r
+ height = d->dy_button;\r
+\r
+ for(i=0; i<a->n_alert_commands; i++) {\r
+ wchar_t caption[256];\r
+ khui_action * action;\r
+ HWND hw_button;\r
+\r
+ if(a->alert_commands[i] == 0)\r
+ continue;\r
+\r
+ action = khui_find_action(a->alert_commands[i]);\r
+ if(action == NULL)\r
+ continue;\r
+\r
+ LoadString(khm_hInstance, action->is_caption, \r
+ caption, ARRAYLENGTH(caption));\r
+ \r
+ hw_button = \r
+ CreateWindowEx(0,\r
+ L"BUTTON",\r
+ caption,\r
+ WS_VISIBLE | WS_CHILD,\r
+ x,y,width,height,\r
+ hwnd,\r
+ (HMENU)(INT_PTR) (action->cmd),\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+ SendMessage(hw_button, WM_SETFONT, \r
+ (WPARAM) d->hfont, MAKELPARAM(TRUE, 0));\r
+\r
+ d->hwnd_buttons[i] = hw_button;\r
+\r
+ x += d->dx_button_incr;\r
+ }\r
+ }\r
+\r
+ khui_notify_icon_change(a->severity);\r
+\r
+ khui_alert_unlock(a);\r
+\r
+ d->metrics_done = FALSE;\r
+ \r
+ return TRUE;\r
+ }\r
+ break; /* not reached */\r
+\r
+ case WM_DESTROY:\r
+ {\r
+ alerter_wnd_data * d;\r
+\r
+ /* khm_leave_modal() could be here, but instead it is in\r
+ the WM_COMMAND handler. This is because the modal loop\r
+ has to be exited before DestroyWindow() is issued. */\r
+ //khm_leave_modal();\r
+ khm_del_dialog(hwnd);\r
+\r
+ d = (alerter_wnd_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, NTF_PARAM);\r
+\r
+ LDELETE(&khui_alerts, d);\r
+\r
+ khui_alert_lock(d->alert);\r
+ d->alert->flags &= ~KHUI_ALERT_FLAG_DISPLAY_WINDOW;\r
+ khui_alert_unlock(d->alert);\r
+\r
+ khui_alert_release(d->alert);\r
+\r
+ DeleteObject(d->hfont);\r
+\r
+ free(d);\r
+\r
+ khui_notify_icon_change(KHERR_NONE);\r
+\r
+ return TRUE;\r
+ }\r
+ break;\r
+\r
+ case WM_PAINT:\r
+ {\r
+ RECT r_update;\r
+ PAINTSTRUCT ps;\r
+ HDC hdc;\r
+ LONG dlgb;\r
+ alerter_wnd_data * d;\r
+ HFONT hf_old;\r
+ BOOL need_resize = FALSE;\r
+\r
+ if(!GetUpdateRect(hwnd, &r_update, TRUE))\r
+ return FALSE;\r
+\r
+ d = (alerter_wnd_data *)(LONG_PTR)\r
+ GetWindowLongPtr(hwnd, NTF_PARAM);\r
+\r
+ dlgb = GetDialogBaseUnits();\r
+\r
+ hdc = BeginPaint(hwnd, &ps);\r
+\r
+ hf_old = SelectFont(hdc, d->hfont);\r
+\r
+ khui_alert_lock(d->alert);\r
+\r
+ // draw the severity icon\r
+ {\r
+ HICON hicon;\r
+ int x,y;\r
+ int iid;\r
+\r
+ /* GOINGHERE! If the metrics for the window haven't\r
+ been calculated yet, then calculate them. If the\r
+ hight needs to be expanded, then do that and wait\r
+ for the next repaint cycle. Also move the button\r
+ controls down. */\r
+ x = d->dx_margin;\r
+ y = d->dy_margin;\r
+\r
+ if(d->alert->severity == KHERR_ERROR)\r
+ iid = OIC_HAND;\r
+ else if(d->alert->severity == KHERR_WARNING)\r
+ iid = OIC_BANG;\r
+ else\r
+ iid = OIC_NOTE;\r
+\r
+ hicon = LoadImage(NULL, \r
+ MAKEINTRESOURCE(iid), \r
+ IMAGE_ICON,\r
+ SM_CXICON, SM_CYICON,\r
+ LR_SHARED);\r
+\r
+ DrawIcon(hdc, x, y, hicon);\r
+ }\r
+\r
+ // draw the message\r
+ if(d->alert->message) {\r
+ RECT r;\r
+ int width;\r
+ int height;\r
+ size_t cch;\r
+\r
+ r.left = d->x_message;\r
+ r.top = d->dy_margin;\r
+ width = d->dx_message;\r
+ r.right = r.left + width;\r
+ height = d->dy_message;\r
+ r.bottom = r.top + height;\r
+\r
+ StringCchLength(d->alert->message, \r
+ KHUI_MAXCCH_MESSAGE, &cch);\r
+ \r
+ height = DrawText(hdc,\r
+ d->alert->message,\r
+ (int) cch,\r
+ &r,\r
+ DT_WORDBREAK |\r
+ DT_CALCRECT);\r
+\r
+ if (height > d->dy_message) {\r
+ d->dy_message = height;\r
+ need_resize = TRUE;\r
+ } else {\r
+ DrawText(hdc,\r
+ d->alert->message,\r
+ (int) cch,\r
+ &r,\r
+ DT_WORDBREAK);\r
+ }\r
+\r
+ d->y_message = r.top;\r
+ }\r
+\r
+ // and the suggestion\r
+ if (d->alert->suggestion) {\r
+ RECT r, ro;\r
+ int height;\r
+ size_t cch;\r
+ HICON h_sug_ico;\r
+\r
+ r.left = d->x_message;\r
+ r.top = d->y_message + d->dy_message + d->dy_margin;\r
+ r.right = r.left + d->dx_message;\r
+ r.bottom = r.top + d->dy_suggestion;\r
+\r
+ CopyRect(&ro, &r);\r
+\r
+ // adjust for icon and padding\r
+ r.left += SM_CXICON + d->dx_suggest_pad * 2;\r
+ r.top += d->dx_suggest_pad;\r
+ r.right -= d->dx_suggest_pad;\r
+ r.bottom -= d->dx_suggest_pad;\r
+\r
+ StringCchLength(d->alert->suggestion,\r
+ KHUI_MAXCCH_SUGGESTION, &cch);\r
+\r
+ height = DrawText(hdc,\r
+ d->alert->suggestion,\r
+ (int) cch,\r
+ &r,\r
+ DT_WORDBREAK |\r
+ DT_CALCRECT);\r
+\r
+ if (height > d->dy_suggestion) {\r
+ d->dy_suggestion = height;\r
+ need_resize = TRUE;\r
+ } else {\r
+ int old_bk_mode;\r
+\r
+ ro.bottom = r.bottom + d->dx_suggest_pad;\r
+\r
+ FillRect(hdc, &ro, (HBRUSH) (COLOR_INFOBK + 1));\r
+ DrawEdge(hdc, &ro, EDGE_SUNKEN, BF_FLAT | BF_RECT);\r
+\r
+ h_sug_ico = \r
+ LoadImage(0,\r
+ MAKEINTRESOURCE(OIC_INFORMATION),\r
+ IMAGE_ICON,\r
+ SM_CXICON, SM_CYICON,\r
+ LR_SHARED);\r
+\r
+ assert(h_sug_ico != NULL);\r
+\r
+ DrawIconEx(hdc, \r
+ ro.left + d->dx_suggest_pad, \r
+ ro.top + d->dx_suggest_pad, \r
+ h_sug_ico,\r
+ SM_CXICON, SM_CYICON,\r
+ 0, NULL,\r
+ DI_NORMAL);\r
+\r
+ old_bk_mode = SetBkMode(hdc, TRANSPARENT);\r
+\r
+ DrawText(hdc,\r
+ d->alert->suggestion,\r
+ (int) cch,\r
+ &r,\r
+ DT_WORDBREAK);\r
+\r
+ SetBkMode(hdc, old_bk_mode);\r
+ }\r
+\r
+ d->y_suggestion = r.top;\r
+ }\r
+\r
+ khui_alert_unlock(d->alert);\r
+\r
+ SelectObject(hdc, hf_old);\r
+\r
+ EndPaint(hwnd, &ps);\r
+\r
+ if (need_resize) {\r
+ RECT r;\r
+ int x,y;\r
+ int width, height;\r
+ int i;\r
+ \r
+ GetClientRect(hwnd, &r);\r
+\r
+ height = max(d->dy_icon,\r
+ d->dy_message +\r
+ ((d->dy_suggestion > 0)?\r
+ (d->dy_suggestion + d->dy_margin):\r
+ 0)) +\r
+ d->dy_margin * 3 + d->dy_bb;\r
+ r.bottom = r.top + height;\r
+\r
+ d->dy_client = height;\r
+\r
+ AdjustWindowRectEx(&r,\r
+ GetWindowLongPtr(hwnd, GWL_STYLE),\r
+ FALSE,\r
+ GetWindowLongPtr(hwnd, GWL_EXSTYLE));\r
+\r
+ SetWindowPos(hwnd,\r
+ NULL,\r
+ 0, 0,\r
+ r.right - r.left,\r
+ r.bottom - r.top,\r
+ SWP_NOACTIVATE | SWP_NOCOPYBITS |\r
+ SWP_NOMOVE | SWP_NOOWNERZORDER |\r
+ SWP_NOZORDER);\r
+\r
+ x = d->x_message;\r
+ y = d->dy_client - d->dy_bb;\r
+ width = d->dx_button;\r
+ height = d->dy_button;\r
+\r
+ for(i=0; i<d->alert->n_alert_commands; i++) {\r
+ MoveWindow(d->hwnd_buttons[i],\r
+ x,y,\r
+ width,height,\r
+ TRUE);\r
+\r
+ x += d->dx_button_incr;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+ }\r
+ break; /* not reached */\r
+\r
+ case WM_COMMAND:\r
+ {\r
+ alerter_wnd_data * d;\r
+\r
+ d = (alerter_wnd_data *)(LONG_PTR) \r
+ GetWindowLongPtr(hwnd, NTF_PARAM);\r
+\r
+ if(HIWORD(wParam) == BN_CLICKED) {\r
+ khui_alert_lock(d->alert);\r
+ d->alert->response = LOWORD(wParam);\r
+ khui_alert_unlock(d->alert);\r
+\r
+ khm_leave_modal();\r
+\r
+ DestroyWindow(hwnd);\r
+ return 0;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+\r
+ return DefDlgProc(hwnd, uMsg, wParam, lParam);\r
+ //return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+ATOM khui_register_alerter_wnd_class(void)\r
+{\r
+ WNDCLASSEX wcx;\r
+\r
+ ZeroMemory(&wcx, sizeof(wcx));\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = CS_DROPSHADOW | CS_OWNDC;\r
+ wcx.lpfnWndProc = alerter_wnd_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR);\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP));\r
+ wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
+ wcx.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_ALERTER_CLASS;\r
+ wcx.hIconSm = NULL;\r
+\r
+ atom_alerter = RegisterClassEx(&wcx);\r
+\r
+ return atom_alerter;\r
+}\r
+\r
+/**********************************************************************\r
+ Notification Icon\r
+***********************************************************************/\r
+\r
+#define KHUI_NOTIFY_ICON_ID 0\r
+\r
+void khui_notify_icon_add(void) {\r
+ NOTIFYICONDATA ni;\r
+ wchar_t buf[256];\r
+\r
+ ZeroMemory(&ni, sizeof(ni));\r
+\r
+ ni.cbSize = sizeof(ni);\r
+ ni.hWnd = hwnd_notifier;\r
+ ni.uID = KHUI_NOTIFY_ICON_ID;\r
+ ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;\r
+ ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_NOTIFY_NONE));\r
+ ni.uCallbackMessage = KHUI_WM_NOTIFIER;\r
+ LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf));\r
+ StringCbCopy(ni.szTip, sizeof(ni.szTip), buf);\r
+ LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf));\r
+ StringCbCat(ni.szTip, sizeof(ni.szTip), buf);\r
+\r
+ Shell_NotifyIcon(NIM_ADD, &ni);\r
+\r
+ ni.cbSize = sizeof(ni);\r
+ ni.uVersion = NOTIFYICON_VERSION;\r
+ Shell_NotifyIcon(NIM_SETVERSION, &ni);\r
+\r
+ DestroyIcon(ni.hIcon);\r
+}\r
+\r
+void \r
+khui_notify_icon_balloon(khm_int32 severity,\r
+ wchar_t * title,\r
+ wchar_t * msg,\r
+ khm_int32 timeout) {\r
+ NOTIFYICONDATA ni;\r
+ int iid;\r
+\r
+ if (!msg || !title)\r
+ return;\r
+\r
+ ZeroMemory(&ni, sizeof(ni));\r
+ ni.cbSize = sizeof(ni);\r
+\r
+ if (severity == KHERR_INFO) {\r
+ ni.dwInfoFlags = NIIF_INFO;\r
+ iid = IDI_NOTIFY_INFO;\r
+ } else if (severity == KHERR_WARNING) {\r
+ ni.dwInfoFlags = NIIF_WARNING;\r
+ iid = IDI_NOTIFY_WARN;\r
+ } else if (severity == KHERR_ERROR) {\r
+ ni.dwInfoFlags = NIIF_ERROR;\r
+ iid = IDI_NOTIFY_ERROR;\r
+ } else {\r
+ ni.dwInfoFlags = NIIF_NONE;\r
+ iid = IDI_NOTIFY_NONE;\r
+ }\r
+\r
+ ni.hWnd = hwnd_notifier;\r
+ ni.uID = KHUI_NOTIFY_ICON_ID;\r
+ ni.uFlags = NIF_INFO | NIF_ICON;\r
+ ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid));\r
+\r
+ if (FAILED(StringCbCopy(ni.szInfo, sizeof(ni.szInfo), msg))) {\r
+ /* too long? */\r
+ StringCchCopyN(ni.szInfo, ARRAYLENGTH(ni.szInfo),\r
+ msg, \r
+ ARRAYLENGTH(ni.szInfo) - ARRAYLENGTH(ELIPSIS));\r
+ StringCchCat(ni.szInfo, ARRAYLENGTH(ni.szInfo),\r
+ ELIPSIS);\r
+ }\r
+\r
+ if (FAILED(StringCbCopy(ni.szInfoTitle, sizeof(ni.szInfoTitle), \r
+ title))) {\r
+ StringCchCopyN(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle),\r
+ title, \r
+ ARRAYLENGTH(ni.szInfoTitle) - ARRAYLENGTH(ELIPSIS));\r
+ StringCchCat(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle),\r
+ ELIPSIS);\r
+ }\r
+ ni.uTimeout = timeout;\r
+\r
+ Shell_NotifyIcon(NIM_MODIFY, &ni);\r
+\r
+ DestroyIcon(ni.hIcon);\r
+}\r
+\r
+void khui_notify_icon_change(khm_int32 severity) {\r
+ NOTIFYICONDATA ni;\r
+ wchar_t buf[256];\r
+ int iid;\r
+\r
+ if (severity == KHERR_INFO)\r
+ iid = IDI_NOTIFY_INFO;\r
+ else if (severity == KHERR_WARNING)\r
+ iid = IDI_NOTIFY_WARN;\r
+ else if (severity == KHERR_ERROR)\r
+ iid = IDI_NOTIFY_ERROR;\r
+ else\r
+ iid = IDI_NOTIFY_NONE;\r
+\r
+ ZeroMemory(&ni, sizeof(ni));\r
+\r
+ ni.cbSize = sizeof(ni);\r
+ ni.hWnd = hwnd_notifier;\r
+ ni.uID = KHUI_NOTIFY_ICON_ID;\r
+ ni.uFlags = NIF_ICON | NIF_TIP;\r
+ ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid));\r
+ LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf));\r
+ StringCbCopy(ni.szTip, sizeof(ni.szTip), buf);\r
+ if(severity == KHERR_NONE)\r
+ LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf));\r
+ else\r
+ LoadString(khm_hInstance, IDS_NOTIFY_ATTENTION, buf, ARRAYLENGTH(buf));\r
+ StringCbCat(ni.szTip, sizeof(ni.szTip), buf);\r
+\r
+ Shell_NotifyIcon(NIM_MODIFY, &ni);\r
+\r
+ DestroyIcon(ni.hIcon);\r
+}\r
+\r
+void khui_notify_icon_remove(void) {\r
+ NOTIFYICONDATA ni;\r
+\r
+ ZeroMemory(&ni, sizeof(ni));\r
+\r
+ ni.cbSize = sizeof(ni);\r
+ ni.hWnd = hwnd_notifier;\r
+ ni.uID = KHUI_NOTIFY_ICON_ID;\r
+\r
+ Shell_NotifyIcon(NIM_DELETE, &ni);\r
+}\r
+\r
+/*********************************************************************\r
+ Initialization\r
+**********************************************************************/\r
+\r
+void khui_init_notifier(void)\r
+{\r
+ if(!khui_register_notifier_wnd_class())\r
+ return;\r
+\r
+ if(!khui_register_alerter_wnd_class())\r
+ return;\r
+\r
+ hwnd_notifier = CreateWindowEx(0,\r
+ MAKEINTATOM(atom_notifier),\r
+ KHUI_NOTIFIER_WINDOW,\r
+ 0,\r
+ 0,0,0,0,\r
+ HWND_MESSAGE,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+ if(hwnd_notifier != NULL) {\r
+ kmq_subscribe_hwnd(KMSG_ALERT, hwnd_notifier);\r
+ kmq_subscribe_hwnd(KMSG_CRED, hwnd_notifier);\r
+ notifier_ready = TRUE;\r
+\r
+ khui_notify_icon_add();\r
+ }\r
+#ifdef DEBUG\r
+ else {\r
+ assert(hwnd_notifier != NULL);\r
+ }\r
+#endif\r
+ khm_timer_init();\r
+}\r
+\r
+void khui_exit_notifier(void)\r
+{\r
+ khm_timer_exit();\r
+\r
+ if(hwnd_notifier != NULL) {\r
+ khui_notify_icon_remove();\r
+ kmq_unsubscribe_hwnd(KMSG_ALERT, hwnd_notifier);\r
+ kmq_unsubscribe_hwnd(KMSG_CRED, hwnd_notifier);\r
+ DestroyWindow(hwnd_notifier);\r
+ hwnd_notifier = NULL;\r
+ }\r
+\r
+ if(atom_notifier != 0) {\r
+ UnregisterClass(MAKEINTATOM(atom_notifier), khm_hInstance);\r
+ atom_notifier = 0;\r
+ }\r
+\r
+ if(atom_alerter != 0) {\r
+ UnregisterClass(MAKEINTATOM(atom_alerter), khm_hInstance);\r
+ atom_alerter = 0;\r
+ }\r
+\r
+ notifier_ready = FALSE;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_NOTIFIER_H\r
+#define __KHIMAIRA_NOTIFIER_H\r
+\r
+void \r
+khui_init_notifier(void);\r
+\r
+void \r
+khui_exit_notifier(void);\r
+\r
+void \r
+khui_notify_icon_change(khm_int32 severity);\r
+\r
+void \r
+khui_notify_icon_balloon(khm_int32 severity,\r
+ wchar_t * title,\r
+ wchar_t * msg,\r
+ khm_int32 timeout);\r
+\r
+#endif\r
--- /dev/null
+#include<khmapp.h>\r
+\r
+static ATOM sAtom = 0;\r
+static HINSTANCE shInstance = 0;\r
+\r
+/* Callback for the MITPasswordControl\r
+This is a replacement for the normal edit control. It does not show the \r
+annoying password char in the edit box so that the number of chars in the \r
+password are not known.\r
+*/\r
+\r
+#define PASSWORDCHAR L'#'\r
+#define DLGHT(ht) (HIWORD(GetDialogBaseUnits())*(ht)/8)\r
+#define DLGWD(wd) (LOWORD(GetDialogBaseUnits())*(wd)/4)\r
+\r
+static\r
+LRESULT\r
+CALLBACK\r
+MITPasswordEditProc(\r
+ HWND hWnd,\r
+ UINT message,\r
+ WPARAM wParam,\r
+ LPARAM lParam\r
+ )\r
+{\r
+ static SIZE pwdcharsz;\r
+ BOOL pass_the_buck = FALSE;\r
+ \r
+ if (message > WM_USER && message < 0x7FFF)\r
+ pass_the_buck = TRUE;\r
+ \r
+ switch(message)\r
+ {\r
+ case WM_GETTEXT:\r
+ case WM_GETTEXTLENGTH:\r
+ case WM_SETTEXT:\r
+ pass_the_buck = TRUE;\r
+ break;\r
+ case WM_PAINT:\r
+ {\r
+ HDC hdc;\r
+ PAINTSTRUCT ps;\r
+ RECT r;\r
+ \r
+ hdc = BeginPaint(hWnd, &ps);\r
+ GetClientRect(hWnd, &r);\r
+ Rectangle(hdc, 0, 0, r.right, r.bottom);\r
+ EndPaint(hWnd, &ps);\r
+ }\r
+ break;\r
+ case WM_SIZE:\r
+ {\r
+ MoveWindow(GetDlgItem(hWnd, 1), DLGWD(2), DLGHT(2),\r
+ pwdcharsz.cx / 2, pwdcharsz.cy, TRUE);\r
+ }\r
+ break;\r
+ case WM_LBUTTONDOWN:\r
+ case WM_SETFOCUS:\r
+ {\r
+ SetFocus(GetDlgItem(hWnd, 1));\r
+ }\r
+ break;\r
+ case WM_CREATE:\r
+ {\r
+ HWND heditchild;\r
+ wchar_t pwdchar = PASSWORDCHAR;\r
+ HDC hdc;\r
+ /* Create a child window of this control for default processing. */\r
+ hdc = GetDC(hWnd);\r
+ GetTextExtentPoint32(hdc, &pwdchar, 1, &pwdcharsz);\r
+ ReleaseDC(hWnd, hdc);\r
+ \r
+ heditchild =\r
+ CreateWindow(L"edit", L"", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL |\r
+ ES_LEFT | ES_PASSWORD | WS_TABSTOP,\r
+ 0, 0, 0, 0,\r
+ hWnd,\r
+ (HMENU)1,\r
+ ((LPCREATESTRUCT)lParam)->hInstance,\r
+ NULL);\r
+ SendMessage(heditchild, EM_SETPASSWORDCHAR, PASSWORDCHAR, 0L);\r
+ }\r
+ break;\r
+ }\r
+ \r
+ if (pass_the_buck)\r
+ return SendMessage(GetDlgItem(hWnd, 1), message, wParam, lParam);\r
+ return DefWindowProc(hWnd, message, wParam, lParam);\r
+}\r
+\r
+khm_int32\r
+khm_register_passwnd_class(void)\r
+{\r
+ if (!sAtom) {\r
+ WNDCLASS wndclass;\r
+\r
+ memset(&wndclass, 0, sizeof(WNDCLASS));\r
+\r
+ shInstance = khm_hInstance;\r
+\r
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;\r
+ wndclass.lpfnWndProc = (WNDPROC)MITPasswordEditProc;\r
+ wndclass.cbClsExtra = sizeof(HWND);\r
+ wndclass.cbWndExtra = 0;\r
+ wndclass.hInstance = shInstance;\r
+ wndclass.hbrBackground = (void *)(COLOR_WINDOW + 1);\r
+ wndclass.lpszClassName = MIT_PWD_DLL_CLASS;\r
+ wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_IBEAM);\r
+ \r
+ sAtom = RegisterClass(&wndclass);\r
+ }\r
+\r
+ return (sAtom)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN;\r
+}\r
+\r
+khm_int32\r
+khm_unregister_passwnd_class(void)\r
+{\r
+ BOOL result = TRUE;\r
+\r
+ if ((khm_hInstance != shInstance) || !sAtom) {\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+ }\r
+\r
+ result = UnregisterClass(MIT_PWD_DLL_CLASS, khm_hInstance);\r
+ if (result) {\r
+ sAtom = 0;\r
+ shInstance = 0;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ return KHM_ERROR_UNKNOWN;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_PASSWND_H\r
+#define __KHIMAIRA_PASSWND_H\r
+\r
+/* Declarations for the MIT password change control. Functionally the\r
+ same as the regular Windows password edit control but doesn't\r
+ display the '*' password character. */\r
+\r
+#define MIT_PWD_DLL_CLASS L"MITPasswordWnd"\r
+\r
+khm_int32 khm_unregister_passwnd_class(void);\r
+khm_int32 khm_register_passwnd_class(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+typedef struct tag_pw_data {\r
+ khm_handle record;\r
+ HWND hwnd_lv;\r
+} pw_data;\r
+\r
+ATOM khui_propertywnd_cls;\r
+\r
+#define ID_LISTVIEW 1\r
+\r
+#define PW_WM_SET_RECORD WM_USER\r
+\r
+void pw_update_property_data(HWND hw, pw_data * d)\r
+{\r
+ HWND hwnd_lv;\r
+ khm_int32 * attrs = NULL;\r
+\r
+ hwnd_lv = d->hwnd_lv;\r
+\r
+ if(hwnd_lv == NULL)\r
+ return;\r
+\r
+ ListView_DeleteAllItems(hwnd_lv);\r
+\r
+ if(d->record != NULL) {\r
+ wchar_t * buffer;\r
+ khm_size attr_count;\r
+ khm_size i;\r
+ khm_size cb_buf;\r
+ khm_size t;\r
+ LVITEM lvi;\r
+ int idx;\r
+\r
+ if(KHM_FAILED(kcdb_attrib_get_count(\r
+ KCDB_ATTR_FLAG_VOLATILE |\r
+ KCDB_ATTR_FLAG_HIDDEN,\r
+ 0,\r
+ &attr_count)))\r
+ return;\r
+\r
+ attrs = malloc(sizeof(khm_int32) * attr_count);\r
+ assert(attrs != NULL);\r
+\r
+ kcdb_attrib_get_ids(\r
+ KCDB_ATTR_FLAG_VOLATILE |\r
+ KCDB_ATTR_FLAG_HIDDEN,\r
+ 0,\r
+ attrs,\r
+ &attr_count);\r
+\r
+ cb_buf = sizeof(wchar_t) * 2048;\r
+ buffer = malloc(cb_buf);\r
+ assert(buffer != NULL);\r
+\r
+ for(i=0; i<attr_count; i++) {\r
+ if(KHM_FAILED(kcdb_buf_get_attr(d->record, attrs[i], NULL, NULL, NULL)))\r
+ continue;\r
+\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;\r
+ lvi.iItem = (int) i;\r
+ lvi.iSubItem = 0;\r
+ lvi.pszText = buffer;\r
+ lvi.lParam = (LPARAM) attrs[i];\r
+\r
+ t = cb_buf;\r
+ kcdb_attrib_describe(attrs[i], buffer, &t, KCDB_TS_SHORT);\r
+\r
+ idx = ListView_InsertItem(hwnd_lv, &lvi);\r
+\r
+ ZeroMemory(&lvi, sizeof(lvi));\r
+ lvi.mask = LVIF_TEXT;\r
+ lvi.iItem = idx;\r
+ lvi.iSubItem = 1;\r
+ lvi.pszText = buffer;\r
+\r
+ t = cb_buf;\r
+ kcdb_buf_get_attr_string(d->record, attrs[i], buffer, &t, 0);\r
+\r
+ ListView_SetItem(hwnd_lv, &lvi);\r
+ }\r
+\r
+ free(attrs);\r
+ free(buffer);\r
+ }\r
+}\r
+\r
+LRESULT CALLBACK khui_property_wnd_proc(\r
+ HWND hwnd,\r
+ UINT msg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ BOOL child_msg = FALSE;\r
+ pw_data * child;\r
+\r
+ switch(msg) {\r
+ case WM_CREATE: \r
+ {\r
+ CREATESTRUCT * cs;\r
+ LVCOLUMN lvc;\r
+ wchar_t sz_title[256];\r
+\r
+ cs = (CREATESTRUCT *) lParam;\r
+\r
+ child = malloc(sizeof(*child));\r
+ ZeroMemory(child, sizeof(*child));\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable:4244)\r
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) child);\r
+#pragma warning(pop)\r
+\r
+ child->hwnd_lv = CreateWindow(\r
+ WC_LISTVIEW, \r
+ L"",\r
+ WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |\r
+ LVS_REPORT | LVS_SORTASCENDING,\r
+ 0, 0,\r
+ cs->cx, cs->cy,\r
+ hwnd, \r
+ (HMENU) ID_LISTVIEW, \r
+ khm_hInstance, \r
+ NULL);\r
+\r
+ ListView_SetExtendedListViewStyle(child->hwnd_lv, \r
+ LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);\r
+\r
+ ZeroMemory(&lvc, sizeof(lvc));\r
+ lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_TEXT | LVCF_WIDTH;\r
+ lvc.fmt = LVCFMT_LEFT;\r
+ lvc.cx = (cs->cx * 2)/ 5;\r
+ lvc.pszText = sz_title;\r
+ lvc.iSubItem = 0;\r
+ lvc.iOrder = 0;\r
+ LoadString(khm_hInstance, IDS_PROP_COL_PROPERTY, sz_title, ARRAYLENGTH(sz_title));\r
+\r
+ ListView_InsertColumn(child->hwnd_lv, 0, &lvc);\r
+\r
+ ZeroMemory(&lvc, sizeof(lvc));\r
+ lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;\r
+ lvc.fmt = LVCFMT_LEFT;\r
+ lvc.cx = (cs->cx * 3)/ 5;\r
+ lvc.pszText = sz_title;\r
+ lvc.iSubItem = 1;\r
+ lvc.iOrder = 1;\r
+ LoadString(khm_hInstance, IDS_PROP_COL_VALUE, sz_title, ARRAYLENGTH(sz_title));\r
+\r
+ ListView_InsertColumn(child->hwnd_lv, 1, &lvc);\r
+\r
+ if(cs->lpCreateParams != NULL) {\r
+ child->record = cs->lpCreateParams;\r
+ kcdb_buf_hold(child->record);\r
+ pw_update_property_data(hwnd, child);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case PW_WM_SET_RECORD:\r
+ {\r
+ child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ kcdb_buf_release(child->record);\r
+ child->record = (khm_handle) lParam;\r
+ kcdb_buf_hold(child->record);\r
+ pw_update_property_data(hwnd, child);\r
+ }\r
+ return 0;\r
+\r
+ case WM_DESTROY:\r
+ {\r
+ child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ kcdb_buf_release(child->record);\r
+ free(child);\r
+ }\r
+ break;\r
+\r
+ case WM_PAINT:\r
+ break;\r
+\r
+ default:\r
+ child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\r
+ child_msg = TRUE;\r
+ }\r
+\r
+ /*\r
+ if(child_msg && child && child->hwnd_lv)\r
+ return SendMessage(child->hwnd_lv, msg, wParam, lParam);\r
+ else\r
+ */\r
+ return DefWindowProc(hwnd, msg, wParam, lParam);\r
+}\r
+\r
+khm_int32 khm_register_propertywnd_class(void)\r
+{\r
+ WNDCLASSEX wcx;\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = CS_DBLCLKS;\r
+ wcx.lpfnWndProc = khui_property_wnd_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = sizeof(LONG_PTR);\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = NULL;\r
+ wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);\r
+ wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_PROPERTYWND_CLASS_NAME;\r
+ wcx.hIconSm = NULL;\r
+\r
+ khui_propertywnd_cls = RegisterClassEx(&wcx);\r
+\r
+ return (khui_propertywnd_cls == 0)?KHM_ERROR_UNKNOWN:KHM_ERROR_SUCCESS;\r
+}\r
+\r
+khm_int32 khm_unregister_propertywnd_class(void)\r
+{\r
+ UnregisterClass(MAKEINTATOM(khui_propertywnd_cls), khm_hInstance);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_PROPERTYWND_H\r
+#define __KHIMAIRA_PROPERTYWND_H\r
+\r
+#define KHUI_PROPERTYWND_CLASS_NAME L"NetIDMgrPropertyWnd"\r
+\r
+khm_int32 khm_register_propertywnd_class(void);\r
+\r
+khm_int32 khm_unregister_propertywnd_class(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+ATOM reqdaemon_atom = 0;\r
+HANDLE reqdaemon_thread = NULL;\r
+HWND reqdaemon_hwnd = NULL;\r
+\r
+LRESULT CALLBACK\r
+reqdaemonwnd_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam) {\r
+\r
+ switch(uMsg) {\r
+ case WM_CREATE:\r
+ break;\r
+\r
+ case WM_CLOSE:\r
+ DestroyWindow(hwnd);\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ reqdaemon_hwnd = NULL;\r
+ PostQuitMessage(0);\r
+ break;\r
+\r
+ /* Leash compatibility */\r
+ case ID_OBTAIN_TGT_WITH_LPARAM:\r
+ {\r
+ wchar_t widname[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t wmapping[ARRAYLENGTH(KHUI_REQD_MAPPING_FORMAT) + 10];\r
+ khm_handle identity = NULL;\r
+ LPNETID_DLGINFO pdlginfo;\r
+ LRESULT lr = 1;\r
+ khm_int32 result;\r
+ HANDLE hmap = NULL;\r
+ HRESULT hr;\r
+\r
+ hr = StringCbPrintf(wmapping, sizeof(wmapping),\r
+ KHUI_REQD_MAPPING_FORMAT, (DWORD) lParam);\r
+#ifdef DEBUG\r
+ assert(SUCCEEDED(hr));\r
+#endif\r
+ hmap = CreateFileMapping(INVALID_HANDLE_VALUE,\r
+ NULL,\r
+ PAGE_READWRITE,\r
+ 0, 4096,\r
+ wmapping);\r
+\r
+ if (hmap == NULL) {\r
+ return -1;\r
+ } else if (hmap != NULL && GetLastError() != ERROR_ALREADY_EXISTS) {\r
+ CloseHandle(hmap);\r
+ return -1;\r
+ }\r
+\r
+ pdlginfo = MapViewOfFile(hmap,\r
+ FILE_MAP_WRITE,\r
+ 0, 0,\r
+ sizeof(*pdlginfo));\r
+\r
+ if (pdlginfo == NULL) {\r
+ CloseHandle(hmap);\r
+ return 1;\r
+ }\r
+\r
+ if (pdlginfo->in.username[0] &&\r
+ pdlginfo->in.realm[0] &&\r
+ SUCCEEDED(StringCbPrintf(widname,\r
+ sizeof(widname),\r
+ L"%s@%s",\r
+ pdlginfo->in.username,\r
+ pdlginfo->in.realm))) {\r
+\r
+ kcdb_identity_create(widname,\r
+ KCDB_IDENT_FLAG_CREATE,\r
+ &identity);\r
+\r
+ }\r
+\r
+ do {\r
+ if (khm_cred_is_in_dialog()) {\r
+ khm_cred_wait_for_dialog(INFINITE, NULL);\r
+ }\r
+\r
+ if (identity)\r
+ khui_context_set_ex(KHUI_SCOPE_IDENT,\r
+ identity,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ NULL,\r
+ pdlginfo,\r
+ sizeof(*pdlginfo));\r
+ else\r
+ khui_context_reset();\r
+\r
+\r
+ if (pdlginfo->dlgtype == NETID_DLGTYPE_TGT)\r
+ SendMessage(khm_hwnd_main, WM_COMMAND,\r
+ MAKEWPARAM(KHUI_ACTION_NEW_CRED, 0), 0);\r
+ else if (pdlginfo->dlgtype == NETID_DLGTYPE_CHPASSWD)\r
+ SendMessage(khm_hwnd_main, WM_COMMAND,\r
+ MAKEWPARAM(KHUI_ACTION_PASSWD_ID, 0), 0);\r
+ else\r
+ break;\r
+\r
+ if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE, &result)))\r
+ continue;\r
+ else {\r
+ lr = (result != KHUI_NC_RESULT_GET_CREDS);\r
+ break;\r
+ }\r
+ } while(TRUE);\r
+\r
+ if (pdlginfo)\r
+ UnmapViewOfFile(pdlginfo);\r
+ if (hmap)\r
+ CloseHandle(hmap);\r
+\r
+ return lr;\r
+ }\r
+\r
+#if 0\r
+ /* deprecated */\r
+ case ID_OBTAIN_TGT_WITH_LPARAM:\r
+ {\r
+ char * param = (char *) GlobalLock((HGLOBAL) lParam);\r
+ char * username = NULL;\r
+ char * realm = NULL;\r
+ char * title = NULL;\r
+ char * ccache = NULL;\r
+ wchar_t widname[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t wtitle[KHUI_MAXCCH_TITLE];\r
+ size_t cch;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle identity = NULL;\r
+ NETID_DLGINFO dlginfo;\r
+\r
+ if (param) {\r
+ if (*param)\r
+ title = param;\r
+\r
+ if (FAILED(StringCchLengthA(param, KHUI_MAXCCH_TITLE, &cch))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit_tgt_with_lparam;\r
+ }\r
+\r
+ param += cch + 1;\r
+\r
+ if (*param)\r
+ username = param;\r
+\r
+ if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit_tgt_with_lparam;\r
+ }\r
+\r
+ param += cch + 1;\r
+\r
+ if (*param)\r
+ realm = param;\r
+\r
+ if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit_tgt_with_lparam;\r
+ }\r
+\r
+ param += cch + 1;\r
+\r
+ if (*param)\r
+ ccache = param;\r
+ }\r
+\r
+ if (username && realm) {\r
+\r
+ if (FAILED(StringCbPrintf(widname, sizeof(widname),\r
+ L"%hs@%hs", username, realm))) {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ goto _exit_tgt_with_lparam;\r
+ }\r
+\r
+ rv = kcdb_identity_create(widname,\r
+ KCDB_IDENT_FLAG_CREATE,\r
+ &identity);\r
+ if (KHM_FAILED(rv)) {\r
+ goto _exit_tgt_with_lparam;\r
+ }\r
+ }\r
+\r
+ ZeroMemory(&dlginfo, sizeof(dlginfo));\r
+\r
+ dlginfo.size = NETID_DLGINFO_V1_SZ;\r
+ dlginfo.dlgtype = NETID_DLGTYPE_TGT;\r
+ \r
+ if (title)\r
+ StringCbCopy(dlginfo.in.title, sizeof(dlginfo.in.title),\r
+ wtitle);\r
+ if (username)\r
+ AnsiStrToUnicode(dlginfo.in.username, sizeof(dlginfo.in.username),\r
+ username);\r
+ if (realm)\r
+ AnsiStrToUnicode(dlginfo.in.realm, sizeof(dlginfo.in.realm),\r
+ realm);\r
+\r
+ if (ccache)\r
+ AnsiStrToUnicode(dlginfo.in.ccache, sizeof(dlginfo.in.ccache),\r
+ ccache);\r
+\r
+ dlginfo.in.use_defaults = TRUE;\r
+\r
+ do {\r
+ if (khm_cred_is_in_dialog()) {\r
+ khm_cred_wait_for_dialog(INFINITE);\r
+ }\r
+\r
+ khui_context_set_ex(KHUI_SCOPE_IDENT,\r
+ identity,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ NULL,\r
+ &dlginfo,\r
+ sizeof(dlginfo));\r
+\r
+ if (title) {\r
+ AnsiStrToUnicode(wtitle, sizeof(wtitle),\r
+ title);\r
+\r
+ khm_cred_obtain_new_creds(wtitle);\r
+ } else {\r
+ khm_cred_obtain_new_creds(NULL);\r
+ }\r
+\r
+ if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE)))\r
+ continue;\r
+ else\r
+ break;\r
+ } while(TRUE);\r
+\r
+ _exit_tgt_with_lparam:\r
+ if (identity)\r
+ kcdb_identity_release(identity);\r
+\r
+ GlobalUnlock((HGLOBAL) lParam);\r
+ }\r
+ return 0;\r
+#endif\r
+\r
+ }\r
+\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+DWORD WINAPI\r
+khm_reqdaemon_thread_proc(LPVOID vparam) {\r
+ BOOL rv;\r
+ MSG msg;\r
+ DWORD dw;\r
+\r
+ khm_register_reqdaemonwnd_class();\r
+\r
+#ifdef DEBUG\r
+ assert(reqdaemon_atom != 0);\r
+#endif\r
+\r
+ reqdaemon_hwnd = CreateWindowEx(0,\r
+ MAKEINTATOM(reqdaemon_atom),\r
+ KHUI_REQDAEMONWND_NAME,\r
+ 0,\r
+ 0,0,0,0,\r
+ HWND_MESSAGE,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+#ifdef DEBUG\r
+ dw = GetLastError();\r
+ assert(reqdaemon_hwnd != NULL);\r
+#endif\r
+\r
+ while(rv = GetMessage(&msg, NULL, 0, 0)) {\r
+ if (rv == -1) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ break;\r
+ } else {\r
+ TranslateMessage(&msg);\r
+ DispatchMessage(&msg);\r
+ }\r
+ }\r
+\r
+ reqdaemon_thread = NULL;\r
+\r
+ khm_unregister_reqdaemonwnd_class();\r
+\r
+ return 0;\r
+}\r
+\r
+void\r
+khm_register_reqdaemonwnd_class(void) {\r
+ WNDCLASSEX wcx;\r
+\r
+ ZeroMemory(&wcx, sizeof(wcx));\r
+\r
+ wcx.cbSize = sizeof(wcx);\r
+ wcx.style = 0;\r
+ wcx.lpfnWndProc = reqdaemonwnd_proc;\r
+ wcx.cbClsExtra = 0;\r
+ wcx.cbWndExtra = 0;\r
+ wcx.hInstance = khm_hInstance;\r
+ wcx.hIcon = NULL;\r
+ wcx.hCursor = NULL;\r
+ wcx.hbrBackground = NULL;\r
+ wcx.lpszMenuName = NULL;\r
+ wcx.lpszClassName = KHUI_REQDAEMONWND_CLASS;\r
+ wcx.hIconSm = NULL;\r
+\r
+ reqdaemon_atom = RegisterClassEx(&wcx);\r
+\r
+#ifdef DEBUG\r
+ assert(reqdaemon_atom != 0);\r
+#endif \r
+}\r
+\r
+void\r
+khm_unregister_reqdaemonwnd_class(void) {\r
+ if (reqdaemon_atom != 0) {\r
+ UnregisterClass(MAKEINTATOM(reqdaemon_atom), khm_hInstance);\r
+ reqdaemon_atom = 0;\r
+ }\r
+}\r
+\r
+void\r
+khm_init_request_daemon(void) {\r
+#ifdef DEBUG\r
+ assert(reqdaemon_thread == NULL);\r
+#endif\r
+\r
+ reqdaemon_thread = CreateThread(NULL,\r
+ 0,\r
+ khm_reqdaemon_thread_proc,\r
+ NULL,\r
+ 0,\r
+ NULL);\r
+\r
+#ifdef DEBUG\r
+ assert(reqdaemon_thread != NULL);\r
+#endif \r
+}\r
+\r
+void\r
+khm_exit_request_daemon(void) {\r
+ if (reqdaemon_hwnd == NULL)\r
+ return;\r
+\r
+ SendMessage(reqdaemon_hwnd, WM_CLOSE, 0, 0);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_REQDAEMON_H\r
+#define __KHIMAIRA_REQDAEMON_H\r
+\r
+void\r
+khm_register_reqdaemonwnd_class(void);\r
+\r
+void\r
+khm_unregister_reqdaemonwnd_class(void);\r
+\r
+void\r
+khm_init_request_daemon(void);\r
+\r
+void\r
+khm_exit_request_daemon(void);\r
+\r
+#endif\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by D:\work\khimaira\src\ui\lang\en_us\khapp.rc\r
+//\r
+#define IDI_MAIN_APP 104\r
+#define IDD_PROPPAGE_MEDIUM 106\r
+#define IDD_PP_CRED 106\r
+#define IDD_PP_IDENT 107\r
+#define IDB_TK_REFRESH 108\r
+#define IDS_MAIN_WINDOW_TITLE 108\r
+#define IDS_MENU_FILE 109\r
+#define IDB_ID 110\r
+#define IDS_MENU_IDENTITY 110\r
+#define IDS_MENU_CRED 110\r
+#define IDB_ID_DELETE 111\r
+#define IDS_MENU_VIEW 111\r
+#define IDB_ID_NEW 112\r
+#define IDS_MENU_OPTIONS 112\r
+#define IDB_ID_REFRESH 113\r
+#define IDS_MENU_HELP 113\r
+#define IDB_TK 114\r
+#define IDS_ACTION_PROPERTIES 114\r
+#define IDB_TK_DELETE 115\r
+#define IDS_ACTION_EXIT 115\r
+#define IDB_TK_NEW 116\r
+#define IDS_ACTION_NEW_ID 116\r
+#define IDS_CFG_ROOT_NAME 116\r
+#define IDS_ACTION_SET_DEF_ID 117\r
+#define IDS_ACTION_SET_SRCH_ID 118\r
+#define IDB_VW_REFRESH_SM 118\r
+#define IDS_ACTION_DESTROY_ID 119\r
+#define IDR_MENU_BAR 119\r
+#define IDS_CFG_ROOT_TITLE 119\r
+#define IDS_ACTION_RENEW_ID 120\r
+#define IDS_CFG_GENERAL_SHORT 120\r
+#define IDS_ACTION_ADD_CRED 121\r
+#define IDB_TB_BLANK 121\r
+#define IDS_ACTION_NEW_CRED 121\r
+#define IDS_ACTION_PASSWD_ID 122\r
+#define IDS_ACTION_CHOOSE_COLS 123\r
+#define IDB_TB_BLANK_SM 123\r
+#define IDS_ACTION_DEBUG_WINDOW 124\r
+#define IDB_VW_REFRESH 124\r
+#define IDS_ACTION_VIEW_REFRESH 125\r
+#define IDB_ID_DELETE_DIS 125\r
+#define IDS_MENU_LAYOUT 126\r
+#define IDB_ID_DELETE_DIS_SM 126\r
+#define IDS_MENU_TOOLBARS 127\r
+#define IDB_ID_DELETE_SM 127\r
+#define IDS_ACTION_LAYOUT_ID 128\r
+#define IDB_ID_DIS 128\r
+#define IDS_ACTION_LAYOUT_TYPE 129\r
+#define IDB_ID_DIS_SM 129\r
+#define IDS_ACTION_LAYOUT_LOC 130\r
+#define IDB_ID_NEW_DIS 130\r
+#define IDS_ACTION_TB_STANDARD 131\r
+#define IDB_ID_NEW_DIS_SM 131\r
+#define IDS_ACTION_OPT_KHIM 132\r
+#define IDB_ID_NEW_SM 132\r
+#define IDS_ACTION_OPT_INIT 133\r
+#define IDB_ID_REFRESH_DIS 133\r
+#define IDS_ACTION_OPT_IDENTS 133\r
+#define IDS_ACTION_OPT_NOTIF 134\r
+#define IDB_ID_REFRESH_SM 134\r
+#define IDS_ACTION_HELP_CTX 135\r
+#define IDB_ID_REFRESH_DIS_SM 135\r
+#define IDS_ACTION_HELP_CONTENTS 136\r
+#define IDB_TK_DELETE_DIS 136\r
+#define IDS_ACTION_HELP_INDEX 137\r
+#define IDB_TK_DELETE_DIS_SM 137\r
+#define IDS_ACTION_HELP_ABOUT 138\r
+#define IDB_TK_DELETE_SM 138\r
+#define IDB_TK_DIS_SM 139\r
+#define IDS_ACTIONINFO_NEW_ID 139\r
+#define IDS_CFG_GENERAL_LONG 139\r
+#define IDB_TK_NEW_DIS 140\r
+#define IDS_SAMPLE_STRING 140\r
+#define IDB_TK_NEW_DIS_SM 141\r
+#define IDS_NO_CREDS 141\r
+#define IDB_TK_NEW_SM 142\r
+#define IDS_WT_INIT_CREDS 142\r
+#define IDB_TK_REFRESH_DIS 143\r
+#define IDS_WT_NEW_CREDS 143\r
+#define IDB_TK_REFRESH_DIS_SM 144\r
+#define IDS_NC_PASSWORD 144\r
+#define IDS_NC_IDENTITY 144\r
+#define IDB_TK_REFRESH_SM 145\r
+#define IDS_NC_IDENTS 145\r
+#define IDB_TK_SM 146\r
+#define IDS_NC_CREDTEXT_ID_NONE 146\r
+#define IDB_HELP_SM 147\r
+#define IDS_NC_CREDTEXT_ID_ONE 147\r
+#define IDB_HELP 148\r
+#define IDS_NC_CREDTEXT_ID_MANY 148\r
+#define IDB_LOGO_SHADE 149\r
+#define IDS_NC_CREDTEXT_ID_INVALID 149\r
+#define IDI_WGT_COLLAPSE 150\r
+#define IDS_WTPOST_INIT_CREDS 150\r
+#define IDI_WGT_EXPAND 151\r
+#define IDS_WTPOST_NEW_CREDS 151\r
+#define IDB_WDG_EXPAND 152\r
+#define IDS_ACTION_RENEW_CRED 152\r
+#define IDB_WDG_COLLAPSE 153\r
+#define IDS_ACTION_DESTROY_CRED 153\r
+#define IDB_ID_SM 154\r
+#define IDS_DEFAULT_FONT 154\r
+#define IDB_WDG_EXPAND_HI 155\r
+#define IDS_NC_CREDTEXT_TABS 155\r
+#define IDB_WDG_COLLAPSE_HI 156\r
+#define IDS_NOTIFY_PREFIX 156\r
+#define IDB_WDG_CREDTYPE 157\r
+#define IDS_NOTIFY_READY 157\r
+#define IDB_WDG_FLAG 158\r
+#define IDS_NOTIFY_ATTENTION 158\r
+#define IDB_FLAG_WARN 159\r
+#define IDS_ALERT_DEFAULT 159\r
+#define IDB_FLAG_EXPIRED 160\r
+#define IDS_PACTION_OK 160\r
+#define IDB_FLAG_CRITICAL 161\r
+#define IDS_PACTION_CANCEL 161\r
+#define IDD_NC_PASSWORD 162\r
+#define IDS_PACTION_CLOSE 162\r
+#define IDD_NC_NEWCRED 162\r
+#define IDD_NC_BBAR 163\r
+#define IDS_ALERT_NOSEL_TITLE 163\r
+#define IDD_NC_TS 164\r
+#define IDS_ALERT_NOSEL 164\r
+#define IDI_ENABLED 165\r
+#define IDS_NC_CREDTEXT_ID_VALID 165\r
+#define IDI_DISABLED 166\r
+#define IDS_NC_CREDTEXT_ID_UNCHECKED 166\r
+#define IDS_PROP_COL_PROPERTY 167\r
+#define IDS_PROP_COL_VALUE 168\r
+#define IDI_NOTIFY_NONE 169\r
+#define IDS_NC_NEW_IDENT 169\r
+#define IDI_NOTIFY_INFO 170\r
+#define IDS_NC_CREDTEXT_ID_CHECKING 170\r
+#define IDI_NOTIFY_WARN 171\r
+#define IDS_ACTION_OPEN_APP 171\r
+#define IDI_NOTIFY_ERROR 172\r
+#define IDS_CTX_NEW_IDENT 172\r
+#define IDS_CTX_NEW_CREDS 173\r
+#define IDD_CFG_MAIN 173\r
+#define IDS_CTX_RENEW_CREDS 174\r
+#define IDD_CFG_GENERIC 174\r
+#define IDS_CTX_PROC_NEW_IDENT 175\r
+#define IDB_LOGO_OPAQUE 175\r
+#define IDS_CTX_PROC_NEW_CREDS 176\r
+#define IDD_CFG_GENERAL 176\r
+#define IDS_CTX_PROC_RENEW_CREDS 177\r
+#define IDD_CFG_IDENTITIES 177\r
+#define IDS_ACTION_CLOSE_APP 178\r
+#define IDD_CFG_NOTIF 178\r
+#define IDS_NC_FAILED_TITLE 179\r
+#define IDD_CFG_PLUGINS 179\r
+#define IDS_CFG_IDENTITIES_SHORT 180\r
+#define IDD_CFG_IDENTITY 180\r
+#define IDS_CFG_IDENTITIES_LONG 181\r
+#define IDI_CFG_DEFAULT 181\r
+#define IDS_CFG_NOTIF_SHORT 182\r
+#define IDI_CFG_MODIFIED 182\r
+#define IDS_CFG_NOTIF_LONG 183\r
+#define IDI_CFG_APPLIED 183\r
+#define IDS_CFG_PLUGINS_SHORT 184\r
+#define IDD_CFG_IDS_TAB 184\r
+#define IDS_CFG_PLUGINS_LONG 185\r
+#define IDD_CFG_ID_TAB 185\r
+#define IDS_CFG_IDENTITY_SHORT 186\r
+#define IDI_CFG_DELETED 186\r
+#define IDS_CFG_IDENTITY_LONG 187\r
+#define IDI_ICON1 187\r
+#define IDI_ID 187\r
+#define IDS_CTX_DESTROY_CREDS 188\r
+#define IDB_IMPORT_SM_DIS 188\r
+#define IDS_WARN_EXPIRE 189\r
+#define IDB_IMPORT 189\r
+#define IDS_WARN_TITLE 190\r
+#define IDB_IMPORT_DIS 190\r
+#define IDS_ALERT_MOREINFO 191\r
+#define IDB_IMPORT_SM 191\r
+#define IDS_WARN_EXPIRED 192\r
+#define IDB_CHPW_SM 192\r
+#define IDS_WARN_EXPIRE_ID 193\r
+#define IDB_CHPW 193\r
+#define IDS_WARN_EXPIRED_ID 194\r
+#define IDB_CHPW_DIS 194\r
+#define IDS_WARN_WM_TITLE 195\r
+#define IDB_CHPW_DIS_SM 195\r
+#define IDS_WARN_WM_MSG 196\r
+#define IDD_ABOUT 196\r
+#define IDS_CFG_ID_TAB_SHORT 197\r
+#define IDB_TB_SPACE 197\r
+#define IDS_CFG_ID_TAB_LONG 198\r
+#define IDS_CFG_IDS_TAB_SHORT 199\r
+#define IDS_CFG_IDS_TAB_LONG 200\r
+#define IDS_CFG_IDS_IDENTITY 201\r
+#define IDS_ACTION_IMPORT 202\r
+#define IDS_CTX_IMPORT 203\r
+#define IDS_CFG_PI_COL_PLUGINS 204\r
+#define IDS_PISTATE_FAILUNK 205\r
+#define IDS_PISTATE_FAILMAX 206\r
+#define IDS_PISTATE_FAILREG 207\r
+#define IDS_PISTATE_FAILDIS 208\r
+#define IDS_PISTATE_FAILLOD 209\r
+#define IDS_PISTATE_PLACEHOLD 210\r
+#define IDS_PISTATE_REG 211\r
+#define IDS_PISTATE_HOLD 212\r
+#define IDS_PISTATE_INIT 213\r
+#define IDS_PISTATE_RUN 214\r
+#define IDS_PISTATE_EXIT 215\r
+#define IDS_CTX_PASSWORD 216\r
+#define IDS_WT_PASSWORD 217\r
+#define IDS_WTPOST_PASSWORD 218\r
+#define IDS_CTX_PROC_PASSWORD 219\r
+#define IDS_NC_PWD_FAILED_TITLE 220\r
+#define IDS_CMDLINE_HELP 221\r
+#define IDC_NC_USERNAME 1007\r
+#define IDC_NC_PASSWORD 1008\r
+#define IDC_NC_CREDTEXT_LABEL 1009\r
+#define IDC_NC_PASSWORD_LABEL 1010\r
+#define IDC_NC_USERNAME_LABEL 1011\r
+#define IDC_NC_CREDTEXT 1012\r
+#define IDC_NC_HELP 1017\r
+#define IDC_NC_OPTIONS 1019\r
+#define IDC_PP_IDNAME 1026\r
+#define IDC_PP_IDDEF 1027\r
+#define IDC_PP_IDSEARCH 1028\r
+#define IDC_PP_IDSTATUS 1029\r
+#define IDC_PP_IDSTATUSIMG 1030\r
+#define IDC_PP_IDVALID 1031\r
+#define IDC_PP_IDRENEW 1032\r
+#define IDC_NC_IDENTITY 1033\r
+#define IDC_NC_IDENTITY_LABEL 1034\r
+#define IDC_PP_PROPLIST 1035\r
+#define IDC_PP_CPROPLIST 1036\r
+#define IDC_NC_REALM 1037\r
+#define IDC_NC_REALM_LABEL 1038\r
+#define IDC_NC_TPL_ROW 1039\r
+#define IDC_NC_TPL_PANEL 1040\r
+#define IDC_NC_TPL_LABEL 1041\r
+#define IDC_NC_TPL_INPUT 1042\r
+#define IDC_NC_TPL_LABEL_LG 1043\r
+#define IDC_NC_TPL_INPUT_LG 1044\r
+#define IDC_NC_TPL_ROW2 1045\r
+#define IDC_NC_TPL_ROW_LG 1045\r
+#define IDC_CFG_NODELIST 1045\r
+#define IDAPPLY 1048\r
+#define IDC_CFG_SUMMARY 1049\r
+#define IDC_CFG_TITLE 1050\r
+#define IDC_CFG_PANE 1051\r
+#define IDC_NOTIF_MONITOR 1053\r
+#define IDC_PP_DUMMY 1054\r
+#define IDC_NOTIF_RENEW 1055\r
+#define IDC_NOTIF_RENEW_THR 1056\r
+#define IDC_NOTIF_WARN1 1057\r
+#define IDC_NOTIF_WARN1_THR 1058\r
+#define IDC_NOTIF_WARN2 1059\r
+#define IDC_NOTIF_WARN2_THR 1060\r
+#define IDC_CFG_KEEPRUNNING 1061\r
+#define IDC_CFG_STARTUP_GROUP 1062\r
+#define IDC_CFG_AUTOSTART 1063\r
+#define IDC_CFG_AUTOIMPORT 1064\r
+#define IDC_CFG_AUTOINIT 1065\r
+#define IDC_CFG_OTHER 1066\r
+#define IDC_CFG_MONITOR 1069\r
+#define IDC_CFG_STICKY 1070\r
+#define IDC_CFG_IDENTS 1071\r
+#define IDC_CFG_IDENTITY 1072\r
+#define IDC_CFG_RENEW 1075\r
+#define IDC_CFG_REMOVE 1076\r
+#define IDC_CFG_TAB 1077\r
+#define IDC_CFG_TARGET 1078\r
+#define IDC_CFG_PLUGINS 1079\r
+#define IDC_CFG_PLUGINGRP 1080\r
+#define IDC_CFG_LBL_DESC 1083\r
+#define IDC_CFG_DESC 1084\r
+#define IDC_CFG_LBL_STATE 1085\r
+#define IDC_CFG_STATE 1086\r
+#define IDC_CFG_LBL_DEPS 1087\r
+#define IDC_CFG_DEPS 1088\r
+#define IDC_CFG_DISABLE 1089\r
+#define IDC_CFG_ENABLE 1090\r
+#define IDC_CFG_PROVGRP 1091\r
+#define IDC_CFG_LBL_MOD 1092\r
+#define IDC_CFG_MODULE 1093\r
+#define IDC_CFG_LBL_VEN 1094\r
+#define IDC_CFG_VENDOR 1095\r
+#define IDC_CFG_REGISTER 1097\r
+#define IDC_CFG_NETDETECT 1098\r
+#define IDC_PP_STICKY 1099\r
+#define IDC_PRODUCT 1100\r
+#define IDC_COPYRIGHT 1101\r
+#define IDC_BUILDINFO 1102\r
+#define IDC_LIST1 1103\r
+#define IDC_MODULES 1103\r
+#define IDA_ACTIVATE_MENU 40003\r
+#define IDA_UP 40004\r
+#define IDA_DOWN 40005\r
+#define IDA_LEFT 40006\r
+#define IDA_RIGHT 40007\r
+#define IDA_ESC 40008\r
+#define IDA_ENTER 40009\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 198\r
+#define _APS_NEXT_COMMAND_VALUE 40010\r
+#define _APS_NEXT_CONTROL_VALUE 1104\r
+#define _APS_NEXT_SYMED_VALUE 101\r
+#endif\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+\r
+khui_statusbar_part khui_statusbar_parts[] = {\r
+ {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER},\r
+ {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE},\r
+ {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE}\r
+};\r
+\r
+int khui_n_statusbar_parts = sizeof(khui_statusbar_parts) / sizeof(khui_statusbar_part);\r
+\r
+HWND khui_hwnd_statusbar = NULL;\r
+\r
+void khui_statusbar_set_parts(HWND parent) {\r
+ int i;\r
+ int fillerwidth;\r
+ int staticwidth;\r
+ int lastx;\r
+ int width;\r
+ RECT r;\r
+ INT * parts;\r
+\r
+ GetClientRect(parent, &r);\r
+ width = r.right - r.left;\r
+\r
+ /* calculate fillerwidth and staticwidth */\r
+ staticwidth = 0;\r
+ for(i=0;i<khui_n_statusbar_parts;i++) {\r
+ if(khui_statusbar_parts[i].wtype == KHUI_SB_WTYPE_ABSOLUTE) {\r
+ staticwidth += khui_statusbar_parts[i].width;\r
+ } else if(khui_statusbar_parts[i].wtype == KHUI_SB_WTYPE_RELATIVE) {\r
+ staticwidth += (khui_statusbar_parts[i].width * width) / 100;\r
+ }\r
+ }\r
+\r
+ fillerwidth = width - staticwidth;\r
+\r
+ parts = malloc(sizeof(INT) * khui_n_statusbar_parts);\r
+\r
+ lastx = 0;\r
+ for(i=0;i<khui_n_statusbar_parts;i++) {\r
+ int w;\r
+ switch(khui_statusbar_parts[i].wtype) {\r
+ case KHUI_SB_WTYPE_ABSOLUTE:\r
+ w = khui_statusbar_parts[i].width;\r
+ break;\r
+\r
+ case KHUI_SB_WTYPE_RELATIVE:\r
+ w = (khui_statusbar_parts[i].width * width) / 100;\r
+ break;\r
+\r
+ case KHUI_SB_WTYPE_FILLER:\r
+ w = fillerwidth;\r
+ break;\r
+ }\r
+ lastx += w;\r
+\r
+ if(i==khui_n_statusbar_parts - 1)\r
+ parts[i] = -1;\r
+ else\r
+ parts[i] = lastx;\r
+ }\r
+\r
+ SendMessage(\r
+ khui_hwnd_statusbar,\r
+ SB_SETPARTS,\r
+ khui_n_statusbar_parts,\r
+ (LPARAM) parts);\r
+\r
+ free(parts);\r
+}\r
+\r
+void khui_create_statusbar(HWND parent) {\r
+ HWND hwsb;\r
+\r
+ hwsb = CreateWindowEx(\r
+ 0,\r
+ STATUSCLASSNAME,\r
+ NULL,\r
+ SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE,\r
+ 0,0,0,0,\r
+ parent,\r
+ NULL,\r
+ khm_hInstance,\r
+ NULL);\r
+\r
+ if(!hwsb)\r
+ return;\r
+\r
+ khui_hwnd_statusbar = hwsb;\r
+\r
+ khui_statusbar_set_parts(parent);\r
+}\r
+\r
+void khui_update_statusbar(HWND parent) {\r
+ MoveWindow(khui_hwnd_statusbar, 0, 0, 0, 0, TRUE);\r
+ khui_statusbar_set_parts(parent);\r
+}\r
+\r
+int sb_find_index(int id) {\r
+ int i;\r
+\r
+ for(i=0;i<khui_n_statusbar_parts;i++) {\r
+ if(khui_statusbar_parts[i].id == id)\r
+ return i;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+void khui_statusbar_set_text(int id, wchar_t * text) {\r
+ int idx;\r
+\r
+ idx = sb_find_index(id);\r
+ if(idx < 0)\r
+ return;\r
+\r
+ SendMessage(\r
+ khui_hwnd_statusbar,\r
+ SB_SETTEXT,\r
+ idx,\r
+ (LPARAM) text);\r
+}\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_STATUSBAR_H\r
+#define __KHIMAIRA_STATUSBAR_H\r
+\r
+typedef struct khui_statusbar_part_t {\r
+ int id;\r
+ int width;\r
+ int wtype; /* one of KHUI_SB_WTYPE_* */\r
+} khui_statusbar_part;\r
+\r
+#define KHUI_SB_WTYPE_RELATIVE 1\r
+#define KHUI_SB_WTYPE_ABSOLUTE 2\r
+#define KHUI_SB_WTYPE_FILLER 4\r
+\r
+/* statusbar parts */\r
+#define KHUI_SBPART_INFO 1\r
+#define KHUI_SBPART_NOTICE 2\r
+#define KHUI_SBPART_LOC 3\r
+\r
+extern HWND khui_hwnd_statusbar;\r
+extern khui_statusbar_part khui_statusbar_parts[];\r
+extern int khui_n_statusbar_parts;\r
+\r
+void khui_create_statusbar(HWND p);\r
+void khui_update_statusbar(HWND parent);\r
+void khui_statusbar_set_text(int id, wchar_t * text);\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+/* in seconds */\r
+#if 0\r
+khm_int32 khui_timeout_warn = KHUI_DEF_TIMEOUT_WARN;\r
+khm_int32 khui_timeout_crit = KHUI_DEF_TIMEOUT_CRIT;\r
+khm_int32 khui_timeout_renew = KHUI_DEF_TIMEOUT_RENEW;\r
+\r
+khm_boolean khui_do_renew = TRUE;\r
+khm_boolean khui_do_warn = TRUE;\r
+khm_boolean khui_do_crit = TRUE;\r
+#endif\r
+\r
+khui_timer_event * khui_timers = NULL;\r
+khm_size khui_n_timers = 0;\r
+khm_size khui_nc_timers = 0;\r
+\r
+CRITICAL_SECTION cs_timers;\r
+\r
+/*********************************************************************\r
+ Timers\r
+ *********************************************************************/\r
+\r
+\r
+#define KHUI_TIMER_ALLOC_INCR 16\r
+\r
+void \r
+khm_timer_init(void) {\r
+#ifdef DEBUG\r
+ assert(khui_timers == NULL);\r
+#endif\r
+\r
+ khui_nc_timers = KHUI_TIMER_ALLOC_INCR;\r
+ khui_n_timers = 0;\r
+ khui_timers = malloc(sizeof(*khui_timers) * khui_nc_timers);\r
+\r
+#ifdef DEBUG\r
+ assert(khui_timers != NULL);\r
+#endif\r
+\r
+ InitializeCriticalSection(&cs_timers);\r
+}\r
+\r
+void \r
+khm_timer_exit(void) {\r
+ EnterCriticalSection(&cs_timers);\r
+\r
+ if (khui_timers)\r
+ free(khui_timers);\r
+ khui_timers = NULL;\r
+ khui_n_timers = 0;\r
+ khui_nc_timers = 0;\r
+\r
+ LeaveCriticalSection(&cs_timers);\r
+ DeleteCriticalSection(&cs_timers);\r
+}\r
+\r
+/* called with cs_timers held */\r
+static void\r
+tmr_fire_timer(void) {\r
+ int i;\r
+ __int64 curtime;\r
+ __int64 err;\r
+ __int64 next_event;\r
+ int tmr_count[KHUI_N_TTYPES];\r
+ __int64 tmr_offset[KHUI_N_TTYPES];\r
+ int t;\r
+ khm_handle eff_ident = NULL;\r
+ khui_timer_type eff_type = 0; /* meaningless */\r
+ int fire_count = 0;\r
+\r
+ TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, \r
+ (LPFILETIME) &err);\r
+ GetSystemTimeAsFileTime((LPFILETIME) &curtime);\r
+ next_event = 0;\r
+\r
+ ZeroMemory(tmr_count, sizeof(tmr_count));\r
+ ZeroMemory(tmr_offset, sizeof(tmr_offset));\r
+\r
+ for (i=0; i < (int) khui_n_timers; i++) {\r
+ if (!(khui_timers[i].flags & \r
+ (KHUI_TE_FLAG_STALE | KHUI_TE_FLAG_EXPIRED)) &&\r
+ khui_timers[i].type != KHUI_TTYPE_ID_MARK &&\r
+ khui_timers[i].expire < curtime + err) {\r
+\r
+ t = khui_timers[i].type;\r
+\r
+ switch(t) {\r
+ case KHUI_TTYPE_ID_RENEW:\r
+ khm_cred_renew_identity(khui_timers[i].key);\r
+ khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED;\r
+ break;\r
+\r
+ case KHUI_TTYPE_CRED_RENEW:\r
+ /* the equivalence threshold for setting the timer is\r
+ a lot larger than what we are testing for here\r
+ (KHUI_TIMEEQ_ERROR vs KHUI_TIMEEQ_ERROR_SMALL) so\r
+ we assume that it is safe to trigger a renew_cred\r
+ call here without checking if there's an imminent\r
+ renew_identity call. */\r
+ khm_cred_renew_cred(khui_timers[i].key);\r
+ khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED;\r
+ break;\r
+\r
+ default:\r
+ if (t < KHUI_N_TTYPES) {\r
+ tmr_count[t]++;\r
+ if (tmr_offset[t] == 0 ||\r
+ tmr_offset[t] > khui_timers[i].offset)\r
+ tmr_offset[t] = khui_timers[i].offset;\r
+ if (next_event == 0 ||\r
+ next_event > \r
+ khui_timers[i].expire + khui_timers[i].offset)\r
+ next_event = khui_timers[i].expire +\r
+ khui_timers[i].offset;\r
+\r
+ if (eff_ident == NULL &&\r
+ (t == KHUI_TTYPE_ID_EXP ||\r
+ t == KHUI_TTYPE_ID_CRIT ||\r
+ t == KHUI_TTYPE_ID_WARN)) {\r
+ /* we don't need a hold since we will be done\r
+ with the handle before the marker is\r
+ expired (the marker is the timer with the\r
+ KHUI_TTYPE_ID_MARK which contains a held\r
+ handle and is not really a timer.) */\r
+ eff_ident = khui_timers[i].key;\r
+ eff_type = t;\r
+ }\r
+\r
+ fire_count++;\r
+\r
+ khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED;\r
+ }\r
+#ifdef DEBUG\r
+ else {\r
+ assert(FALSE);\r
+ }\r
+#endif\r
+ }\r
+ }\r
+ }\r
+\r
+ /* See if we have anything to do */\r
+ if (next_event == 0)\r
+ return;\r
+ else {\r
+ wchar_t fmt[128];\r
+ wchar_t wtime[128];\r
+ wchar_t wmsg[256];\r
+ wchar_t wtitle[64];\r
+ __int64 ft_second;\r
+ khui_alert * alert = NULL;\r
+\r
+ khm_size cb;\r
+\r
+ next_event -= curtime;\r
+\r
+ /* Due to measurement errors we may be slightly off on our\r
+ next_event calculation which shows up as '4 mins 59\r
+ seconds' instead of '5 mins' and so on when converting to a\r
+ string. So we add half a second to make the message\r
+ neater. */\r
+ TimetToFileTimeInterval(1, (LPFILETIME) &ft_second);\r
+ next_event += ft_second / 2;\r
+\r
+ cb = sizeof(wtime);\r
+\r
+ FtIntervalToString((LPFILETIME) &next_event,\r
+ wtime,\r
+ &cb);\r
+\r
+ if (fire_count == 1 &&\r
+ eff_ident != NULL &&\r
+ (eff_type == KHUI_TTYPE_ID_EXP ||\r
+ eff_type == KHUI_TTYPE_ID_CRIT ||\r
+ eff_type == KHUI_TTYPE_ID_WARN)) {\r
+\r
+ wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
+\r
+ cb = sizeof(idname);\r
+ kcdb_identity_get_name(eff_ident, idname, &cb);\r
+\r
+ if (next_event < ft_second) {\r
+ LoadString(khm_hInstance, IDS_WARN_EXPIRED_ID,\r
+ fmt, ARRAYLENGTH(fmt));\r
+\r
+ StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname);\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_WARN_EXPIRE_ID,\r
+ fmt, ARRAYLENGTH(fmt));\r
+\r
+ StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname, wtime);\r
+ }\r
+ } else {\r
+ if (next_event < ft_second) {\r
+ LoadString(khm_hInstance, IDS_WARN_EXPIRED,\r
+ wmsg, ARRAYLENGTH(wmsg));\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_WARN_EXPIRE, \r
+ fmt, ARRAYLENGTH(fmt));\r
+\r
+ StringCbPrintf(wmsg, sizeof(wmsg), fmt, wtime);\r
+ }\r
+ }\r
+\r
+ LoadString(khm_hInstance, IDS_WARN_TITLE,\r
+ wtitle, ARRAYLENGTH(wtitle));\r
+\r
+ khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert);\r
+ khui_alert_set_flags(alert, KHUI_ALERT_FLAG_REQUEST_BALLOON,\r
+ KHUI_ALERT_FLAG_REQUEST_BALLOON);\r
+ khui_alert_show(alert);\r
+ khui_alert_release(alert);\r
+ }\r
+}\r
+\r
+void \r
+khm_timer_fire(HWND hwnd) {\r
+ EnterCriticalSection(&cs_timers);\r
+ tmr_fire_timer();\r
+ LeaveCriticalSection(&cs_timers);\r
+\r
+ khm_timer_refresh(hwnd);\r
+}\r
+\r
+static int\r
+tmr_update(khm_handle key, khui_timer_type type, __int64 expire,\r
+ __int64 offset, void * data) {\r
+ int i;\r
+\r
+ for (i=0; i < (int) khui_n_timers; i++) {\r
+ if (khui_timers[i].key == key &&\r
+ khui_timers[i].type == type)\r
+ break;\r
+ }\r
+\r
+ if (i >= (int) khui_n_timers) {\r
+ i = (int) khui_n_timers;\r
+\r
+ if (i >= (int) khui_nc_timers) {\r
+ khui_timer_event * nt;\r
+#ifdef DEBUG\r
+ assert(khui_timers);\r
+#endif\r
+ khui_nc_timers = UBOUNDSS(i+1, KHUI_TIMER_ALLOC_INCR,\r
+ KHUI_TIMER_ALLOC_INCR);\r
+ nt = malloc(sizeof(*nt) * khui_nc_timers);\r
+#ifdef DEBUG\r
+ assert(nt);\r
+#endif\r
+ memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers);\r
+\r
+ free(khui_timers);\r
+ khui_timers = nt;\r
+ }\r
+\r
+ khui_timers[i].key = key;\r
+ khui_timers[i].type = type;\r
+ khui_timers[i].flags = 0;\r
+ khui_n_timers++;\r
+ }\r
+\r
+ khui_timers[i].expire = expire;\r
+ khui_timers[i].offset = offset;\r
+ khui_timers[i].data = data;\r
+\r
+ khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE;\r
+\r
+ return i;\r
+}\r
+\r
+/* called with cs_timers held */\r
+static int\r
+tmr_find(khm_handle key, khui_timer_type type,\r
+ khm_int32 and_flags, khm_int32 eq_flags) {\r
+ int i;\r
+\r
+ eq_flags &= and_flags;\r
+\r
+ for (i=0; i < (int) khui_n_timers; i++) {\r
+ if (khui_timers[i].key == key &&\r
+ khui_timers[i].type == type &&\r
+ (khui_timers[i].flags & and_flags) == eq_flags)\r
+ break;\r
+ }\r
+\r
+ if (i < (int) khui_n_timers)\r
+ return i;\r
+ else\r
+ return -1;\r
+}\r
+\r
+/* called with cs_timers held */\r
+static khm_int32 KHMAPI\r
+tmr_cred_apply_proc(khm_handle cred, void * rock) {\r
+ khm_handle ident = NULL;\r
+ int mark_idx;\r
+ int idx;\r
+ __int64 ft_expiry;\r
+ __int64 ft_current;\r
+ __int64 ft_cred_expiry;\r
+ __int64 ft;\r
+ __int64 fte;\r
+ khm_size cb;\r
+\r
+ kcdb_cred_get_identity(cred, &ident);\r
+#ifdef DEBUG\r
+ assert(ident);\r
+#endif\r
+\r
+ /* now get the expiry */\r
+ cb = sizeof(ft_expiry);\r
+ if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE,\r
+ NULL,\r
+ &ft_expiry, &cb)))\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE,\r
+ NULL,\r
+ &ft_expiry, &cb))) {\r
+ /* we don't have an expiry time to work with */\r
+ kcdb_identity_release(ident);\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ /* and the current time */\r
+ GetSystemTimeAsFileTime((LPFILETIME) &ft_current);\r
+\r
+ mark_idx = tmr_find(ident, KHUI_TTYPE_ID_MARK, 0, 0);\r
+\r
+ if (mark_idx < 0) {\r
+ mark_idx = tmr_update(ident, KHUI_TTYPE_ID_MARK, 0, 0, 0);\r
+ kcdb_identity_hold(ident);\r
+#ifdef DEBUG\r
+ assert(mark_idx >= 0);\r
+#endif\r
+ khui_timers[mark_idx].flags |= KHUI_TE_FLAG_STALE;\r
+ }\r
+\r
+ if (khui_timers[mark_idx].flags & KHUI_TE_FLAG_STALE) {\r
+ /* first time we are touching this */\r
+ khm_handle csp_cw = NULL;\r
+ khm_handle csp_id = NULL;\r
+ khm_int32 rv;\r
+ khm_int32 t;\r
+ khm_boolean do_warn = TRUE;\r
+ khm_boolean do_crit = TRUE;\r
+ khm_boolean do_renew = TRUE;\r
+ khm_boolean renew_done = FALSE;\r
+ khm_boolean monitor = TRUE;\r
+ khm_int32 to_warn = KHUI_DEF_TIMEOUT_WARN;\r
+ khm_int32 to_crit = KHUI_DEF_TIMEOUT_CRIT;\r
+ khm_int32 to_renew = KHUI_DEF_TIMEOUT_RENEW;\r
+\r
+ if (ft_expiry < ft_current)\r
+ /* already expired */\r
+ goto _done_with_ident;\r
+\r
+ rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, \r
+ &csp_cw);\r
+\r
+ assert(KHM_SUCCEEDED(rv));\r
+\r
+ rv = kcdb_identity_get_config(ident, KHM_PERM_READ, &csp_id);\r
+ if (KHM_SUCCEEDED(rv)) {\r
+ khc_shadow_space(csp_id, csp_cw);\r
+ khc_close_space(csp_cw);\r
+ } else {\r
+ csp_id = csp_cw;\r
+ }\r
+ csp_cw = NULL;\r
+\r
+ rv = khc_read_int32(csp_id, L"Monitor", &t);\r
+ if (KHM_SUCCEEDED(rv))\r
+ monitor = t;\r
+\r
+ rv = khc_read_int32(csp_id, L"AllowWarn", &t);\r
+ if (KHM_SUCCEEDED(rv))\r
+ do_warn = t;\r
+\r
+ rv = khc_read_int32(csp_id, L"AllowCritical", &t);\r
+ if (KHM_SUCCEEDED(rv)) \r
+ do_crit = t;\r
+\r
+ rv = khc_read_int32(csp_id, L"AllowAutoRenew", &t);\r
+ if (KHM_SUCCEEDED(rv))\r
+ do_renew = t;\r
+\r
+ rv = khc_read_int32(csp_id, L"WarnThreshold", &t);\r
+ if (KHM_SUCCEEDED(rv))\r
+ to_warn = t;\r
+\r
+ rv = khc_read_int32(csp_id, L"CriticalThreshold", &t);\r
+ if (KHM_SUCCEEDED(rv))\r
+ to_crit = t;\r
+\r
+ rv = khc_read_int32(csp_id, L"AutoRenewThreshold", &t);\r
+ if (KHM_SUCCEEDED(rv))\r
+ to_renew = t;\r
+\r
+ khc_close_space(csp_id);\r
+\r
+ if (monitor && do_renew) {\r
+ TimetToFileTimeInterval(to_renew, (LPFILETIME) &ft);\r
+ fte = ft_expiry - ft;\r
+\r
+ if (fte > ft_current) {\r
+ tmr_update(ident, KHUI_TTYPE_ID_RENEW, fte, ft, 0);\r
+ renew_done = TRUE;\r
+ }\r
+ }\r
+\r
+ if (monitor && do_warn && !renew_done) {\r
+ TimetToFileTimeInterval(to_warn, (LPFILETIME) &ft);\r
+ fte = ft_expiry - ft;\r
+\r
+ if (fte > ft_current)\r
+ tmr_update(ident, KHUI_TTYPE_ID_WARN, fte, ft, 0);\r
+ }\r
+\r
+ if (monitor && do_crit && !renew_done) {\r
+ TimetToFileTimeInterval(to_crit, (LPFILETIME) &ft);\r
+ fte = ft_expiry - ft;\r
+\r
+ if (fte > ft_current)\r
+ tmr_update(ident, KHUI_TTYPE_ID_CRIT, fte, ft, 0);\r
+ }\r
+\r
+ if (monitor && !renew_done) {\r
+ if (ft_expiry > ft_current)\r
+ tmr_update(ident, KHUI_TTYPE_ID_EXP, ft_expiry, 0, 0);\r
+ }\r
+\r
+ _done_with_ident:\r
+ khui_timers[mark_idx].flags &= ~KHUI_TE_FLAG_STALE;\r
+ }\r
+\r
+ cb = sizeof(ft_cred_expiry);\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE,\r
+ NULL,\r
+ &ft_cred_expiry,\r
+ &cb)))\r
+ goto _cleanup;\r
+\r
+ TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, (LPFILETIME) &ft);\r
+\r
+ if (ft_cred_expiry >= ft_expiry ||\r
+ (ft_expiry - ft_cred_expiry) < ft)\r
+ goto _cleanup;\r
+\r
+ if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 &&\r
+ !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {\r
+\r
+ fte = ft_cred_expiry - khui_timers[idx].offset;\r
+ if (fte > ft_current) {\r
+ tmr_update(cred, KHUI_TTYPE_CRED_WARN, fte, \r
+ khui_timers[idx].offset, 0);\r
+ kcdb_cred_hold(cred);\r
+ }\r
+ }\r
+\r
+ if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 &&\r
+ !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {\r
+\r
+ fte = ft_cred_expiry - khui_timers[idx].offset;\r
+ if (fte > ft_current) {\r
+ tmr_update(cred, KHUI_TTYPE_CRED_CRIT, fte,\r
+ khui_timers[idx].offset, 0);\r
+ kcdb_cred_hold(cred);\r
+ }\r
+ }\r
+\r
+ if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 &&\r
+ !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {\r
+\r
+ fte = ft_cred_expiry - khui_timers[idx].offset;\r
+ if (fte > ft_current) {\r
+ tmr_update(cred, KHUI_TTYPE_CRED_RENEW, fte,\r
+ khui_timers[idx].offset, 0);\r
+ kcdb_cred_hold(cred);\r
+ }\r
+ }\r
+\r
+ if ((idx = tmr_find(ident, KHUI_TTYPE_ID_EXP, 0, 0)) >= 0 &&\r
+ !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {\r
+\r
+ if (ft_cred_expiry > ft_current) {\r
+ tmr_update(cred, KHUI_TTYPE_CRED_EXP, ft_cred_expiry,\r
+ 0, 0);\r
+ }\r
+ }\r
+\r
+ _cleanup:\r
+\r
+ if (ident)\r
+ kcdb_identity_release(ident);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/* called with cs_timers held */\r
+static void\r
+tmr_purge(void) {\r
+ int i, j;\r
+\r
+ for (i=0,j=0; i < (int) khui_n_timers; i++) {\r
+ if (khui_timers[i].flags & KHUI_TE_FLAG_STALE) {\r
+ if (khui_timers[i].type == KHUI_TTYPE_ID_MARK) {\r
+ kcdb_identity_release(khui_timers[i].key);\r
+#ifdef DEBUG\r
+ {\r
+ int idx;\r
+\r
+ idx = tmr_find(khui_timers[i].key, \r
+ KHUI_TTYPE_ID_CRIT, 0, 0);\r
+ assert(idx < 0 || \r
+ (khui_timers[idx].flags & \r
+ KHUI_TE_FLAG_STALE));\r
+\r
+ idx = tmr_find(khui_timers[i].key, \r
+ KHUI_TTYPE_ID_RENEW, 0, 0);\r
+ assert(idx < 0 || \r
+ (khui_timers[idx].flags & \r
+ KHUI_TE_FLAG_STALE));\r
+\r
+ idx = tmr_find(khui_timers[i].key, \r
+ KHUI_TTYPE_ID_WARN, 0, 0);\r
+ assert(idx < 0 || \r
+ (khui_timers[idx].flags & \r
+ KHUI_TE_FLAG_STALE));\r
+\r
+ idx = tmr_find(khui_timers[i].key, \r
+ KHUI_TTYPE_ID_EXP, 0, 0);\r
+ assert(idx < 0 || \r
+ (khui_timers[idx].flags & \r
+ KHUI_TE_FLAG_STALE));\r
+ }\r
+#endif\r
+ } else if (khui_timers[i].type == KHUI_TTYPE_CRED_WARN ||\r
+ khui_timers[i].type == KHUI_TTYPE_CRED_CRIT ||\r
+ khui_timers[i].type == KHUI_TTYPE_CRED_RENEW ||\r
+ khui_timers[i].type == KHUI_TTYPE_CRED_EXP) {\r
+ kcdb_cred_release(khui_timers[i].key);\r
+ }\r
+ } else {\r
+ if (i != j)\r
+ khui_timers[j] = khui_timers[i];\r
+ j++;\r
+ }\r
+ }\r
+\r
+ khui_n_timers = j;\r
+}\r
+\r
+void \r
+khm_timer_refresh(HWND hwnd) {\r
+ int i;\r
+ __int64 next_event = 0;\r
+ __int64 curtime;\r
+ __int64 diff;\r
+\r
+ EnterCriticalSection(&cs_timers);\r
+\r
+ KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID);\r
+\r
+ for (i=0; i < (int) khui_n_timers; i++) {\r
+#ifdef NOT_IMPLEMENTED_YET\r
+ if (khui_timers[i].type == KHUI_TTYPE_BMSG ||\r
+ khui_timers[i].type == KHUI_TTYPE_SMSG) {\r
+ khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE;\r
+ } else\r
+#endif\r
+ khui_timers[i].flags |= KHUI_TE_FLAG_STALE;\r
+ }\r
+\r
+ kcdb_credset_apply(NULL,\r
+ tmr_cred_apply_proc,\r
+ NULL);\r
+\r
+ tmr_purge();\r
+\r
+ _check_next_event:\r
+\r
+ next_event = 0;\r
+ for (i=0; i < (int) khui_n_timers; i++) {\r
+ if (next_event == 0 ||\r
+ (!(khui_timers[i].flags & KHUI_TE_FLAG_EXPIRED) &&\r
+ khui_timers[i].type != KHUI_TTYPE_ID_MARK &&\r
+ next_event > khui_timers[i].expire))\r
+ next_event = khui_timers[i].expire;\r
+ }\r
+\r
+ if (next_event != 0) {\r
+ GetSystemTimeAsFileTime((LPFILETIME) &curtime);\r
+\r
+ TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL,\r
+ (LPFILETIME) &diff);\r
+\r
+ if (curtime + diff > next_event) {\r
+ tmr_fire_timer();\r
+ goto _check_next_event;\r
+ } else {\r
+ diff = next_event - curtime;\r
+ SetTimer(hwnd,\r
+ KHUI_TRIGGER_TIMER_ID,\r
+ FtIntervalToMilliseconds((LPFILETIME) &diff),\r
+ NULL);\r
+ }\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_timers);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_TIMER_H\r
+#define __KHIMAIRA_TIMER_H\r
+\r
+/* note that the ordering of the first few enum constants are\r
+ significant. The values of the constants up to KHUI_N_TTYPES are\r
+ used as indices. */\r
+typedef enum tag_khui_timer_type {\r
+ KHUI_TTYPE_ID_EXP = 0, /* Identity expiration */\r
+ KHUI_TTYPE_ID_CRIT, /* Identity critical */\r
+ KHUI_TTYPE_ID_WARN, /* Identity warning */\r
+ KHUI_TTYPE_CRED_EXP, /* Credential expiration */\r
+ KHUI_TTYPE_CRED_CRIT, /* Credential critical */ \r
+ KHUI_TTYPE_CRED_WARN, /* Credential warning */\r
+\r
+ KHUI_N_TTYPES, /* Count of the timers that we\r
+ aggregate for notifications */\r
+\r
+ KHUI_TTYPE_ID_MARK, /* Identity marker */\r
+\r
+ KHUI_TTYPE_ID_RENEW, /* Identity auto renewal */\r
+ KHUI_TTYPE_CRED_RENEW, /* Credential renewal */\r
+\r
+#if 0\r
+ KHUI_TTYPE_BMSG, /* Custom. Sends broadcast message\r
+ when triggered.*/\r
+ KHUI_TTYPE_SMSG, /* Custom. Sends subscription message\r
+ when triggered. */\r
+#endif\r
+} khui_timer_type;\r
+\r
+typedef struct tag_khui_timer_event {\r
+ khm_handle key;\r
+ khui_timer_type type;\r
+\r
+ __int64 expire; /* time at which the timer expires */\r
+ __int64 offset; /* time offset at which the event that\r
+ the timer warns of happens */\r
+ void * data;\r
+ khm_int32 flags;\r
+} khui_timer_event;\r
+\r
+#define KHUI_TRIGGER_TIMER_ID 48\r
+#define KHUI_REFRESH_TIMER_ID 49\r
+\r
+#define KHUI_REFRESH_TIMEOUT 5000\r
+\r
+#define KHUI_TE_FLAG_EXPIRED 0x00000001\r
+#define KHUI_TE_FLAG_STALE 0x00000002\r
+\r
+#define KHUI_DEF_TIMEOUT_WARN 900\r
+#define KHUI_DEF_TIMEOUT_CRIT 300\r
+#define KHUI_DEF_TIMEOUT_RENEW 60\r
+\r
+/* the max absolute difference between two timers (in seconds) that\r
+ can exist where we consider both timers to be in the same\r
+ timeslot. */\r
+#define KHUI_TIMEEQ_ERROR 20\r
+\r
+/* the small error. */\r
+#define KHUI_TIMEEQ_ERROR_SMALL 1\r
+\r
+void\r
+khm_timer_refresh(HWND hwnd);\r
+\r
+void\r
+khm_timer_fire(HWND hwnd);\r
+\r
+void\r
+khm_timer_init(void);\r
+\r
+void\r
+khm_timer_exit(void);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khmapp.h>\r
+#include<assert.h>\r
+\r
+HWND khui_hwnd_standard_toolbar;\r
+int khui_tb_blank;\r
+\r
+khui_ilist * ilist_toolbar;\r
+\r
+void khui_init_toolbar(void) {\r
+ ilist_toolbar = khui_create_ilist(KHUI_TOOLBAR_IMAGE_WIDTH, KHUI_TOOLBAR_IMAGE_HEIGHT, KHUI_TOOLBAR_MAX_BTNS, 5, 0);\r
+}\r
+\r
+void khui_exit_toolbar(void) {\r
+ khui_delete_ilist(ilist_toolbar);\r
+}\r
+\r
+LRESULT khm_toolbar_notify(LPNMHDR notice) {\r
+ switch(notice->code) {\r
+ case NM_CUSTOMDRAW:\r
+ {\r
+ LPNMTBCUSTOMDRAW nmcd = (LPNMTBCUSTOMDRAW) notice;\r
+ if(nmcd->nmcd.dwDrawStage == CDDS_PREPAINT) {\r
+ return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTERASE;\r
+ } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {\r
+ return CDRF_NOTIFYPOSTPAINT;\r
+ } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) {\r
+ /* draw the actual icon */\r
+ int iidx;\r
+ int ibmp;\r
+ HBITMAP hbmp;\r
+ RECT r;\r
+\r
+ khui_action * act = \r
+ khui_find_action((int) nmcd->nmcd.dwItemSpec);\r
+\r
+ if(!act || !act->ib_normal)\r
+ return CDRF_DODEFAULT;\r
+\r
+ if((act->state & KHUI_ACTIONSTATE_DISABLED) && \r
+ act->ib_disabled) {\r
+ ibmp = act->ib_disabled;\r
+ } else if(act->ib_hot && \r
+ ((nmcd->nmcd.uItemState & CDIS_HOT) || \r
+ (nmcd->nmcd.uItemState & CDIS_SELECTED))){\r
+ ibmp = act->ib_hot;\r
+ } else {\r
+ ibmp = act->ib_normal;\r
+ }\r
+\r
+ iidx = khui_ilist_lookup_id(ilist_toolbar, ibmp);\r
+ if(iidx < 0) {\r
+ hbmp = LoadImage(khm_hInstance, \r
+ MAKEINTRESOURCE(ibmp), \r
+ IMAGE_BITMAP, \r
+ KHUI_TOOLBAR_IMAGE_WIDTH, \r
+ KHUI_TOOLBAR_IMAGE_HEIGHT, 0);\r
+ iidx = \r
+ khui_ilist_add_masked_id(ilist_toolbar, \r
+ hbmp, \r
+ KHUI_TOOLBAR_BGCOLOR, \r
+ ibmp);\r
+ DeleteObject(hbmp);\r
+ }\r
+\r
+ if(iidx < 0)\r
+ return CDRF_DODEFAULT;\r
+\r
+ CopyRect(&r, &(nmcd->nmcd.rc));\r
+ r.left += ((r.right - r.left) - \r
+ KHUI_TOOLBAR_IMAGE_WIDTH) / 2;\r
+ r.top += ((r.bottom - r.top) -\r
+ KHUI_TOOLBAR_IMAGE_HEIGHT) / 2;\r
+\r
+ khui_ilist_draw(ilist_toolbar, \r
+ iidx, \r
+ nmcd->nmcd.hdc, \r
+ r.left,\r
+ r.top, \r
+ 0);\r
+\r
+ return CDRF_DODEFAULT;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+void khui_add_action_to_toolbar(HWND tb, khui_action *a, int opt, HIMAGELIST hiList) {\r
+ wchar_t buf[MAX_RES_STRING] = L"";\r
+ int idx_caption = 0;\r
+ TBBUTTON bn;\r
+ LRESULT lr;\r
+\r
+ ZeroMemory(&bn,sizeof(bn));\r
+\r
+ if(opt & KHUI_TOOLBAR_ADD_SEP) {\r
+ bn.fsStyle = BTNS_SEP;\r
+ bn.iBitmap = 3;\r
+\r
+ lr = SendMessage(\r
+ tb,\r
+ TB_ADDBUTTONS,\r
+ 1,\r
+ (LPARAM) &bn);\r
+#ifdef DEBUG\r
+ assert(lr);\r
+#endif\r
+ return;\r
+ }\r
+\r
+ bn.fsStyle = BTNS_BUTTON;\r
+\r
+ if(opt & KHUI_TOOLBAR_VARSIZE) {\r
+ bn.fsStyle |= BTNS_AUTOSIZE;\r
+ }\r
+\r
+ if(opt & KHUI_TOOLBAR_ADD_TEXT) {\r
+ int sid = 0;\r
+ if((opt & KHUI_TOOLBAR_ADD_LONGTEXT) == \r
+ KHUI_TOOLBAR_ADD_LONGTEXT) {\r
+ sid = a->is_tooltip;\r
+ }\r
+ if(!sid)\r
+ sid = a->is_caption;\r
+ if(sid) {\r
+ LoadString(khm_hInstance, \r
+ sid, \r
+ buf, ARRAYLENGTH(buf));\r
+ buf[wcslen(buf) + 1] = L'\0';\r
+ idx_caption = (int) SendMessage(tb,\r
+ TB_ADDSTRING,\r
+ (WPARAM) NULL,\r
+ (LPARAM) buf);\r
+ bn.fsStyle |= BTNS_SHOWTEXT;\r
+ bn.iString = idx_caption;\r
+ }\r
+ }\r
+\r
+ if(opt & KHUI_TOOLBAR_ADD_DROPDOWN) {\r
+ bn.fsStyle |= BTNS_DROPDOWN;\r
+ }\r
+\r
+ if((opt & KHUI_TOOLBAR_ADD_BITMAP) && a->ib_normal) {\r
+ bn.fsStyle |= TBSTYLE_CUSTOMERASE;\r
+ bn.iBitmap = khui_tb_blank;\r
+ } else\r
+ bn.iBitmap = I_IMAGENONE;\r
+\r
+ bn.idCommand = a->cmd;\r
+\r
+ if(a->state & KHUI_ACTIONSTATE_DISABLED) {\r
+ bn.fsState = 0;\r
+ } else {\r
+ bn.fsState = TBSTATE_ENABLED;\r
+ }\r
+\r
+ if(a->state & KHUI_ACTIONSTATE_CHECKED) {\r
+ bn.fsState |= TBSTATE_CHECKED;\r
+ }\r
+\r
+ bn.dwData = 0;\r
+\r
+ lr = SendMessage(\r
+ tb,\r
+ TB_ADDBUTTONS,\r
+ 1,\r
+ (LPARAM) &bn);\r
+\r
+#ifdef DEBUG\r
+ assert(lr);\r
+#endif\r
+}\r
+\r
+void khm_update_standard_toolbar(void)\r
+{\r
+ khui_menu_def * def;\r
+ khui_action_ref * aref;\r
+ khui_action * act;\r
+\r
+ def = khui_find_menu(KHUI_TOOLBAR_STANDARD);\r
+\r
+ aref = def->items;\r
+\r
+ while(aref && aref->action != KHUI_MENU_END) {\r
+ if(aref->action == KHUI_MENU_SEP) {\r
+ aref++;\r
+ continue;\r
+ }\r
+\r
+ act = khui_find_action(aref->action);\r
+ if(act) {\r
+ BOOL enable;\r
+\r
+ enable = !(act->state & KHUI_ACTIONSTATE_DISABLED);\r
+ SendMessage(khui_hwnd_standard_toolbar, \r
+ TB_ENABLEBUTTON, \r
+ (WPARAM) act->cmd,\r
+ MAKELPARAM(enable, 0));\r
+ }\r
+\r
+ aref++;\r
+ }\r
+}\r
+\r
+void khm_create_standard_toolbar(HWND rebar) {\r
+ HWND hwtb;\r
+ SIZE sz;\r
+ HBITMAP hbm_blank;\r
+ HIMAGELIST hiList;\r
+ REBARBANDINFO rbi;\r
+ khui_menu_def * def;\r
+ khui_action * act;\r
+ khui_action_ref * aref;\r
+ int idx_blank;\r
+\r
+ def = khui_find_menu(KHUI_TOOLBAR_STANDARD);\r
+\r
+ hwtb = CreateWindowEx(\r
+ TBSTYLE_EX_MIXEDBUTTONS,\r
+ TOOLBARCLASSNAME,\r
+ (LPWSTR) NULL,\r
+ WS_CHILD |\r
+ TBSTYLE_FLAT |\r
+ TBSTYLE_AUTOSIZE | \r
+ TBSTYLE_LIST |\r
+ CCS_NORESIZE | \r
+ CCS_NOPARENTALIGN |\r
+ CCS_ADJUSTABLE |\r
+ CCS_NODIVIDER,\r
+ 0, 0, 0, 0, rebar,\r
+ (HMENU) NULL, khm_hInstance,\r
+ NULL);\r
+\r
+ if(!hwtb) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#else\r
+ return;\r
+#endif\r
+ }\r
+\r
+ hiList = ImageList_Create(\r
+ KHUI_TOOLBAR_IMAGE_WIDTH,\r
+ KHUI_TOOLBAR_IMAGE_HEIGHT,\r
+ ILC_MASK,\r
+ (int) khui_action_list_length(def->items),\r
+ 3);\r
+\r
+ hbm_blank = LoadImage(khm_hInstance, \r
+ MAKEINTRESOURCE(IDB_TB_BLANK), \r
+ IMAGE_BITMAP, \r
+ KHUI_TOOLBAR_IMAGE_WIDTH, \r
+ KHUI_TOOLBAR_IMAGE_HEIGHT, 0);\r
+ idx_blank = ImageList_AddMasked(hiList, hbm_blank, RGB(0,0,0));\r
+\r
+ khui_hwnd_standard_toolbar = hwtb;\r
+ khui_tb_blank = idx_blank;\r
+\r
+ def = khui_find_menu(KHUI_TOOLBAR_STANDARD);\r
+\r
+ aref = def->items;\r
+\r
+ SendMessage(hwtb,\r
+ TB_BUTTONSTRUCTSIZE,\r
+ sizeof(TBBUTTON),\r
+ 0);\r
+\r
+ SendMessage(hwtb,\r
+ TB_SETBITMAPSIZE,\r
+ 0,\r
+ MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT));\r
+\r
+ SendMessage(hwtb,\r
+ TB_SETIMAGELIST,\r
+ 0,\r
+ (LPARAM) hiList);\r
+\r
+ SendMessage(hwtb,\r
+ TB_SETBUTTONSIZE,\r
+ 0,\r
+ MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT));\r
+\r
+ while(aref && aref->action != KHUI_MENU_END) {\r
+ if(aref->action == KHUI_MENU_SEP) {\r
+ khui_add_action_to_toolbar(hwtb, \r
+ NULL, \r
+ KHUI_TOOLBAR_ADD_SEP, \r
+ hiList);\r
+ } else {\r
+ act = khui_find_action(aref->action);\r
+ khui_add_action_to_toolbar(hwtb, \r
+ act, \r
+ KHUI_TOOLBAR_ADD_BITMAP, \r
+ hiList);\r
+ }\r
+ aref ++;\r
+ }\r
+\r
+ SendMessage(hwtb,\r
+ TB_AUTOSIZE,\r
+ 0,0);\r
+\r
+ SendMessage(hwtb,\r
+ TB_GETMAXSIZE,\r
+ 0,\r
+ (LPARAM) &sz);\r
+\r
+ sz.cy += 5;\r
+\r
+ ZeroMemory(&rbi, sizeof(rbi));\r
+\r
+ rbi.cbSize = sizeof(rbi);\r
+ rbi.fMask = \r
+ RBBIM_ID |\r
+ RBBIM_CHILD | \r
+ RBBIM_CHILDSIZE | \r
+ RBBIM_IDEALSIZE | \r
+ RBBIM_SIZE | \r
+ RBBIM_STYLE;\r
+ rbi.fStyle = \r
+ RBBS_USECHEVRON |\r
+ RBBS_BREAK;\r
+ rbi.hwndChild = hwtb;\r
+\r
+ rbi.wID = KHUI_TOOLBAR_STANDARD;\r
+ rbi.cx = sz.cx;\r
+ rbi.cxMinChild = sz.cx;\r
+ rbi.cyMinChild = sz.cy;\r
+ rbi.cyChild = rbi.cyMinChild;\r
+ rbi.cyMaxChild = rbi.cyMinChild;\r
+ rbi.cyIntegral = rbi.cyMinChild;\r
+\r
+ rbi.cxIdeal = rbi.cx;\r
+\r
+ SendMessage(rebar,\r
+ RB_INSERTBAND,\r
+ 1,\r
+ (LPARAM) &rbi);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_TOOLBAR_H\r
+#define __KHIMAIRA_TOOLBAR_H\r
+\r
+extern HWND khui_hwnd_standard_toolbar;\r
+\r
+void khui_init_toolbar(void);\r
+void khui_exit_toolbar(void);\r
+LRESULT khm_toolbar_notify(LPNMHDR notice);\r
+void khm_create_standard_toolbar(HWND rebar);\r
+void khui_add_action_to_toolbar(HWND toolbar, khui_action * act, int opt, HIMAGELIST hiList);\r
+void khm_update_standard_toolbar(void);\r
+\r
+/* options for khui_add_action_to_toolbar */\r
+#define KHUI_TOOLBAR_ADD_TEXT 1\r
+#define KHUI_TOOLBAR_ADD_BITMAP 2\r
+#define KHUI_TOOLBAR_ADD_LONGTEXT 5\r
+#define KHUI_TOOLBAR_ADD_DROPDOWN 8\r
+#define KHUI_TOOLBAR_ADD_SEP 16\r
+#define KHUI_TOOLBAR_VARSIZE 32\r
+\r
+#define KHUI_TOOLBAR_IMAGE_WIDTH 29\r
+#define KHUI_TOOLBAR_IMAGE_HEIGHT 27\r
+#define KHUI_TOOLBAR_BGCOLOR RGB(0xd7,0xd7,0xd7)\r
+#define KHUI_TOOLBAR_MAX_BTNS 64\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+Name,Type,Value,Description\r
+CredWindow,KC_SPACE,0,Options for the credentials window\r
+ AutoInit,KC_INT32,0,Prompt for creds if there arent any\r
+ AutoStart,KC_INT32,0,Start Khimaira when Windows starts\r
+ AutoImport,KC_INT32,0,Import Windows creds when Khimaira starts\r
+ AutoDetectNet,KC_INT32,1,Automatically detect network connectivity changes\r
+ KeepRunning,KC_INT32,1,Keep running after closing Khimaira\r
+ DefaultView,KC_STRING,ByIdentity,\r
+ ViewList,KC_STRING,"ByIdentity,ByLocation",\r
+ PaddingHorizontal,KC_INT32,4,\r
+ PaddingVertical,KC_INT32,2,\r
+ PaddingHeader,KC_INT32,16,\r
+ Monitor,KC_INT32,1,Monitor credentials\r
+ RefreshTimeout,KC_INT32,60,In seconds\r
+ WarnThreshold,KC_INT32,900,In seconds\r
+ AllowWarn,KC_INT32,1,Boolean. Enables warning.\r
+ CriticalThreshold,KC_INT32,300,In seconds\r
+ AllowCritical,KC_INT32,1,Boolean. Enables critical.\r
+ AutoRenewThreshold,KC_INT32,600,In seconds\r
+ AllowAutoRenew,KC_INT32,1,Boolean.\r
+ MaxThreshold,KC_INT32,86400,Max value for a threshold (1 day)\r
+ MinThreshold,KC_INT32,10,Min value for a threshold (0)\r
+ Windows,KC_SPACE,0,Window parameters\r
+ _Schema,KC_SPACE,0,Schema\r
+ Width,KC_INT32,0,\r
+ Height,KC_INT32,0,\r
+ XPos,KC_INT32,0,\r
+ YPos,KC_INT32,0,\r
+ _Schema,KC_ENDSPACE,0,\r
+ Main,KC_SPACE,0,Main window\r
+ Main,KC_ENDSPACE,0,\r
+ Windows,KC_ENDSPACE,0,\r
+ Views,KC_SPACE,0,Preconfigured views for credentials\r
+ Custom_0,KC_SPACE,0,First custom view. Additional views have names of the form Custom_N\r
+ Custom_0,KC_ENDSPACE,0,\r
+ ByIdentity,KC_SPACE,0,The default view\r
+ Description,KC_STRING,View grouped by identity and credential type,\r
+ ColumnList,KC_STRING,"_CWFlags,_CWTypeIcon,IdentityName,TypeName,Name,TimeLeft",\r
+ Columns,KC_SPACE,0,Columns\r
+ _CWFlags,KC_SPACE,0,\r
+ Width,KC_INT32,20,\r
+ Flags,KC_INT32,112,\r
+ _CWFlags,KC_ENDSPACE,0,\r
+ _CWTypeIcon,KC_SPACE,0,\r
+ Width,KC_INT32,20,\r
+ Flags,KC_INT32,112,\r
+ _CWTypeIcon,KC_ENDSPACE,0,\r
+ IdentityName,KC_SPACE,0,\r
+ Width,KC_INT32,100,\r
+ SortIndex,KC_INT32,0,\r
+ Flags,KC_INT32,11,\r
+ IdentityName,KC_ENDSPACE,0\r
+ TypeName,KC_SPACE,0\r
+ Width,KC_INT32,100\r
+ SortIndex,KC_INT32,1\r
+ Flags,KC_INT32,11\r
+ TypeName,KC_ENDSPACE,0\r
+ Name,KC_SPACE,0\r
+ Width,KC_INT32,200\r
+ SortIndex,KC_INT32,2\r
+ Flags,KC_INT32,3\r
+ Name,KC_ENDSPACE,0\r
+ TimeLeft,KC_SPACE,0\r
+ Width,KC_INT32,200\r
+ Flags,KC_INT32,1\r
+ TimeLeft,KC_ENDSPACE,0\r
+ Columns,KC_ENDSPACE,0\r
+ ByIdentity,KC_ENDSPACE,0\r
+ ByLocation,KC_SPACE,0,View by location\r
+ Description,KC_STRING,View grouped by location,\r
+ ColumnList,KC_STRING,"_CWFlags,_CWTypeIcon,Location,IdentityName,TypeName,Name,TimeLeft",\r
+ Columns,KC_SPACE,0,Columns\r
+ _CWFlags,KC_SPACE,0,\r
+ Width,KC_INT32,20,\r
+ Flags,KC_INT32,112,\r
+ _CWFlags,KC_ENDSPACE,0,\r
+ _CWTypeIcon,KC_SPACE,0,\r
+ Width,KC_INT32,20,\r
+ Flags,KC_INT32,112,\r
+ _CWTypeIcon,KC_ENDSPACE,0,\r
+ Location,KC_SPACE,0,\r
+ Width,KC_INT32,100,\r
+ SortIndex,KC_INT32,0,\r
+ Flags,KC_INT32,11,\r
+ Location,KC_ENDSPACE,0,\r
+ IdentityName,KC_SPACE,0,\r
+ Width,KC_INT32,100,\r
+ SortIndex,KC_INT32,1,\r
+ Flags,KC_INT32,11,\r
+ IdentityName,KC_ENDSPACE,0\r
+ TypeName,KC_SPACE,0\r
+ Width,KC_INT32,100\r
+ SortIndex,KC_INT32,2\r
+ Flags,KC_INT32,11\r
+ TypeName,KC_ENDSPACE,0\r
+ Name,KC_SPACE,0\r
+ Width,KC_INT32,200\r
+ SortIndex,KC_INT32,3\r
+ Flags,KC_INT32,3\r
+ Name,KC_ENDSPACE,0\r
+ TimeLeft,KC_SPACE,0\r
+ Width,KC_INT32,200\r
+ Flags,KC_INT32,1\r
+ TimeLeft,KC_ENDSPACE,0\r
+ Columns,KC_ENDSPACE,0\r
+ ByLocation,KC_ENDSPACE,0\r
+ Views,KC_ENDSPACE,0\r
+ Notices,KC_SPACE,0,Notices and alerts\r
+ MinimizeWarning,KC_INT32,1,Show the minimize warning?\r
+ Notices,KC_ENDSPACE,0\r
+CredWindow,KC_ENDSPACE,0\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=uilib\r
+!include <../config/Makefile.w32>\r
+\r
+UIDLLOBJFILES= \\r
+ $(OBJ)\rescache.obj \\r
+ $(OBJ)\action.obj \\r
+ $(OBJ)\creddlg.obj \\r
+ $(OBJ)\alert.obj \\r
+ $(OBJ)\propsheet.obj \\r
+ $(OBJ)\propwnd.obj \\r
+ $(OBJ)\uilibmain.obj \\r
+ $(OBJ)\actiondef.obj \\r
+ $(OBJ)\acceldef.obj \\r
+ $(OBJ)\configui.obj \\r
+ $(OBJ)\trackerwnd.obj\r
+\r
+INCFILES= \\r
+ $(INCDIR)\khuidefs.h \\r
+ $(INCDIR)\khrescache.h \\r
+ $(INCDIR)\khaction.h \\r
+ $(INCDIR)\khactiondef.h \\r
+ $(INCDIR)\khalerts.h \\r
+ $(INCDIR)\khhtlink.h \\r
+ $(INCDIR)\khnewcred.h \\r
+ $(INCDIR)\khprops.h \\r
+ $(INCDIR)\khconfigui.h \\r
+ $(INCDIR)\khtracker.h \\r
+ $(INCDIR)\khremote.h\r
+\r
+$(OBJ)\actiondef.c: actions.csv actiondef.cfg\r
+ $(CCSV) $** $@\r
+\r
+$(OBJ)\acceldef.c: accel.csv acceldef.cfg\r
+ $(CCSV) $** $@\r
+\r
+all: mkdirs $(INCFILES) $(UIDLLOBJFILES)\r
+\r
--- /dev/null
+command,mod,key,scope\r
+KHUI_PACTION_MENU,FVIRTKEY,VK_F10,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_UP,FVIRTKEY,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_UP_EXTEND,FVIRTKEY|FSHIFT,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_UP_TOGGLE,FVIRTKEY|FCONTROL,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_DOWN,FVIRTKEY,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_DOWN_EXTEND,FVIRTKEY|FSHIFT,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_DOWN_TOGGLE,FVIRTKEY|FCONTROL,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_LEFT,FVIRTKEY,VK_LEFT,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_RIGHT,FVIRTKEY,VK_RIGHT,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_ENTER,FVIRTKEY,VK_RETURN,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_PACTION_ESC,FVIRTKEY,VK_ESCAPE,KHUI_ACCEL_SCOPE_GLOBAL\r
+#KHUI_PACTION_DELETE,FVIRTKEY,VK_DELETE,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_ACTION_DESTROY_CRED,FVIRTKEY,VK_DELETE,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_ACTION_EXIT,FCONTROL,\'X\',KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_ACTION_VIEW_REFRESH,FVIRTKEY,VK_F5,KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_ACTION_NEW_CRED,FCONTROL,\'N\',KHUI_ACCEL_SCOPE_GLOBAL\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation\r
+# files (the "Software"), to deal in the Software without\r
+# restriction, including without limitation the rights to use, copy,\r
+# modify, merge, publish, distribute, sublicense, and/or sell copies\r
+# of the Software, and to permit persons to whom the Software is\r
+# furnished to do so, subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+#\r
+\r
+$file_prefix = <<EOS;\r
+/*\r
+This file was autogenerated from src/ui/acceldef.cfg and src/ui/accel.csv.\r
+\r
+Do not modify directly.\r
+*/\r
+#include<khuidefs.h>\r
+\r
+khui_accel_def khui_accel_global[] = {\r
+EOS\r
+\r
+$record_prefix = "{";\r
+\r
+$record_sep = ",\n";\r
+\r
+$record_postfix = "}";\r
+\r
+$file_postfix = <<EOS;\r
+\r
+};\r
+\r
+int khui_n_accel_global = sizeof(khui_accel_global) / sizeof(khui_accel_def);\r
+\r
+EOS\r
+\r
+$skip_lines = 1;\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#define NOEXPORT\r
+#include<khuidefs.h>\r
+#include<assert.h>\r
+\r
+khui_action_ref khui_main_menu[] = {\r
+ MENU_ACTION(KHUI_MENU_FILE),\r
+ MENU_ACTION(KHUI_MENU_CRED),\r
+ MENU_ACTION(KHUI_MENU_VIEW),\r
+ MENU_ACTION(KHUI_MENU_OPTIONS),\r
+ MENU_ACTION(KHUI_MENU_HELP),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_file[] = {\r
+ MENU_ACTION(KHUI_ACTION_PROPERTIES),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_EXIT),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_cred[] = {\r
+ MENU_ACTION(KHUI_ACTION_NEW_CRED),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_SET_DEF_ID),\r
+ MENU_ACTION(KHUI_ACTION_SET_SRCH_ID),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_PASSWD_ID),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_IMPORT),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_layout[] = {\r
+ MENU_ACTION(KHUI_ACTION_LAYOUT_ID),\r
+ MENU_ACTION(KHUI_ACTION_LAYOUT_TYPE),\r
+ MENU_ACTION(KHUI_ACTION_LAYOUT_LOC),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_toolbars[] = {\r
+ MENU_ACTION(KHUI_ACTION_TB_STANDARD),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_view[] = {\r
+ MENU_ACTION(KHUI_ACTION_CHOOSE_COLS),\r
+ MENU_ACTION(KHUI_MENU_LAYOUT),\r
+ MENU_ACTION(KHUI_MENU_TOOLBARS),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_DEBUG_WINDOW),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_VIEW_REFRESH),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_options[] = {\r
+ MENU_ACTION(KHUI_ACTION_OPT_KHIM),\r
+ MENU_ACTION(KHUI_ACTION_OPT_IDENTS),\r
+ MENU_ACTION(KHUI_ACTION_OPT_NOTIF),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_help[] = {\r
+ MENU_ACTION(KHUI_ACTION_HELP_CTX),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_HELP_CONTENTS),\r
+ MENU_ACTION(KHUI_ACTION_HELP_INDEX),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_HELP_ABOUT),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_toolbar_standard[] = {\r
+ MENU_ACTION(KHUI_ACTION_NEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_IMPORT),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_PASSWD_ID),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_VIEW_REFRESH),\r
+ MENU_ACTION(KHUI_PACTION_BLANK),\r
+ MENU_ACTION(KHUI_ACTION_HELP_CTX),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_ident_ctx[] = {\r
+ MENU_ACTION(KHUI_ACTION_PROPERTIES),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_SET_DEF_ID),\r
+ MENU_ACTION(KHUI_ACTION_SET_SRCH_ID),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_NEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_tok_ctx[] = {\r
+ MENU_ACTION(KHUI_ACTION_PROPERTIES),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_NEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_ico_ctx_min[] = {\r
+ MENU_DEFACTION(KHUI_ACTION_OPEN_APP),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_NEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_EXIT),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_menu_ico_ctx_normal[] = {\r
+ MENU_DEFACTION(KHUI_ACTION_CLOSE_APP),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_NEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_SEP(),\r
+ MENU_ACTION(KHUI_ACTION_EXIT),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_pmenu_tok_sel[] = {\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_END()\r
+};\r
+\r
+khui_action_ref khui_pmenu_id_sel[] = {\r
+ MENU_ACTION(KHUI_ACTION_DESTROY_CRED),\r
+ MENU_ACTION(KHUI_ACTION_RENEW_CRED),\r
+ MENU_END()\r
+};\r
+\r
+/* all stock menus and toolbars */\r
+khui_menu_def khui_all_menus[] = {\r
+ CONSTMENU(KHUI_MENU_MAIN, KHUI_MENUSTATE_CONSTANT, khui_main_menu),\r
+ CONSTMENU(KHUI_MENU_FILE, KHUI_MENUSTATE_CONSTANT, khui_menu_file),\r
+ CONSTMENU(KHUI_MENU_CRED, KHUI_MENUSTATE_CONSTANT, khui_menu_cred),\r
+ CONSTMENU(KHUI_MENU_VIEW, KHUI_MENUSTATE_CONSTANT, khui_menu_view),\r
+ CONSTMENU(KHUI_MENU_LAYOUT, KHUI_MENUSTATE_CONSTANT, khui_menu_layout),\r
+ CONSTMENU(KHUI_MENU_TOOLBARS, KHUI_MENUSTATE_CONSTANT, khui_menu_toolbars),\r
+ CONSTMENU(KHUI_MENU_OPTIONS, KHUI_MENUSTATE_CONSTANT, khui_menu_options),\r
+ CONSTMENU(KHUI_MENU_HELP, KHUI_MENUSTATE_CONSTANT, khui_menu_help),\r
+\r
+ /* toolbars */\r
+ CONSTMENU(KHUI_TOOLBAR_STANDARD, KHUI_MENUSTATE_CONSTANT, khui_toolbar_standard),\r
+\r
+ /* context menus */\r
+ CONSTMENU(KHUI_MENU_IDENT_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_ident_ctx),\r
+ CONSTMENU(KHUI_MENU_TOK_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_tok_ctx),\r
+ CONSTMENU(KHUI_MENU_ICO_CTX_MIN, KHUI_MENUSTATE_CONSTANT, khui_menu_ico_ctx_min),\r
+ CONSTMENU(KHUI_MENU_ICO_CTX_NORMAL, KHUI_MENUSTATE_CONSTANT, khui_menu_ico_ctx_normal),\r
+\r
+ /* pseudo menus */\r
+ CONSTMENU(KHUI_PMENU_TOK_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_tok_sel),\r
+ CONSTMENU(KHUI_PMENU_ID_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_id_sel)\r
+};\r
+\r
+int khui_n_all_menus = sizeof(khui_all_menus) / sizeof(khui_menu_def);\r
+CRITICAL_SECTION cs_actions;\r
+\r
+KHMEXP void KHMAPI \r
+khui_init_actions(void) {\r
+ InitializeCriticalSection(&cs_actions);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_exit_actions(void) {\r
+ DeleteCriticalSection(&cs_actions);\r
+}\r
+\r
+#define MENU_NC_ITEMS 8\r
+\r
+KHMEXP khui_menu_def * KHMAPI \r
+khui_menu_create(int cmd)\r
+{\r
+ khui_menu_def * d;\r
+ d = malloc(sizeof(*d));\r
+ ZeroMemory(d, sizeof(*d));\r
+\r
+ d->cmd = cmd;\r
+ d->nc_items = MENU_NC_ITEMS;\r
+ d->items = malloc(sizeof(*(d->items)) * d->nc_items);\r
+\r
+ d->state = KHUI_MENUSTATE_ALLOCD;\r
+\r
+ return d;\r
+}\r
+\r
+KHMEXP khui_menu_def * KHMAPI \r
+khui_menu_dup(khui_menu_def * src)\r
+{\r
+ khui_menu_def * d;\r
+ size_t i;\r
+ size_t n;\r
+\r
+ d = khui_menu_create(src->cmd);\r
+\r
+ if(src->n_items == -1)\r
+ n = khui_action_list_length(src->items);\r
+ else\r
+ n = src->n_items;\r
+\r
+ for(i=0; i<n; i++) {\r
+ if(src->items[i].flags & KHUI_ACTIONREF_PACTION) {\r
+ khui_menu_add_paction(d, src->items[i].p_action, src->items[i].flags);\r
+ } else {\r
+ khui_menu_add_action(d, src->items[i].action);\r
+ }\r
+ }\r
+\r
+ return d;\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_menu_delete(khui_menu_def * d)\r
+{\r
+ int i;\r
+\r
+ /* non-allocated menus are assumed to have no pointers to other\r
+ allocated blocks */\r
+ if(!(d->state & KHUI_MENUSTATE_ALLOCD))\r
+ return;\r
+\r
+ for(i=0; i< (int) d->n_items; i++) {\r
+ if(d->items[i].flags & KHUI_ACTIONREF_FREE_PACTION)\r
+ free(d->items[i].p_action);\r
+ }\r
+\r
+ if(d->items)\r
+ free(d->items);\r
+ free(d);\r
+}\r
+\r
+static void khui_menu_assert_size(khui_menu_def * d, size_t n)\r
+{\r
+ if(n > (int) d->nc_items) {\r
+ khui_action_ref * ni;\r
+\r
+ d->nc_items = UBOUNDSS(n, MENU_NC_ITEMS, MENU_NC_ITEMS);\r
+ ni = malloc(sizeof(*(d->items)) * d->nc_items);\r
+ memcpy(ni, d->items, sizeof(*(d->items)) * d->n_items);\r
+ free(d->items);\r
+ d->items = ni;\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id)\r
+{\r
+ khui_menu_assert_size(d, d->n_items + 1);\r
+ d->items[d->n_items].flags = 0;\r
+ d->items[d->n_items ++].action = id;\r
+}\r
+\r
+KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags)\r
+{\r
+ khui_menu_assert_size(d, d->n_items + 1);\r
+ d->items[d->n_items].flags = flags | KHUI_ACTIONREF_PACTION;\r
+ d->items[d->n_items ++].p_action = act;\r
+}\r
+\r
+KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id) {\r
+ khui_menu_def * d;\r
+ int i;\r
+\r
+ d = khui_all_menus;\r
+ for(i=0;i<khui_n_all_menus;i++) {\r
+ if(id == d[i].cmd)\r
+ return &d[i];\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+KHMEXP khui_action * KHMAPI khui_find_action(int id) {\r
+ khui_action * act;\r
+ int i;\r
+\r
+ act = khui_actions;\r
+ for(i=0;i<khui_n_actions;i++) {\r
+ if(act[i].cmd == id)\r
+ return &act[i];\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name) {\r
+ int i;\r
+ khui_action * act;\r
+\r
+ if(!name)\r
+ return NULL;\r
+\r
+ act = khui_actions;\r
+ for(i=0;i<khui_n_actions;i++) {\r
+ if(!act[i].name)\r
+ continue;\r
+ if(!wcscmp(act[i].name, name))\r
+ return &act[i];\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref) {\r
+ size_t c = 0;\r
+ while(ref && ref->action != KHUI_MENU_END) {\r
+ c++;\r
+ ref++;\r
+ }\r
+ return c;\r
+}\r
+\r
+KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd)\r
+{\r
+ khui_action_ref * r;\r
+ khui_action * act;\r
+\r
+ r = d->items;\r
+ while(r && r->action != KHUI_MENU_END) {\r
+ if(r->flags & KHUI_ACTIONREF_PACTION) {\r
+ act = r->p_action;\r
+ } else {\r
+ act = khui_find_action(r->action);\r
+ }\r
+\r
+ if(act) {\r
+ if(act->cmd == cmd)\r
+ act->state |= KHUI_ACTIONSTATE_CHECKED;\r
+ else\r
+ act->state &= ~KHUI_ACTIONSTATE_CHECKED;\r
+ }\r
+ r++;\r
+ }\r
+\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0);\r
+}\r
+\r
+KHMEXP void KHMAPI khui_check_action(int cmd, khm_boolean check) {\r
+ khui_action * act;\r
+\r
+ act = khui_find_action(cmd);\r
+ if (!act)\r
+ return;\r
+\r
+ if (check && !(act->state & KHUI_ACTIONSTATE_CHECKED))\r
+ act->state |= KHUI_ACTIONSTATE_CHECKED;\r
+ else if (!check && (act->state & KHUI_ACTIONSTATE_CHECKED))\r
+ act->state &= ~KHUI_ACTIONSTATE_CHECKED;\r
+ else\r
+ return;\r
+\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0);\r
+}\r
+\r
+KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable)\r
+{\r
+ khui_action_ref * r;\r
+ int delta = FALSE;\r
+ khui_action * act;\r
+\r
+ r = d->items;\r
+ while(r && r->action != KHUI_MENU_END) {\r
+ if(r->flags & KHUI_ACTIONREF_PACTION) {\r
+ act = r->p_action;\r
+ } else {\r
+ act = khui_find_action(r->action);\r
+ }\r
+\r
+ if(act) {\r
+ int old_state = act->state;\r
+\r
+ if(enable)\r
+ act->state &= ~KHUI_ACTIONSTATE_DISABLED;\r
+ else\r
+ act->state |= KHUI_ACTIONSTATE_DISABLED;\r
+\r
+ if(old_state != act->state)\r
+ delta = TRUE;\r
+ }\r
+ r++;\r
+ }\r
+\r
+ if(delta) {\r
+ kmq_send_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable) {\r
+ khui_action * act;\r
+\r
+ act = khui_find_action(cmd);\r
+ if (!act)\r
+ return;\r
+\r
+ if (enable && (act->state & KHUI_ACTIONSTATE_DISABLED)) {\r
+ act->state &= ~KHUI_ACTIONSTATE_DISABLED;\r
+ } else if (!enable && !(act->state & KHUI_ACTIONSTATE_DISABLED)) {\r
+ act->state |= KHUI_ACTIONSTATE_DISABLED;\r
+ } else\r
+ return;\r
+\r
+ kmq_send_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0);\r
+}\r
+\r
+KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void) {\r
+ int i;\r
+ ACCEL * accels;\r
+ HACCEL ha;\r
+\r
+ accels = malloc(sizeof(ACCEL) * khui_n_accel_global);\r
+ for(i=0;i<khui_n_accel_global;i++) {\r
+ accels[i].cmd = khui_accel_global[i].cmd;\r
+ accels[i].fVirt = khui_accel_global[i].mod;\r
+ accels[i].key = khui_accel_global[i].key;\r
+ }\r
+\r
+ ha = CreateAcceleratorTable(accels, khui_n_accel_global);\r
+\r
+ free(accels);\r
+\r
+ return ha;\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI \r
+khui_get_cmd_accel_string(int cmd, \r
+ wchar_t * buf, \r
+ size_t bufsiz) {\r
+ int i;\r
+ khui_accel_def * def;\r
+\r
+ /* should at least hold 2 characters */\r
+ if(bufsiz < sizeof(wchar_t) * 2)\r
+ return FALSE;\r
+\r
+ buf[0] = L'\0';\r
+\r
+ for(i=0;i<khui_n_accel_global;i++) {\r
+ if(khui_accel_global[i].cmd == cmd)\r
+ break;\r
+ }\r
+\r
+ if(i==khui_n_accel_global)\r
+ return FALSE;\r
+\r
+ def = &khui_accel_global[i];\r
+\r
+ if(def->mod & FALT) {\r
+ if(FAILED(StringCbCat(buf, bufsiz, L"ALT+")))\r
+ return FALSE;\r
+ }\r
+\r
+\r
+ if(def->mod & FCONTROL) {\r
+ if(FAILED(StringCbCat(buf, bufsiz, L"CTRL+")))\r
+ return FALSE;\r
+ }\r
+\r
+ if(def->mod & FSHIFT) {\r
+ if(FAILED(StringCbCat(buf, bufsiz, L"SHIFT+")))\r
+ return FALSE;\r
+ }\r
+\r
+ if(def->mod & FVIRTKEY) {\r
+ wchar_t mbuf[6];\r
+ wchar_t * ap = NULL;\r
+ switch(def->key) {\r
+ case VK_TAB:\r
+ ap = L"Tab";\r
+ break;\r
+\r
+ case VK_ESCAPE:\r
+ ap = L"Esc";\r
+ break;\r
+\r
+ case VK_RETURN:\r
+ ap = L"Enter";\r
+ break;\r
+\r
+ case VK_F5:\r
+ ap = L"F5";\r
+ break;\r
+\r
+ case VK_DELETE:\r
+ ap = L"Del";\r
+ break;\r
+\r
+ default:\r
+ if((def->key >= '0' && \r
+ def->key <= '9') || \r
+ (def->key >= 'A' && \r
+ def->key <= 'Z')) {\r
+ ap = mbuf;\r
+ mbuf[0] = (wchar_t) def->key;\r
+ mbuf[1] = L'\0';\r
+ }\r
+ }\r
+ if(ap) {\r
+ if(FAILED(StringCbCat(buf, bufsiz, ap)))\r
+ return FALSE;\r
+ }\r
+ else {\r
+ if(FAILED(StringCbCat(buf, bufsiz,L"???")))\r
+ return FALSE;\r
+ }\r
+\r
+ } else {\r
+ wchar_t mbuf[2];\r
+\r
+ mbuf[0] = def->key;\r
+ mbuf[1] = L'\0';\r
+\r
+ if(FAILED(StringCbCat(buf, bufsiz, mbuf)))\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/******************************************/\r
+/* contexts */\r
+\r
+#define KHUI_ACTION_CONTEXT_MAGIC 0x39c49db5\r
+\r
+static khm_int32 KHMAPI\r
+khuiint_filter_selected(khm_handle cred,\r
+ khm_int32 vflags,\r
+ void * rock) {\r
+ khm_int32 flags;\r
+ if (KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &flags)) &&\r
+ (flags & KCDB_CRED_FLAG_SELECTED))\r
+ return TRUE;\r
+ else\r
+ return FALSE;\r
+}\r
+\r
+static void\r
+khuiint_context_release(khui_action_context * ctx) {\r
+ ctx->scope = KHUI_SCOPE_NONE;\r
+ if (ctx->identity)\r
+ kcdb_identity_release(ctx->identity);\r
+ ctx->identity = NULL;\r
+ ctx->cred_type = KCDB_CREDTYPE_INVALID;\r
+ if (ctx->cred)\r
+ kcdb_cred_release(ctx->cred);\r
+ ctx->cred = NULL;\r
+ ctx->n_headers = 0;\r
+ if (ctx->credset)\r
+ kcdb_credset_flush(ctx->credset);\r
+ ctx->n_sel_creds = 0;\r
+ ctx->int_cb_used = 0;\r
+ ctx->vparam = NULL;\r
+ ctx->cb_vparam = 0;\r
+}\r
+\r
+static void\r
+khuiint_copy_context(khui_action_context * ctxdest,\r
+ const khui_action_context * ctxsrc)\r
+{\r
+ ctxdest->scope = ctxsrc->scope;\r
+\r
+ if (ctxsrc->scope == KHUI_SCOPE_IDENT) {\r
+ ctxdest->identity = ctxsrc->identity;\r
+ kcdb_identity_hold(ctxsrc->identity);\r
+ } else if (ctxsrc->scope == KHUI_SCOPE_CREDTYPE) {\r
+ ctxdest->identity = ctxsrc->identity;\r
+ ctxdest->cred_type = ctxsrc->cred_type;\r
+ if (ctxsrc->identity != NULL)\r
+ kcdb_identity_hold(ctxsrc->identity);\r
+ } else if (ctxsrc->scope == KHUI_SCOPE_CRED) {\r
+ kcdb_cred_get_identity(ctxsrc->cred, &ctxdest->identity);\r
+ kcdb_cred_get_type(ctxsrc->cred, &ctxdest->cred_type);\r
+ ctxdest->cred = ctxsrc->cred;\r
+ kcdb_cred_hold(ctxsrc->cred);\r
+ } else if (ctxsrc->scope == KHUI_SCOPE_GROUP) {\r
+ khm_size cb_total;\r
+ int i;\r
+\r
+ ctxdest->n_headers = ctxsrc->n_headers;\r
+ cb_total = 0;\r
+ for (i=0; i < (int) ctxsrc->n_headers; i++) {\r
+ cb_total += UBOUND32(ctxsrc->headers[i].cb_data);\r
+ }\r
+\r
+ if (ctxdest->int_cb_buf < cb_total) {\r
+\r
+ if (ctxdest->int_buf)\r
+ free(ctxdest->int_buf);\r
+\r
+ ctxdest->int_cb_buf = cb_total;\r
+ ctxdest->int_buf = malloc(cb_total);\r
+ }\r
+\r
+#ifdef DEBUG\r
+ assert(ctxdest->int_buf || cb_total == 0);\r
+#endif\r
+ ctxdest->int_cb_used = 0;\r
+\r
+ for (i=0; i < (int) ctxsrc->n_headers; i++) {\r
+ ctxdest->headers[i].attr_id = ctxsrc->headers[i].attr_id;\r
+ ctxdest->headers[i].cb_data = ctxsrc->headers[i].cb_data;\r
+ if (ctxsrc->headers[i].cb_data > 0) {\r
+ ctxdest->headers[i].data = \r
+ BYTEOFFSET(ctxdest->int_buf,\r
+ ctxdest->int_cb_used);\r
+ memcpy(ctxdest->headers[i].data,\r
+ ctxsrc->headers[i].data,\r
+ ctxsrc->headers[i].cb_data);\r
+ ctxdest->int_cb_used += \r
+ UBOUND32(ctxsrc->headers[i].cb_data);\r
+ } else {\r
+ ctxdest->headers[i].data = NULL;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (ctxsrc->credset) {\r
+\r
+ if (ctxdest->credset == NULL)\r
+ kcdb_credset_create(&ctxdest->credset);\r
+#ifdef DEBUG\r
+ assert(ctxdest->credset != NULL);\r
+#endif\r
+\r
+ kcdb_credset_flush(ctxdest->credset);\r
+ \r
+ kcdb_credset_extract_filtered(ctxdest->credset,\r
+ ctxsrc->credset,\r
+ khuiint_filter_selected,\r
+ NULL);\r
+\r
+ kcdb_credset_get_size(ctxdest->credset,\r
+ &ctxdest->n_sel_creds);\r
+ } else {\r
+ if (ctxdest->credset != NULL)\r
+ kcdb_credset_flush(ctxdest->credset);\r
+ ctxdest->n_sel_creds = 0;\r
+ }\r
+\r
+ /* For now, we simply transfer the vparam buffer into the new\r
+ context. If we are copying, we also need to modify\r
+ khui_context_release() to free the allocated buffer */\r
+#if 0\r
+ if (ctxsrc->vparam && ctxsrc->cb_vparam) {\r
+ ctxdest->vparam = malloc(ctxsrc->cb_vparam);\r
+#ifdef DEBUG\r
+ assert(ctxdest->vparam);\r
+#endif\r
+ memcpy(ctxdest->vparam, ctxsrc->vparam, ctxsrc->cb_vparam);\r
+ ctxdest->cb_vparam = ctxsrc->cb_vparam;\r
+ } else {\r
+#endif\r
+ ctxdest->vparam = ctxsrc->vparam;\r
+ ctxdest->cb_vparam = ctxsrc->cb_vparam;\r
+#if 0\r
+ }\r
+#endif\r
+}\r
+\r
+static void \r
+khuiint_context_init(khui_action_context * ctx) {\r
+ ctx->magic = KHUI_ACTION_CONTEXT_MAGIC;\r
+ ctx->scope = KHUI_SCOPE_NONE;\r
+ ctx->identity = NULL;\r
+ ctx->cred_type = KCDB_CREDTYPE_INVALID;\r
+ ctx->cred = NULL;\r
+ ZeroMemory(ctx->headers, sizeof(ctx->headers));\r
+ ctx->n_headers = 0;\r
+ ctx->credset = NULL;\r
+ ctx->n_sel_creds = 0;\r
+ ctx->int_buf = NULL;\r
+ ctx->int_cb_buf = 0;\r
+ ctx->int_cb_used = 0;\r
+ ctx->vparam = NULL;\r
+ ctx->cb_vparam = 0;\r
+}\r
+\r
+khui_action_context khui_ctx = {\r
+ KHUI_ACTION_CONTEXT_MAGIC,\r
+ KHUI_SCOPE_NONE,\r
+ NULL, \r
+ KCDB_CREDTYPE_INVALID, \r
+ NULL,\r
+ {\r
+ {KCDB_ATTR_INVALID,NULL,0},\r
+ {KCDB_ATTR_INVALID,NULL,0},\r
+ {KCDB_ATTR_INVALID,NULL,0},\r
+ {KCDB_ATTR_INVALID,NULL,0},\r
+ {KCDB_ATTR_INVALID,NULL,0},\r
+ {KCDB_ATTR_INVALID,NULL,0}\r
+ },\r
+ 0,\r
+ NULL,\r
+ 0,\r
+ NULL,\r
+ 0,\r
+ 0,\r
+ NULL,\r
+ 0};\r
+\r
+KHMEXP void KHMAPI\r
+khui_context_create(khui_action_context * ctx,\r
+ khui_scope scope,\r
+ khm_handle identity,\r
+ khm_int32 cred_type,\r
+ khm_handle cred)\r
+{\r
+ khui_action_context tctx;\r
+\r
+ khuiint_context_init(&tctx);\r
+ khuiint_context_init(ctx);\r
+\r
+ tctx.scope = scope;\r
+ tctx.identity = identity;\r
+ tctx.cred_type = cred_type;\r
+ tctx.cred = cred;\r
+\r
+ khuiint_copy_context(ctx, &tctx);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_context_set(khui_scope scope, \r
+ khm_handle identity, \r
+ khm_int32 cred_type, \r
+ khm_handle cred,\r
+ khui_header *headers,\r
+ khm_size n_headers,\r
+ khm_handle cs_src) {\r
+\r
+ khui_context_set_ex(scope,\r
+ identity,\r
+ cred_type,\r
+ cred,\r
+ headers,\r
+ n_headers,\r
+ cs_src,\r
+ NULL,\r
+ 0);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_context_set_ex(khui_scope scope, \r
+ khm_handle identity, \r
+ khm_int32 cred_type, \r
+ khm_handle cred,\r
+ khui_header *headers,\r
+ khm_size n_headers,\r
+ khm_handle cs_src,\r
+ void * vparam,\r
+ khm_size cb_vparam)\r
+{\r
+ khui_action_context tctx;\r
+\r
+ EnterCriticalSection(&cs_actions);\r
+\r
+ khuiint_context_release(&khui_ctx);\r
+\r
+ khuiint_context_init(&tctx);\r
+\r
+ tctx.scope = scope;\r
+ tctx.identity = identity;\r
+ tctx.cred_type = cred_type;\r
+ tctx.cred = cred;\r
+ if (headers) {\r
+ tctx.n_headers = n_headers;\r
+ memcpy(tctx.headers,\r
+ headers,\r
+ sizeof(*headers) * n_headers);\r
+ } else {\r
+ tctx.n_headers = 0;\r
+ }\r
+ tctx.credset = cs_src;\r
+ tctx.n_sel_creds = 0; /* ignored */\r
+ tctx.vparam = vparam;\r
+ tctx.cb_vparam = cb_vparam;\r
+ tctx.int_buf = NULL;\r
+ tctx.int_cb_buf = 0;\r
+ tctx.int_cb_used = 0;\r
+\r
+ khuiint_copy_context(&khui_ctx, &tctx);\r
+\r
+ khui_context_refresh();\r
+\r
+ LeaveCriticalSection(&cs_actions);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_context_refresh(void) {\r
+ khm_int32 flags;\r
+\r
+ EnterCriticalSection(&cs_actions);\r
+ if (khui_ctx.identity) {\r
+ /* an identity is selected */\r
+\r
+ if (KHM_SUCCEEDED(kcdb_identity_get_flags(khui_ctx.identity,\r
+ &flags)) &&\r
+ (flags & KCDB_IDENT_FLAG_DEFAULT)) {\r
+ khui_check_action(KHUI_ACTION_SET_DEF_ID, TRUE);\r
+ khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE);\r
+ } else {\r
+ khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE);\r
+ khui_enable_action(KHUI_ACTION_SET_DEF_ID, TRUE);\r
+ }\r
+\r
+ khui_enable_action(KHUI_ACTION_PASSWD_ID, TRUE);\r
+ } else {\r
+ khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE);\r
+ khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE);\r
+ khui_enable_action(KHUI_ACTION_PASSWD_ID, FALSE);\r
+ }\r
+\r
+ if (khui_ctx.scope != KHUI_SCOPE_NONE) {\r
+ khui_enable_action(KHUI_ACTION_PROPERTIES, TRUE);\r
+ khui_enable_action(KHUI_ACTION_DESTROY_CRED, TRUE);\r
+ khui_enable_action(KHUI_ACTION_RENEW_CRED, TRUE);\r
+ } else {\r
+ khui_enable_action(KHUI_ACTION_PROPERTIES, FALSE);\r
+ khui_enable_action(KHUI_ACTION_DESTROY_CRED, FALSE);\r
+ khui_enable_action(KHUI_ACTION_RENEW_CRED, FALSE);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_actions);\r
+\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_context_get(khui_action_context * ctx)\r
+{\r
+ EnterCriticalSection(&cs_actions);\r
+\r
+ khuiint_context_init(ctx);\r
+ khuiint_copy_context(ctx, &khui_ctx);\r
+\r
+ if (ctx->credset) {\r
+ kcdb_credset_seal(ctx->credset);\r
+ }\r
+\r
+ LeaveCriticalSection(&cs_actions);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_context_release(khui_action_context * ctx)\r
+{\r
+#ifdef DEBUG\r
+ assert(ctx->magic == KHUI_ACTION_CONTEXT_MAGIC);\r
+#endif\r
+\r
+ khuiint_context_release(ctx);\r
+ if (ctx->credset) {\r
+ kcdb_credset_unseal(ctx->credset);\r
+ kcdb_credset_delete(ctx->credset);\r
+ }\r
+ ctx->credset = NULL;\r
+ if (ctx->int_buf)\r
+ free(ctx->int_buf);\r
+ ctx->int_buf = NULL;\r
+#if 0\r
+ if (ctx->vparam && ctx->cb_vparam > 0) {\r
+ free(ctx->vparam);\r
+ ctx->vparam = NULL;\r
+ }\r
+ ctx->cb_vparam = 0;\r
+#else\r
+ ctx->vparam = 0;\r
+ ctx->cb_vparam = 0;\r
+#endif\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_context_reset(void)\r
+{\r
+ EnterCriticalSection(&cs_actions);\r
+\r
+ khuiint_context_release(&khui_ctx);\r
+\r
+ khui_context_refresh();\r
+\r
+ LeaveCriticalSection(&cs_actions);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_context_cursor_filter(khm_handle cred,\r
+ khm_int32 flags,\r
+ void * rock) {\r
+ khui_action_context * ctx = (khui_action_context *) rock;\r
+ khm_int32 rv;\r
+\r
+ if (ctx->scope == KHUI_SCOPE_NONE)\r
+ return 0;\r
+ else if (ctx->scope == KHUI_SCOPE_IDENT) {\r
+ khm_handle c_ident;\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident)))\r
+ return 0;\r
+\r
+ rv = (c_ident == ctx->identity);\r
+\r
+ kcdb_identity_release(c_ident);\r
+\r
+ return rv;\r
+ } else if (ctx->scope == KHUI_SCOPE_CREDTYPE) {\r
+ khm_handle c_ident;\r
+ khm_int32 c_type;\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_type(cred, &c_type)) ||\r
+ c_type != ctx->cred_type)\r
+ return 0;\r
+\r
+ if (ctx->identity == NULL)\r
+ return 1;\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident)))\r
+ return 0;\r
+\r
+ rv = (c_ident == ctx->identity);\r
+\r
+ kcdb_identity_release(c_ident);\r
+\r
+ return rv;\r
+ } else if (ctx->scope == KHUI_SCOPE_CRED) {\r
+ return kcdb_creds_is_equal(cred, ctx->cred);\r
+ } else if (ctx->scope == KHUI_SCOPE_GROUP) {\r
+ int i;\r
+\r
+ rv = 1;\r
+\r
+ for (i=0; i < (int) ctx->n_headers && rv; i++) {\r
+ kcdb_attrib * pattr;\r
+ kcdb_type * ptype;\r
+ DWORD buffer[1024]; /* 4096 bytes */\r
+ khm_size cb;\r
+\r
+ if (kcdb_cred_get_attr(cred, ctx->headers[i].attr_id,\r
+ NULL,\r
+ NULL,\r
+ &cb) != KHM_ERROR_TOO_LONG) {\r
+ /* the header doesn't exist anyway */\r
+ rv = (ctx->headers[i].cb_data == 0);\r
+ continue;\r
+ }\r
+#ifdef DEBUG\r
+ assert(cb <= sizeof(buffer));\r
+#endif\r
+ cb = sizeof(buffer);\r
+\r
+ if (KHM_FAILED(kcdb_cred_get_attr(cred,\r
+ ctx->headers[i].attr_id,\r
+ NULL,\r
+ (void *) buffer,\r
+ &cb))) {\r
+ rv = 0;\r
+ continue;\r
+ }\r
+\r
+ if (KHM_FAILED(kcdb_attrib_get_info(ctx->headers[i].attr_id,\r
+ &pattr))) {\r
+ rv = 0;\r
+ continue;\r
+ }\r
+\r
+ if (KHM_FAILED(kcdb_type_get_info(pattr->type, &ptype))) {\r
+ rv = 0;\r
+ kcdb_attrib_release_info(pattr);\r
+ continue;\r
+ }\r
+\r
+ if ((*ptype->comp)(ctx->headers[i].data,\r
+ ctx->headers[i].cb_data,\r
+ (void *) buffer,\r
+ cb) != 0)\r
+ rv = 1;\r
+\r
+ kcdb_type_release_info(ptype);\r
+ kcdb_attrib_release_info(pattr);\r
+ }\r
+\r
+ return rv;\r
+ } else\r
+ return 0;\r
+}\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation\r
+# files (the "Software"), to deal in the Software without\r
+# restriction, including without limitation the rights to use, copy,\r
+# modify, merge, publish, distribute, sublicense, and/or sell copies\r
+# of the Software, and to permit persons to whom the Software is\r
+# furnished to do so, subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+#\r
+\r
+$file_prefix = <<EOS;\r
+/*\r
+This file was autogenerated from src/ui/actiondef.cfg and src/ui/actions.csv.\r
+\r
+Do not modify directly.\r
+*/\r
+\r
+#include<khuidefs.h>\r
+#include<khhelp.h>\r
+#include"../ui/resource.h"\r
+\r
+khui_action khui_actions [] = {\r
+EOS\r
+\r
+$record_prefix = "{";\r
+\r
+$record_sep = ",\n";\r
+\r
+$record_postfix = "}";\r
+\r
+$file_postfix = <<EOS;\r
+\r
+};\r
+\r
+int khui_n_actions = sizeof(khui_actions) / sizeof(khui_action);\r
+\r
+EOS\r
+\r
+$skip_lines = 1;\r
+\r
+sub rec_handler {\r
+ $arr = shift;\r
+ if($$arr[2] =~ /^$/) {\r
+ $$arr[2] = "NULL";\r
+ } else {\r
+ $$arr[2] = "L\"".$$arr[2]."\"";\r
+ }\r
+}\r
+\r
+$record_parser = \&rec_handler;\r
--- /dev/null
+Command,Type,Name,Img Normal,Img Hot,Img Disabled,Ico Normal,Ico Disabled,Caption,Tooltip,Topic,State\r
+KHUI_MENU_FILE,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_FILE,0,IDH_MENU_FILE,0\r
+KHUI_MENU_CRED,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_CRED,0,IDH_MENU_CRED,0\r
+KHUI_MENU_VIEW,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_VIEW,0,IDH_MENU_VIEW,0\r
+KHUI_MENU_OPTIONS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_OPTIONS,0,IDH_MENU_OPTIONS,0\r
+KHUI_MENU_HELP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_HELP,0,IDH_MENU_HELP,0\r
+KHUI_MENU_LAYOUT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_LAYOUT,0,0,0\r
+KHUI_MENU_TOOLBARS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_TOOLBARS,0,0,0\r
+KHUI_ACTION_PROPERTIES,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_PROPERTIES,0,IDH_ACTION_PROPERTIES,0\r
+KHUI_ACTION_EXIT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_EXIT,0,IDH_ACTION_EXIT,0\r
+KHUI_ACTION_SET_DEF_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_SET_DEF_ID,0,IDH_ACTION_SET_DEF_ID,0\r
+KHUI_ACTION_SET_SRCH_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_SET_SRCH_ID,0,IDH_ACTION_SET_SRCH_ID,KHUI_ACTIONSTATE_DISABLED\r
+KHUI_ACTION_PASSWD_ID,KHUI_ACTIONTYPE_TRIGGER,,IDB_CHPW,0,IDB_CHPW_DIS,IDB_CHPW_SM,IDB_CHPW_DIS_SM,IDS_ACTION_PASSWD_ID,0,IDH_ACTION_PASSWD_ID,0\r
+KHUI_ACTION_NEW_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_NEW,0,IDB_TK_NEW_DIS,IDB_TK_NEW_SM,IDB_TK_NEW_DIS_SM,IDS_ACTION_NEW_CRED,0,IDH_ACTION_NEW_CRED,0\r
+KHUI_ACTION_RENEW_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_REFRESH,0,IDB_TK_REFRESH_DIS,IDB_TK_REFRESH_SM,IDB_TK_REFRESH_DIS_SM,IDS_ACTION_RENEW_CRED,0,0,0\r
+KHUI_ACTION_DESTROY_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_DELETE,0,IDB_TK_DELETE_DIS,IDB_TK_DELETE_SM,IDB_TK_DELETE_DIS_SM,IDS_ACTION_DESTROY_CRED,0,0,0\r
+KHUI_ACTION_LAYOUT_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_ID,0,0,KHUI_ACTIONSTATE_CHECKED\r
+KHUI_ACTION_LAYOUT_TYPE,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_TYPE,0,0,KHUI_ACTIONSTATE_DISABLED\r
+KHUI_ACTION_LAYOUT_LOC,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_LOC,0,0,0\r
+KHUI_ACTION_TB_STANDARD,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_TB_STANDARD,0,0,KHUI_ACTIONSTATE_CHECKED\r
+KHUI_ACTION_CHOOSE_COLS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_CHOOSE_COLS,0,IDH_ACTION_CHOOSE_COLS,KHUI_ACTIONSTATE_DISABLED\r
+KHUI_ACTION_DEBUG_WINDOW,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_DEBUG_WINDOW,0,IDH_ACTION_DEBUG_WINDOW,KHUI_ACTIONSTATE_DISABLED\r
+KHUI_ACTION_VIEW_REFRESH,KHUI_ACTIONTYPE_TRIGGER,,IDB_VW_REFRESH,0,0,IDB_VW_REFRESH_SM,0,IDS_ACTION_VIEW_REFRESH,0,IDH_ACTION_VIEW_REFRESH,0\r
+KHUI_ACTION_OPT_IDENTS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_IDENTS,0,IDH_ACTION_OPT_INIT,0\r
+KHUI_ACTION_OPT_KHIM,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_KHIM,0,IDH_ACTION_OPT_KHIM,0\r
+KHUI_ACTION_OPT_NOTIF,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_NOTIF,0,IDH_ACTION_OPT_NOTIF,0\r
+KHUI_ACTION_HELP_CTX,KHUI_ACTIONTYPE_TRIGGER,,IDB_HELP,0,0,IDB_HELP_SM,0,IDS_ACTION_HELP_CTX,0,0,0\r
+KHUI_ACTION_HELP_CONTENTS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_CONTENTS,0,0,0\r
+KHUI_ACTION_HELP_INDEX,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_INDEX,0,0,0\r
+KHUI_ACTION_HELP_ABOUT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_ABOUT,0,0,0\r
+KHUI_ACTION_OPEN_APP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPEN_APP,0,0,0\r
+KHUI_ACTION_CLOSE_APP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_CLOSE_APP,0,0,0\r
+KHUI_ACTION_IMPORT,KHUI_ACTIONTYPE_TRIGGER,,IDB_IMPORT,0,IDB_IMPORT_DIS,IDB_IMPORT_SM,IDB_IMPORT_SM_DIS,IDS_ACTION_IMPORT,0,0,0\r
+KHUI_PACTION_OK,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_OK,0,0,0\r
+KHUI_PACTION_CANCEL,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_CANCEL,0,0,0\r
+KHUI_PACTION_CLOSE,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_CLOSE,0,0,0\r
+KHUI_PACTION_BLANK,0,,IDB_TB_SPACE,0,IDB_TB_SPACE,IDB_TB_BLANK_SM,IDB_TB_BLANK_SM,0,0,0,KHUI_ACTIONSTATE_DISABLED\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+#include<assert.h>\r
+\r
+/***********************************************************************\r
+ Alerter\r
+***********************************************************************/\r
+\r
+khui_alert * kh_alerts = NULL;\r
+CRITICAL_SECTION cs_alerts;\r
+\r
+void \r
+alert_init(void)\r
+{\r
+ InitializeCriticalSection(&cs_alerts);\r
+}\r
+\r
+void \r
+alert_exit(void)\r
+{\r
+ DeleteCriticalSection(&cs_alerts);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_create_empty(khui_alert ** result)\r
+{\r
+ khui_alert * a;\r
+\r
+ a = malloc(sizeof(*a));\r
+ ZeroMemory(a, sizeof(*a));\r
+\r
+ a->magic = KHUI_ALERT_MAGIC;\r
+\r
+ /* set defaults */\r
+ a->severity = KHERR_INFO;\r
+ a->flags = KHUI_ALERT_FLAG_FREE_STRUCT;\r
+ \r
+ khui_alert_hold(a);\r
+ EnterCriticalSection(&cs_alerts);\r
+ LPUSH(&kh_alerts, a);\r
+ LeaveCriticalSection(&cs_alerts);\r
+\r
+ *result = a;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_create_simple(const wchar_t * title, \r
+ const wchar_t * message, \r
+ khm_int32 severity, \r
+ khui_alert ** result)\r
+{\r
+ khui_alert * a;\r
+\r
+ khui_alert_create_empty(&a);\r
+ khui_alert_set_title(a, title);\r
+ khui_alert_set_message(a, message);\r
+ khui_alert_set_severity(a, severity);\r
+\r
+ *result = a;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_title(khui_alert * alert, const wchar_t * title)\r
+{\r
+ size_t cb = 0;\r
+\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ if(title) {\r
+ if(FAILED(StringCbLength(title, \r
+ KHUI_MAXCB_TITLE - sizeof(wchar_t), \r
+ &cb))) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ cb += sizeof(wchar_t);\r
+ }\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ if(alert->title && (alert->flags & KHUI_ALERT_FLAG_FREE_TITLE)) {\r
+ free(alert->title);\r
+ alert->title = NULL;\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE;\r
+ }\r
+ if(title) {\r
+ alert->title = malloc(cb);\r
+ StringCbCopy(alert->title, cb, title);\r
+ alert->flags |= KHUI_ALERT_FLAG_FREE_TITLE;\r
+ }\r
+ LeaveCriticalSection(&cs_alerts);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags) \r
+{\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ if (mask & ~KHUI_ALERT_FLAGMASK_RDWR)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ alert->flags = \r
+ (alert->flags & ~mask) |\r
+ (flags & mask);\r
+ LeaveCriticalSection(&cs_alerts);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_severity(khui_alert * alert, khm_int32 severity)\r
+{\r
+\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ alert->severity = severity;\r
+ LeaveCriticalSection(&cs_alerts);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_suggestion(khui_alert * alert,\r
+ const wchar_t * suggestion) {\r
+ size_t cb = 0;\r
+\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ if(suggestion) {\r
+ if(FAILED(StringCbLength(suggestion, \r
+ KHUI_MAXCB_MESSAGE - sizeof(wchar_t), \r
+ &cb))) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ cb += sizeof(wchar_t);\r
+ }\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ if(alert->suggestion && \r
+ (alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST)) {\r
+\r
+ free(alert->suggestion);\r
+ alert->suggestion = NULL;\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST;\r
+\r
+ }\r
+\r
+ if(suggestion) {\r
+ alert->suggestion = malloc(cb);\r
+ StringCbCopy(alert->suggestion, cb, suggestion);\r
+ alert->flags |= KHUI_ALERT_FLAG_FREE_SUGGEST;\r
+ }\r
+ LeaveCriticalSection(&cs_alerts);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_message(khui_alert * alert, const wchar_t * message)\r
+{\r
+ size_t cb = 0;\r
+\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ if(message) {\r
+ if(FAILED(StringCbLength(message, \r
+ KHUI_MAXCB_MESSAGE - sizeof(wchar_t), \r
+ &cb))) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ cb += sizeof(wchar_t);\r
+ }\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ if(alert->message && \r
+ (alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE)) {\r
+\r
+ free(alert->message);\r
+ alert->message = NULL;\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE;\r
+\r
+ }\r
+\r
+ if(message) {\r
+ alert->message = malloc(cb);\r
+ StringCbCopy(alert->message, cb, message);\r
+ alert->flags |= KHUI_ALERT_FLAG_FREE_MESSAGE;\r
+ }\r
+ LeaveCriticalSection(&cs_alerts);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_clear_commands(khui_alert * alert)\r
+{\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ alert->n_alert_commands = 0;\r
+ LeaveCriticalSection(&cs_alerts);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_add_command(khui_alert * alert, khm_int32 command_id)\r
+{\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ if(alert->n_alert_commands >= KHUI_MAX_ALERT_COMMANDS)\r
+ rv = KHM_ERROR_NO_RESOURCES;\r
+ else {\r
+ alert->alert_commands[alert->n_alert_commands++] = command_id;\r
+ }\r
+ LeaveCriticalSection(&cs_alerts);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_show(khui_alert * alert)\r
+{\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ khui_alert_hold(alert);\r
+ /* the alert will be released when the message is processed */\r
+ kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW, 0, (void *) alert);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_show_simple(const wchar_t * title, \r
+ const wchar_t * message, \r
+ khm_int32 severity)\r
+{\r
+ khui_alert * a = NULL;\r
+ khm_int32 rv;\r
+\r
+ rv = khui_alert_create_simple(title, message, severity, &a);\r
+\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ rv = khui_alert_show(a);\r
+\r
+ khui_alert_release(a);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_hold(khui_alert * alert) \r
+{\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ alert->refcount++;\r
+ LeaveCriticalSection(&cs_alerts);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/* called with cs_alert held */\r
+static void \r
+free_alert(khui_alert * alert)\r
+{\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ LDELETE(&kh_alerts, alert);\r
+\r
+ if(alert->flags & KHUI_ALERT_FLAG_FREE_TITLE) {\r
+ assert(alert->title);\r
+ free(alert->title);\r
+ alert->title = NULL;\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE;\r
+ }\r
+ if(alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE) {\r
+ assert(alert->message);\r
+ free(alert->message);\r
+ alert->message = NULL;\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE;\r
+ }\r
+ if(alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST) {\r
+ assert(alert->suggestion);\r
+ free(alert->suggestion);\r
+ alert->suggestion = NULL;\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST;\r
+ }\r
+ if(alert->flags & KHUI_ALERT_FLAG_FREE_STRUCT) {\r
+ alert->flags &= ~KHUI_ALERT_FLAG_FREE_STRUCT;\r
+ alert->magic = 0;\r
+ free(alert);\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_release(khui_alert * alert) \r
+{\r
+ assert(alert->magic == KHUI_ALERT_MAGIC);\r
+\r
+ EnterCriticalSection(&cs_alerts);\r
+ if((--(alert->refcount)) == 0) {\r
+ free_alert(alert);\r
+ }\r
+ LeaveCriticalSection(&cs_alerts);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP void KHMAPI khui_alert_lock(khui_alert * alert)\r
+{\r
+ EnterCriticalSection(&cs_alerts);\r
+}\r
+\r
+KHMEXP void KHMAPI khui_alert_unlock(khui_alert * alert)\r
+{\r
+ LeaveCriticalSection(&cs_alerts);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+#include<kmm.h>\r
+#include<configui.h>\r
+#include<assert.h>\r
+\r
+khm_int32 cfgui_node_serial;\r
+LONG init_once = 0;\r
+CRITICAL_SECTION cs_cfgui;\r
+khui_config_node_i * cfgui_root_config;\r
+HWND hwnd_cfgui = NULL;\r
+\r
+static khui_config_node_i *\r
+cfgui_create_new_node(void) {\r
+ khui_config_node_i * node;\r
+\r
+ node = malloc(sizeof(*node));\r
+#ifdef DEBUG\r
+ assert(node);\r
+#endif\r
+ ZeroMemory(node, sizeof(*node));\r
+ node->magic = KHUI_CONFIG_NODE_MAGIC;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ node->id = ++cfgui_node_serial;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return node;\r
+}\r
+\r
+/* called with cs_cfgui held */\r
+static void \r
+cfgui_free_node(khui_config_node_i * node) {\r
+ if (!cfgui_is_valid_node(node))\r
+ return;\r
+\r
+ if (node->reg.name)\r
+ free((void *) node->reg.name);\r
+\r
+ if (node->reg.short_desc)\r
+ free((void *) node->reg.short_desc);\r
+\r
+ if (node->reg.long_desc)\r
+ free((void *) node->reg.long_desc);\r
+\r
+ node->magic = 0;\r
+\r
+ if (node->owner)\r
+ kmm_release_plugin(node->owner);\r
+\r
+ ZeroMemory(node, sizeof(*node));\r
+\r
+ free(node);\r
+}\r
+\r
+\r
+static void\r
+cfgui_hold_node(khui_config_node_i * node) {\r
+ EnterCriticalSection(&cs_cfgui);\r
+ node->refcount++;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+\r
+static void\r
+cfgui_release_node(khui_config_node_i * node) {\r
+ EnterCriticalSection(&cs_cfgui);\r
+ node->refcount--;\r
+ if (node->refcount == 0 &&\r
+ (node->flags & KHUI_CN_FLAG_DELETED)) {\r
+ khui_config_node_i * parent;\r
+ parent = TPARENT(node);\r
+#ifdef DEBUG\r
+ assert(TFIRSTCHILD(node) == NULL);\r
+ assert(parent != NULL);\r
+#endif\r
+ TDELCHILD(parent, node);\r
+ cfgui_free_node(node);\r
+ cfgui_release_node(parent);\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+static void \r
+cfgui_init_once(void) {\r
+ if (init_once == 0 &&\r
+ InterlockedIncrement(&init_once) == 1) {\r
+ InitializeCriticalSection(&cs_cfgui);\r
+ cfgui_root_config = cfgui_create_new_node();\r
+ cfgui_node_serial = 0;\r
+ hwnd_cfgui = NULL;\r
+ }\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_register(khui_config_node vparent,\r
+ const khui_config_node_reg * reg) {\r
+\r
+ size_t cb_name;\r
+ size_t cb_short_desc;\r
+ size_t cb_long_desc;\r
+ khui_config_node_i * node;\r
+ khui_config_node_i * parent;\r
+ khui_config_node t;\r
+ wchar_t * name;\r
+ wchar_t * short_desc;\r
+ wchar_t * long_desc;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (!reg ||\r
+ FAILED(StringCbLength(reg->name,\r
+ KHUI_MAXCB_NAME,\r
+ &cb_name)) ||\r
+ FAILED(StringCbLength(reg->short_desc,\r
+ KHUI_MAXCB_SHORT_DESC,\r
+ &cb_short_desc)) ||\r
+ FAILED(StringCbLength(reg->long_desc,\r
+ KHUI_MAXCB_LONG_DESC,\r
+ &cb_long_desc)) ||\r
+ (vparent &&\r
+ !cfgui_is_valid_node_handle(vparent)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if (KHM_SUCCEEDED(khui_cfg_open(vparent,\r
+ reg->name,\r
+ &t))) {\r
+ khui_cfg_release(t);\r
+ return KHM_ERROR_DUPLICATE;\r
+ }\r
+\r
+ cb_name += sizeof(wchar_t);\r
+ cb_short_desc += sizeof(wchar_t);\r
+ cb_long_desc += sizeof(wchar_t);\r
+\r
+ node = cfgui_create_new_node();\r
+\r
+ node->reg = *reg;\r
+ node->reg.flags &= KHUI_CNFLAGMASK_STATIC;\r
+\r
+ name = malloc(cb_name);\r
+ StringCbCopy(name, cb_name, reg->name);\r
+ short_desc = malloc(cb_short_desc);\r
+ StringCbCopy(short_desc, cb_short_desc, reg->short_desc);\r
+ long_desc = malloc(cb_long_desc);\r
+ StringCbCopy(long_desc, cb_long_desc, reg->long_desc);\r
+\r
+ node->reg.name = name;\r
+ node->reg.short_desc = short_desc;\r
+ node->reg.long_desc = long_desc;\r
+ node->flags = node->reg.flags;\r
+\r
+ if (vparent == NULL) {\r
+ parent = cfgui_root_config;\r
+ } else {\r
+ parent = cfgui_node_i_from_handle(vparent);\r
+ }\r
+\r
+ //node->owner = kmm_this_plugin();\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ TADDCHILD(parent, node);\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_open(khui_config_node vparent,\r
+ const wchar_t * name,\r
+ khui_config_node * result) {\r
+ khui_config_node_i * parent;\r
+ khui_config_node_i * c;\r
+ size_t sz;\r
+\r
+ cfgui_init_once();\r
+\r
+ if ((vparent &&\r
+ !cfgui_is_valid_node_handle(vparent)) ||\r
+ FAILED(StringCbLength(name, KHUI_MAXCCH_NAME, &sz)) ||\r
+ !result)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (vparent)\r
+ parent = cfgui_node_i_from_handle(vparent);\r
+ else\r
+ parent = cfgui_root_config;\r
+\r
+ c = TFIRSTCHILD(parent);\r
+ while(c) {\r
+ if (!(c->flags & KHUI_CN_FLAG_DELETED) &&\r
+ !wcscmp(c->reg.name, name))\r
+ break;\r
+ c = LNEXT(c);\r
+ }\r
+\r
+ if (c) {\r
+ *result = cfgui_handle_from_node_i(c);\r
+ cfgui_hold_node(c);\r
+ } else {\r
+ *result = NULL;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ if (*result)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_remove(khui_config_node vnode) {\r
+ khui_config_node_i * node;\r
+ if (!cfgui_is_valid_node_handle(vnode))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ node->flags |= KHUI_CN_FLAG_DELETED;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_hold(khui_config_node vnode) {\r
+ if (!cfgui_is_valid_node_handle(vnode))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cfgui_hold_node(cfgui_node_i_from_handle(vnode));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_release(khui_config_node vnode) {\r
+ if (!cfgui_is_valid_node_handle(vnode))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cfgui_release_node(cfgui_node_i_from_handle(vnode));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_first_child(khui_config_node vparent,\r
+ khui_config_node * result) {\r
+ khui_config_node_i * parent;\r
+ khui_config_node_i * c;\r
+\r
+ cfgui_init_once();\r
+\r
+ if((vparent && !cfgui_is_valid_node_handle(vparent)) ||\r
+ !result)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vparent)) {\r
+ parent = cfgui_node_i_from_handle(vparent);\r
+ } else if (!vparent) {\r
+ parent = cfgui_root_config;\r
+ } else {\r
+ parent = NULL;\r
+ }\r
+\r
+ if (parent) {\r
+ for(c = TFIRSTCHILD(parent);\r
+ c && (c->reg.flags & KHUI_CNFLAG_SUBPANEL);\r
+ c = LNEXT(c));\r
+ } else {\r
+ c = NULL;\r
+ }\r
+\r
+ if (c)\r
+ cfgui_hold_node(c);\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ *result = c;\r
+\r
+ if (c)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_first_subpanel(khui_config_node vparent,\r
+ khui_config_node * result) {\r
+ khui_config_node_i * parent;\r
+ khui_config_node_i * c;\r
+\r
+ cfgui_init_once();\r
+\r
+ if((vparent && !cfgui_is_valid_node_handle(vparent)) ||\r
+ !result)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vparent)) {\r
+ parent = cfgui_node_i_from_handle(vparent);\r
+ } else if (!vparent) {\r
+ parent = cfgui_root_config;\r
+ } else {\r
+ parent = NULL;\r
+ }\r
+\r
+ if (parent) {\r
+ for(c = TFIRSTCHILD(parent);\r
+ c && !(c->reg.flags & KHUI_CNFLAG_SUBPANEL);\r
+ c = LNEXT(c));\r
+ } else {\r
+ c = NULL;\r
+ }\r
+\r
+ if (c)\r
+ cfgui_hold_node(c);\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ *result = c;\r
+\r
+ if (c)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_next(khui_config_node vnode,\r
+ khui_config_node * result) {\r
+\r
+ khui_config_node_i * node;\r
+ khui_config_node_i * nxt_node;\r
+\r
+ if (!cfgui_is_valid_node_handle(vnode) ||\r
+ !result)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode)) {\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ for(nxt_node = LNEXT(node);\r
+ nxt_node &&\r
+ ((node->reg.flags ^ nxt_node->reg.flags) & \r
+ KHUI_CNFLAG_SUBPANEL);\r
+ nxt_node = LNEXT(nxt_node));\r
+ if (nxt_node)\r
+ cfgui_hold_node(nxt_node);\r
+ } else {\r
+ nxt_node = NULL;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ *result = cfgui_handle_from_node_i(nxt_node);\r
+\r
+ if (nxt_node)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_next_release(khui_config_node * pvnode) {\r
+\r
+ khui_config_node_i * node;\r
+ khui_config_node_i * nxt_node;\r
+\r
+ if (!pvnode || \r
+ !cfgui_is_valid_node_handle(*pvnode))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(*pvnode)) {\r
+ node = cfgui_node_i_from_handle(*pvnode);\r
+ for(nxt_node = LNEXT(node);\r
+ nxt_node &&\r
+ ((node->reg.flags ^ nxt_node->reg.flags) & \r
+ KHUI_CNFLAG_SUBPANEL);\r
+ nxt_node = LNEXT(nxt_node));\r
+ if (nxt_node)\r
+ cfgui_hold_node(nxt_node);\r
+ cfgui_release_node(node);\r
+ } else {\r
+ nxt_node = NULL;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ *pvnode = cfgui_handle_from_node_i(nxt_node);\r
+\r
+ if (nxt_node)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_reg(khui_config_node vnode,\r
+ khui_config_node_reg * reg) {\r
+\r
+ khui_config_node_i * node;\r
+\r
+ cfgui_init_once();\r
+\r
+ if ((vnode && !cfgui_is_valid_node_handle(vnode)) ||\r
+ !reg)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode)) {\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ *reg = node->reg;\r
+ } else if (!vnode) {\r
+ node = cfgui_root_config;\r
+ *reg = node->reg;\r
+ } else {\r
+ node = NULL;\r
+ ZeroMemory(reg, sizeof(*reg));\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ if (node)\r
+ return KHM_ERROR_SUCCESS;\r
+ else\r
+ return KHM_ERROR_INVALID_PARM;\r
+}\r
+\r
+KHMEXP HWND KHMAPI\r
+khui_cfg_get_hwnd(khui_config_node vnode) {\r
+ khui_config_node_i * node;\r
+ HWND hwnd;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return NULL;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else \r
+ node = NULL;\r
+\r
+ if (node)\r
+ hwnd = node->hwnd;\r
+ else\r
+ hwnd = NULL;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return hwnd;\r
+}\r
+\r
+KHMEXP LPARAM KHMAPI\r
+khui_cfg_get_param(khui_config_node vnode) {\r
+ khui_config_node_i * node;\r
+ LPARAM param;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return 0;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else \r
+ node = NULL;\r
+\r
+ if (node)\r
+ param = node->param;\r
+ else\r
+ param = 0;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return param;\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_hwnd(khui_config_node vnode, HWND hwnd) {\r
+ khui_config_node_i * node;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else\r
+ node = NULL;\r
+\r
+ if (node)\r
+ node->hwnd = hwnd;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_param(khui_config_node vnode, LPARAM param) {\r
+ khui_config_node_i * node;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else\r
+ node = NULL;\r
+\r
+ if (node)\r
+ node->param = param;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+static cfg_node_data *\r
+get_node_data(khui_config_node_i * node,\r
+ void * key, \r
+ khm_boolean create) {\r
+ khm_size i;\r
+\r
+ for (i=0; i<node->n_data; i++) {\r
+ if (node->data[i].key == key)\r
+ return &(node->data[i]);\r
+ }\r
+\r
+ if (!create)\r
+ return NULL;\r
+\r
+ if (node->n_data + 1 > node->nc_data) {\r
+ cfg_node_data * newdata;\r
+\r
+ node->nc_data = UBOUNDSS((node->n_data + 1),\r
+ KHUI_NODEDATA_ALLOC_INCR,\r
+ KHUI_NODEDATA_ALLOC_INCR);\r
+#ifdef DEBUG\r
+ assert(node->nc_data >= node->n_data + 1);\r
+#endif\r
+ newdata = malloc(sizeof(*newdata) * node->nc_data);\r
+#ifdef DEBUG\r
+ assert(newdata);\r
+#endif\r
+ ZeroMemory(newdata, sizeof(*newdata) * node->nc_data);\r
+\r
+ if (node->data && node->n_data > 0) {\r
+ memcpy(newdata, node->data, node->n_data * sizeof(*newdata));\r
+ free(node->data);\r
+ }\r
+ node->data = newdata;\r
+ }\r
+\r
+ node->data[node->n_data].key = key;\r
+ node->n_data++;\r
+\r
+ return &(node->data[node->n_data - 1]);\r
+}\r
+\r
+KHMEXP HWND KHMAPI\r
+khui_cfg_get_hwnd_inst(khui_config_node vnode,\r
+ khui_config_node noderef) {\r
+ khui_config_node_i * node;\r
+ cfg_node_data * data;\r
+ HWND hwnd;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return NULL;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else \r
+ node = NULL;\r
+\r
+ if (node) {\r
+ data = get_node_data(node, noderef, FALSE);\r
+ if (data)\r
+ hwnd = data->hwnd;\r
+ else\r
+ hwnd = NULL;\r
+ } else\r
+ hwnd = NULL;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return hwnd;\r
+}\r
+\r
+KHMEXP LPARAM KHMAPI\r
+khui_cfg_get_param_inst(khui_config_node vnode,\r
+ khui_config_node noderef) {\r
+ khui_config_node_i * node;\r
+ cfg_node_data * data;\r
+ LPARAM lParam;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return 0;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else \r
+ node = NULL;\r
+\r
+ if (node) {\r
+ data = get_node_data(node, noderef, FALSE);\r
+ if (data)\r
+ lParam = data->param;\r
+ else\r
+ lParam = 0;\r
+ } else\r
+ lParam = 0;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return lParam;\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_hwnd_inst(khui_config_node vnode, \r
+ khui_config_node noderef,\r
+ HWND hwnd) {\r
+ khui_config_node_i * node;\r
+ cfg_node_data * data;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else \r
+ node = NULL;\r
+\r
+ if (node) {\r
+ data = get_node_data(node, noderef, TRUE);\r
+ if (data)\r
+ data->hwnd = hwnd;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_param_inst(khui_config_node vnode, \r
+ khui_config_node noderef,\r
+ LPARAM param) {\r
+ khui_config_node_i * node;\r
+ cfg_node_data * data;\r
+\r
+ cfgui_init_once();\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode))\r
+ node = cfgui_node_i_from_handle(vnode);\r
+ else if (!vnode)\r
+ node = cfgui_root_config;\r
+ else \r
+ node = NULL;\r
+\r
+ if (node) {\r
+ data = get_node_data(node, noderef, TRUE);\r
+ if (data)\r
+ data->param = param;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+\r
+/* called with cs_cfgui held */\r
+static void \r
+cfgui_clear_params(khui_config_node_i * node) {\r
+ khui_config_node_i * c;\r
+\r
+ node->hwnd = NULL;\r
+ node->param = 0;\r
+ node->flags &= KHUI_CNFLAGMASK_STATIC;\r
+ c = TFIRSTCHILD(node);\r
+ while(c) {\r
+ cfgui_clear_params(c);\r
+ c = LNEXT(c);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_clear_params(void) {\r
+\r
+ cfgui_init_once();\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ cfgui_clear_params(cfgui_root_config);\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_configui_handle(HWND hwnd) {\r
+ EnterCriticalSection(&cs_cfgui);\r
+ hwnd_cfgui = hwnd;\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_flags(khui_config_node vnode, \r
+ khm_int32 flags,\r
+ khm_int32 mask) {\r
+ khui_config_node_i * node;\r
+ khm_int32 newflags;\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return;\r
+\r
+ mask &= KHUI_CNFLAGMASK_DYNAMIC;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode) &&\r
+ hwnd_cfgui != NULL) {\r
+\r
+ node = cfgui_node_i_from_handle(vnode);\r
+\r
+ newflags = \r
+ (flags & mask) |\r
+ (node->flags & ~mask);\r
+\r
+ if (newflags != node->flags) {\r
+ node->flags = newflags;\r
+\r
+ if (hwnd_cfgui)\r
+ PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM((WORD)newflags, WMCFG_UPDATE_STATE),\r
+ (LPARAM) vnode);\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+/* called with cs_cfgui held */\r
+static void\r
+recalc_node_flags(khui_config_node vnode) {\r
+ khui_config_node_i * node;\r
+ khui_config_node_i * parent;\r
+ khm_int32 flags;\r
+ khm_size i;\r
+\r
+#ifdef DEBUG\r
+ assert(cfgui_is_valid_node_handle(vnode));\r
+#endif\r
+\r
+ node = cfgui_node_i_from_handle(vnode);\r
+\r
+ parent = TPARENT(node);\r
+#ifdef DEBUG\r
+ assert(parent);\r
+#endif\r
+\r
+ flags = 0;\r
+\r
+ /* this code is wrong. we need to go through all the subpanels in\r
+ the parent and pick the data record corresponding to this node\r
+ and then merge the flags from there. */\r
+ /* TODO: fix this */\r
+ for (i=0; i < parent->n_data; i++) {\r
+ if (parent->data[i].key == vnode)\r
+ flags |= parent->data[i].flags;\r
+ }\r
+\r
+ flags &= KHUI_CNFLAGMASK_DYNAMIC;\r
+\r
+ if ((node->flags & flags) != flags) {\r
+ node->flags = flags |\r
+ (node->flags & ~KHUI_CNFLAGMASK_DYNAMIC);\r
+\r
+ if (hwnd_cfgui)\r
+ PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY,\r
+ MAKEWPARAM((WORD) node->flags, WMCFG_UPDATE_STATE),\r
+ (LPARAM) vnode);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_flags_inst(khui_config_init_data * d,\r
+ khm_int32 flags,\r
+ khm_int32 mask) {\r
+ khui_config_node_i * node;\r
+ cfg_node_data * data;\r
+\r
+ cfgui_init_once();\r
+ if (!cfgui_is_valid_node_handle(d->this_node))\r
+ return;\r
+\r
+ mask &= KHUI_CNFLAGMASK_DYNAMIC;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(d->this_node))\r
+ node = cfgui_node_i_from_handle(d->this_node);\r
+ else \r
+ node = NULL;\r
+\r
+ if (node) {\r
+ data = get_node_data(node, d->ctx_node, TRUE);\r
+ if (data) {\r
+ khm_int32 new_flags;\r
+\r
+ new_flags = (flags & mask) |\r
+ (data->flags & ~mask);\r
+\r
+ if (new_flags != data->flags) {\r
+ data->flags = new_flags;\r
+\r
+ if (d->ctx_node != d->ref_node)\r
+ recalc_node_flags(d->ctx_node);\r
+ }\r
+ }\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_flags(khui_config_node vnode) {\r
+ khui_config_node_i * node;\r
+ khm_int32 flags = 0;\r
+\r
+ if (vnode &&\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return 0;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode) &&\r
+ hwnd_cfgui != NULL) {\r
+\r
+ node = cfgui_node_i_from_handle(vnode);\r
+\r
+ flags = node->flags;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return flags;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_name(khui_config_node vnode,\r
+ wchar_t * buf,\r
+ khm_size * cb_buf) {\r
+ khui_config_node_i * node;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if (!cb_buf ||\r
+ !cfgui_is_valid_node_handle(vnode))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ EnterCriticalSection(&cs_cfgui);\r
+ if (cfgui_is_valid_node_handle(vnode) &&\r
+ hwnd_cfgui != NULL) {\r
+ khm_size cb;\r
+\r
+ node = cfgui_node_i_from_handle(vnode);\r
+\r
+ StringCbLength(node->reg.name, KHUI_MAXCCH_NAME, &cb);\r
+\r
+ if (buf == NULL || cb > *cb_buf) {\r
+ *cb_buf = cb;\r
+ rv = KHM_ERROR_TOO_LONG;\r
+ } else {\r
+ StringCbCopy(buf, *cb_buf, node->reg.name);\r
+ *cb_buf = cb;\r
+ }\r
+ } else {\r
+ rv = KHM_ERROR_INVALID_PARM;\r
+ }\r
+ LeaveCriticalSection(&cs_cfgui);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_init_dialog_data(HWND hwnd_dlg,\r
+ const khui_config_init_data * data,\r
+ khm_size cb_extra,\r
+ khui_config_init_data ** new_data,\r
+ void ** extra) {\r
+ khm_size cb;\r
+ khui_config_init_data * d;\r
+\r
+ cb = sizeof(khui_config_init_data) + cb_extra;\r
+ d = malloc(cb);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ ZeroMemory(d, cb);\r
+\r
+ *d = *data;\r
+\r
+ if (d->ctx_node)\r
+ khui_cfg_hold(d->ctx_node);\r
+ if (d->this_node)\r
+ khui_cfg_hold(d->this_node);\r
+ if (d->ref_node)\r
+ khui_cfg_hold(d->ref_node);\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ SetWindowLongPtr(hwnd_dlg, DWLP_USER, (LONG_PTR) d);\r
+#pragma warning(pop)\r
+\r
+ if (new_data)\r
+ *new_data = d;\r
+ if (extra)\r
+ *extra = (void *) (d + 1);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_dialog_data(HWND hwnd_dlg,\r
+ khui_config_init_data ** data,\r
+ void ** extra) {\r
+ khui_config_init_data * d;\r
+\r
+ d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg,\r
+ DWLP_USER);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+\r
+ *data = d;\r
+ if (extra)\r
+ *extra = (void *) (d + 1);\r
+\r
+ return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_free_dialog_data(HWND hwnd_dlg) {\r
+ khui_config_init_data * d;\r
+\r
+ d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg,\r
+ DWLP_USER);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+\r
+ if (d) {\r
+ free(d);\r
+ }\r
+\r
+ return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_CONFIGUI_H\r
+#define __KHIMAIRA_CONFIGUI_H\r
+\r
+typedef struct tag_cfg_node_data {\r
+ void * key;\r
+ HWND hwnd;\r
+ LPARAM param;\r
+ khm_int32 flags;\r
+} cfg_node_data;\r
+\r
+typedef struct tag_khui_config_node_i {\r
+ khm_int32 magic;\r
+\r
+ khui_config_node_reg reg;\r
+ kmm_plugin owner;\r
+ khm_int32 id;\r
+\r
+ HWND hwnd;\r
+ LPARAM param;\r
+\r
+ cfg_node_data * data;\r
+ khm_size n_data;\r
+ khm_size nc_data;\r
+\r
+ khm_int32 refcount;\r
+ khm_int32 flags;\r
+ TDCL(struct tag_khui_config_node_i);\r
+} khui_config_node_i;\r
+\r
+#define KHUI_CONFIG_NODE_MAGIC 0x38f4cb52\r
+\r
+#define KHUI_NODEDATA_ALLOC_INCR 8\r
+\r
+#define KHUI_CN_FLAG_DELETED 0x0008\r
+\r
+#define cfgui_is_valid_node_handle(v) \\r
+((v) && ((khui_config_node_i *) (v))->magic == KHUI_CONFIG_NODE_MAGIC)\r
+\r
+#define cfgui_is_valid_node(n) \\r
+((n)->magic == KHUI_CONFIG_NODE_MAGIC)\r
+\r
+#define cfgui_node_i_from_handle(v) \\r
+((khui_config_node_i *) v)\r
+\r
+#define cfgui_handle_from_node_i(n) \\r
+((khui_config_node) n)\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+#include<assert.h>\r
+\r
+#define CW_ALLOC_INCR 8\r
+\r
+static void cw_free_prompts(khui_new_creds * c);\r
+\r
+static void cw_free_prompt(khui_new_creds_prompt * p);\r
+\r
+static khui_new_creds_prompt * \r
+cw_create_prompt(\r
+ khm_size idx,\r
+ khm_int32 type,\r
+ wchar_t * prompt,\r
+ wchar_t * def,\r
+ khm_int32 flags);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_create_cred_blob(khui_new_creds ** ppnc)\r
+{\r
+ khui_new_creds * c;\r
+\r
+ c = malloc(sizeof(*c));\r
+ ZeroMemory(c, sizeof(*c));\r
+\r
+ c->magic = KHUI_NC_MAGIC;\r
+ InitializeCriticalSection(&c->cs);\r
+ c->result = KHUI_NC_RESULT_CANCEL;\r
+ c->mode = KHUI_NC_MODE_MINI;\r
+\r
+ *ppnc = c;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_destroy_cred_blob(khui_new_creds *c)\r
+{\r
+ khm_size i;\r
+ size_t len;\r
+ EnterCriticalSection(&c->cs);\r
+ for(i=0;i<c->n_identities;i++) {\r
+ kcdb_identity_release(c->identities[i]);\r
+ }\r
+ cw_free_prompts(c);\r
+ khui_context_release(&c->ctx);\r
+ LeaveCriticalSection(&c->cs);\r
+ DeleteCriticalSection(&c->cs);\r
+\r
+ if(c->password) {\r
+ len = wcslen(c->password);\r
+ SecureZeroMemory(c->password, sizeof(wchar_t) * len);\r
+ free(c->password);\r
+ }\r
+\r
+ if(c->identities)\r
+ free(c->identities);\r
+\r
+ if(c->types)\r
+ free(c->types);\r
+\r
+ if (c->window_title)\r
+ free(c->window_title);\r
+\r
+ free(c);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_lock_nc(khui_new_creds * c)\r
+{\r
+ EnterCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_unlock_nc(khui_new_creds * c)\r
+{\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+#define NC_N_IDENTITIES 4\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_add_identity(khui_new_creds * c, \r
+ khm_handle id)\r
+{\r
+ if(id == NULL)\r
+ return KHM_ERROR_SUCCESS; /* we return success because adding\r
+ a NULL id is equivalent to adding\r
+ nothing. */\r
+ EnterCriticalSection(&(c->cs));\r
+\r
+ if(c->identities == NULL) {\r
+ c->nc_identities = NC_N_IDENTITIES;\r
+ c->identities = malloc(sizeof(*(c->identities)) * \r
+ c->nc_identities);\r
+ c->n_identities = 0;\r
+ } else if(c->n_identities + 1 > c->nc_identities) {\r
+ khm_handle * ni;\r
+\r
+ c->nc_identities = UBOUNDSS(c->n_identities + 1, \r
+ NC_N_IDENTITIES, \r
+ NC_N_IDENTITIES);\r
+ ni = malloc(sizeof(*(c->identities)) * c->nc_identities);\r
+ memcpy(ni, c->identities, \r
+ sizeof(*(c->identities)) * c->n_identities);\r
+ free(c->identities);\r
+ c->identities = ni;\r
+ }\r
+\r
+ kcdb_identity_hold(id);\r
+ c->identities[c->n_identities++] = id;\r
+ LeaveCriticalSection(&(c->cs));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_set_primary_id(khui_new_creds * c, \r
+ khm_handle id)\r
+{\r
+ khm_size i;\r
+ khm_int32 rv;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+\r
+ /* no change */\r
+ if((c->n_identities > 0 && c->identities[0] == id) ||\r
+ (c->n_identities == 0 && id == NULL)) {\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ for(i=0; i<c->n_identities; i++) {\r
+ kcdb_identity_release(c->identities[i]);\r
+ }\r
+ c->n_identities = 0;\r
+\r
+ LeaveCriticalSection(&(c->cs));\r
+ rv = khui_cw_add_identity(c,id);\r
+ if(c->hwnd != NULL) {\r
+ PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0);\r
+ }\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_add_type(khui_new_creds * c, \r
+ khui_new_creds_by_type * t)\r
+{\r
+ EnterCriticalSection(&c->cs);\r
+\r
+ if(c->n_types >= KHUI_MAX_NCTYPES) {\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_OUT_OF_BOUNDS;\r
+ }\r
+\r
+ if(c->types == NULL) {\r
+ c->nc_types = CW_ALLOC_INCR;\r
+ c->types = malloc(sizeof(*(c->types)) * c->nc_types);\r
+ c->type_subs = malloc(sizeof(*(c->type_subs)) * c->nc_types);\r
+ c->n_types = 0;\r
+ }\r
+\r
+ if(c->nc_types < c->n_types + 1) {\r
+ void * t;\r
+ khm_size n;\r
+\r
+ n = UBOUNDSS(c->n_types + 1, CW_ALLOC_INCR, CW_ALLOC_INCR);\r
+\r
+ t = malloc(sizeof(*(c->types)) * n);\r
+ memcpy(t, (void *) c->types, sizeof(*(c->types)) * c->n_types);\r
+ free(c->types);\r
+ c->types = t;\r
+\r
+ t = malloc(sizeof(*(c->type_subs)) * n);\r
+ memcpy(t, (void *) c->type_subs, sizeof(*(c->type_subs)) * c->n_types);\r
+ free(c->type_subs);\r
+ c->type_subs = t;\r
+\r
+ c->nc_types = n;\r
+ }\r
+\r
+ c->type_subs[c->n_types] = kcdb_credtype_get_sub(t->type);\r
+ c->types[c->n_types++] = t;\r
+ t->nc = c;\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_del_type(khui_new_creds * c, \r
+ khm_int32 type_id)\r
+{\r
+ khm_size i;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ for(i=0; i < c->n_types; i++) {\r
+ if(c->types[i]->type == type_id)\r
+ break;\r
+ }\r
+ if(i >= c->n_types) {\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+ c->n_types--;\r
+ for(;i < c->n_types; i++) {\r
+ c->types[i] = c->types[i+1];\r
+ c->type_subs[i] = c->type_subs[i+1];\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_find_type(\r
+ khui_new_creds * c, \r
+ khm_int32 type, \r
+ khui_new_creds_by_type **t)\r
+{\r
+ khm_size i;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ *t = NULL;\r
+ for(i=0;i<c->n_types;i++) {\r
+ if(c->types[i]->type == type) {\r
+ *t = c->types[i];\r
+ break;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ if(*t)\r
+ return KHM_ERROR_SUCCESS;\r
+ return KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_enable_type(\r
+ khui_new_creds * c,\r
+ khm_int32 type,\r
+ khm_boolean enable)\r
+{\r
+ khui_new_creds_by_type * t = NULL;\r
+ BOOL delta = FALSE;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) {\r
+ if(enable) {\r
+ delta = t->flags & KHUI_NCT_FLAG_DISABLED;\r
+ t->flags &= ~KHUI_NCT_FLAG_DISABLED;\r
+ }\r
+ else {\r
+ delta = !(t->flags & KHUI_NCT_FLAG_DISABLED);\r
+ t->flags |= KHUI_NCT_FLAG_DISABLED;\r
+ }\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ if(delta)\r
+ PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0,WMNC_TYPE_STATE), (LPARAM) type);\r
+\r
+ return (t)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI \r
+khui_cw_type_succeeded(\r
+ khui_new_creds * c,\r
+ khm_int32 type)\r
+{\r
+ khui_new_creds_by_type * t;\r
+ khm_boolean s;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) {\r
+ s = (t->flags & KHUI_NCT_FLAG_PROCESSED) && !(t->flags & KHUI_NC_RESPONSE_FAILED);\r
+ } else {\r
+ s = FALSE;\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return s;\r
+}\r
+\r
+static khui_new_creds_prompt * \r
+cw_create_prompt(khm_size idx,\r
+ khm_int32 type,\r
+ wchar_t * prompt,\r
+ wchar_t * def,\r
+ khm_int32 flags)\r
+{\r
+ khui_new_creds_prompt * p;\r
+ size_t cb_prompt;\r
+ size_t cb_def;\r
+\r
+ if(prompt && FAILED(StringCbLength(prompt, KHUI_MAXCB_PROMPT, &cb_prompt)))\r
+ return NULL;\r
+ if(def && FAILED(StringCbLength(def, KHUI_MAXCB_PROMPT_VALUE, &cb_def)))\r
+ return NULL;\r
+\r
+ p = malloc(sizeof(*p));\r
+ ZeroMemory(p, sizeof(*p));\r
+\r
+ if(prompt) {\r
+ cb_prompt += sizeof(wchar_t);\r
+ p->prompt = malloc(cb_prompt);\r
+ StringCbCopy(p->prompt, cb_prompt, prompt);\r
+ }\r
+\r
+ if(def) {\r
+ cb_def += sizeof(wchar_t);\r
+ p->def = malloc(cb_def);\r
+ StringCbCopy(p->def, cb_def, def);\r
+ }\r
+\r
+ p->value = malloc(KHUI_MAXCB_PROMPT_VALUE);\r
+ ZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE);\r
+\r
+ p->type = type;\r
+ p->flags = flags;\r
+ p->index = idx;\r
+\r
+ return p;\r
+}\r
+\r
+static void \r
+cw_free_prompt(khui_new_creds_prompt * p) {\r
+ size_t cb;\r
+\r
+ if(p->prompt) {\r
+ if(SUCCEEDED(StringCbLength(p->prompt, KHUI_MAXCB_PROMPT, &cb)))\r
+ SecureZeroMemory(p->prompt, cb);\r
+ free(p->prompt);\r
+ }\r
+\r
+ if(p->def) {\r
+ if(SUCCEEDED(StringCbLength(p->def, KHUI_MAXCB_PROMPT, &cb)))\r
+ SecureZeroMemory(p->def, cb);\r
+ free(p->def);\r
+ }\r
+\r
+ if(p->value) {\r
+ if(SUCCEEDED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb)))\r
+ SecureZeroMemory(p->value, cb);\r
+ free(p->value);\r
+ }\r
+\r
+ free(p);\r
+}\r
+\r
+static void \r
+cw_free_prompts(khui_new_creds * c)\r
+{\r
+ khm_size i;\r
+\r
+ if(c->banner != NULL) {\r
+ free(c->banner);\r
+ c->banner = NULL;\r
+ }\r
+\r
+ if(c->pname != NULL) {\r
+ free(c->pname);\r
+ c->pname = NULL;\r
+ }\r
+\r
+ for(i=0;i < c->n_prompts; i++) {\r
+ if(c->prompts[i]) {\r
+ cw_free_prompt(c->prompts[i]);\r
+ c->prompts[i] = NULL;\r
+ }\r
+ }\r
+\r
+ if(c->prompts != NULL) {\r
+ free(c->prompts);\r
+ c->prompts = NULL;\r
+ }\r
+\r
+ c->nc_prompts = 0;\r
+ c->n_prompts = 0;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_clear_prompts(khui_new_creds * c)\r
+{\r
+ SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c);\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ cw_free_prompts(c);\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_begin_custom_prompts(khui_new_creds * c, \r
+ khm_size n_prompts, \r
+ wchar_t * banner, \r
+ wchar_t * pname)\r
+{\r
+ size_t cb;\r
+\r
+ PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c);\r
+\r
+ EnterCriticalSection(&c->cs);\r
+#ifdef DEBUG\r
+ assert(c->n_prompts == 0);\r
+#endif\r
+ cw_free_prompts(c);\r
+\r
+ if(SUCCEEDED(StringCbLength(banner, KHUI_MAXCB_BANNER, &cb)) && \r
+ cb > 0) {\r
+ cb += sizeof(wchar_t);\r
+ c->banner = malloc(cb);\r
+ StringCbCopy(c->banner, cb, banner);\r
+ } else {\r
+ c->banner = NULL;\r
+ }\r
+\r
+ if(SUCCEEDED(StringCbLength(pname, KHUI_MAXCB_PNAME, &cb)) && \r
+ cb > 0) {\r
+\r
+ cb += sizeof(wchar_t);\r
+ c->pname = malloc(cb);\r
+ StringCbCopy(c->pname, cb, pname);\r
+\r
+ } else {\r
+\r
+ c->pname = NULL;\r
+\r
+ }\r
+\r
+ if(n_prompts > 0) {\r
+\r
+ c->prompts = malloc(sizeof(*(c->prompts)) * n_prompts);\r
+ ZeroMemory(c->prompts, sizeof(*(c->prompts)) * n_prompts);\r
+ c->nc_prompts = n_prompts;\r
+ c->n_prompts = 0;\r
+\r
+ } else {\r
+\r
+ c->prompts = NULL;\r
+ c->n_prompts = 0;\r
+ c->nc_prompts = 0;\r
+\r
+ PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c);\r
+ }\r
+\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_add_prompt(khui_new_creds * c, \r
+ khm_int32 type, \r
+ wchar_t * prompt, \r
+ wchar_t * def, \r
+ khm_int32 flags)\r
+{\r
+ khui_new_creds_prompt * p;\r
+\r
+ if(c->nc_prompts == 0 ||\r
+ c->n_prompts == c->nc_prompts)\r
+ return KHM_ERROR_INVALID_OPERATION;\r
+\r
+#ifdef DEBUG\r
+ assert(c->prompts != NULL);\r
+#endif\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ p = cw_create_prompt(c->n_prompts, type, prompt, def, flags);\r
+ if(p == NULL) {\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+ c->prompts[c->n_prompts++] = p;\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ if(c->n_prompts == c->nc_prompts) {\r
+ PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c);\r
+ /* once we are done adding prompts, switch to the auth\r
+ panel */\r
+#if 0\r
+ /* Actually, don't. Doing so can mean an unexpected panel\r
+ switch if fiddling on some other panel causes a change in\r
+ custom prompts. */\r
+ SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0, WMNC_DIALOG_SWITCH_PANEL), \r
+ (LPARAM) c);\r
+#endif\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_get_prompt_count(khui_new_creds * c,\r
+ khm_size * np) {\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ *np = c->n_prompts;\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_get_prompt(\r
+ khui_new_creds * c, \r
+ khm_size idx, \r
+ khui_new_creds_prompt ** prompt)\r
+{\r
+ khm_int32 rv;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ if(c->n_prompts <= idx ||\r
+ c->prompts == NULL) {\r
+\r
+ rv = KHM_ERROR_OUT_OF_BOUNDS;\r
+ *prompt = NULL;\r
+ } else {\r
+\r
+ *prompt = c->prompts[idx];\r
+ rv = KHM_ERROR_SUCCESS;\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_sync_prompt_values(khui_new_creds * c)\r
+{\r
+ khm_size i;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+ for(i=0;i<c->n_prompts;i++) {\r
+ khui_new_creds_prompt * p;\r
+ p = c->prompts[i];\r
+ if(p->hwnd_edit) {\r
+ /* Ideally, we would retrieve the text to a temporary\r
+ buffer with the c->cs released, obtain c->cs and copy the\r
+ text to p->value. However, I'm not going to bother as the\r
+ code paths we are touching here do not need c->cs while\r
+ setting p->value does */\r
+ GetWindowText(p->hwnd_edit, p->value, \r
+ KHUI_MAXCCH_PROMPT_VALUE);\r
+ }\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_get_prompt_value(khui_new_creds * c, \r
+ khm_size idx, \r
+ wchar_t * buf, \r
+ khm_size *cbbuf)\r
+{\r
+ khui_new_creds_prompt * p;\r
+ khm_int32 rv;\r
+ size_t cb;\r
+\r
+ rv = khui_cw_get_prompt(c, idx, &p);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ EnterCriticalSection(&c->cs);\r
+\r
+ if(FAILED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) {\r
+ *cbbuf = 0;\r
+ if(buf != NULL)\r
+ *buf = 0;\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+ cb += sizeof(wchar_t);\r
+\r
+ if(buf == NULL || *cbbuf < cb) {\r
+ *cbbuf = cb;\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ StringCbCopy(buf, *cbbuf, p->value);\r
+ *cbbuf = cb;\r
+ LeaveCriticalSection(&c->cs);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_set_response(khui_new_creds * c, \r
+ khm_int32 type, \r
+ khm_int32 response)\r
+{\r
+ khui_new_creds_by_type * t = NULL;\r
+ EnterCriticalSection(&c->cs);\r
+ khui_cw_find_type(c, type, &t);\r
+ c->response |= response & KHUI_NCMASK_RESPONSE;\r
+ if(t) {\r
+ t->flags &= ~KHUI_NCMASK_RESULT;\r
+ t->flags |= (response & KHUI_NCMASK_RESULT);\r
+ if (!(response & KHUI_NC_RESPONSE_NOEXIT) &&\r
+ !(response & KHUI_NC_RESPONSE_PENDING))\r
+ t->flags |= KHUI_NC_RESPONSE_COMPLETED;\r
+ }\r
+ LeaveCriticalSection(&c->cs);\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+/* only called from a identity provider callback */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cw_add_control_row(khui_new_creds * c,\r
+ HWND label,\r
+ HWND input,\r
+ khui_control_size size)\r
+{\r
+ if (c && c->hwnd) {\r
+ khui_control_row row;\r
+\r
+ row.label = label;\r
+ row.input = input;\r
+ row.size = size;\r
+\r
+ SendMessage(c->hwnd,\r
+ KHUI_WM_NC_NOTIFY,\r
+ MAKEWPARAM(0, WMNC_ADD_CONTROL_ROW),\r
+ (LPARAM) &row);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_ACTION_H\r
+#define __KHIMAIRA_ACTION_H\r
+\r
+/*! \addtogroup khui\r
+ @{*/\r
+/*! \defgroup khui_actions Actions\r
+ @{*/\r
+\r
+/*! \brief An action */\r
+typedef struct tag_khui_action {\r
+ int cmd; /*!< command id */\r
+ int type; /*!< combination of KHUI_ACTIONTYPE_* */\r
+ wchar_t * name; /*!< name for named actions. NULL if not named. */\r
+\r
+ /* normal, hot and disabled are toolbar sized bitmaps */\r
+ int ib_normal; /*!< normal bitmap (index) */\r
+ int ib_hot; /*!< hot bitmap (index) */\r
+ int ib_disabled; /*!< disabled bitmap (index) */\r
+\r
+ int ib_icon; /*!< index of small (16x16) icon (for menu) */\r
+ int ib_icon_dis; /*!< index of disabled (greyed) icon */\r
+\r
+ int is_caption; /*!< index of string resource for caption */\r
+ int is_tooltip; /*!< same for description / tooltip */\r
+ int ih_topic; /*!< help topic */\r
+ int state; /*!< current state. combination of KHUI_ACTIONSTATE_* */\r
+} khui_action;\r
+\r
+/*! \brief Unknown action type */\r
+#define KHUI_ACTIONTYPE_NONE 0\r
+\r
+/*! \brief A trigger type action */\r
+#define KHUI_ACTIONTYPE_TRIGGER 1\r
+\r
+/*! \brief A toggle type action\r
+\r
+ A toggle type action typically changes the CHECKED state of the\r
+ action each time it is invoked.\r
+ */\r
+#define KHUI_ACTIONTYPE_TOGGLE 2\r
+\r
+/*! \brief The action is enabled */\r
+#define KHUI_ACTIONSTATE_ENABLED 0\r
+/*! \brief The action is diabled */\r
+#define KHUI_ACTIONSTATE_DISABLED 1\r
+/*! \brief For toggle type actions, the action is checked */\r
+#define KHUI_ACTIONSTATE_CHECKED 2\r
+/*! \brief The action is hot\r
+\r
+ Typically this means that the user is hovering the pointing device\r
+ over a UI element representing the action.\r
+ */\r
+#define KHUI_ACTIONSTATE_HOT 4\r
+\r
+#ifdef NOEXPORT\r
+#define ACTION_SIMPLE(c,cap,des,top) \\r
+ {c,KHUI_ACTIONTYPE_TRIGGER,0,0,0,0,0,cap,des,top,0}\r
+\r
+#define ACTION_FULL(cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state) \\r
+ {cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state}\r
+\r
+#define ACTION_SIMPLE_IMAGE(c,inormal, ihot, idis, isml, ismld,cap, des, top) \\r
+ {c,KHUI_ACTIONTYPE_TRIGGER,inormal,ihot,idis,isml,ismld,cap,des,top,0}\r
+#endif\r
+\r
+/*! \brief A reference to an action */\r
+typedef struct tag_khui_action_ref {\r
+ int flags;\r
+ union {\r
+ int action;\r
+ khui_action * p_action;\r
+ };\r
+} khui_action_ref;\r
+\r
+#define KHUI_ACTIONREF_SUBMENU 0x01\r
+#define KHUI_ACTIONREF_SEP 0x02\r
+#define KHUI_ACTIONREF_PACTION 0x04\r
+#define KHUI_ACTIONREF_FREE_PACTION 0x08\r
+#define KHUI_ACTIONREF_END 0x10\r
+#define KHUI_ACTIONREF_DEFAULT 0x20\r
+\r
+#ifdef NOEXPORT\r
+#define MENU_ACTION(c) {0,c}\r
+#define MENU_DEFACTION(c) {KHUI_ACTIONREF_DEFAULT, c}\r
+#define MENU_SUBMENU(s) {KHUI_ACTIONREF_SUBMENU,s}\r
+#define MENU_SEP() {KHUI_ACTIONREF_SEP,KHUI_MENU_SEP}\r
+#define MENU_END() {KHUI_ACTIONREF_END,KHUI_MENU_END}\r
+#endif\r
+\r
+/*! \brief Menu definition */\r
+typedef struct tag_khui_menu_def {\r
+ int cmd; /*!< Action associated with menu */\r
+ int state; /*!< combination of KHUI_MENUSTATE_* */\r
+ size_t n_items; /*!< total number of items or -1 if not\r
+ set. If this is -1, then the list of\r
+ actions must be terminated with a\r
+ ACTION_LIST_END entry. */\r
+ size_t nc_items; /*!< max number of items in the buffer\r
+ alocated for items. Ignored if\r
+ KHUI_MENUSTATE_CONSTANT is set in \a\r
+ state.*/\r
+ khui_action_ref *items; /*!< Action list terminated by,\r
+ ACTION_LIST_END. If \a n_items is set\r
+ to a value other than -1, the list\r
+ doesn't necessarily have to end with a\r
+ ACTION_LIST_END. */\r
+} khui_menu_def;\r
+\r
+#ifdef NOEXPORT\r
+#define CONSTMENU(c,s,i) {c,s,-1,-1,i}\r
+#endif\r
+\r
+#define KHUI_MENU_END -2\r
+#define KHUI_MENU_SEP -1\r
+\r
+#define KHUI_MENUSTATE_CONSTANT 0\r
+#define KHUI_MENUSTATE_ALLOCD 1\r
+\r
+/*! \brief Accelerator definition */\r
+typedef struct tag_khui_accel_def {\r
+ int cmd;\r
+ int mod;\r
+ int key;\r
+ int scope;\r
+} khui_accel_def;\r
+\r
+#define KHUI_ACCEL_SCOPE_GLOBAL 0\r
+\r
+#ifdef NOEXPORT\r
+\r
+extern khui_accel_def khui_accel_global[];\r
+extern int khui_n_accel_global;\r
+\r
+extern khui_action khui_actions[];\r
+extern int khui_n_actions;\r
+\r
+extern khui_menu_def khui_all_menus[];\r
+extern int khui_n_all_menus;\r
+\r
+#endif /* NOEXPORT */\r
+\r
+/* functions */\r
+\r
+KHMEXP khui_menu_def * KHMAPI khui_menu_create(int cmd);\r
+KHMEXP khui_menu_def * KHMAPI khui_menu_dup(khui_menu_def * src);\r
+KHMEXP void KHMAPI khui_menu_delete(khui_menu_def * d);\r
+KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id);\r
+KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags);\r
+\r
+/*! \brief Action scope identifiers \r
+\r
+ The scope identifier is a value which describes the scope of the\r
+ cursor context. See documentation on individual scope identifiers\r
+ for details.\r
+\r
+ The role of the scope identifier is to provide a summary of the\r
+ current cursor context. Specifically, these identify several\r
+ special cases of credential selection, such as the selection of an\r
+ entire identity, a credential type or a single credential. If\r
+ none of these are applicable, then the generic scope identifier\r
+ ::KHUI_SCOPE_GROUP is set or ::KHUI_SCOPE_NONE if there is nothing\r
+ selected.\r
+\r
+ Note that the scope typically only apply to cursor contexts and\r
+ not the selection context. Please see \r
+ \ref khui_context "UI Contexts" for more information.\r
+\r
+ \see \ref khui_context "UI Contexts"\r
+*/\r
+typedef enum tag_khui_scope {\r
+ KHUI_SCOPE_NONE,\r
+ /*!< No context. Nothing is selected. */\r
+\r
+ KHUI_SCOPE_IDENT, \r
+ /*!< Identity. The selection is the entire identity specified in\r
+ the \a identity field of the context. */\r
+\r
+ KHUI_SCOPE_CREDTYPE, \r
+ /*!< A credentials type. The selection is an entire credentials\r
+ type. If \a identity is non-NULL, then the scope is all the\r
+ credentials of type \a cred_type which belong to \a identity.\r
+ Otherwise, the selection is all credentials of type \a\r
+ cred_type.\r
+\r
+ \note The \a identity can be non-NULL even for the case where\r
+ all credentials of type \a cred_type under \a identity is the\r
+ same scope as all credentials of type \a cred_type under all\r
+ identities. */\r
+\r
+ KHUI_SCOPE_GROUP,\r
+ /*!< A grouping of credentials. The scope is a group of\r
+ credentials which can not be simplified using one of the other\r
+ context identifiers. The \a headers array contains \a n_headers\r
+ elements describing the outline level that has been selected.\r
+\r
+ \see ::khui_header\r
+ \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" */\r
+\r
+ KHUI_SCOPE_CRED\r
+ /*!< A single credential. Only a single credential was\r
+ selected. The \a cred field of the context specifies the\r
+ credential. The \a identity and \a cred_type fields specify the\r
+ identity and the credential type respectively. */\r
+} khui_scope;\r
+\r
+\r
+/*! \brief Outline header\r
+\r
+ Describes an outline header in the user interface.\r
+\r
+ \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description"\r
+ */\r
+typedef struct tag_khui_header {\r
+ khm_int32 attr_id; /*!< Attribute ID */\r
+ void * data; /*!< Value of attribute */\r
+ khm_size cb_data; /*!< Size of the value */\r
+} khui_header;\r
+\r
+/*! \brief Maximum number of outline headers\r
+\r
+ This is the maximum number of fields that the credentials view can\r
+ be grouped by.\r
+ */\r
+#define KHUI_MAX_HEADERS 6\r
+\r
+/*! \brief Action context\r
+\r
+ Represents the UI context for an action.\r
+ */\r
+typedef struct tag_khui_action_context {\r
+ khm_int32 magic; /*!< Internal. */\r
+ khui_scope scope; /*!< Context scope. One of ::khui_scope*/\r
+ khm_handle identity; /*!< Identity */\r
+ khm_int32 cred_type; /*!< Credential type ID */\r
+ khm_handle cred; /*!< Credential */\r
+\r
+ khui_header headers[KHUI_MAX_HEADERS];\r
+ /*!< The ordered set of outline\r
+ headers which define the current\r
+ cursor location. */\r
+\r
+ khm_size n_headers; /*!< Number of actual headers defined\r
+ above */\r
+\r
+ khm_handle credset; /*!< Handle to a credential set\r
+ containing the currently selected\r
+ credentials. When the context is\r
+ obtained through khui_context_get(),\r
+ this credential is returned in a\r
+ sealed state. */\r
+\r
+ khm_size n_sel_creds; /*!< Number of selected credentials */\r
+\r
+ void * int_buf; /*!< Internal. Do not use. */\r
+ khm_size int_cb_buf; /*!< Internal. Do not use. */\r
+ khm_size int_cb_used; /*!< Internal. Do not use. */\r
+\r
+ void * vparam; /*!< Optional data */\r
+ khm_size cb_vparam; /*!< Size of optional data */\r
+} khui_action_context;\r
+\r
+/*! \brief Set the current context\r
+\r
+ Changes the UI context to that represented by the parameters to\r
+ the function. Note that specifying a valid \a identity or \a cred\r
+ parameter will result in an automatic hold on the respective\r
+ object. The hold will stay until another call to\r
+ khui_context_set() overwrites the identity or credential handle or\r
+ a call to khui_context_reset() is made.\r
+\r
+ While this API is available, it is only called from the main\r
+ NetIDMgr application. Plugins do not have a good reason to call\r
+ this API directly and should not do so.\r
+\r
+ \param[in] scope The new context scope\r
+\r
+ \param[in] identity A handle to an identity. If this is not NULL,\r
+ then it should be a valid handle to an identity. Required if\r
+ \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope\r
+ specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise.\r
+\r
+ \param[in] cred_type A credentials type. Specify\r
+ ::KCDB_CREDTYPE_INVALID if this parameter is not given or not\r
+ relevant. Required if \a scope specifies\r
+ ::KHUI_SCOPE_CREDTYPE. Ignored otherwise.\r
+\r
+ \param[in] cred A handle to a credential. If this parameter is\r
+ not NULL it is expected to be a valid handle to a credential.\r
+ Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored\r
+ otherwise.\r
+\r
+ \param[in] headers An array of headers. The \a n_headers\r
+ parameter specifies the number of elements in the array. Set\r
+ to NULL if not specified. Required if \a scope specifies\r
+ ::KHUI_SCOPE_GROUP.\r
+\r
+ \param[in] n_headers Number of elements in \a headers. Must be\r
+ less than or equal to ::KHUI_MAX_HEADERS. Required if \a\r
+ headers is not NULL. Ignored otherwise.\r
+\r
+ \param[in] cs_src A handle to a credential set from which the\r
+ selected credentials will be extracted. The credentials that\r
+ are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set.\r
+\r
+ \note This function should only be called from the UI thread.\r
+ */\r
+KHMEXP void KHMAPI \r
+khui_context_set(khui_scope scope, \r
+ khm_handle identity, \r
+ khm_int32 cred_type, \r
+ khm_handle cred,\r
+ khui_header *headers,\r
+ khm_size n_headers,\r
+ khm_handle cs_src);\r
+\r
+/*! \brief Set the current context\r
+\r
+ Changes the UI context to that represented by the parameters to\r
+ the function. Note that specifying a valid \a identity or \a cred\r
+ parameter will result in an automatic hold on the respective\r
+ object. The hold will stay until another call to\r
+ khui_context_set() overwrites the identity or credential handle or\r
+ a call to khui_context_reset() is made.\r
+\r
+ While this API is available, it is only called from the main\r
+ NetIDMgr application. Plugins do not have a good reason to call\r
+ this API directly and should not do so.\r
+\r
+ \param[in] scope The new context scope\r
+\r
+ \param[in] identity A handle to an identity. If this is not NULL,\r
+ then it should be a valid handle to an identity. Required if\r
+ \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope\r
+ specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise.\r
+\r
+ \param[in] cred_type A credentials type. Specify\r
+ ::KCDB_CREDTYPE_INVALID if this parameter is not given or not\r
+ relevant. Required if \a scope specifies\r
+ ::KHUI_SCOPE_CREDTYPE. Ignored otherwise.\r
+\r
+ \param[in] cred A handle to a credential. If this parameter is\r
+ not NULL it is expected to be a valid handle to a credential.\r
+ Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored\r
+ otherwise.\r
+\r
+ \param[in] headers An array of headers. The \a n_headers\r
+ parameter specifies the number of elements in the array. Set\r
+ to NULL if not specified. Required if \a scope specifies\r
+ ::KHUI_SCOPE_GROUP.\r
+\r
+ \param[in] n_headers Number of elements in \a headers. Must be\r
+ less than or equal to ::KHUI_MAX_HEADERS. Required if \a\r
+ headers is not NULL. Ignored otherwise.\r
+\r
+ \param[in] cs_src A handle to a credential set from which the\r
+ selected credentials will be extracted. The credentials that\r
+ are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set.\r
+\r
+ \param[in] vparam Optional parameter blob\r
+\r
+ \param[in] cb_vparam Size of parameter blob\r
+\r
+ \note This function should only be called from the UI thread.\r
+ */\r
+KHMEXP void KHMAPI \r
+khui_context_set_ex(khui_scope scope, \r
+ khm_handle identity, \r
+ khm_int32 cred_type, \r
+ khm_handle cred,\r
+ khui_header *headers,\r
+ khm_size n_headers,\r
+ khm_handle cs_src,\r
+ void * vparam,\r
+ khm_size cb_vparam);\r
+\r
+/*! \brief Obtain the current UI context\r
+\r
+ The parameter specified by \a ctx will receive the current UI\r
+ context. If the context contains an identity or a credential\r
+ handle, a hold will be obtained on the relevant object. Use\r
+ khui_context_release() to release the holds obtained in a prior\r
+ call to khui_context_get().\r
+\r
+ \note The returned context should not be modified prior to calling\r
+ khui_context_release().\r
+*/\r
+KHMEXP void KHMAPI \r
+khui_context_get(khui_action_context * ctx);\r
+\r
+/*! \brief Create a new UI context\r
+\r
+ The created context does not have any relation to the current UI\r
+ context. This function is provided for use in situations where an\r
+ application needs to provide a scope description through a\r
+ ::khui_action_context structure.\r
+\r
+ Once the application is done with the context, it should call\r
+ khui_context_release() to release the created context.\r
+ */\r
+KHMEXP void KHMAPI\r
+khui_context_create(khui_action_context * ctx,\r
+ khui_scope scope,\r
+ khm_handle identity,\r
+ khm_int32 cred_type,\r
+ khm_handle cred);\r
+\r
+/*! \brief Release a context obtained using khui_context_get()\r
+\r
+ Releases all holds obtained on related objects in a prior call to\r
+ khui_context_get() and nullifies the context.\r
+\r
+ \note The context should not have been modified between calling\r
+ khui_context_get() and khui_context_release()\r
+ */\r
+KHMEXP void KHMAPI \r
+khui_context_release(khui_action_context * ctx);\r
+\r
+/*! \brief Reset the UI context\r
+\r
+ Nullifies the current UI context and releases any holds obtained\r
+ on objects related to the previous context.\r
+*/\r
+KHMEXP void KHMAPI \r
+khui_context_reset(void);\r
+\r
+/*! \brief Refresh context data\r
+\r
+ Setting the UI context involves other side effects such as\r
+ activation of or disabling certain actions based on the selection.\r
+ If an operation is performed which may affect the side effects,\r
+ khui_context_refresh() is called to refresh them.\r
+\r
+ An example is when setting the default identity. The state of the\r
+ action ::KHUI_ACTION_SET_DEF_ID depends on whether the currently\r
+ selected identity is the default. However, if the currently\r
+ selected identity becomes the default after selection, then\r
+ khui_context_refresh() should be called to adjust the state of the\r
+ ::KHUI_ACTION_SET_DEF_ID action.\r
+ */\r
+KHMEXP void KHMAPI \r
+khui_context_refresh(void);\r
+\r
+/*! \brief A filter function that filters for credentials in the cursor context\r
+\r
+ This is a function of type ::kcdb_cred_filter_func which can be\r
+ used to filter for credentials that are included in the cursor\r
+ context.\r
+\r
+ The \a rock parameter should be a pointer to a\r
+ ::khui_action_context structure which will be used as the filter.\r
+\r
+ For example, the following code will extract the cursor context\r
+ credentials into the credential set \a my_credset based on the UI\r
+ context \a my context:\r
+\r
+ \code\r
+ kcdb_credset_extract_filtered(my_credset,\r
+ NULL,\r
+ khui_context_cursor_filter,\r
+ (void *) my_context);\r
+ \endcode\r
+*/\r
+KHMEXP khm_int32 KHMAPI\r
+khui_context_cursor_filter(khm_handle cred,\r
+ khm_int32 flags,\r
+ void * rock);\r
+\r
+/*! \brief Get a string representation of an accelerator\r
+\r
+ \param[in] cmd Command for which to obtain the accelerator string for\r
+ \param[out] buf Buffer to receive the accelerator string\r
+ \param[in] bufsiz Size of the buffer in bytes. Note that the size of the\r
+ buffer must be sufficient to hold at least one character and a\r
+ NULL terminator.\r
+\r
+ \return TRUE if the operation was successful. FALSE otherwise.\r
+ */\r
+KHMEXP khm_boolean KHMAPI khui_get_cmd_accel_string(int cmd, wchar_t * buf, size_t bufsiz);\r
+\r
+KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void);\r
+\r
+/*! \brief Find a menu by id */\r
+KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id);\r
+\r
+/*! \brief Find an action by id */\r
+KHMEXP khui_action * KHMAPI khui_find_action(int id);\r
+\r
+/*! \brief Get the length of the action list */\r
+KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref);\r
+\r
+/*! \brief Find an action by name */\r
+KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name);\r
+\r
+/*! \brief Enables or disables a group of actions\r
+\r
+ The group of actions are specified by the menu definition. All\r
+ valid action entries in the menu are marked as enabled or disabled\r
+ according to the value of \a enable.\r
+ */\r
+KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable);\r
+\r
+/*! \brief Enables or disables an action\r
+\r
+ The action designated by the command \a cmd will either be enabled\r
+ or disabled depending on the \a enable parameter. If \a enable is\r
+ TRUE then the action is enabled.\r
+ */\r
+KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable);\r
+\r
+/*! \brief Check an action in an action group\r
+\r
+ Marks the action denoted by \a cmd as checked and resets the\r
+ checked bit in all other actions.\r
+\r
+ \param[in] d A menu definition.\r
+ \param[in] cmd A command identifier. Setting this to -1 will\r
+ reset the checked bit in all the actions in the menu\r
+ definition.\r
+ */\r
+KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd);\r
+\r
+/*!\cond INTERNAL */\r
+\r
+/*! \brief Initialize actions\r
+\r
+ \note Only called by the NetIDMgr application\r
+ */\r
+KHMEXP void KHMAPI khui_init_actions(void);\r
+\r
+/*! \brief Exit actions\r
+\r
+ \note Only called by the NetIDMgr application\r
+ */\r
+KHMEXP void KHMAPI khui_exit_actions(void);\r
+\r
+/*! \endcond */\r
+\r
+/*@}*/\r
+/*@}*/\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_ACTIONDEF_H\r
+#define __KHIMAIRA_ACTIONDEF_H\r
+\r
+/*! \ingroup khui_actions\r
+ @{*/\r
+/*! \defgroup khui_std_actions Standard Actions\r
+@{ */\r
+\r
+/*!\name Standard actions\r
+ @{*/\r
+#define KHUI_ACTION_BASE 50000\r
+\r
+#define KHUI_ACTION_PROPERTIES (KHUI_ACTION_BASE + 0)\r
+#define KHUI_ACTION_EXIT (KHUI_ACTION_BASE + 1)\r
+#define KHUI_ACTION_SET_DEF_ID (KHUI_ACTION_BASE + 3)\r
+#define KHUI_ACTION_SET_SRCH_ID (KHUI_ACTION_BASE + 4)\r
+#define KHUI_ACTION_PASSWD_ID (KHUI_ACTION_BASE + 7)\r
+#define KHUI_ACTION_NEW_CRED (KHUI_ACTION_BASE + 8)\r
+#define KHUI_ACTION_CHOOSE_COLS (KHUI_ACTION_BASE + 9)\r
+#define KHUI_ACTION_DEBUG_WINDOW (KHUI_ACTION_BASE + 10)\r
+#define KHUI_ACTION_VIEW_REFRESH (KHUI_ACTION_BASE + 11)\r
+#define KHUI_ACTION_LAYOUT_ID (KHUI_ACTION_BASE + 12)\r
+#define KHUI_ACTION_LAYOUT_TYPE (KHUI_ACTION_BASE + 13)\r
+#define KHUI_ACTION_LAYOUT_LOC (KHUI_ACTION_BASE + 14)\r
+#define KHUI_ACTION_TB_STANDARD (KHUI_ACTION_BASE + 15)\r
+#define KHUI_ACTION_OPT_KHIM (KHUI_ACTION_BASE + 16)\r
+#define KHUI_ACTION_OPT_IDENTS (KHUI_ACTION_BASE + 17)\r
+#define KHUI_ACTION_OPT_NOTIF (KHUI_ACTION_BASE + 18)\r
+#define KHUI_ACTION_HELP_CTX (KHUI_ACTION_BASE + 19)\r
+#define KHUI_ACTION_HELP_CONTENTS (KHUI_ACTION_BASE + 20)\r
+#define KHUI_ACTION_HELP_INDEX (KHUI_ACTION_BASE + 21)\r
+#define KHUI_ACTION_HELP_ABOUT (KHUI_ACTION_BASE + 22)\r
+#define KHUI_ACTION_DESTROY_CRED (KHUI_ACTION_BASE + 23)\r
+#define KHUI_ACTION_RENEW_CRED (KHUI_ACTION_BASE + 24)\r
+#define KHUI_ACTION_OPEN_APP (KHUI_ACTION_BASE + 25)\r
+#define KHUI_ACTION_MENU_ACTIVATE (KHUI_ACTION_BASE + 26)\r
+#define KHUI_ACTION_CLOSE_APP (KHUI_ACTION_BASE + 27)\r
+#define KHUI_ACTION_IMPORT (KHUI_ACTION_BASE + 28)\r
+/*@}*/\r
+\r
+/*! \name Pseudo actions \r
+\r
+Pseudo actions do not trigger any specific function, but acts as a\r
+signal of some generic event which will be interpreted based on\r
+context.\r
+\r
+@{*/\r
+#define KHUI_PACTION_BASE (KHUI_ACTION_BASE + 500)\r
+\r
+#define KHUI_PACTION_MENU (KHUI_PACTION_BASE + 0)\r
+#define KHUI_PACTION_UP (KHUI_PACTION_BASE + 1)\r
+#define KHUI_PACTION_DOWN (KHUI_PACTION_BASE + 2)\r
+#define KHUI_PACTION_LEFT (KHUI_PACTION_BASE + 3)\r
+#define KHUI_PACTION_RIGHT (KHUI_PACTION_BASE + 4)\r
+#define KHUI_PACTION_ENTER (KHUI_PACTION_BASE + 5)\r
+#define KHUI_PACTION_ESC (KHUI_PACTION_BASE + 6)\r
+#define KHUI_PACTION_OK (KHUI_PACTION_BASE + 7)\r
+#define KHUI_PACTION_CANCEL (KHUI_PACTION_BASE + 8)\r
+#define KHUI_PACTION_CLOSE (KHUI_PACTION_BASE + 9)\r
+#define KHUI_PACTION_DELETE (KHUI_PACTION_BASE + 10)\r
+#define KHUI_PACTION_UP_EXTEND (KHUI_PACTION_BASE + 11)\r
+#define KHUI_PACTION_UP_TOGGLE (KHUI_PACTION_BASE + 12)\r
+#define KHUI_PACTION_DOWN_EXTEND (KHUI_PACTION_BASE + 13)\r
+#define KHUI_PACTION_DOWN_TOGGLE (KHUI_PACTION_BASE + 14)\r
+#define KHUI_PACTION_BLANK (KHUI_PACTION_BASE + 15)\r
+/*@}*/\r
+\r
+/*! \name Menus\r
+\r
+Stock menus.\r
+\r
+@{*/\r
+#define KHUI_MENU_BASE (KHUI_ACTION_BASE + 1000)\r
+\r
+#define KHUI_MENU_MAIN (KHUI_MENU_BASE + 0)\r
+#define KHUI_MENU_FILE (KHUI_MENU_BASE + 1)\r
+#define KHUI_MENU_CRED (KHUI_MENU_BASE + 2)\r
+#define KHUI_MENU_VIEW (KHUI_MENU_BASE + 3)\r
+#define KHUI_MENU_OPTIONS (KHUI_MENU_BASE + 4)\r
+#define KHUI_MENU_HELP (KHUI_MENU_BASE + 5)\r
+\r
+#define KHUI_MENU_LAYOUT (KHUI_MENU_BASE + 6)\r
+#define KHUI_MENU_TOOLBARS (KHUI_MENU_BASE + 7)\r
+\r
+#define KHUI_MENU_IDENT_CTX (KHUI_MENU_BASE + 8)\r
+#define KHUI_MENU_TOK_CTX (KHUI_MENU_BASE + 9)\r
+#define KHUI_MENU_ICO_CTX_MIN (KHUI_MENU_BASE + 12)\r
+#define KHUI_MENU_ICO_CTX_NORMAL (KHUI_MENU_BASE + 13)\r
+\r
+#define KHUI_PMENU_TOK_SEL (KHUI_MENU_BASE + 10)\r
+#define KHUI_PMENU_ID_SEL (KHUI_MENU_BASE + 11)\r
+\r
+/* Next menu: 14 */\r
+/*@}*/\r
+\r
+/*! \name Toolbars\r
+@{*/\r
+#define KHUI_TOOLBAR_BASE (KHUI_ACTION_BASE + 2000)\r
+\r
+#define KHUI_TOOLBAR_STANDARD (KHUI_TOOLBAR_BASE + 0)\r
+/*@}*/\r
+\r
+/* base for user actions */\r
+#define KHUI_USERACTION_BASE (KHUI_ACTION_BASE + 10000)\r
+/*@}*/\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHALERTS_H\r
+#define __KHIMAIRA_KHALERTS_H\r
+\r
+/*********************************************************************\r
+ Alerter and error reporting\r
+**********************************************************************/\r
+\r
+/*! \addtogroup khui\r
+@{ */\r
+\r
+/*!\defgroup khui_alert Alerter and Error Reporting\r
+@{*/\r
+\r
+#define KHUI_MAX_ALERT_COMMANDS 4\r
+\r
+/*! \brief An alert\r
+\r
+ Describes an alert message that will be shown to the user in a\r
+ variety of ways depending on the state of the NetIDMgr\r
+ application.\r
+ */\r
+typedef struct tag_khui_alert {\r
+ khm_int32 magic; /*!< Magic number. Always set to\r
+ KHUI_ALERT_MAGIC */\r
+\r
+ khm_int32 severity; /*!< The severity of the alert. One\r
+ of KHERR_ERROR, KHERR_WARNING or\r
+ KHERR_INFO. The default is\r
+ KHERR_INFO. Do not set directly.\r
+ Use khui_alert_set_severity(). */\r
+\r
+ khm_int32 alert_commands[KHUI_MAX_ALERT_COMMANDS];\r
+ /*!< The command buttons associated\r
+ with the alert. Use\r
+ khui_alert_add_command() to add a\r
+ command. The buttons will appear in\r
+ the order in which they were added.\r
+ The first button will be the\r
+ default. Each command should be a\r
+ known action identifier. */\r
+ khm_int32 n_alert_commands;\r
+\r
+ wchar_t * title; /*!< The title of the alert. Subject\r
+ to ::KHUI_MAXCCH_TITLE. Use\r
+ khui_alert_set_title() to set. Do\r
+ not modify directly. */\r
+\r
+ wchar_t * message; /*!< The main message of the alert.\r
+ Subject to ::KHUI_MAXCCH_MESSAGE.\r
+ Use khui_alert_set_message() to\r
+ set. Do not modify direcly. */\r
+\r
+ wchar_t * suggestion; /*!< A suggestion. Appears below\r
+ the message text. Use\r
+ khui_alert_set_suggestion() to\r
+ set. Do not modify directly. */\r
+\r
+#ifdef _WIN32\r
+ POINT target;\r
+#endif\r
+\r
+ khm_int32 flags; /*!< combination of\r
+ ::khui_alert_flags. Do not modify\r
+ directly. */\r
+\r
+ kherr_context * err_context; \r
+ /*!< If non-NULL at the time the alert\r
+ window is shown, this indicates that\r
+ the alert window should provide an\r
+ error viewer for the given error\r
+ context. */\r
+\r
+ kherr_event * err_event; \r
+ /*!< If non-NULL at the time the alert\r
+ window is shown, this indicates that\r
+ the alert window should provide an\r
+ error viewer for the given error\r
+ event. If an \a err_context is also\r
+ given, the error viewer for the\r
+ context will be below this error. */\r
+\r
+ khm_int32 response; \r
+ /*!< Once the alert is displayed to\r
+ the user, when the user clicks one\r
+ of the command buttons, the command\r
+ ID will be assigned here. */\r
+\r
+ int refcount; /* internal */\r
+\r
+ LDCL(struct tag_khui_alert); /* internal */\r
+} khui_alert;\r
+\r
+#define KHUI_ALERT_MAGIC 0x48c39ce9\r
+\r
+/*! \brief Maximum number of characters in title including terminating NULL\r
+ */\r
+#define KHUI_MAXCCH_TITLE 256\r
+\r
+/*! \brief Maximum number of bytes in title including terminating NULL\r
+ */\r
+#define KHUI_MAXCB_TITLE (KHUI_MAXCCH_TITLE * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum number of characters in message including terminating NULL\r
+ */\r
+#define KHUI_MAXCCH_MESSAGE 1024\r
+\r
+/*! \brief Maximum number of bytes in message including terminating NULL\r
+ */\r
+#define KHUI_MAXCB_MESSAGE (KHUI_MAXCCH_MESSAGE * sizeof(wchar_t))\r
+\r
+/*! \brief Maxumum number of characters in a suggestion including terminating NULL */\r
+#define KHUI_MAXCCH_SUGGESTION 1024\r
+\r
+/*! \brief Maximum number of bytes in a suggestion, including terminating NULL */\r
+#define KHUI_MAXCB_SUGGESTION (KHUI_MAXCCH_SUGGESTION * sizeof(wchar_t))\r
+\r
+/*! \brief Flags for an alert */\r
+enum khui_alert_flags {\r
+ KHUI_ALERT_FLAG_FREE_STRUCT =0x00000001, \r
+ /*!< Internal. Free the structure once the alert is done. */\r
+\r
+ KHUI_ALERT_FLAG_FREE_TITLE =0x00000002,\r
+ /*!< Internal. Free the \a title field when the alert is done.*/\r
+\r
+ KHUI_ALERT_FLAG_FREE_MESSAGE =0x00000004,\r
+ /*!< Internal. Free the \a message field when the alert is done. */\r
+\r
+ KHUI_ALERT_FLAG_FREE_SUGGEST =0x00000008,\r
+ /*!< Internal. Free the \a suggest field when the alert is done */\r
+\r
+ KHUI_ALERT_FLAG_DEFACTION =0x00000010,\r
+ /*!< If the message is displayed as a balloon prompt, then perform\r
+ the default action when it is clicked. The default action is\r
+ the first action added to the alert. Cannot be used if there\r
+ are no actions or if ::KHUI_ALERT_FLAG_REQUEST_WINDOW is\r
+ specified.*/\r
+\r
+ KHUI_ALERT_FLAG_VALID_TARGET =0x00010000,\r
+ /*!< There is a valid target for the alert */\r
+\r
+ KHUI_ALERT_FLAG_VALID_ERROR =0x00020000,\r
+ /*!< There is a valid error context associated with the alert */\r
+\r
+ KHUI_ALERT_FLAG_DISPLAY_WINDOW =0x01000000,\r
+ /*!< The alert has been displayed in a window */\r
+\r
+ KHUI_ALERT_FLAG_DISPLAY_BALLOON =0x02000000,\r
+ /*!< The alert has been displayed in a ballon */\r
+\r
+ KHUI_ALERT_FLAG_REQUEST_WINDOW =0x04000000,\r
+ /*!< The alert should be displayed in a window */\r
+\r
+ KHUI_ALERT_FLAG_REQUEST_BALLOON =0x08000000,\r
+ /*!< The alert should be displayed in a balloon */\r
+\r
+ KHUI_ALERT_FLAGMASK_RDWR =0x0C000010,\r
+ /*!< Bit mask of flags that can be set by khui_alert_set_flags() */\r
+};\r
+\r
+/*! \brief Create an empty alert object\r
+\r
+ The returned result is a held pointer to a ::khui_alert object.\r
+ Use khui_alert_release() to release the object.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_create_empty(khui_alert ** result);\r
+\r
+/*! \brief Create a simple alert object\r
+\r
+ The returned result is a held pointer to a ::khui_alert object.\r
+ Use khui_alert_release() to release the object.\r
+\r
+ \param[in] title The title of the alert. (Required, Localized)\r
+ Limited by ::KHUI_MAXCCH_TITLE.\r
+\r
+ \param[in] message The message. (Required. Localized). Limited\r
+ by ::KHUI_MAXCCH_MESSAGE.\r
+\r
+ \param[in] severity One of ::tag_kherr_severity\r
+\r
+ \param[out] result Receives a held pointer to a ::khui_alert\r
+ object upon successful completion.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_create_simple(const wchar_t * title, \r
+ const wchar_t * message, \r
+ khm_int32 severity, \r
+ khui_alert ** result);\r
+\r
+/*! \brief Set the title of an alert object\r
+\r
+ The title is limited by ::KHUI_MAXCCH_TITLE.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_title(khui_alert * alert, \r
+ const wchar_t * title);\r
+\r
+/*! \brief Set the message of an alert object\r
+\r
+ The message is limited by ::KHUI_MAXCCH_MESSAGE.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_message(khui_alert * alert, \r
+ const wchar_t * message);\r
+\r
+/*! \brief Set the suggestion of an alert object \r
+\r
+ The suggestion is limited by ::KHUI_MAXCCH_SUGGESTION\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_suggestion(khui_alert * alert,\r
+ const wchar_t * suggestion);\r
+\r
+/*! \brief Set the severity of the alert object\r
+\r
+ The severity value is one of ::tag_kherr_severity\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_set_severity(khui_alert * alert, \r
+ khm_int32 severity);\r
+\r
+/*! \brief Sets the flags of the alert\r
+\r
+ The flags are as defined in ::khui_alert_flags. The bits that are\r
+ on in \a mask will be set to the corresponding values in \a flags.\r
+ Only the bits specified in ::KHUI_ALERT_FLAGMASK_RDWR can be\r
+ specified in \a mask.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags);\r
+\r
+/*! \brief Clear all the commands from an alert object\r
+\r
+ \see khui_alert_add_command()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_clear_commands(khui_alert * alert);\r
+\r
+/*! \brief Add a command to an alert object\r
+\r
+ The command ID should be a valid registered command.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_add_command(khui_alert * alert, \r
+ khm_int32 command_id);\r
+\r
+/*! \brief Display an alert\r
+\r
+ The alert must have a valid \a severity, \a title and a \a message\r
+ to be displayed. Otherwise the function immediately returns with\r
+ a failure code.\r
+\r
+ The method used to display the alert is as follows:\r
+\r
+ - A balloon alert will be shown if one of the following is true: \r
+ - The NetIDMgr application is minimized or in the background. \r
+ - ::KHUI_ALERT_FLAG_REQUEST_BALLOON is specified in \a flags. \r
+ - Otherwise an alert window will be shown.\r
+\r
+ If the message, title of the alert is too long to fit in a balloon\r
+ prompt, there's a suggestion or if there are custom commands then\r
+ a placeholder balloon prompt will be shown which when clicked on,\r
+ shows the actual alert in an alert window. \r
+\r
+ An exception is when ::KHUI_ALERT_FLAG_DEFACTION is specified in\r
+ flags. In this case instead of a placeholder balloon prompt, one\r
+ will be shown with the actual title and message (truncated if\r
+ necessary). Clicking on the balloon will have the same effect as\r
+ choosing the first command in the action.\r
+\r
+ The placeholder balloon prompt will have a title derived from the\r
+ first 63 characters of the \a title field in the alert and a\r
+ message notifying the user that they should click the balloon\r
+ prompt for more information.\r
+\r
+ To this end, it is beneficial to limit the length of the title to\r
+ 63 characters (64 counting the terminating NULL). This limit is\r
+ enforced on Windows. Also, try to make the title descriptive.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_show(khui_alert * alert);\r
+\r
+/*! \brief Display a simple alert\r
+\r
+ \see khui_alert_show()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_show_simple(const wchar_t * title, \r
+ const wchar_t * message, \r
+ khm_int32 severity);\r
+\r
+/*! \brief Obtain a hold on the alert\r
+\r
+ An alert structure is only considered valid for the duration that\r
+ there is a hold on it.\r
+\r
+ Use khui_alert_release() to release the hold.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_hold(khui_alert * alert);\r
+\r
+/*! \brief Release the hold on the alert\r
+\r
+ Holds obtained on an alert using any of the functions that either\r
+ return a held pointer to an alert or implicitly obtains a hold on\r
+ it need to be undone through a call to khui_alert_release().\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_alert_release(khui_alert * alert);\r
+\r
+/*! \brief Lock an alert \r
+\r
+ Locking an alert disallows any other thread from accessing the\r
+ alert at the same time. NetIDMgr keeps a global list of all alert\r
+ objects and the user interface may access any of them at various\r
+ points in time. Locking the alert allows a thread to modify an\r
+ alert without causing another thread to be exposed to an\r
+ inconsistent state.\r
+\r
+ Once a thread obtains a lock on the alert, it must call\r
+ khui_alert_unlock() to unlock it. Otherwise no other thread will\r
+ be able to access the alert.\r
+\r
+ \note Currently the alert lock is global. Locking one alert\r
+ disallows access to all other alerts as well.\r
+\r
+ \note Calling khui_alert_lock() is only necessary if you are\r
+ modifying the ::khui_alert structure directly. Calling any of\r
+ the khui_alert_* functions to modify the alert does not\r
+ require obtaining a lock, as they perform synchronization\r
+ internally.\r
+*/\r
+KHMEXP void KHMAPI \r
+khui_alert_lock(khui_alert * alert);\r
+\r
+/*! \brief Unlock an alert \r
+\r
+ \see khui_alert_lock()\r
+*/\r
+KHMEXP void KHMAPI \r
+khui_alert_unlock(khui_alert * alert);\r
+\r
+/*!@}*/\r
+/*!@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHCONFIGUI_H\r
+#define __KHIMAIRA_KHCONFIGUI_H\r
+\r
+/*! \addtogroup khui\r
+@{ */\r
+\r
+/*! \defgroup khui_cfg Configuration Panels\r
+\r
+ Configuration panels are the primary means from which the user is\r
+ presented with an interface to change NetIDMgr and plugin\r
+ configuration.\r
+\r
+@{ */\r
+\r
+/*! \brief Configuration window notification message\r
+\r
+ This is the message that will be used to notify dialog panels.\r
+\r
+ The format of the message is :\r
+ - uMsg : KHUI_WM_CFG_NOTIFY\r
+ - HIWORD(wParam) : one of ::khui_wm_cfg_notifications\r
+\r
+ \note This is the same as ::KHUI_WM_NC_NOTIFY\r
+ */\r
+#define KHUI_WM_CFG_NOTIFY (WM_APP + 0x101)\r
+\r
+/*! \brief Configuration notifications\r
+\r
+ These are sent thorugh a ::KHUI_WM_CFG_NOTIFY message.\r
+\r
+ The format of the message is :\r
+ - uMsg : KHUI_WM_CFG_NOTIFY\r
+ - HIWORD(wParam) : one of ::khui_wm_cfg_notifications\r
+ */\r
+enum khui_wm_cfg_notifications {\r
+ WMCFG_SHOW_NODE = 1,\r
+ /*!< Sent to the configuration dialog to request that the panel\r
+ for the specified node be shown. The \a lParam message\r
+ parameter will contain a held ::khui_config_node handle. The\r
+ sender of the mssage is responsible for releasing the handle.*/\r
+\r
+ WMCFG_UPDATE_STATE = 2,\r
+ /*!< Sent to the configuration dialog to indicate that the state\r
+ flags for the specified configuration node have changed.\r
+\r
+ - LOWORD(wParam) : new flags\r
+ - lParam : ::khui_config_node for the node*/\r
+\r
+ WMCFG_APPLY = 3,\r
+ /*!< Sent to all the configuration panels when the user clicks the\r
+ 'Apply' button or the 'Ok' button. The panels are responsible\r
+ for applying the configuration changes and updating their flags\r
+ using khui_cfg_set_flags(). */\r
+};\r
+\r
+/*! \brief Registration information for a configuration node\r
+\r
+ \see khui_cfg_register_node()\r
+*/\r
+typedef struct tag_khui_config_node_reg {\r
+ const wchar_t * name; /*!< Internal identifier\r
+ (not-localized, required). The name\r
+ is required to be unique among\r
+ sibling nodes. However it is not\r
+ required to be unique globally. The\r
+ size of the name is constrained by\r
+ ::KHUI_MAXCCH_NAME*/\r
+\r
+ const wchar_t * short_desc; /*!< Short description (Localized,\r
+ required). This is the name which\r
+ identifies the node within a\r
+ collection of siblings. The size of\r
+ the string is constrained by\r
+ ::KHUI_MAXCCH_SHORT_DESC*/\r
+\r
+ const wchar_t * long_desc; /*!< Global name of the node.\r
+ (Localized, required). This\r
+ uniquely identifies the node in the\r
+ collection of all configuration\r
+ nodes. The size of the string is\r
+ constrained by\r
+ ::KHUI_MAXCCH_LONG_DESC.*/\r
+\r
+ HMODULE h_module; /*!< Module which contains the dialog\r
+ resource specified in \a\r
+ dlg_template */\r
+\r
+ LPWSTR dlg_template; /*!< Dialog template for the\r
+ configuration window */\r
+\r
+ DLGPROC dlg_proc; /*!< Dialog procedure */\r
+\r
+ khm_int32 flags; /*!< Flags. Can be a combination of\r
+ ::KHUI_CNFLAG_SORT_CHILDREN and\r
+ ::KHUI_CNFLAG_SUBPANEL*/\r
+\r
+} khui_config_node_reg;\r
+\r
+/*! \brief Sort the child nodes by short description */\r
+#define KHUI_CNFLAG_SORT_CHILDREN 0x0001\r
+\r
+/*! \brief Is a subpanel */\r
+#define KHUI_CNFLAG_SUBPANEL 0x0002\r
+\r
+/*! \brief Node represents a panel that is replicated for all child nodes */\r
+#define KHUI_CNFLAG_PLURAL 0x0004\r
+\r
+#define KHUI_CNFLAG_MODIFIED 0x0010\r
+#define KHUI_CNFLAG_APPLIED 0x0020\r
+\r
+#define KHUI_CNFLAGMASK_STATIC 0x000f\r
+#define KHUI_CNFLAGMASK_DYNAMIC 0x00f0\r
+\r
+/*! \brief Maximum length of the name in characters\r
+\r
+ The length includes the terminating NULL\r
+ */\r
+#define KHUI_MAXCCH_NAME 256\r
+\r
+/*! \brief Maximum length of the name in bytes\r
+\r
+ The length includes the terminating NULL\r
+ */\r
+#define KHUI_MAXCB_NAME (KHUI_MAXCCH_NAME * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum length of the long description in characters\r
+\r
+ The length includes the terminating NULL\r
+ */\r
+#define KHUI_MAXCCH_LONG_DESC 1024\r
+\r
+/*! \brief Maximum length of the long description in bytes\r
+\r
+ The length includes the terminating NULL\r
+ */\r
+#define KHUI_MAXCB_LONG_DESC (KHUI_MAXCCH_LONG_DESC * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum length of the short description in chracters\r
+\r
+ The length includes the terminating NULL\r
+ */\r
+#define KHUI_MAXCCH_SHORT_DESC 256\r
+\r
+/*! \brief Maximum length of the short description in bytes\r
+\r
+ The length includes the terminating NULL\r
+ */\r
+#define KHUI_MAXCB_SHORT_DESC (KHUI_MAXCCH_SHORT_DESC * sizeof(wchar_t))\r
+\r
+/*! \brief Width of a configuration dialog in dialog units\r
+\r
+ ::CFGDLG_WIDTH and ::CFGDLG_HEIGHT specify the dimensions of a\r
+ configuration dialog width and height in dialog units. The dialog\r
+ will be created as a child of the configuration dialog and placed\r
+ within it.\r
+ */\r
+#define CFGDLG_WIDTH 255\r
+\r
+/*! \brief Height of a configuration dialog in dialog units \r
+\r
+ \see ::CFGDLG_WIDTH\r
+*/\r
+#define CFGDLG_HEIGHT 182\r
+\r
+/*! \brief Width of a configuration tab dialog in dialog units\r
+\r
+ ::CFGDLG_TAB_WIDTH and ::CFGDLG_TAB_HEIGHT specify the dimensions\r
+ (in dialog units) of a dialog that will be placed within a tab\r
+ control for dialogs where multiple display panels need to be\r
+ shown.\r
+ */\r
+#define CFGDLG_TAB_WIDTH 235\r
+\r
+/*! \brief Height of configuration tab dialog in dialog units\r
+\r
+ \see ::CFGDLG_TAB_WIDTH\r
+ */\r
+#define CFGDLG_TAB_HEIGHT 151\r
+\r
+/*! \brief A handle to a configuration node\r
+\r
+ \see khui_cfg_open_node(), khui_cfg_close_node()\r
+*/\r
+typedef khm_handle khui_config_node;\r
+\r
+/*! \brief Initialization data passed in to a subpanel \r
+\r
+ When creating a subpanel, a pointer to the following strucutred\r
+ will be passed in as the creation parameter for the dialog.\r
+*/\r
+typedef struct tag_khui_config_init_data {\r
+ khui_config_node ctx_node; /*!< The node under which the current\r
+ dialog subpanel is being created. */\r
+\r
+ khui_config_node this_node; /*!< The node which provided the\r
+ registration information for the\r
+ creation of the subpanel. */\r
+\r
+ khui_config_node ref_node; /*!< The parent node of the subpanel\r
+ node. In nodes which have the\r
+ ::KHUI_CNFLAG_PLURAL, this would be\r
+ different from the \a node. This is\r
+ the node under which the subpanel\r
+ was registered. */\r
+} khui_config_init_data;\r
+\r
+/*! \brief Register a configuration node\r
+\r
+ The caller fills the registration information in the\r
+ ::khui_config_node_reg structre. If the call succeeds, the\r
+ function will return KHM_ERROR_SUCCESS.\r
+\r
+ \param[in] parent Parent of the node to be registered. Set to\r
+ NULL if the parent is the root node.\r
+\r
+ \param[in] reg Registration information\r
+\r
+ \param[out] new_id Receives the new unique identifier of the\r
+ configuration node. Pass in NULL if the new identifier is not\r
+ required.\r
+\r
+ \retval KHM_ERROR_SUCCESS Success\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters, or fields\r
+ of reg were invalid\r
+ \retval KHM_ERROR_DUPLICATE A node with the same name exists as a\r
+ child of the specified parent node.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_register(khui_config_node parent,\r
+ const khui_config_node_reg * reg);\r
+\r
+/*!\brief Open a configuration node by name\r
+\r
+ If successful, the \a result parameter will receive a handle to\r
+ the configuration node. Use khui_cfg_release() to release\r
+ the handle.\r
+\r
+ \param[in] parent Parent node. Set to NULL to specify root node.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_open(khui_config_node parent,\r
+ const wchar_t * name,\r
+ khui_config_node * result);\r
+\r
+/*! \brief Remove a configuration node\r
+\r
+ Marks a configuration node as deleted. Once all the handles,\r
+ including the handle specified in \a node have been released, it\r
+ will be deleted.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_remove(khui_config_node node);\r
+\r
+/*! \brief Hold a handle to a configuration node\r
+\r
+ Obtains an additional hold on the handle specified by \a node.\r
+ The hold must be released with a call to \a\r
+ khui_cfg_release()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_hold(khui_config_node node);\r
+\r
+/*! \brief Release a handle to a configuration node\r
+\r
+ \see khui_cfg_hold()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_release(khui_config_node node);\r
+\r
+/*! \brief Get a handle to the first child node\r
+\r
+ If the call is successful, \a result will receieve a handle to the\r
+ first child node of the specified node. The returned handle must\r
+ be released with a call to khui_cfg_release()\r
+\r
+ If \a parent does not have any child nodes, the function will\r
+ return KHM_ERROR_NOT_FOUND and set \a result to NULL.\r
+\r
+ \param[in] parent Parent node. Set to NULL to specify root node.\r
+ \param[out] result Receives a held handle to the first child node.\r
+\r
+ \see khui_cfg_get_next()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_first_child(khui_config_node parent,\r
+ khui_config_node * result);\r
+\r
+/*! \brief Get a handle to the first subpanel\r
+\r
+ If the call is successful, \a result will receieve a handle to the\r
+ first subpanel node of the specified node. The returned handle\r
+ must be released with a call to khui_cfg_release()\r
+\r
+ If \a parent does not have any subpanels, the function will return\r
+ KHM_ERROR_NOT_FOUND and set \a result to NULL.\r
+\r
+ A subpanel node is a node which has the ::KHUI_CNFLAG_SUBPANEL\r
+ flag set.\r
+\r
+ \param[in] parent Parent node. Set to NULL to specify root node.\r
+ \param[out] result Receives a held handle to the first subpanel node.\r
+\r
+ \see khui_cfg_get_next()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_first_subpanel(khui_config_node vparent,\r
+ khui_config_node * result);\r
+\r
+/*! \brief Get a handle to the next sibling node\r
+\r
+ If the call is successful, \a result will receive a held handle to\r
+ the next sibling node. The returned handle must be released with\r
+ a call to khui_cfg_release().\r
+\r
+ If there are no more sibling nodes, then the function return\r
+ KHM_ERROR_NOT_FOUND and set \a result to NULL.\r
+\r
+ This function can be used to traverse a list of child nodes as\r
+ well as a list of subpanel nodes.\r
+\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_next(khui_config_node node,\r
+ khui_config_node * result);\r
+\r
+/*! \brief Get a handle to the next sibling node\r
+\r
+ Similar to khui_cfg_get_next(), but implicitly releases the handle\r
+ that was supplied. Equivalent to doing :\r
+\r
+ \code\r
+ khui_cfg_get_next(node, &next);\r
+ khui_cfg_release(node);\r
+ node = next;\r
+ \endcode\r
+\r
+ \param[in,out] node On entry, specifies the node whose sibling\r
+ needs to be fetched. On exit, will have either NULL or a held\r
+ handle to the sibling node. The handle which was supplied to\r
+ the function is released.\r
+\r
+ \retval KHM_ERROR_SUCCESS The next node is now in \a node\r
+ \retval KHM_ERROR_INVALID_PARM \a node was not a valid handle\r
+ \retval KHM_ERROR_NOT_FOUND There are no more siblings. \a node\r
+ is set to NULL.\r
+\r
+ \note Even if there are no more siblings, the handle specified in\r
+ \a node on entry is released.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_next_release(khui_config_node * node);\r
+\r
+/*! \brief Get the name of a configuration node \r
+\r
+ Gets the name (not the short description or the long description)\r
+ of the given configuration node.\r
+*/\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_name(khui_config_node node,\r
+ wchar_t * buf,\r
+ khm_size * cb_buf);\r
+\r
+/*! \brief Get registration information for a node\r
+\r
+ The registration information that is returned is a shallow copy of\r
+ the data kept by NetIDMgr. In particular, the strings that will\r
+ be returned actually point to internal buffers and should not be\r
+ modified.\r
+\r
+ No further action is necessary to release the information.\r
+ However, the returned data ceases to be valid when \a node is\r
+ released with a call to khui_cfg_release().\r
+\r
+ \param[in] node Node for which information is requested. Can be NULL if requesting information about the root node.\r
+ \param[out] reg Pointer to a ::khui_config_node_reg structure.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_reg(khui_config_node node,\r
+ khui_config_node_reg * reg);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP HWND KHMAPI\r
+khui_cfg_get_hwnd_inst(khui_config_node node,\r
+ khui_config_node noderef);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP LPARAM KHMAPI\r
+khui_cfg_get_param_inst(khui_config_node node,\r
+ khui_config_node noderef);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_hwnd_inst(khui_config_node node, \r
+ khui_config_node noderef,\r
+ HWND hwnd);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_param_inst(khui_config_node node, \r
+ khui_config_node noderef,\r
+ LPARAM param);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP HWND KHMAPI\r
+khui_cfg_get_hwnd(khui_config_node node);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP LPARAM KHMAPI\r
+khui_cfg_get_param(khui_config_node node);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_hwnd(khui_config_node node, HWND hwnd);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_param(khui_config_node node, LPARAM param);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP void KHMAPI\r
+khui_cfg_clear_params(void);\r
+\r
+/*! \brief Internal use\r
+\r
+ This function is used internally by NetIDMgr. Do not use.\r
+*/\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_configui_handle(HWND hwnd);\r
+\r
+/*! \brief Update the state for the specified node\r
+\r
+ \param[in] node ::khui_config_node handle for the configuration node.\r
+\r
+ \param[in] flags New flags. Combination of ::KHUI_CNFLAG_APPLIED and ::KHUI_CNFLAG_MODIFIED\r
+\r
+ \param[in] mask Valid bits in \a flags\r
+\r
+ \note Should only be called from within the dialog procedure for\r
+ the configuration node.\r
+ */\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_flags(khui_config_node vnode, khm_int32 flags, khm_int32 mask);\r
+\r
+/*! \brief Retrieve the state flags for the configuration node\r
+\r
+ \see khui_cfg_set_flags()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_flags(khui_config_node vnode);\r
+\r
+/*! \brief Utility function: Initialize dialog box window data\r
+\r
+ This function initializes the dialog box window data using the\r
+ ::khui_config_init_data that was passed into the WM_INITDIALOG\r
+ message.\r
+\r
+ A new block of memory will be alocated to store the dialog data as\r
+ well as any extra space specified. A pointer to this memory block\r
+ will be stored in the \a DWLP_USER slot in the dialog box.\r
+\r
+ The allocated block of memory must be freed by a call to\r
+ khui_cfg_free_dialog_data(). While handling other messages, the\r
+ dialog data can be retrieved using khui_cfg_get_dialog_data().\r
+\r
+ \param[in] hwnd_dlg Handle to the dialog box\r
+\r
+ \param[in] data Pointer to the ::khui_config_init_data that was\r
+ passed in to WM_INITDIALOG (this is the value of \a lParam)\r
+\r
+ \param[in] cb_extra Number of extra bytes to allocate, along with\r
+ the space required to store the contents of\r
+ ::khui_config_init_data. The extra space will be initialized\r
+ to zero.\r
+\r
+ \param[out] new_data Receives a pointer to the copy of the\r
+ initialization data that was allocated. Optional. Pass in\r
+ NULL if this value is not required.\r
+\r
+ \param[out] extra Receives a pointer to the block of extra memory\r
+ allocated as specified in \a cb_extra. If \a cb_extra is 0,\r
+ then this receives a NULL.\r
+\r
+ \see khui_cfg_get_dialog_data(), khui_cfg_free_dialog_data()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_init_dialog_data(HWND hwnd_dlg,\r
+ const khui_config_init_data * data,\r
+ khm_size cb_extra,\r
+ khui_config_init_data ** new_data,\r
+ void ** extra);\r
+\r
+/*! \brief Utility function: Retrieves dialog data \r
+\r
+ Retrieves the dialog data previoulsy stored using\r
+ khui_cfg_init_dialog_data().\r
+\r
+ \param[in] hwnd_dlg Handle to the dialog box \r
+\r
+ \param[out] data Receives a pointer to the ::khui_config_init_data\r
+ block.\r
+ \r
+ \param[out] extra Receives a pointer to the extra memory\r
+ allocated. Optional (set to NULL if this value is not needed).\r
+*/\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_get_dialog_data(HWND hwnd_dlg,\r
+ khui_config_init_data ** data,\r
+ void ** extra);\r
+\r
+/*! \brief Utility function: Free dialog data\r
+\r
+ Deallocates the memory allcated in a previous call to\r
+ khui_cfg_init_dialog_data()\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cfg_free_dialog_data(HWND hwnd_dlg);\r
+\r
+/*! \brief Sets the instance flags for a subpanel\r
+\r
+ Since there can be more than one subpanel in a configuration\r
+ panel, they shouldn't modify the flags of the configuration node\r
+ directly. Instead, they should call this function to set the\r
+ instance flags.\r
+\r
+ The instance flags will be merged with the flags for the\r
+ configuration node automatically.\r
+ */\r
+KHMEXP void KHMAPI\r
+khui_cfg_set_flags_inst(khui_config_init_data * d,\r
+ khm_int32 flags,\r
+ khm_int32 mask);\r
+\r
+/*!@} */\r
+/*!@} */\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHHTLINK_H\r
+#define __KHIMAIRA_KHHTLINK_H\r
+\r
+/*! \addtogroup khui \r
+@{ */\r
+\r
+/*! \defgroup khui_hyperlink Hyperlink \r
+@{*/\r
+\r
+/*! \brief A hyperlink\r
+\r
+ When a link in a hypertext window is clicked, this structure is\r
+ passed along with the message.\r
+\r
+ The link text fields do to point to NULL terminated strings.\r
+ Instead, the length fields should be used to extract the string.\r
+ */\r
+typedef struct tag_khui_htwnd_link {\r
+ RECT r;\r
+ wchar_t * id;\r
+ int id_len;\r
+ wchar_t * param;\r
+ int param_len;\r
+} khui_htwnd_link;\r
+\r
+#define KHUI_MAXCCH_HTLINK_FIELD 256\r
+#define KHUI_MAXCB_HTLINK_FIELD (KHUI_MAXCCH_HTLINK_FIELD * sizeof(wchar_t))\r
+\r
+/*!@}*/\r
+/*!@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHNEWCRED_H\r
+#define __KHIMAIRA_KHNEWCRED_H\r
+\r
+/********************************************************************\r
+ New credentials windows\r
+*********************************************************************/\r
+\r
+/*! \addtogroup khui\r
+@{ */\r
+\r
+/*! \defgroup khui_cred Credentials acquisition \r
+\r
+ Declarations associated with credentials acquisition.\r
+\r
+@{ */\r
+\r
+/*! \brief Window message sent to credentials type panels\r
+\r
+ This message is sent to the child windows.\r
+\r
+ The format of the message is :\r
+ - uMsg : KHUI_WM_NC_NOTIFY\r
+ - HIWORD(wParam) : one of ::khui_wm_nc_notifications\r
+ - LPARAM : pointer to the ::khui_new_creds structure\r
+*/\r
+#define KHUI_WM_NC_NOTIFY (WM_APP + 0x101)\r
+\r
+/*! \brief The first control ID that may be used by an identity provider */\r
+#define KHUI_CW_ID_MIN 8016\r
+\r
+/*! \brief The maximum number of controls that may be created by an identity provider*/\r
+#define KHUI_CW_MAX_CTRLS 8\r
+\r
+/*! \brief The maximum control ID that may be used by an identity provider */\r
+#define KHUI_CW_ID_MAX (KHUI_CW_ID_MIN + KHUI_CW_MAX_CTRLS - 1)\r
+\r
+\r
+/*! \brief Credentials dialog notifications\r
+\r
+ These notifications will be sent to the individual dialog\r
+ procedures of the credential type panels as a ::KHUI_WM_NC_NOTIFY\r
+ message.\r
+*/\r
+enum khui_wm_nc_notifications {\r
+ WMNC_DIALOG_EXPAND = 1, \r
+ /*!< The dialog is getting expanded.\r
+\r
+ This message is sent to the new creds dialog to set the dialog\r
+ to expanded mode. In expanded mode, all credentials type panels\r
+ are visible as opposed to the compressed mode where they are not\r
+ visible. The message is not sent to credentials type panels.*/\r
+\r
+ WMNC_DIALOG_SETUP, \r
+ /*!< Sent by NetIDMgr to the new creds window to notify it that\r
+ the dialog should create all the type configuration panels.\r
+ \r
+ Until this message is issued, none of the credentials type\r
+ panels exist. The credentials type panels will receive\r
+ WM_INITDIALOG etc as per the normal dialog creation process. */\r
+\r
+ WMNC_DIALOG_ACTIVATE, \r
+ /*!< Sent by NetIDMgr to the new creds window to notify it that\r
+ the dialog should do final initialization work and activate. */\r
+\r
+ WMNC_DIALOG_MOVE, \r
+ /*!< Sent by the new creds widnow to all the panels notifying them\r
+ that the NC window is moving. */\r
+\r
+ WMNC_DIALOG_SWITCH_PANEL, \r
+ /*!< Sent to the new creds window to cause it to switch to the\r
+ panel identified by LOWORD(wParam).\r
+\r
+ Does nothing if the specified panel is already the current\r
+ panel. If the dialog is in compact mode and making the\r
+ specified panel visible requires switching to expanded mode, the\r
+ dialog will do so. */\r
+\r
+ WMNC_UPDATE_CREDTEXT, \r
+ /*!< Sent to all the credential type panels for a credentials\r
+ window to request them to update the credential text.\r
+\r
+ When sent to the new credentials window, causes it to send the\r
+ WMNC_UPDATE_CREDTEXT message to all the credential type panels\r
+ and update the cred text window.*/\r
+\r
+ WMNC_CREDTEXT_LINK, \r
+ /*!< Sent to a panel dialog proc when a user clicks a credtext\r
+ embedded link that belongs to that panel */\r
+\r
+ WMNC_IDENTITY_CHANGE, \r
+ /*!< The primary identity has changed */\r
+\r
+ WMNC_CLEAR_PROMPTS, \r
+ /*!< Sent to the new creds window to clear any custom prompts */\r
+\r
+ WMNC_SET_PROMPTS, \r
+ /*!< Sent to the new creds window to set custom prompts */\r
+ \r
+ WMNC_DIALOG_PREPROCESS, \r
+ /*!< Sent to all the credentials type panels to notify them that\r
+ the dialog is about to be processed */\r
+\r
+ WMNC_DIALOG_PROCESS, \r
+ /*!< Process the dialog and signal whether to exit the dialog or\r
+ not */\r
+\r
+ WMNC_DIALOG_PROCESS_COMPLETE, \r
+ /*!< Sent to the new creds window to indicate that the all the\r
+ threads have completed processing.*/\r
+\r
+ WMNC_TYPE_STATE, \r
+ /*!< Sent to the new creds window as notification that a\r
+ particular credentials type has changed state from enabled to\r
+ disabled or vice versa. The LPARAM member of the message\r
+ specifies the credentials type identifier for the changed\r
+ type */\r
+\r
+ WMNC_ADD_CONTROL_ROW,\r
+ /*!< Add a row of controls to a new cred dialog. This is an\r
+ internal message. */\r
+};\r
+\r
+/*! \brief Notifications to the identity provider\r
+\r
+ These notifications are sent through to the identity provider's UI\r
+ callback that was obtained using a ::KMSG_IDENT_GET_UI_CB message.\r
+\r
+ The callback routine is called from the context of the UI thread\r
+ and is expected to not make any blocking calls. One of the\r
+ following commands will be passed in as the \a cmd parameter to\r
+ the callback.\r
+ */\r
+enum khui_wm_nc_ident_notify {\r
+ WMNC_IDENT_INIT, \r
+ /*!< Initialize an identity selector for a new credentials\r
+ dialog. The \a lParam parameter contains a handle to the\r
+ dialog window which will contain the identity selector\r
+ controls. The identity provider may make use of the \a\r
+ ident_aux field of the ::khui_new_creds structure to hold any\r
+ data pertaining to the credentials acquisition dialog.*/\r
+\r
+ WMNC_IDENT_WMSG,\r
+ /*!< Windows message. Presumably sent from one of the controls\r
+ that was created by the identity provider. The callback is\r
+ expected to return TRUE if it processed the message or FALSE\r
+ if it did not. The \a uMsg, \a wParam and \a lParam\r
+ parameters are set to the values passed in by Windows. */\r
+\r
+ WMNC_IDENT_EXIT,\r
+ /*!< Terminate a credentials acquisition dialog. Sent just before\r
+ the dialog is terminated. */\r
+};\r
+\r
+/*! \name Standard credtext link IDs\r
+@{*/\r
+\r
+/*! \brief Switch the panel\r
+ \r
+ The \a id attribute of the link specifies the ordinal of the panel\r
+ to switch to.\r
+*/\r
+#define CTLINKID_SWITCH_PANEL L"SwitchPanel"\r
+\r
+/*@}*/\r
+\r
+/*forward dcl*/\r
+struct tag_khui_new_creds_by_type;\r
+typedef struct tag_khui_new_creds_by_type khui_new_creds_by_type;\r
+struct tag_khui_new_creds_prompt;\r
+typedef struct tag_khui_new_creds_prompt khui_new_creds_prompt;\r
+struct tag_khui_new_creds;\r
+typedef struct tag_khui_new_creds khui_new_creds;\r
+\r
+typedef LRESULT\r
+(KHMAPI *khui_ident_new_creds_cb)(khui_new_creds * nc,\r
+ UINT cmd,\r
+ HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam);\r
+\r
+/*! \brief New credentials acquisition blob\r
+\r
+ A pointer to an object of this type is passed in along with the\r
+ credentials acquisition messages.\r
+\r
+ \see \ref cred_acq for more information\r
+*/\r
+typedef struct tag_khui_new_creds {\r
+ khm_int32 magic;\r
+\r
+ khm_int32 subtype; /*!< Subtype of the request that is\r
+ being handled through this object.\r
+ One of ::KMSG_CRED_INITIAL_CREDS,\r
+ ::KMSG_CRED_NEW_CREDS or\r
+ ::KMSG_CRED_RENEW_CREDS */\r
+\r
+ CRITICAL_SECTION cs;\r
+\r
+ khm_handle *identities; /*!< The list of identities associated\r
+ with this request. The first\r
+ identity in this list (\a\r
+ identities[0]) is the primary\r
+ identity. */\r
+\r
+ khm_size n_identities; /*!< Number of identities in the list\r
+ \a identities */\r
+\r
+ khm_size nc_identities; /*!< Internal use */\r
+\r
+ khui_action_context ctx; /*!< An action context specifying the\r
+ context in which the credentials\r
+ acquisition operation was\r
+ launced. */\r
+\r
+ khm_int32 mode; /*!< The mode of the user interface.\r
+ One of ::KHUI_NC_MODE_MINI or\r
+ ::KHUI_NC_MODE_EXPANDED. */\r
+\r
+ HWND hwnd; /*!< Handle to the new credentials\r
+ window. */\r
+\r
+ struct tag_khui_new_creds_by_type **types;\r
+ /*!< Internal use */\r
+ khm_handle *type_subs; /*!< Internal use */\r
+ khm_size n_types; /*!< Internal use */\r
+ khm_size nc_types; /*!< Internal use */\r
+\r
+ khm_int32 result; /*!< One of ::KHUI_NC_RESULT_CANCEL or\r
+ ::KHUI_NC_RESULT_GET_CREDS indicating\r
+ the result of the dialog with the\r
+ user */\r
+\r
+ khm_int32 response; /*!< Response. See individual message\r
+ documentation for info on what to do\r
+ with this field */\r
+\r
+ wchar_t *password; /*!< Not set until the dialog ends */\r
+\r
+ /* UI stuff */\r
+\r
+ wchar_t *banner; /*!< Internal use */\r
+ wchar_t *pname; /*!< Internal use */\r
+ khm_size n_prompts; /*!< Internal use */\r
+ khm_size nc_prompts; /*!< Internal use */\r
+ struct tag_khui_new_creds_prompt ** prompts; /*!< Internal use */\r
+\r
+ khui_ident_new_creds_cb ident_cb; /*!< Internal use */\r
+\r
+ wchar_t *window_title; /*!< Internal use */\r
+\r
+ LPARAM ident_aux; /*!< Auxilliary field which is\r
+ reserved for use by the identity\r
+ provider during the course of\r
+ conducting this dialog. */\r
+\r
+} khui_new_creds;\r
+\r
+#define KHUI_NC_MAGIC 0x84270427\r
+\r
+/*!\name Result values for khui_new_creds_t::result\r
+ @{*/\r
+#define KHUI_NC_RESULT_GET_CREDS 0\r
+#define KHUI_NC_RESULT_CANCEL 1\r
+/*@}*/\r
+\r
+/*!\name Mode values for khui_new_creds_t::mode\r
+ @{*/\r
+#define KHUI_NC_MODE_MINI 0\r
+#define KHUI_NC_MODE_EXPANDED 1\r
+/*@}*/\r
+\r
+/*!\name Response values for khui_new_creds_t::response\r
+ @{*/\r
+/*!\brief No known response */\r
+#define KHUI_NC_RESPONSE_NONE 0\r
+\r
+/*!\brief It is okay to exit the dialog now \r
+\r
+ This is the default, which is why it has a value of zero. In\r
+ order to prevent the dialog from exiting, set the\r
+ KHUI_NC_RESPONSE_NOEXIT response bit. */\r
+#define KHUI_NC_RESPONSE_EXIT 0\r
+\r
+/*!\brief It is NOT okay to exit the dialog now\r
+\r
+ Used to indicate that further user-interaction is necessary to\r
+ process the dialog. Usually this is accompanied by setting\r
+ necessary custom prompts and notifications so the user knows why\r
+ the dialog is prompting for more information.\r
+ */\r
+#define KHUI_NC_RESPONSE_NOEXIT 0x00000002\r
+\r
+/*!\brief The dialog was processed successfully\r
+\r
+ Since this is the default response, the value is zero. Use one of\r
+ KHUI_NC_RESPONSE_FAILED or KHUI_NC_RESPONSE_PENDING to indicate an\r
+ error or pending status.\r
+ */\r
+#define KHUI_NC_RESPONSE_SUCCESS 0\r
+\r
+/*!\brief The processing of the dialog failed\r
+\r
+ Self explanatory. More information about the failure should have\r
+ been reported using the khlog API, however, this response value\r
+ indicates to other credential types that depend on this credential\r
+ type that whatever it was that this credential type was supposed\r
+ to do didn't happen.\r
+*/\r
+#define KHUI_NC_RESPONSE_FAILED 0x00000008\r
+\r
+/*!\brief Further interaction required\r
+\r
+ Set along with KHUI_NC_RESPONSE_NOEXIT although it is not\r
+ required. Setting this bit will automatically add the\r
+ KHUI_NC_RESPONSE_NOEXIT.\r
+\r
+ If this bit is set, all dependent plugins will be set on hold\r
+ until another round of processing clears the pending bit.\r
+ */\r
+#define KHUI_NC_RESPONSE_PENDING 0x00000010\r
+\r
+/*! \brief Completed\r
+\r
+ This is automatically set if the plugin sets a response which does\r
+ not indicate either KHUI_NC_RESPONSE_NOEXIT or\r
+ KHUI_NC_RESPONSE_PENDING, which is considered to mean that the\r
+ plugin is completed processing.\r
+\r
+ This flag cannot be explicitly specified in a response.\r
+ */\r
+#define KHUI_NC_RESPONSE_COMPLETED 0x00000020\r
+\r
+#define KHUI_NCMASK_RESPONSE (KHUI_NC_RESPONSE_EXIT|KHUI_NC_RESPONSE_NOEXIT)\r
+#define KHUI_NCMASK_RESULT (KHUI_NC_RESPONSE_SUCCESS|KHUI_NC_RESPONSE_FAILED|KHUI_NC_RESPONSE_PENDING)\r
+/*@}*/\r
+\r
+/*!\brief Maximum number of dependencies for a credentials type */\r
+#define KHUI_MAX_TYPE_DEPS 8\r
+\r
+/*!\brief Maximum number of credential types for a new creds window */\r
+#define KHUI_MAX_NCTYPES 16\r
+\r
+/*!\brief Maximum number of characters in a password\r
+\r
+ Length includes the termininating NULL\r
+*/\r
+#define KHUI_MAXCCH_PASSWORD 512\r
+\r
+/*! \brief Maximum number of bytes in a password\r
+\r
+ Includes terminating NULL\r
+*/\r
+#define KHUI_MAXCB_PASSWORD (KHUI_MAXCCH_PASSWORD * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum number of characters in a custom banner\r
+\r
+ Length includes terminating NULL\r
+*/\r
+#define KHUI_MAXCCH_BANNER 256\r
+\r
+\r
+/*! \brief Maximum number of bytes in a custom banner\r
+\r
+ Length includes terminating NULL\r
+*/\r
+#define KHUI_MAXCB_BANNER (KHUI_MAXCCH_BANNER * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum number of characters in a panel name\r
+\r
+ Length includes terminating NULL\r
+*/\r
+#define KHUI_MAXCCH_PNAME 256\r
+\r
+/*! \brief Maximum number of bytes in a panel name\r
+\r
+ Length includes terminating NULL\r
+*/\r
+#define KHUI_MAXCB_PNAME (KHUI_MAXCCH_PNAME * sizeof(wchar_t))\r
+\r
+/*! \brief A descriptor of a panel in the new credentials acquisition tab\r
+*/\r
+typedef struct tag_khui_new_creds_by_type {\r
+ khui_new_creds * nc; /*!< Internal use. Do not set */\r
+ khm_int32 flags; /*!< Internal use. Do not set */\r
+\r
+ khm_int32 type; /*!< The identifier of the credentials\r
+ type */\r
+\r
+ khm_int32 type_deps[KHUI_MAX_TYPE_DEPS];\r
+ /*!< credentials types that this\r
+ credential type depends on. Each\r
+ element defines a credentials type\r
+ identifier that this type depends\r
+ on for this operation. */\r
+\r
+ khm_size n_type_deps; /*!< Number of dependencies listed\r
+ above. Should be between 0 and\r
+ ::KHUI_MAX_TYPE_DEPS */\r
+\r
+ khm_size ordinal; /*!< The requested ordinal. The UI\r
+ would attempt to place this panel at\r
+ the reqested order in the list of\r
+ panels. Set to -1 if the order does\r
+ not matter. Once the dialog is\r
+ activated this field will be updated\r
+ to reflect the actual ordinal of the\r
+ panel. */\r
+\r
+ wchar_t *name; /*!< Name of the panel (localized,\r
+ optional). If NULL, the localized\r
+ name of the credentials type is\r
+ used. */\r
+\r
+ HICON icon; /*!< Icon for the panel (optional) */\r
+\r
+ wchar_t *tooltip; /*!< Tooltip for the panel (localized,\r
+ optional). If NULL, no tooltip will\r
+ be assigned for the panel */\r
+\r
+ HMODULE h_module; /*!< Handle to the module containing\r
+ the dialog resource */\r
+\r
+ LPWSTR dlg_template; /*!< The dialog resource */\r
+ DLGPROC dlg_proc; /*!< The dialog procedure */\r
+\r
+ HWND hwnd_panel; /*!< The dialog window */\r
+ HWND hwnd_tc; /*!< Internal use. Do not set */\r
+\r
+ wchar_t *credtext; /*!< A brief description of the\r
+ current state of this cred\r
+ type. (localized, optional) */\r
+\r
+ LPARAM aux; /*!< auxilliary field. For use by the\r
+ credential provider */\r
+} khui_new_creds_by_type;\r
+\r
+/*!\name Flags for khui_new_creds_by_type\r
+\r
+ Note that KHUI_NC_RESPONSE_SUCCESS, KHUI_NC_RESPONSE_FAILED,\r
+ KHUI_NC_RESPONSE_PENDING are also stored in the flags. \r
+\r
+@{*/\r
+#define KHUI_NCT_FLAG_PROCESSED 1024\r
+#define KHUI_NCT_FLAG_DISABLED 2048\r
+/*@}*/\r
+\r
+/*! \brief Width of a new creds dialog panel in dialog units*/\r
+#define NCDLG_WIDTH 300\r
+/*! \brief Height of a new creds dialog panel in dialog units*/\r
+#define NCDLG_HEIGHT 166\r
+\r
+/*! \brief Width of the button bar in dialog units */\r
+#define NCDLG_BBAR_WIDTH 60\r
+/*! \brief Height of a tab button in dialog units */\r
+#define NCDLG_TAB_HEIGHT 15\r
+/*! \brief Width of a tab button in dialog units */\r
+#define NCDLG_TAB_WIDTH 60\r
+\r
+/*! \brief A custom prompt */\r
+typedef struct tag_khui_new_creds_prompt {\r
+ khm_size index; /*!< Set to the zero based index\r
+ of this prompt. */\r
+\r
+ khm_int32 type; /*!< one of KHUI_NCPROMPT_TYPE_* */\r
+ wchar_t * prompt; /*!< prompt string. Cannot exceed\r
+ KHUI_MAXCCH_PROMPT */\r
+ wchar_t * def; /*!< default value. Cannot exceed\r
+ KHUI_MAXCCH_PROMPT_VALUE */\r
+ wchar_t * value; /*!< On completion, this is set to the\r
+ value that the user entered. Will\r
+ not exceed\r
+ KHUI_MAXCCH_PROMPT_VALUE */\r
+\r
+ khm_int32 flags; /*!< Combination of\r
+ KHUI_NCPROMPT_FLAG_* */\r
+\r
+ HWND hwnd_static; /* internal use */\r
+ HWND hwnd_edit; /* internal use */\r
+} khui_new_creds_prompt;\r
+\r
+/*! \brief The prompt input is hidden\r
+\r
+ The input is hidden for prompts which accept passwords. The\r
+ control which represents the input will display an asterisk or a\r
+ small circle corresponding to each character typed in, but will\r
+ not show the actual character.\r
+ */\r
+#define KHUI_NCPROMPT_FLAG_HIDDEN 1\r
+\r
+/*! \brief Internal use */\r
+#define KHUI_NCPROMPT_FLAG_STOCK 2\r
+\r
+/*! \brief Maximum number of characters in a prompt\r
+\r
+ Refers to the prompt text that accompanies an input control. THe\r
+ length includes the terminating NULL.\r
+ */\r
+#define KHUI_MAXCCH_PROMPT 256\r
+\r
+/*! \brief Maximum number of bytes in a prompt\r
+\r
+ Refers to the prompt text that accompanies an input control. THe\r
+ length includes the terminating NULL.\r
+ */\r
+#define KHUI_MAXCB_PROMPT (KHUI_MAXCCH_PROMPT * sizeof(wchar_t))\r
+\r
+/*! \brief Maximum number of characters that can be entered in an input control\r
+\r
+ Refers to the input control of a prompt. The length includes the\r
+ terminating NULL.\r
+ */\r
+#define KHUI_MAXCCH_PROMPT_VALUE 256\r
+\r
+/*! \brief Maximum number of bytes that can be entered in an input control\r
+\r
+ Refers to the input control of a prompt. The length includes the\r
+ terminating NULL.\r
+ */\r
+#define KHUI_MAXCB_PROMPT_VALUE (KHUI_MAXCCH_PROMPT_VALUE * sizeof(wchar_t))\r
+\r
+/* from krb5.h. Redefining here because we don't want to depend on\r
+ krb5.h for all credential types */\r
+\r
+/*! \brief A password control */\r
+#define KHUI_NCPROMPT_TYPE_PASSWORD 1\r
+\r
+/*! \brief New password control\r
+\r
+ Used when changing the password\r
+ */\r
+#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD 2\r
+\r
+/*! \brief New password again control\r
+\r
+ Used when changing the password\r
+ */\r
+#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN 3\r
+\r
+/*! \brief Preauthentication (reserved) */\r
+#define KHUI_NCPROMPT_TYPE_PREAUTH 4\r
+\r
+/*! \brief Control sizes */\r
+typedef enum tag_khui_control_size {\r
+ KHUI_CTRLSIZE_SMALL,\r
+ /*!< A small control fits in about 1/5 the width of the new\r
+ credentials panel */\r
+ KHUI_CTRLSIZE_HALF,\r
+ /*!< Half size controls fit in 1/2 the width of the new\r
+ credentials panel */\r
+ KHUI_CTRLSIZE_FULL,\r
+ /*!< Takes up the whole width of the crednetials panel */\r
+} khui_control_size;\r
+\r
+/*! \brief Internal use */\r
+typedef struct tag_khui_control_row {\r
+ HWND label;\r
+ HWND input;\r
+ khui_control_size size;\r
+} khui_control_row;\r
+\r
+/*! \brief Create a ::khui_new_creds object\r
+\r
+ Creates and initializes a ::khui_new_creds object. The created\r
+ object must be destroyed using the khui_cw_destroy_cred_blob()\r
+ function.\r
+\r
+ \note Plugins should not call this function directly. The\r
+ necessary ::khui_new_creds objects will be created by\r
+ NetIDMgr.\r
+\r
+ \see khui_cw_destroy_cred_blob()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_create_cred_blob(khui_new_creds ** c);\r
+\r
+/*! \brief Destroy a ::khui_new_creds object\r
+\r
+ Destroys a ::khui_new_creds object that was fomerly created using\r
+ a call to khui_cw_create_cred_blob().\r
+\r
+ \note Plugins should not call this function directly. The\r
+ necessary ::khui_new_creds objects will be created by\r
+ NetIDMgr.\r
+\r
+ \see khui_cw_create_cred_blob()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_destroy_cred_blob(khui_new_creds *c);\r
+\r
+/*! \brief Lock the new_creds object\r
+\r
+ When a plugin is accessing the fields of a ::khui_new_creds\r
+ object, it must first obtain a lock on the object so that other\r
+ threads will not modify the fields at the same time. Locking the\r
+ object ensures that the fields of the object will be consistent.\r
+\r
+ Use khui_cw_unlock_nc() to undo the lock obtained through a call\r
+ to khui_cw_lock_nc().\r
+\r
+ It is not necessary to lock a new credentials object when\r
+ modifying it using the NetIDMgr API.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_lock_nc(khui_new_creds * c);\r
+\r
+/*! \brief Unlock a new_creds object\r
+\r
+ \see khui_cw_lock_nc()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_unlock_nc(khui_new_creds * c);\r
+\r
+/*! \brief Add a new panel to a new credentials acquisition window \r
+\r
+ See the description of ::khui_new_cred_panel for information on\r
+ how to populate it to describe a credentials type panel.\r
+\r
+ \see khui_cw_del_type()\r
+ \see \ref cred_acq_panel_spec\r
+ \see ::khui_new_cred_panel\r
+ \see ::khui_new_creds\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_add_type(khui_new_creds * c, \r
+ khui_new_creds_by_type * t);\r
+\r
+/*! \brief Remove a panel from a new credentials acquisition window\r
+\r
+ \see khui_cw_add_type()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_del_type(khui_new_creds * c, \r
+ khm_int32 type);\r
+\r
+/*! \brief Find the panel belonging to a particular credentials type\r
+\r
+ This panel would have been added to the new credentials window\r
+ using khui_cw_add_type().\r
+\r
+ \see khui_cw_add_type()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_find_type(khui_new_creds * c, \r
+ khm_int32 type, \r
+ khui_new_creds_by_type **t);\r
+\r
+/*! \brief Enable/disable a particular credentials type\r
+\r
+ Enables or disables the panel associated with a particular\r
+ credentials type. Does not preclude the credentials type from\r
+ participating in the new credentials acquisition. However, the\r
+ user will be prevented from interacting with the specific panel.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_enable_type(khui_new_creds * c,\r
+ khm_int32 type,\r
+ khm_boolean enable);\r
+\r
+/*! \brief Set the primary identity in a new credentials acuisition\r
+\r
+ The primary identity dictates many of the defaults and the\r
+ semantics associated with the credentials acquision process.\r
+ Setting the primary identity also triggers the\r
+ ::WMNC_IDENTITY_CHANGE notification which will be sent to all the\r
+ credentials type panels.\r
+\r
+ Has no effect if the primary identity is already the same as the\r
+ one specified in \a id. Specify NULL for \a id if the current\r
+ primary identity is to be cleared.\r
+\r
+ If the primary identity is changed, then all the additional\r
+ identities associated with the new credentials acquisition dialog\r
+ will also be discarded.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_set_primary_id(khui_new_creds * c, \r
+ khm_handle id);\r
+\r
+/*! \brief Add an additional identity to the new credentials acquisition\r
+\r
+ Individual plugins are free to decide how to handle additional\r
+ identities. Generally, they would attempt to obtain credentials\r
+ for the primary and additional identities, but would not consider\r
+ it an error if an additional identity failed to obtain\r
+ credentials.\r
+\r
+ Calling this function with \a id of NULL does nothing.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_add_identity(khui_new_creds * c, \r
+ khm_handle id);\r
+\r
+/*! \brief Clear all custom prompts\r
+\r
+ Removes all the custom prompts from the new credentials dialog.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_clear_prompts(khui_new_creds * c);\r
+\r
+/*! \brief Synchronize custom prompt values\r
+\r
+ It is important to synchronize the values before accessing their\r
+ values. The controls associated with custom prompts update the\r
+ values in the ::khui_new_creds object periodically. However, the\r
+ values may lose sync intermittently.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_sync_prompt_values(khui_new_creds * c);\r
+\r
+/*! \brief Begin custom prompting\r
+\r
+ Begins the process of defining custom prompts. Implicity removes\r
+ all the custom prompts that are currently being displayed. The \a\r
+ banner and \a name will be displayed in separate controls above\r
+ the set of new custom prompts.\r
+\r
+ The controls associated with the prompts will not actually be\r
+ created until all the prompts have been added using\r
+ khui_cw_add_prompt(). The number of promtps that can be added\r
+ will be exactly \a n_prompts.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_begin_custom_prompts(khui_new_creds * c, \r
+ khm_size n_prompts, \r
+ wchar_t * banner, \r
+ wchar_t * name);\r
+\r
+/*! \brief Add a custom prompt\r
+\r
+ After khui_cw_begin_custom_prompts() is called, the plugin should\r
+ call khui_cw_add_prompt() to add the actual prompts. The number\r
+ of prompts that can be added is the \a n_prompts value specified\r
+ in the earlier call to \a khui_cw_begin_custom_prompts().\r
+\r
+ Once \a n_prompts prompts have been added, the new prompts will\r
+ automatically be created and shown in the user interface.\r
+ However, if less than that prompts are added, nothing is displayed\r
+ to the user.\r
+\r
+ \param[in] c Pointer to ::khui_new_creds structure\r
+\r
+ \param[in] type Type of prompt. One of\r
+ ::KHUI_NCPROMPT_TYPE_PREAUTH, ::KHUI_NCPROMPT_TYPE_PASSWORD,\r
+ ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD,\r
+ ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN\r
+\r
+ \param[in] prompt Text of the prompt. Constrained by\r
+ ::KHUI_MAXCCH_PROMPT. (Localized, required)\r
+\r
+ \param[in] def Default value. (optional). Constrained by\r
+ ::KHUI_MAXCCH_PROMPT_VALUE. Set to NULL if not provided.\r
+\r
+ \param[in] flags Flags. Combination of\r
+ ::KHUI_NCPROMPT_FLAG_HIDDEN\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_add_prompt(khui_new_creds * c, \r
+ khm_int32 type, \r
+ wchar_t * prompt, \r
+ wchar_t * def, \r
+ khm_int32 flags);\r
+\r
+/*! \brief Retrieve a custom prompt\r
+\r
+ Retrieves an individual prompt. The \a idx parameter is a\r
+ zero-based index of the prompt to retrieve. The ordering is the\r
+ same as the order in which khui_cw_add_prompt() was called.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_get_prompt(khui_new_creds * c, \r
+ khm_size idx, \r
+ khui_new_creds_prompt ** prompt);\r
+\r
+/*! \brief Get the number of custom prompts\r
+\r
+ Retrieves the number of custom prompts currently displayed. If\r
+ this function is called between calling\r
+ khui_cw_begin_custom_prompts() and adding all the prompts, the\r
+ number returned will be the number of prompts that is expected to\r
+ be registered (i.e. the \a n_prompts parameter passed to\r
+ khui_cw_begin_custom_prompts()).\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_get_prompt_count(khui_new_creds * c,\r
+ khm_size * np);\r
+\r
+\r
+/*! \brief Get the value of a custom prompt\r
+\r
+ Retrieve the value of a specific prompt. The value is the string\r
+ that was typed into the input control associated with a custom\r
+ prompt. The \a idx parameter is the zero-based index of the\r
+ prompt from which to retrieve the value from. The ordering is the\r
+ same as the order in which khui_cw_add_prompt() was called.\r
+\r
+ It is important to call khui_cw_sync_prompt_values() before\r
+ starting to call khui_cw_get_prompt_value() so that the values\r
+ returned are up-to-date.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_get_prompt_value(khui_new_creds * c, \r
+ khm_size idx, \r
+ wchar_t * buf, \r
+ khm_size *cbbuf);\r
+\r
+/*! \brief Set the response for a plugin\r
+\r
+ When handling ::KMSG_CRED_DIALOG_PROCESS from within the plugin\r
+ thread, it is important to set the response by calling this\r
+ function. The response can be used to signal whether the plugin\r
+ successfully obtained credentials or whether further interaction\r
+ is required, or the credentials acquisition failed.\r
+\r
+ The response is a combination of :\r
+ - ::KHUI_NC_RESPONSE_PENDING\r
+ - ::KHUI_NC_RESPONSE_FAILED\r
+ - ::KHUI_NC_RESPONSE_PENDING\r
+ - ::KHUI_NC_RESPONSE_SUCCESS\r
+ - ::KHUI_NC_RESPONSE_NOEXIT\r
+ - ::KHUI_NC_RESPONSE_EXIT\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_cw_set_response(khui_new_creds * c,\r
+ khm_int32 type,\r
+ khm_int32 response);\r
+\r
+/*! \brief Check whether a specified credential type panel succeeded\r
+\r
+ This is called during the processing of KMSG_CRED_DIALOG_PROCESS\r
+ to determine whether a specified credential type succeeded in\r
+ obtaining credentials. The credential type that is being queried\r
+ should have also been listed as a dependency when adding the\r
+ current credentials type, otherwise the type queried may not have\r
+ been invoked yet.\r
+\r
+ \return TRUE iff the queried type has reported that it successfully\r
+ completed the credentials acquision operation.\r
+ */\r
+KHMEXP khm_boolean KHMAPI \r
+khui_cw_type_succeeded(khui_new_creds * c,\r
+ khm_int32 type);\r
+\r
+/*! \brief Add a row of controls to the identity specifier area\r
+\r
+ Only for use by identity provider callbacks that wish to add an\r
+ identity selector control. A row of controls consist of a label\r
+ control and some input control.\r
+\r
+ When the ::WMNC_IDENT_INIT message is sent to the identity\r
+ provider, it receives a handle to the dialog panel in the \a\r
+ lParam parameter which should be the parent window of both the\r
+ windows specified here. The control ID for any controls created\r
+ must fall within the ::KHUI_CW_ID_MIN and ::KHUI_CW_ID_MAX range.\r
+\r
+ Both controls will be resized to fit in the row.\r
+\r
+ If \a long_label is TRUE then the size of the label will be larger\r
+ than normal and will accomodate more text.\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_cw_add_control_row(khui_new_creds * c,\r
+ HWND label,\r
+ HWND input,\r
+ khui_control_size size);\r
+\r
+/*!@}*/ /* Credentials acquisition */\r
+/*!@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHPROPS_H\r
+#define __KHIMAIRA_KHPROPS_H\r
+\r
+/*********************************************************************\r
+ Property sheets\r
+**********************************************************************/\r
+\r
+/*! \addtogroup khui \r
+\r
+@{*/\r
+\r
+/*!\defgroup khui_pp Property sheets\r
+@{*/\r
+\r
+/* forward dcl */\r
+struct tag_khui_property_page;\r
+\r
+/*! \brief A property sheet\r
+ */\r
+typedef struct tag_khui_property_sheet {\r
+ PROPSHEETHEADER header; /*!< property sheet header */\r
+ khm_int32 status; /*!< status of property sheet. One of\r
+ ::KHUI_PS_STATUS_NONE,\r
+ ::KHUI_PS_STATUS_RUNNING or\r
+ ::KHUI_PS_STATUS_DONE */\r
+\r
+ HWND hwnd; /*!< handle to the property sheet window.\r
+ Only valid when \a status is NOT\r
+ ::KHUI_PS_STATUS_NONE */\r
+\r
+ HWND hwnd_page; /*!< handle to the current page in the\r
+ property sheet. Only valid when \a\r
+ status is ::KHUI_PS_STATUS_RUNNING */\r
+\r
+ khui_action_context ctx; /*!< Context for the property sheet. See\r
+ documentation for\r
+ ::khui_action_context */\r
+\r
+ khm_handle identity; /*!< Handle to the associated identity,\r
+ if applicable */\r
+ khm_int32 credtype; /*!< Type ID of the credentials type, if\r
+ applicable */\r
+ khm_handle cred; /*!< Handle to the associated credential,\r
+ if applicable */\r
+\r
+ khm_int32 n_pages; /*!< Number of property pages.\r
+ Upperbound of ::KHUI_PS_MAX_PSP */\r
+\r
+ QDCL(struct tag_khui_property_page);\r
+} khui_property_sheet;\r
+\r
+/*! \brief The property sheet hasn't been created yet */\r
+#define KHUI_PS_STATUS_NONE 0\r
+\r
+/*! \brief The property sheet is visible and running */\r
+#define KHUI_PS_STATUS_RUNNING 1\r
+\r
+/*! \brief The property sheet has completed running.\r
+\r
+ At this point, it is safe to call khui_ps_destroy_sheet() to\r
+ destroy the property sheet.\r
+*/\r
+#define KHUI_PS_STATUS_DONE 2\r
+\r
+/*! \brief The property sheet is in the process of being destroyed\r
+ */\r
+#define KHUI_PS_STATUS_DESTROY 3\r
+\r
+/*! \brief Maximum number of property sheet pages in a property sheet */\r
+#define KHUI_PS_MAX_PSP 16\r
+\r
+\r
+/*! \brief A property sheet page\r
+ */\r
+typedef struct tag_khui_property_page {\r
+ HPROPSHEETPAGE h_page;\r
+ LPPROPSHEETPAGE p_page;\r
+ HWND hwnd;\r
+ khm_int32 credtype;\r
+ khm_int32 ordinal;\r
+\r
+ LDCL(struct tag_khui_property_page);\r
+} khui_property_page;\r
+\r
+/*! \brief Special pseudo credtype for identity page\r
+ */\r
+#define KHUI_PPCT_IDENTITY (-8)\r
+\r
+/*! \brief Special pseudo credtype for credential page\r
+ */\r
+#define KHUI_PPCT_CREDENTIAL (-9)\r
+\r
+/*! \brief Create a property sheet\r
+\r
+ \note Only called by the NetIDMgr application.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_ps_create_sheet(khui_property_sheet ** sheet);\r
+\r
+/*! \brief Add a page to a property sheet\r
+\r
+ Called by a plugin or the NetIDMgr application to add a page to a\r
+ property sheet.\r
+\r
+ Pages can only be added before the property sheet is made visible\r
+ to the user.\r
+\r
+ \param[in] sheet The property sheet to add the page to\r
+\r
+ \param[in] credtype The credentials type ID of the owner of the\r
+ property page. This should be set to ::KCDB_CREDTYPE_INVALID\r
+ if the type is not relevant.\r
+\r
+ \param[in] ordinal Requested ordinal. A positive integer which is\r
+ used to order the pages in a property sheet. The pages are\r
+ ordered based on ordinal first and then alphabetically by\r
+ credentials type name. If the type is unavailable, then the\r
+ ordering is undefined.\r
+\r
+ \param[in] ppage Pointer to structure that will be passed to\r
+ CreatePropertySheetPage() to create the property page. The\r
+ structure is not managed by NetIDMgr at all, and must exist\r
+ until the status of the property sheet changes to\r
+ ::KHUI_PS_STATUS_RUNNING. The same pointer will be found in\r
+ the \a p_page member of the ::khui_property_page structure.\r
+\r
+ \param[out] page A pointer will be returned here that will point\r
+ to the newly created khui_property_page structure. Specify\r
+ NULL if this value is not required. You can use\r
+ khui_ps_find_page() to retrieve a pointer to the structure\r
+ later.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+khui_ps_add_page(khui_property_sheet * sheet,\r
+ khm_int32 credtype,\r
+ khm_int32 ordinal,\r
+ LPPROPSHEETPAGE ppage,\r
+ khui_property_page ** page);\r
+\r
+/*! \brief Retrieve a property page structure from a property sheet\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+khui_ps_find_page(khui_property_sheet * sheet,\r
+ khm_int32 credtype,\r
+ khui_property_page ** page);\r
+\r
+/*! \brief Display the property sheet\r
+\r
+ \note Only called by the NetIDMgr application\r
+ */\r
+KHMEXP HWND KHMAPI \r
+khui_ps_show_sheet(HWND parent, \r
+ khui_property_sheet * sheet);\r
+\r
+/*! \brief Check if the given message belongs to the property sheet\r
+\r
+ \note Only called by the NetIDMgr application\r
+ */\r
+KHMEXP LRESULT KHMAPI \r
+khui_ps_check_message(khui_property_sheet * sheet, \r
+ PMSG msg);\r
+\r
+/*! \brief Destroy a property sheet and all associated data structures.\r
+\r
+ \note Only called by the NetIDMgr application.\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+khui_ps_destroy_sheet(khui_property_sheet * sheet);\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record);\r
+\r
+/*!@}*/\r
+/*!@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_REMOTE_H\r
+#define __KHIMAIRA_REMOTE_H\r
+\r
+/*! \addtogroup khui\r
+ @{*/\r
+/*! \defgroup khui_remote Connecting to NetIDMgr from another process\r
+ @{*/\r
+\r
+/* Leash compatibility */\r
+#define ID_OBTAIN_TGT_WITH_LPARAM 32809\r
+\r
+#define KHUI_REQDAEMONWND_CLASS L"IDMgrRequestDaemonCls"\r
+#define KHUI_REQDAEMONWND_NAME L"IDMgrRequestDaemon"\r
+\r
+#define KHUI_REQD_MAPPING_FORMAT L"Local\\NetIDMgr_DlgInfo_%lu"\r
+\r
+#define NETID_USERNAME_SZ 128\r
+#define NETID_REALM_SZ 192\r
+#define NETID_TITLE_SZ 256\r
+#define NETID_CCACHE_NAME_SZ 264\r
+ \r
+#define NETID_DLGTYPE_TGT 0\r
+#define NETID_DLGTYPE_CHPASSWD 1\r
+typedef struct {\r
+ DWORD size;\r
+ DWORD dlgtype;\r
+ // Tells whether dialog box is in change pwd mode or init ticket mode\r
+ struct {\r
+ WCHAR title[NETID_TITLE_SZ];\r
+ WCHAR username[NETID_USERNAME_SZ];\r
+ WCHAR realm[NETID_REALM_SZ];\r
+ WCHAR ccache[NETID_CCACHE_NAME_SZ];\r
+ DWORD use_defaults;\r
+ DWORD forwardable;\r
+ DWORD noaddresses;\r
+ DWORD lifetime;\r
+ DWORD renew_till;\r
+ DWORD proxiable;\r
+ DWORD publicip;\r
+ DWORD must_use_specified_principal;\r
+ } in;\r
+ struct {\r
+ WCHAR username[NETID_USERNAME_SZ];\r
+ WCHAR realm[NETID_REALM_SZ];\r
+ WCHAR ccache[NETID_CCACHE_NAME_SZ];\r
+ } out;\r
+ // Version 1 of this structure ends here\r
+} NETID_DLGINFO, *LPNETID_DLGINFO;\r
+ \r
+#define NETID_DLGINFO_V1_SZ (10 * sizeof(DWORD) \\r
+ + sizeof(WCHAR) * (NETID_TITLE_SZ + \\r
+ 2 * NETID_USERNAME_SZ + 2 * NETID_REALM_SZ + \\r
+ 2 * NETID_CCACHE_NAME_SZ))\r
+\r
+/*!@} */\r
+/*!@} */\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_RESCACHE_H\r
+#define __KHIMAIRA_RESCACHE_H\r
+\r
+#include<khdefs.h>\r
+\r
+KHMEXP void KHMAPI \r
+khui_init_rescache(void);\r
+\r
+KHMEXP void KHMAPI \r
+khui_exit_rescache(void);\r
+\r
+KHMEXP void KHMAPI \r
+khui_cache_bitmap(UINT id, HBITMAP hbm);\r
+\r
+KHMEXP HBITMAP KHMAPI \r
+khui_get_cached_bitmap(UINT id);\r
+\r
+typedef struct khui_ilist_t {\r
+ int cx;\r
+ int cy;\r
+ int n;\r
+ int ng;\r
+ int nused;\r
+ HBITMAP img;\r
+ HBITMAP mask;\r
+ int *idlist;\r
+} khui_ilist;\r
+\r
+typedef struct khui_bitmap_t {\r
+ HBITMAP hbmp;\r
+ int cx;\r
+ int cy;\r
+} khui_bitmap;\r
+\r
+KHMEXP void KHMAPI \r
+khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm);\r
+\r
+KHMEXP void KHMAPI\r
+khui_delete_bitmap(khui_bitmap * kbm);\r
+\r
+KHMEXP void KHMAPI\r
+khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm);\r
+\r
+/* image lists */\r
+KHMEXP khui_ilist * KHMAPI \r
+khui_create_ilist(int cx, int cy, int n, int ng, int opt);\r
+\r
+KHMEXP BOOL KHMAPI \r
+khui_delete_ilist(khui_ilist * il);\r
+\r
+KHMEXP int KHMAPI \r
+khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg);\r
+\r
+KHMEXP int KHMAPI \r
+khui_ilist_add_masked_id(khui_ilist *il, HBITMAP hbm, \r
+ COLORREF cbkg, int id);\r
+\r
+KHMEXP int KHMAPI \r
+khui_ilist_lookup_id(khui_ilist *il, int id);\r
+\r
+KHMEXP void KHMAPI \r
+khui_ilist_draw(khui_ilist * il, int idx, HDC dc, int x, int y, int opt);\r
+\r
+KHMEXP void KHMAPI \r
+khui_ilist_draw_bg(khui_ilist * il, int idx, HDC dc, int x, int y, \r
+ int opt, COLORREF bgcolor);\r
+\r
+#define khui_ilist_draw_id(il, id, dc, x, y, opt) \\r
+ khui_ilist_draw((il),khui_ilist_lookup_id((il),(id)),(dc),(x),(y),(opt))\r
+\r
+#define KHUI_SMICON_CX 16\r
+#define KHUI_SMICON_CY 16\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_TRACKERWND_H\r
+#define __KHIMAIRA_TRACKERWND_H\r
+\r
+#include<time.h>\r
+\r
+/*! \addtogroup khui \r
+\r
+@{ */\r
+\r
+/*!\defgroup khui_trk Duration sliders\r
+\r
+The duration sliders in the UI are pseudo-log-scaled. This is based\r
+on the assumption that people don't really need 1 minute accuracy when\r
+setting a duration that's several hours long. As a result, it is\r
+easier to hone in on the duration that you want without having\r
+wizardly mouse maneuvering skillz.\r
+\r
+Following are the duration ranges and the granularity that is offered\r
+in each range:\r
+\r
+<table>\r
+<tr><td> Range </td><td> Increment</td></tr>\r
+<tr><td> 0..5m </td><td> 1 min </td></tr>\r
+<tr><td> 5m..1hr </td><td> 5 min </td></tr>\r
+<tr><td> 1hr..4hr </td><td> 15 min </td></tr>\r
+<tr><td> 4hr..10hr </td><td> 30 min </td></tr>\r
+<tr><td> 10hr..24hr</td><td> 1 hr </td></tr>\r
+<tr><td> 24hr..4d </td><td> 6 hr </td></tr>\r
+<tr><td> 4d.. </td><td> 1 day </td></tr>\r
+</table>\r
+\r
+We don't really adjust for durations over 4 days. The ranges we are\r
+concerned with don't get much larger.\r
+\r
+For the purpose of writing this piece of code, I have chosen the term\r
+"tick" to refer to a period of granularity. The number of periods of\r
+granularity (inclusive) within a certain duration interval is referred\r
+to as the number of ticks in the interval. For example, there are 4\r
+ticks between the interval of 3 minutes to 10 minutes. Each occuring\r
+at the start of 3min, 4, 5 and 10mins. And thusly the slider control\r
+will display 4 ticks if it is displaying the interval 3-10mins.\r
+\r
+@{*/\r
+\r
+/*! \brief Tracker data */\r
+typedef struct tag_khui_tracker {\r
+ WNDPROC fn_edit;\r
+ WNDPROC fn_tracker;\r
+ HWND hw_slider;\r
+ HWND hw_edit;\r
+ int lbl_y;\r
+ int lbl_lx;\r
+ int lbl_rx;\r
+\r
+ time_t current; /*!< Current selection */\r
+ time_t min; /*!< Minimum (inclusive) */\r
+ time_t max; /*!< Maximum (inclusive) */\r
+} khui_tracker;\r
+\r
+/*! \brief Install a tracker into an edit control\r
+\r
+ Once installed, the edit control becomes a duration editor. The\r
+ tracker data structure that is supplied should remain as is for\r
+ the lifetime of the edit control.\r
+\r
+ The tracker strucutre should have been initialized with a call to\r
+ khui_tracker_initialize() and should have valid values in the \a\r
+ min, \a max and \a current fields.\r
+ */\r
+KHMEXP void KHMAPI\r
+khui_tracker_install(HWND hwnd_edit, khui_tracker * tc);\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_reposition(khui_tracker * tc);\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_initialize(khui_tracker * tc);\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_refresh(khui_tracker * tc);\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_kill_controls(khui_tracker * tc);\r
+/*!@}*/\r
+/*!@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_KHUIDEFS_H\r
+#define __KHIMAIRA_KHUIDEFS_H\r
+\r
+#include<windows.h>\r
+#include<kmq.h>\r
+#include<kcreddb.h>\r
+#include<kherror.h>\r
+#include<kherr.h>\r
+#include<khmsgtypes.h>\r
+\r
+#include<khaction.h>\r
+#include<khactiondef.h>\r
+#include<khrescache.h>\r
+#include<khhtlink.h>\r
+#include<khnewcred.h>\r
+#include<khprops.h>\r
+#include<khalerts.h>\r
+#include<khconfigui.h>\r
+#include<khtracker.h>\r
+\r
+#include<khremote.h>\r
+\r
+#include<strsafe.h>\r
+\r
+/*! \defgroup khui User Interface\r
+\r
+ Functions and data structures for interacting with the user\r
+ interface.\r
+\r
+*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+#ifdef DEBUG\r
+#include<assert.h>\r
+#endif\r
+\r
+KHMEXP khm_int32 KHMAPI khui_ps_create_sheet(khui_property_sheet ** sheet)\r
+{\r
+ khui_property_sheet * ps;\r
+\r
+ ps = malloc(sizeof(*ps));\r
+ ZeroMemory(ps, sizeof(*ps));\r
+\r
+ ps->header.dwSize = sizeof(ps->header);\r
+ ps->header.dwFlags = PSH_MODELESS | PSH_PROPTITLE;\r
+ ps->status = KHUI_PS_STATUS_NONE;\r
+\r
+ *sheet = ps;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khui_ps_add_page(\r
+ khui_property_sheet * sheet,\r
+ khm_int32 credtype,\r
+ khm_int32 ordinal,\r
+ LPPROPSHEETPAGE ppage,\r
+ khui_property_page ** page)\r
+{\r
+ khui_property_page * p;\r
+\r
+ p = malloc(sizeof(*p));\r
+ ZeroMemory(p, sizeof(*p));\r
+\r
+ p->credtype = credtype;\r
+ p->ordinal = ordinal;\r
+ p->p_page = ppage;\r
+ \r
+ QPUT(sheet, p);\r
+ sheet->n_pages++;\r
+\r
+ if(page)\r
+ *page = p;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khui_ps_find_page(\r
+ khui_property_sheet * sheet,\r
+ khm_int32 credtype,\r
+ khui_property_page ** page)\r
+{\r
+ khui_property_page * p;\r
+\r
+ p = QTOP(sheet);\r
+\r
+ while(p) {\r
+ if(p->credtype == credtype)\r
+ break;\r
+ p = QNEXT(p);\r
+ }\r
+\r
+ if(p) {\r
+ *page = p;\r
+ return KHM_ERROR_SUCCESS;\r
+ } else {\r
+ *page = NULL;\r
+ return KHM_ERROR_NOT_FOUND;\r
+ }\r
+}\r
+\r
+int __cdecl ps_order_func(const void *l, const void * r) {\r
+ /* l is a ** */\r
+ return 0;\r
+}\r
+\r
+KHMEXP HWND KHMAPI khui_ps_show_sheet(HWND parent, khui_property_sheet * s)\r
+{\r
+ khui_property_page * p;\r
+ HPROPSHEETPAGE phpsp[KHUI_PS_MAX_PSP];\r
+ khui_property_page * ppgs[KHUI_PS_MAX_PSP];\r
+ int i;\r
+ INT_PTR prv;\r
+ HWND hw;\r
+\r
+ s->header.hwndParent = parent;\r
+ s->header.nPages = s->n_pages;\r
+\r
+ p = QTOP(s);\r
+ i = 0;\r
+ while(p) {\r
+ p->h_page = CreatePropertySheetPage(p->p_page);\r
+#ifdef DEBUG\r
+ assert(p->h_page);\r
+#endif\r
+ ppgs[i] = p;\r
+ phpsp[i++] = p->h_page;\r
+ p = QNEXT(p);\r
+ }\r
+\r
+ /*TODO: sort property sheets */\r
+\r
+ s->header.phpage = phpsp;\r
+\r
+ prv = PropertySheet(&s->header);\r
+ if(prv <= 0) {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ /*TODO: better handling for this */\r
+ hw = NULL;\r
+ } else {\r
+ DWORD dw;\r
+\r
+ dw = GetLastError();\r
+ s->status = KHUI_PS_STATUS_RUNNING;\r
+\r
+ hw = (HWND) prv;\r
+ s->hwnd = hw;\r
+ s->hwnd_page = PropSheet_GetCurrentPageHwnd(hw);\r
+ }\r
+\r
+ return hw;\r
+}\r
+\r
+KHMEXP LRESULT KHMAPI khui_ps_check_message(\r
+ khui_property_sheet * sheet, \r
+ PMSG pmsg)\r
+{\r
+ LRESULT lr;\r
+\r
+ if(sheet->hwnd == NULL)\r
+ return FALSE;\r
+\r
+ lr = PropSheet_IsDialogMessage(sheet->hwnd, pmsg);\r
+ if(lr) {\r
+ sheet->hwnd_page = PropSheet_GetCurrentPageHwnd(sheet->hwnd);\r
+ if(sheet->hwnd_page == NULL && \r
+ sheet->status == KHUI_PS_STATUS_RUNNING)\r
+\r
+ sheet->status = KHUI_PS_STATUS_DONE;\r
+ }\r
+\r
+ return lr;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI khui_ps_destroy_sheet(khui_property_sheet * sheet)\r
+{\r
+ khui_property_page * p;\r
+\r
+ DestroyWindow(sheet->hwnd);\r
+ sheet->hwnd = NULL;\r
+\r
+ QGET(sheet, &p);\r
+ while(p) {\r
+ free(p);\r
+ QGET(sheet, &p);\r
+ }\r
+\r
+ free(sheet);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+\r
+\r
+#define PW_WM_SET_RECORD WM_USER\r
+\r
+KHMEXP khm_int32 KHMAPI khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record)\r
+{\r
+ SendMessage(hwnd_pwnd, PW_WM_SET_RECORD, 0, (LPARAM) record);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+#include<hashtable.h>\r
+\r
+hashtable * h_bitmaps;\r
+\r
+khm_int32 \r
+hash_id(const void *p) {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4311)\r
+ return (khm_int32) p;\r
+#pragma warning(pop)\r
+}\r
+\r
+khm_int32 \r
+comp_id(const void *p1, const void *p2) {\r
+#pragma warning(push)\r
+#pragma warning(disable: 4311)\r
+ return ((khm_int32)p1) - ((khm_int32)p2);\r
+#pragma warning(pop)\r
+}\r
+\r
+void \r
+del_ref_object(const void *k, void * data) {\r
+ DeleteObject((HGDIOBJ) data);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_init_rescache(void) {\r
+ h_bitmaps = hash_new_hashtable(127, hash_id, comp_id, NULL, \r
+ del_ref_object);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_exit_rescache(void) {\r
+ hash_del_hashtable(h_bitmaps);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_cache_bitmap(UINT id, HBITMAP hbm) {\r
+ hash_add(h_bitmaps, (void *)(size_t) id, (void *) hbm);\r
+}\r
+\r
+KHMEXP HBITMAP KHMAPI \r
+khui_get_cached_bitmap(UINT id) {\r
+ return (HBITMAP) hash_lookup(h_bitmaps, (void *)(size_t) id);\r
+}\r
+\r
+KHMEXP khui_ilist * KHMAPI \r
+khui_create_ilist(int cx, int cy, int n, int ng, int opt) {\r
+ BITMAPV5HEADER head;\r
+ HDC hdc;\r
+\r
+ khui_ilist * il = malloc(sizeof(khui_ilist));\r
+ il->cx = cx;\r
+ il->cy = cy;\r
+ il->n = n;\r
+ il->ng = ng;\r
+ il->nused = 0;\r
+ hdc = GetDC(NULL);\r
+ head.bV5Size = sizeof(head);\r
+ head.bV5Width = cx * n;\r
+ head.bV5Height = cy;\r
+ head.bV5Planes = 1;\r
+ head.bV5BitCount = 24;\r
+ head.bV5Compression = BI_RGB;\r
+ head.bV5SizeImage = 0;\r
+ head.bV5XPelsPerMeter = 2835;\r
+ head.bV5YPelsPerMeter = 2835;\r
+ head.bV5ClrUsed = 0;\r
+ head.bV5ClrImportant = 0;\r
+ head.bV5AlphaMask = 0;\r
+ head.bV5CSType = LCS_WINDOWS_COLOR_SPACE;\r
+ head.bV5Intent = LCS_GM_GRAPHICS;\r
+ head.bV5ProfileData = 0;\r
+ head.bV5ProfileSize = 0;\r
+ head.bV5Reserved = 0;\r
+ il->img = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) &head, 0, NULL, NULL, DIB_RGB_COLORS);\r
+ il->mask = CreateBitmap(cx * n, cy, 1, 1, NULL);\r
+ il->idlist = malloc(sizeof(int) * n);\r
+\r
+ return il;\r
+}\r
+\r
+KHMEXP BOOL KHMAPI \r
+khui_delete_ilist(khui_ilist * il) {\r
+ DeleteObject(il->img);\r
+ DeleteObject(il->mask);\r
+ free(il->idlist);\r
+ free(il);\r
+\r
+ return TRUE;\r
+}\r
+\r
+KHMEXP int KHMAPI \r
+khui_ilist_add_masked_id(khui_ilist *il, \r
+ HBITMAP hbm, \r
+ COLORREF cbkg, \r
+ int id) {\r
+ int idx;\r
+\r
+ idx = khui_ilist_add_masked(il,hbm,cbkg);\r
+ if(idx >= 0) {\r
+ il->idlist[idx] = id;\r
+ }\r
+\r
+ return idx;\r
+}\r
+\r
+KHMEXP int KHMAPI \r
+khui_ilist_lookup_id(khui_ilist *il, int id) {\r
+ int i;\r
+\r
+ for(i=0;i<il->nused;i++) {\r
+ if(il->idlist[i] == id)\r
+ return i;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+KHMEXP int KHMAPI \r
+khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg) {\r
+ HDC dcr,dci,dct,dcb;\r
+ HBITMAP hb_oldb, hb_oldi, hb_oldt;\r
+ int sx, i;\r
+ int x,y;\r
+\r
+ dcr = GetDC(NULL);\r
+ dci = CreateCompatibleDC(dcr);\r
+ dct = CreateCompatibleDC(dcr);\r
+ dcb = CreateCompatibleDC(dcr);\r
+ ReleaseDC(NULL,dcr);\r
+\r
+ i = il->nused++;\r
+ il->idlist[i] = -1;\r
+ sx = i * il->cx;\r
+\r
+ hb_oldb = SelectObject(dcb, hbm);\r
+ hb_oldi = SelectObject(dci, il->img);\r
+ hb_oldt = SelectObject(dct, il->mask);\r
+\r
+ SetBkColor(dct, RGB(0,0,0));\r
+ SetTextColor(dct, RGB(255,255,255));\r
+\r
+ BitBlt(dci, sx, 0, il->cx, il->cy, dcb, 0, 0, SRCCOPY);\r
+ for(y=0;y < il->cy; y++)\r
+ for(x=0; x<il->cx; x++) {\r
+ COLORREF c = GetPixel(dcb, x, y);\r
+ if(c==cbkg) {\r
+ SetPixel(dct, sx + x, y, RGB(255,255,255));\r
+ SetPixel(dci, sx + x, y, RGB(0,0,0));\r
+ } else {\r
+ SetPixel(dct, sx + x, y, RGB(0,0,0));\r
+ }\r
+ }\r
+\r
+ SelectObject(dct, hb_oldt);\r
+ SelectObject(dci, hb_oldi);\r
+ SelectObject(dcb, hb_oldb);\r
+\r
+ DeleteDC(dcb);\r
+ DeleteDC(dct);\r
+ DeleteDC(dci);\r
+\r
+ return i;\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_ilist_draw(khui_ilist * il, \r
+ int idx, \r
+ HDC dc, \r
+ int x, \r
+ int y, \r
+ int opt) {\r
+ HDC dci;\r
+ HBITMAP hb_oldi;\r
+\r
+ if(idx < 0)\r
+ return;\r
+\r
+ dci = CreateCompatibleDC(dc);\r
+\r
+ hb_oldi = SelectObject(dci, il->img);\r
+\r
+ /*BitBlt(dc, x, y, il->cx, il->cy, dci, idx*il->cx, 0, SRCCOPY); */\r
+ MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCPAINT, SRCCOPY));\r
+/* MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCINVERT, SRCCOPY)); */\r
+\r
+ SelectObject(dci, hb_oldi);\r
+\r
+ DeleteDC(dci);\r
+}\r
+\r
+KHMEXP void KHMAPI \r
+khui_ilist_draw_bg(khui_ilist * il, \r
+ int idx, \r
+ HDC dc, \r
+ int x, \r
+ int y, \r
+ int opt, \r
+ COLORREF bgcolor) {\r
+ HDC dcm;\r
+ HBITMAP hb_oldm, hb_mem;\r
+ HBRUSH hbr;\r
+ RECT r;\r
+\r
+ dcm = CreateCompatibleDC(dc);\r
+\r
+ hb_mem = CreateCompatibleBitmap(dc, il->cx, il->cy);\r
+\r
+ hb_oldm = SelectObject(dcm, hb_mem);\r
+\r
+ hbr = CreateSolidBrush(bgcolor);\r
+\r
+ r.left = 0;\r
+ r.top = 0;\r
+ r.right = il->cx;\r
+ r.bottom = il->cy;\r
+\r
+ FillRect(dcm, &r, hbr);\r
+\r
+ khui_ilist_draw(il,idx,dcm,0,0,opt);\r
+\r
+ BitBlt(dc,x,y,il->cx,il->cy,dcm,0,0,SRCCOPY);\r
+\r
+ SelectObject(dcm, hb_oldm);\r
+ \r
+ DeleteObject(hb_mem);\r
+ DeleteObject(hbr);\r
+\r
+ DeleteDC(dcm);\r
+}\r
+\r
+\r
+KHMEXP void KHMAPI \r
+khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm)\r
+{\r
+ HDC hdc;\r
+ BITMAPINFO bmi;\r
+\r
+ hdc = CreateCompatibleDC(NULL);\r
+\r
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
+\r
+ kbm->hbmp = hbm;\r
+\r
+ if(GetDIBits(hdc, hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS)) {\r
+ kbm->cx = bmi.bmiHeader.biWidth;\r
+ kbm->cy = bmi.bmiHeader.biHeight;\r
+ } else {\r
+ kbm->cx = -1;\r
+ kbm->cy = -1;\r
+ }\r
+\r
+ DeleteDC(hdc);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_delete_bitmap(khui_bitmap * kbm) {\r
+ if (kbm->hbmp)\r
+ DeleteObject(kbm->hbmp);\r
+ kbm->hbmp = NULL;\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm) {\r
+ HDC hdcb = CreateCompatibleDC(hdc);\r
+ HBITMAP hbmold = SelectObject(hdcb, kbm->hbmp);\r
+\r
+ BitBlt(hdc, x, y, kbm->cx, kbm->cy,\r
+ hdcb, 0, 0, SRCCOPY);\r
+\r
+ SelectObject(hdcb, hbmold);\r
+ DeleteDC(hdcb);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+#include<commctrl.h>\r
+#include<assert.h>\r
+\r
+#define K5_SLIDER_WIDTH 208\r
+#define K5_SLIDER_HEIGHT 40\r
+\r
+#define K5_SLIDER_LBL_HPAD 5\r
+#define K5_SLIDER_LBL_VPAD 22\r
+\r
+#define KHUI_TRACKER_PROP L"KhmTrackerData"\r
+\r
+\r
+/* Count the number of ticks between tmin and tmax, inclusive\r
+*/\r
+int time_t_to_ticks(time_t tmin, time_t tmax)\r
+{\r
+ int c = 0;\r
+ time_t lo, hi;\r
+\r
+ tmin -= tmin % 60; /* our smallest gran is 1 min */\r
+ if(tmax % 60)\r
+ tmax += 60 - (tmax % 60);\r
+\r
+ lo = tmin;\r
+\r
+#define TFORWARD(limit,gran) \\r
+ if(lo < limit && lo < tmax) { \\r
+ hi = min(tmax, limit); \\r
+ c += (int)((hi - lo) / (gran)); \\r
+ lo = hi; \\r
+ }\r
+\r
+ TFORWARD(300,60);\r
+ TFORWARD(3600,300);\r
+ TFORWARD(3600*4, 60*15);\r
+ TFORWARD(3600*10,60*30);\r
+ TFORWARD(3600*24,3600);\r
+ TFORWARD(3600*24*4,3600*6);\r
+ TFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24);\r
+\r
+#undef TFORWARD\r
+\r
+ return c;\r
+}\r
+\r
+/* Compute tmax given tmin and ticks such that there are ticks ticks\r
+ between tmin and tmax\r
+ */\r
+time_t ticks_to_time_t(int ticks, time_t tmin)\r
+{\r
+ int c = 0;\r
+ tmin -= tmin % 60; /* our smallest gran is 1 min */\r
+\r
+#define SFORWARD(limit,gran) \\r
+ if(tmin < limit && ticks > 0) { \\r
+ c = (int) min(ticks, (limit - tmin) / (gran)); \\r
+ tmin += c * gran; \\r
+ ticks -= c; \\r
+ }\r
+\r
+ SFORWARD(300,60);\r
+ SFORWARD(3600,300);\r
+ SFORWARD(3600*4,60*15);\r
+ SFORWARD(3600*10,60*30);\r
+ SFORWARD(3600*24,3600);\r
+ SFORWARD(3600*24*4,3600*6);\r
+ SFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24);\r
+\r
+#undef SFORWARD\r
+\r
+ return tmin;\r
+}\r
+\r
+/* Prep a tracker control which works in conjunction with the\r
+ duration edit control.\r
+\r
+ NOTE: Runs in the context of the UI thread\r
+*/\r
+void \r
+initialize_tracker(HWND hwnd, \r
+ khui_tracker * tc)\r
+{\r
+ RECT r;\r
+ FILETIME ft;\r
+ wchar_t wbuf[256];\r
+ khm_size cbbuf;\r
+\r
+ SendMessage(tc->hw_slider, TBM_SETRANGE, 0, MAKELONG(0, time_t_to_ticks(tc->min, tc->max)));\r
+ SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current));\r
+\r
+ r.left = K5_SLIDER_LBL_HPAD;\r
+ r.top = K5_SLIDER_LBL_VPAD;\r
+ r.right = K5_SLIDER_WIDTH - K5_SLIDER_LBL_HPAD;\r
+ r.bottom = r.top;\r
+\r
+ MapDialogRect(hwnd, &r);\r
+\r
+ tc->lbl_y = r.top;\r
+ tc->lbl_lx = r.left;\r
+ tc->lbl_rx = r.right;\r
+\r
+ TimetToFileTimeInterval(tc->current, &ft);\r
+ cbbuf = sizeof(wbuf);\r
+ FtIntervalToString(&ft, wbuf, &cbbuf);\r
+\r
+ SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf);\r
+}\r
+\r
+\r
+/* We instance-subclass each tracker control to provide the\r
+ functionality that we need. This is the replacement window\r
+ procedure\r
+\r
+ NOTE: Runs in the context of the UI thread\r
+ */\r
+LRESULT CALLBACK \r
+duration_tracker_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ khui_tracker * tc;\r
+\r
+ tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP);\r
+#ifdef DEBUG\r
+ assert(tc != NULL);\r
+#endif\r
+\r
+ switch(uMsg) {\r
+ case WM_PAINT:\r
+ {\r
+ HDC hdc;\r
+ HFONT hf, hfold;\r
+ LRESULT lr;\r
+ FILETIME ft;\r
+ wchar_t buf[256];\r
+ khm_size cbbuf;\r
+\r
+ lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam);\r
+\r
+ /* Can't use BeginPaint here, since we already called the\r
+ window proc */\r
+ hdc = GetWindowDC(hwnd);\r
+\r
+ hf = (HFONT) SendMessage(tc->hw_edit, WM_GETFONT, 0, 0);\r
+\r
+ hfold = ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hf)));\r
+\r
+ TimetToFileTimeInterval(tc->min, &ft);\r
+ cbbuf = sizeof(buf);\r
+ FtIntervalToString(&ft, buf, &cbbuf);\r
+\r
+ SetTextColor(hdc, RGB(0,0,0));\r
+ SetBkMode(hdc, TRANSPARENT);\r
+\r
+ SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP);\r
+ TextOut(hdc, tc->lbl_lx, tc->lbl_y, buf, (int) wcslen(buf));\r
+ \r
+ TimetToFileTimeInterval(tc->max, &ft);\r
+ cbbuf = sizeof(buf);\r
+ FtIntervalToString(&ft, buf, &cbbuf);\r
+\r
+ SetTextAlign(hdc, TA_RIGHT | TA_TOP | TA_NOUPDATECP);\r
+ TextOut(hdc, tc->lbl_rx, tc->lbl_y, buf, (int) wcslen(buf));\r
+\r
+ ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hfold)));\r
+\r
+ ReleaseDC(hwnd, hdc);\r
+ \r
+ return lr;\r
+ }\r
+ break;\r
+\r
+ case WM_KILLFOCUS:\r
+ {\r
+ if((HWND)wParam != tc->hw_edit)\r
+ ShowWindow(hwnd, SW_HIDE);\r
+ }\r
+ break;\r
+\r
+ case WM_LBUTTONUP:\r
+ case WM_MOUSEMOVE:\r
+ {\r
+ LRESULT lr;\r
+\r
+ lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam);\r
+\r
+ if(wParam & MK_LBUTTON) {\r
+ int c = (int) SendMessage(hwnd, TBM_GETPOS, 0, 0);\r
+ time_t t = ticks_to_time_t(c, tc->min);\r
+\r
+ if(t != tc->current) {\r
+ wchar_t buf[256];\r
+ FILETIME ft;\r
+ khm_size cbbuf;\r
+\r
+ tc->current = t;\r
+ //d->dirty = TRUE;\r
+ cbbuf = sizeof(buf);\r
+ TimetToFileTimeInterval(t, &ft);\r
+ FtIntervalToString(&ft, buf, &cbbuf);\r
+ SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM) buf);\r
+ }\r
+ }\r
+ return lr;\r
+ }\r
+ }\r
+\r
+ return CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+\r
+/* Create the subclassed duration slider on behalf of an edit control */\r
+void \r
+create_edit_sliders(HWND hwnd, \r
+ HWND hwnd_dlg, \r
+ khui_tracker * tc)\r
+{\r
+ RECT r;\r
+ RECT rs;\r
+\r
+ GetWindowRect(hwnd, &r);\r
+\r
+ rs.top = 0;\r
+ rs.left = 0;\r
+ rs.right = K5_SLIDER_WIDTH;\r
+ rs.bottom = K5_SLIDER_HEIGHT;\r
+ MapDialogRect(hwnd_dlg, &rs);\r
+ rs.right -= rs.left;\r
+ rs.bottom -= rs.top;\r
+\r
+ tc->hw_slider = \r
+ CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,\r
+ TRACKBAR_CLASS,\r
+ L"NetIDMgrTimeTickerTrackbar",\r
+ WS_POPUP | TBS_AUTOTICKS | TBS_BOTTOM |\r
+ TBS_DOWNISLEFT | TBS_HORZ | WS_CLIPCHILDREN,\r
+ r.left,r.bottom,rs.right,rs.bottom,\r
+ hwnd,\r
+ NULL,\r
+ (HINSTANCE)(DWORD_PTR) \r
+ GetWindowLongPtr(hwnd, GWLP_HINSTANCE),\r
+ NULL);\r
+\r
+ SetProp(tc->hw_slider, KHUI_TRACKER_PROP,\r
+ (HANDLE) tc);\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ tc->fn_tracker = (WNDPROC)(LONG_PTR) SetWindowLongPtr(tc->hw_slider, GWLP_WNDPROC, (LONG_PTR) duration_tracker_proc);\r
+#pragma warning(pop)\r
+}\r
+\r
+/* An edit control is instance-subclassed to create an edit control\r
+ that holds a duration. Welcome to the window procedure.\r
+\r
+ NOTE: Runs in the context of the UI thread\r
+ */\r
+LRESULT CALLBACK \r
+duration_edit_proc(HWND hwnd,\r
+ UINT uMsg,\r
+ WPARAM wParam,\r
+ LPARAM lParam)\r
+{\r
+ khui_tracker * tc;\r
+\r
+ tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP);\r
+\r
+#ifdef DEBUG\r
+ assert(tc != NULL);\r
+#endif\r
+\r
+ switch(uMsg) {\r
+ case WM_SETFOCUS:\r
+ {\r
+ HWND p;\r
+\r
+ p = GetParent(hwnd);\r
+\r
+ /* we are being activated. show the panel */\r
+ if(tc->hw_slider == NULL) {\r
+ create_edit_sliders(hwnd, p, tc);\r
+ initialize_tracker(p, tc);\r
+ }\r
+ khui_tracker_reposition(tc);\r
+ ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE);\r
+ //SetActiveWindow(p);\r
+ }\r
+ break;\r
+\r
+ case WM_KILLFOCUS:\r
+ {\r
+ wchar_t wbuf[256];\r
+ FILETIME ft;\r
+ khm_size cbbuf;\r
+\r
+ if((HWND) wParam != tc->hw_slider)\r
+ ShowWindow(tc->hw_slider, SW_HIDE);\r
+\r
+ TimetToFileTimeInterval(tc->current, &ft);\r
+ cbbuf = sizeof(wbuf);\r
+ FtIntervalToString(&ft, wbuf, &cbbuf);\r
+\r
+ SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf);\r
+ }\r
+ break;\r
+\r
+ case KHUI_WM_NC_NOTIFY:\r
+ if(HIWORD(wParam) == WMNC_DIALOG_SETUP)\r
+ {\r
+ HWND p;\r
+\r
+ p = GetParent(hwnd);\r
+\r
+ if(tc->hw_slider == NULL) {\r
+ create_edit_sliders(hwnd,p,tc);\r
+ }\r
+\r
+ initialize_tracker(p, tc);\r
+ }\r
+ return TRUE;\r
+\r
+ /* these messages can potentially change the text in the edit\r
+ control. We intercept them and see what changed. We may\r
+ need to grab and handle them */\r
+ case EM_REPLACESEL:\r
+ case EM_UNDO:\r
+ case WM_UNDO:\r
+ case WM_CHAR:\r
+ case WM_UNICHAR:\r
+ {\r
+ wchar_t buf[256];\r
+ size_t nchars;\r
+ time_t ts;\r
+ FILETIME ft;\r
+ BOOL modified;\r
+ LRESULT lr = CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam);\r
+\r
+ modified = (BOOL) SendMessage(hwnd, EM_GETMODIFY, 0, 0);\r
+ if(modified) {\r
+ /* parse the string */\r
+ if(nchars = (size_t) SendMessage(hwnd, WM_GETTEXT, ARRAYLENGTH(buf), (LPARAM) buf)) {\r
+ buf[nchars] = 0;\r
+\r
+ if(KHM_SUCCEEDED(IntervalStringToFt(&ft, buf))) {\r
+ ts = FtIntervalToSeconds(&ft);\r
+ if(ts >= tc->min && ts <= tc->max) {\r
+ tc->current = ts;\r
+ //d->dirty = TRUE;\r
+ if(tc->hw_slider != NULL)\r
+ SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current));\r
+ }\r
+ }\r
+ }\r
+ SendMessage(hwnd, EM_SETMODIFY, FALSE, 0);\r
+ }\r
+\r
+ return lr;\r
+ }\r
+ }\r
+\r
+ return CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_install(HWND hwnd_edit, khui_tracker * tc) {\r
+#ifdef DEBUG\r
+ assert(hwnd_edit);\r
+ assert(tc);\r
+#endif\r
+\r
+ tc->hw_edit = hwnd_edit;\r
+\r
+ SetProp(hwnd_edit, KHUI_TRACKER_PROP, (HANDLE) tc);\r
+\r
+#pragma warning(push)\r
+#pragma warning(disable: 4244)\r
+ tc->fn_edit = (WNDPROC)(LONG_PTR) \r
+ SetWindowLongPtr(hwnd_edit, GWLP_WNDPROC, \r
+ (LONG_PTR) duration_edit_proc);\r
+#pragma warning(pop)\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_reposition(khui_tracker * tc) {\r
+ RECT r;\r
+\r
+ if(tc->hw_slider && tc->hw_edit) {\r
+ GetWindowRect(tc->hw_edit, &r);\r
+ SetWindowPos(tc->hw_slider,\r
+ NULL,\r
+ r.left, r.bottom, \r
+ 0, 0, \r
+ SWP_NOOWNERZORDER | SWP_NOSIZE | \r
+ SWP_NOZORDER | SWP_NOACTIVATE);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_initialize(khui_tracker * tc) {\r
+ ZeroMemory(tc, sizeof(*tc));\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_refresh(khui_tracker * tc) {\r
+ if (!tc->hw_edit)\r
+ return;\r
+\r
+ SendMessage(tc->hw_edit,\r
+ KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);\r
+}\r
+\r
+KHMEXP void KHMAPI\r
+khui_tracker_kill_controls(khui_tracker * tc) {\r
+ if (tc->hw_slider)\r
+ DestroyWindow(tc->hw_slider);\r
+ if (tc->hw_edit)\r
+ DestroyWindow(tc->hw_edit);\r
+ tc->hw_slider = NULL;\r
+ tc->hw_edit = NULL;\r
+ tc->fn_edit = NULL;\r
+ tc->fn_tracker = NULL;\r
+}\r
+\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<khuidefs.h>\r
+\r
+extern void alert_init(void);\r
+extern void alert_exit(void);\r
+\r
+void\r
+uilib_process_attach(void) {\r
+ alert_init();\r
+}\r
+\r
+void\r
+uilib_process_detach(void) {\r
+ alert_exit();\r
+}\r
+\r
--- /dev/null
+#\r
+# Copyright (c) 2004 Massachusetts Institute of Technology\r
+#\r
+# Permission is hereby granted, free of charge, to any person\r
+# obtaining a copy of this software and associated documentation files\r
+# (the "Software"), to deal in the Software without restriction,\r
+# including without limitation the rights to use, copy, modify, merge,\r
+# publish, distribute, sublicense, and/or sell copies of the Software,\r
+# and to permit persons to whom the Software is furnished to do so,\r
+# subject to the following conditions:\r
+#\r
+# The above copyright notice and this permission notice shall be\r
+# included in all copies or substantial portions of the Software.\r
+#\r
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+# SOFTWARE.\r
+\r
+\r
+MODULE=util\r
+!include <../config/Makefile.w32>\r
+\r
+INCFILES= \\r
+ $(INCDIR)\utils.h \\r
+ $(INCDIR)\hashtable.h \\r
+ $(INCDIR)\mstring.h \\r
+ $(INCDIR)\sync.h\r
+\r
+OBJFILES= \\r
+ $(OBJ)\hashtable.obj \\r
+ $(OBJ)\mstring.obj \\r
+ $(OBJ)\sync.obj\r
+\r
+LIBFILES=\r
+\r
+SDKLIBFILES= \r
+\r
+all: mkdirs $(INCFILES) $(OBJFILES)\r
+\r
+clean::\r
+ $(RM) $(INCFILES)\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<hashtable.h>\r
+#include<stdlib.h>\r
+\r
+KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, \r
+ hash_function_t hash, \r
+ comp_function_t comp,\r
+ add_ref_function_t addr,\r
+ del_ref_function_t delr) \r
+{\r
+ hashtable * h;\r
+\r
+ h = malloc(sizeof(hashtable));\r
+\r
+ h->n = n;\r
+ h->addr = addr;\r
+ h->comp = comp;\r
+ h->delr = delr;\r
+ h->hash = hash;\r
+\r
+ h->bins = calloc(sizeof(hash_bin *), n);\r
+\r
+ return h;\r
+}\r
+\r
+KHMEXP void KHMAPI hash_del_hashtable(hashtable * h) {\r
+ hash_bin * b;\r
+ int i;\r
+\r
+ for(i=0;i<h->n;i++) {\r
+ LPOP(&h->bins[i], &b);\r
+ while(b) {\r
+ if(h->delr)\r
+ h->delr(b->key, b->data);\r
+ free(b);\r
+ LPOP(&h->bins[i], &b);\r
+ }\r
+ }\r
+\r
+ free(h);\r
+}\r
+\r
+KHMEXP void KHMAPI hash_add(hashtable * h, void * key, void * data) {\r
+ int hv;\r
+ hash_bin * b;\r
+\r
+ hv = h->hash(key) % h->n;\r
+ b = h->bins[hv];\r
+ while(b) {\r
+ if(!h->comp(b->key, key)) {\r
+ /* found an existing value */\r
+ if(h->delr)\r
+ h->delr(b->key, b->data);\r
+ b->key = key;\r
+ b->data = data;\r
+ if(h->addr)\r
+ h->addr(b->key, b->data);\r
+ break;\r
+ }\r
+ b = LNEXT(b);\r
+ }\r
+\r
+ if(!b) {\r
+ b = malloc(sizeof(hash_bin));\r
+ b->data = data;\r
+ b->key = key;\r
+ LINIT(b);\r
+ LPUSH(&h->bins[hv], b);\r
+ if(h->addr)\r
+ h->addr(b->key, b->data);\r
+ }\r
+}\r
+\r
+KHMEXP void KHMAPI hash_del(hashtable * h, void * key) {\r
+ hash_bin * b;\r
+ int hv;\r
+\r
+ hv = h->hash(key) % h->n;\r
+\r
+ b = h->bins[hv];\r
+ while(b) {\r
+ if(!h->comp(b->key, key)) {\r
+ /* found it */\r
+ LDELETE(&h->bins[hv], b);\r
+ if(h->delr)\r
+ h->delr(b->key, b->data);\r
+ free(b);\r
+ break;\r
+ }\r
+ b = LNEXT(b);\r
+ }\r
+}\r
+\r
+KHMEXP void * KHMAPI hash_lookup(hashtable * h, void * key) {\r
+ hash_bin * b;\r
+ int hv;\r
+\r
+ hv = h->hash(key) % h->n;\r
+\r
+ b = h->bins[hv];\r
+\r
+ while(b) {\r
+ if(!h->comp(b->key, key)) {\r
+ return b->data;\r
+ }\r
+ b = LNEXT(b);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, void * key) {\r
+ hash_bin * b;\r
+ int hv;\r
+\r
+ hv = h->hash(key) % h->n;\r
+ b = h->bins[hv];\r
+ while(b) {\r
+ if(!h->comp(b->key, key))\r
+ return 1;\r
+ b = LNEXT(b);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+KHMEXP khm_int32 hash_string(const void *vs) {\r
+ /* DJB algorithm */\r
+\r
+ khm_int32 hv = 13331;\r
+ wchar_t * c;\r
+ \r
+ for(c = (wchar_t *) vs; *c; c++) {\r
+ hv = ((hv<<5) + hv) + (khm_int32) *c;\r
+ }\r
+\r
+ return (hv & KHM_INT32_MAX);\r
+}\r
+\r
+KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2) {\r
+ return wcscmp((const wchar_t *) vs1, (const wchar_t *) vs2);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_HASHTABLE_H\r
+#define __KHIMAIRA_HASHTABLE_H\r
+\r
+/*! \addtogroup util\r
+ @{ */\r
+\r
+/*! \defgroup util_ht Hashtable\r
+ @{*/\r
+\r
+#include<khdefs.h>\r
+#include<khlist.h>\r
+\r
+/*! \brief A hash function\r
+\r
+ The function should take a key as a parameter and return an\r
+ khm_int32 that serves as the hash of the key.\r
+ */\r
+typedef khm_int32 (*hash_function_t)(const void *key);\r
+\r
+/*! \brief A comparison function\r
+\r
+ The function takes two keys and returns a value indicating the\r
+ relative ordering of the two keys.\r
+\r
+ The return value should be:\r
+ - \b Zero if \a key1 == \a key2\r
+ - \b Negative if \a key1 < \a key2\r
+ - \b Positive if \a key1 > \a key2\r
+ */\r
+typedef khm_int32 (*comp_function_t)(const void *key1, const void *key2);\r
+\r
+/*! \brief Add-reference function\r
+\r
+ When an object is successfully added to a hashtable, this function\r
+ will be called with the \a key and \a data used to add the object.\r
+ The function is allowed to modify \a data, however, the\r
+ modification should not alter the \a key or the relationship\r
+ between \a key and \a data.\r
+ */\r
+typedef void (*add_ref_function_t)(const void *key, void *data);\r
+\r
+/*! \brief Delete-reference function\r
+\r
+ When an object is successfully removed from the hashtable, this\r
+ function will be called. As with the add-ref function, the object\r
+ can be modified, but the \a key and the relationship between \a\r
+ key and \a data should remain intact.\r
+\r
+ An object is removed if it is explicitly removed from the\r
+ hashtable or another object with the same \a key is added to the\r
+ hashtable. There should be a 1-1 correspondence with keys and\r
+ objects in the hashtable. The delete-reference function will be\r
+ called on all the remaining objects in the hashtable when the\r
+ hashtable is deleted.\r
+ */\r
+typedef void (*del_ref_function_t)(const void *key, void *data);\r
+\r
+typedef struct tag_hash_bin {\r
+ void * data;\r
+ void * key;\r
+\r
+ LDCL(struct tag_hash_bin);\r
+} hash_bin;\r
+\r
+typedef struct hashtable_t {\r
+ khm_int32 n;\r
+ hash_function_t hash;\r
+ comp_function_t comp;\r
+ add_ref_function_t addr;\r
+ del_ref_function_t delr;\r
+ hash_bin ** bins;\r
+} hashtable;\r
+\r
+/*! \brief Create a new hashtable\r
+\r
+ \param[in] n Number of bins in hashtable.\r
+ \param[in] hash A hash function. Required.\r
+ \param[in] comp A comparator. Required.\r
+ \param[in] addr An add-ref function. Optional; can be NULL.\r
+ \param[in] delr A del-ref function. Optional; can be NULL.\r
+\r
+ */\r
+KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, \r
+ hash_function_t hash, \r
+ comp_function_t comp,\r
+ add_ref_function_t addr,\r
+ del_ref_function_t delr);\r
+\r
+/*! \brief Delete a hashtable\r
+\r
+ \note Not thread-safe. Applications must serialize calls that\r
+ reference the same hashtable.\r
+ */\r
+KHMEXP void KHMAPI hash_del_hashtable(hashtable * h);\r
+\r
+/*! \brief Add an object to a hashtable\r
+\r
+ Creates an association between the \a key and \a data in the\r
+ hashtable \a h. If there is an add-ref function defined for the\r
+ hashtable, it will be called with \a key and \data after the\r
+ object is added. If there is already an object with the same key\r
+ in the hashtable, that object will be removed (and the del-ref\r
+ function called, if appilcable) before adding the new object and\r
+ before the add-ref function is called for the new object.\r
+\r
+ Note that two keys \a key1 and \a key2 are equal (or same) in a\r
+ hashtable if the comparator returns zero when called with \a key1\r
+ and \a key2.\r
+\r
+ Also note that all additions and removals to the hashtable are\r
+ done by reference. No data is copied. Any objects pointed to are\r
+ expected to exist for the duration that the object and key are\r
+ contained in the hashtable.\r
+\r
+ \param[in] h Hashtable\r
+ \param[in] key A key. If \a key points to a location in memory,\r
+ it should be within the object pointed to by \a data, or be a\r
+ constant. Can be NULL.\r
+ \param[in] data Data. Cannot be NULL.\r
+\r
+ \note Not thread-safe. Applications must serialize calls that\r
+ reference the same hashtable.\r
+ */\r
+KHMEXP void KHMAPI hash_add(hashtable * h, void * key, void * data);\r
+\r
+/*! \brief Delete an object from a hashtable\r
+\r
+ Deletes the object in the hashtable \a h that is associated with\r
+ key \a key. An object is associated with key \a key if the key \a\r
+ key_o that the object is associated with is the same as \a key as\r
+ determined by the comparator. If the del-ref function is defined\r
+ for the hash-table, it will be called with the \a key_o and \a\r
+ data that was used to add the object.\r
+\r
+ \note Not thread-safe. Applications must serialize calls that\r
+ reference the same hashtable.\r
+ */\r
+KHMEXP void KHMAPI hash_del(hashtable * h, void * key);\r
+\r
+/*! \brief Resolve and association\r
+\r
+ Return the object that is associated with key \a key in hashtable\r
+ \a h. An object \a data is associated with key \a key in \a h if\r
+ the key \a key_o that was used to add \a data to \a h is equal to\r
+ \a key as determined by the comparator.\r
+\r
+ Returns NULL if no association is found.\r
+\r
+ \note Not thread-safe. Applications must serialize calls that\r
+ reference the same hashtable.\r
+ */\r
+KHMEXP void * KHMAPI hash_lookup(hashtable * h, void * key);\r
+\r
+/*! \brief Check for the presence of an association\r
+\r
+ Returns non-zero if there exists an association between key \a key\r
+ and some object in hashtable \a h. See hash_lookup() for\r
+ definition of "association".\r
+\r
+ Returns zero if there is no association.\r
+\r
+ \note (hash_lookup(h,key) == NULL) iff (hash_exist(h,key)==0)\r
+\r
+ \note Not thead-safe. Application must serialize calls that\r
+ reference the same hashtable.\r
+ */\r
+KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, void * key);\r
+\r
+/*! \brief Compute a hashvalue for a unicode string\r
+\r
+ The hash value is computed using DJB with parameter 13331.\r
+\r
+ This function is suitable for use as the hash function for a\r
+ hashtable if the keys are NULL terminated safe unicode strings\r
+ that are either part of the data objects or are constants.\r
+\r
+ \param[in] str A pointer to a NULL terminated wchar_t string cast\r
+ as (void *).\r
+ */\r
+KHMEXP khm_int32 hash_string(const void *str);\r
+\r
+/*! \brief Compare two strings\r
+\r
+ Compares two strings are returns a value that is in accordance\r
+ with the comparator for a hashtable.\r
+\r
+ \param[in] vs1 A pointer to a NULL terminated wchar_t string cast\r
+ as (void *).\r
+ \param[in] vs2 A pointer to a NULL terminated wchar_t string cast\r
+ as (void *).\r
+ */\r
+KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2);\r
+\r
+/*@}*/\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+* Copyright (c) 2004 Massachusetts Institute of Technology\r
+*\r
+* Permission is hereby granted, free of charge, to any person\r
+* obtaining a copy of this software and associated documentation\r
+* files (the "Software"), to deal in the Software without\r
+* restriction, including without limitation the rights to use, copy,\r
+* modify, merge, publish, distribute, sublicense, and/or sell copies\r
+* of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be\r
+* included in all copies or substantial portions of the Software.\r
+*\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+* SOFTWARE.\r
+*/\r
+\r
+/* $Id$ */\r
+\r
+#include<mstring.h>\r
+#include<kherror.h>\r
+#include<strsafe.h>\r
+#include<stdlib.h>\r
+\r
+#define TRUE 1\r
+#define FALSE 0\r
+\r
+KHMEXP khm_int32 KHMAPI\r
+multi_string_init(wchar_t * ms,\r
+ khm_size cb_ms) {\r
+ if (!ms || cb_ms < sizeof(wchar_t) * 2)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ memset(ms, 0, cb_ms);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_append(\r
+ wchar_t * ms,\r
+ khm_size * pcb_ms,\r
+ const wchar_t * str)\r
+{\r
+ wchar_t * s;\r
+ size_t cch_s;\r
+ size_t cch_t;\r
+ size_t cch_r;\r
+\r
+ if(!ms || !pcb_ms || !str)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0)\r
+ return KHM_ERROR_INVALID_PARM;\r
+ cch_s++;\r
+\r
+ s = ms;\r
+\r
+ while(*s && ((s - ms) < KHM_MAXCCH_STRING)) {\r
+ if(FAILED(StringCchLength(s, KHM_MAXCB_STRING, &cch_t)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ s += cch_t + 1;\r
+ }\r
+\r
+ if(*s || (s - ms) >= KHM_MAXCCH_STRING) {\r
+ return KHM_ERROR_INVALID_PARM;\r
+ }\r
+\r
+ /* now s points to the second NULL of the terminating double NULL */\r
+\r
+ cch_r = ((s - ms) + cch_s + 1) * sizeof(wchar_t);\r
+ if(*pcb_ms < cch_r) {\r
+ *pcb_ms = cch_r;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ *pcb_ms = cch_r;\r
+\r
+ StringCchCopy(s, cch_s, str);\r
+ s += cch_s;\r
+ *s = 0;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_prepend(\r
+ wchar_t * ms,\r
+ khm_size * pcb_ms,\r
+ const wchar_t * str)\r
+{\r
+ size_t cch_s;\r
+ size_t cch_t;\r
+ size_t cch_r;\r
+ khm_size cb_r;\r
+\r
+ if(!ms || !pcb_ms || !str)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0)\r
+ return KHM_ERROR_INVALID_PARM;\r
+ cch_s++;\r
+\r
+ if(KHM_FAILED(multi_string_length_cch(ms,\r
+ KHM_MAXCCH_STRING,\r
+ &cch_r)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cch_t = cch_s + cch_r;\r
+ cb_r = cch_t * sizeof(wchar_t);\r
+\r
+ if (*pcb_ms < cb_r) {\r
+ *pcb_ms = cb_r;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ memmove(ms + cch_s, ms, cch_r * sizeof(wchar_t));\r
+ memcpy(ms, str, cch_s * sizeof(wchar_t));\r
+\r
+ *pcb_ms = cb_r;\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_delete(\r
+ wchar_t * ms,\r
+ const wchar_t * str,\r
+ const khm_int32 flags)\r
+{\r
+ wchar_t * s;\r
+ wchar_t * n;\r
+ wchar_t * e;\r
+ size_t cch;\r
+\r
+ if(!ms || !str)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ s = multi_string_find(ms, str, flags);\r
+ if(!s)\r
+ return KHM_ERROR_NOT_FOUND;\r
+\r
+ e = s;\r
+ n = NULL;\r
+ while(*e && (e - s) < KHM_MAXCCH_STRING) {\r
+ if(FAILED(StringCchLength(e, KHM_MAXCCH_STRING, &cch)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ e += cch + 1;\r
+\r
+ if(!n)\r
+ n = e;\r
+ }\r
+\r
+ if(*e || (e - s) >= KHM_MAXCCH_STRING)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ if(e == s)\r
+ return KHM_ERROR_SUCCESS;\r
+\r
+ memmove((void *) s, (void *) n, ((e - n) + 1) * sizeof(wchar_t));\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP wchar_t * KHMAPI \r
+multi_string_find(\r
+ const wchar_t * ms,\r
+ const wchar_t * str,\r
+ const khm_int32 flags)\r
+{\r
+ const wchar_t *s;\r
+ size_t cch;\r
+ size_t cch_s;\r
+\r
+ if(!ms || !str)\r
+ return NULL;\r
+\r
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)))\r
+ return NULL;\r
+\r
+ s = ms;\r
+\r
+ while(*s && (s - ms) < KHM_MAXCCH_STRING) {\r
+ if(FAILED(StringCchLength(s, KHM_MAXCCH_STRING, &cch)))\r
+ return NULL;\r
+ /* cch++ at end */\r
+\r
+ if(flags & KHM_PREFIX) {\r
+ if(((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch_s)) ||\r
+ (!(flags & KHM_CASE_SENSITIVE) && !wcsnicmp(s, str, cch_s)))\r
+ return (wchar_t *) s;\r
+ } else {\r
+ if((cch == cch_s) &&\r
+ ((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch)) ||\r
+ (!(flags & KHM_CASE_SENSITIVE) && !wcsnicmp(s, str, cch)))\r
+ return (wchar_t *) s;\r
+ }\r
+\r
+ s += cch + 1;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_to_csv(\r
+ wchar_t * csvbuf,\r
+ khm_size * pcb_csvbuf,\r
+ const wchar_t * ms)\r
+{\r
+ size_t cb;\r
+ size_t cbt;\r
+ const wchar_t * t;\r
+ wchar_t * d;\r
+\r
+ if(!pcb_csvbuf || !ms)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ /* dry run */\r
+ cbt = 0;\r
+ t = ms;\r
+ while(*t && cbt <= KHM_MAXCB_STRING) {\r
+ khm_boolean quotes = FALSE;\r
+\r
+ if(FAILED(StringCbLength(t, KHM_MAXCB_STRING, &cb)))\r
+ return KHM_ERROR_INVALID_PARM;\r
+ cb += sizeof(wchar_t);\r
+\r
+ cbt += cb;\r
+\r
+ if(wcschr(t, L','))\r
+ quotes = TRUE;\r
+\r
+ d = (wchar_t *) t;\r
+ while(d = wcschr(d, L'"')) {\r
+ cbt += sizeof(wchar_t); /* '"'-> '""' */\r
+ d++;\r
+ quotes = TRUE;\r
+ }\r
+\r
+ if(quotes)\r
+ cbt += 2*sizeof(wchar_t); /* make room for quotes */\r
+\r
+ t += cb / sizeof(wchar_t);\r
+ }\r
+\r
+ if(cbt > KHM_MAXCB_STRING)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ /* happens if the multi string contained no strings */\r
+ if(cbt == 0)\r
+ cbt = sizeof(wchar_t);\r
+\r
+ if(!csvbuf || *pcb_csvbuf < cbt)\r
+ {\r
+ *pcb_csvbuf = cbt;\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ *pcb_csvbuf = cbt;\r
+\r
+ /* wet run */\r
+ t = ms;\r
+ d = csvbuf;\r
+ *csvbuf = 0;\r
+ while(*t) {\r
+ const wchar_t * s;\r
+\r
+ StringCbLength(t, KHM_MAXCB_STRING, &cb);\r
+ cb += sizeof(wchar_t);\r
+\r
+ if(d != csvbuf)\r
+ *d++ = L',';\r
+ if(wcschr(t, L',') || wcschr(t, L'"')) {\r
+ *d++ = L'"';\r
+ s = t;\r
+ while(*s) {\r
+ if(*s == L'"') {\r
+ *d++ = L'"';\r
+ *d++ = L'"';\r
+ } else\r
+ *d++ = *s;\r
+ s++;\r
+ }\r
+ *d++ = L'"';\r
+ *d = 0;\r
+ } else {\r
+ StringCbCopy(d, cbt - ((d - csvbuf) * sizeof(wchar_t)), t);\r
+ d += cb / sizeof(wchar_t) - 1;\r
+ }\r
+ t += cb / sizeof(wchar_t);\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+csv_to_multi_string(\r
+ wchar_t * ms,\r
+ khm_size * pcb_ms,\r
+ const wchar_t * csv)\r
+{\r
+ const wchar_t * t;\r
+ wchar_t * p;\r
+ size_t cchr;\r
+ int field = 1;\r
+\r
+\r
+ if(!pcb_ms || !csv)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cchr = 0;\r
+\r
+ /* dry run */\r
+ t = csv;\r
+ while(*t && (t - csv) < KHM_MAXCCH_STRING) {\r
+ if(field && *t == L'"') {\r
+ t++;\r
+ while(*t && (t - csv) < KHM_MAXCCH_STRING) {\r
+ if(*t == L'"') {\r
+ t++;\r
+ if(*t != L'"')\r
+ break;\r
+ }\r
+ cchr++;\r
+ t++;\r
+ }\r
+ }\r
+\r
+ if(*t) {\r
+ cchr++;\r
+ if(*t == L',')\r
+ field = 1;\r
+ else\r
+ field = 0;\r
+\r
+ t++;\r
+ }\r
+ }\r
+\r
+ if((t - csv) >= KHM_MAXCCH_STRING)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ cchr++; /* last string ends */\r
+ cchr++; /* double NULL */\r
+\r
+ if(!ms || *pcb_ms < (cchr * sizeof(wchar_t))) {\r
+ *pcb_ms = cchr * sizeof(wchar_t);\r
+ return KHM_ERROR_TOO_LONG;\r
+ }\r
+\r
+ /* wet run */\r
+ t = csv;\r
+ p = ms;\r
+ field = 1;\r
+ while(*t) {\r
+ if(field && *t == L'"') {\r
+ t++;\r
+ while(*t) {\r
+ if(*t == L'"') {\r
+ t++;\r
+ if(*t != L'"')\r
+ break;\r
+ }\r
+ *p++ = *t;\r
+ t++;\r
+ }\r
+ }\r
+\r
+ if(*t == L',') {\r
+ *p++ = 0;\r
+ field = 1;\r
+ t++;\r
+ } else if(*t) {\r
+ *p++ = *t;\r
+ field = 0;\r
+ t++;\r
+ }\r
+ }\r
+\r
+ *p++ = 0; /* last string ends */\r
+ *p++ = 0; /* double NULL */\r
+\r
+ *pcb_ms = (p - ms) * sizeof(wchar_t);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP wchar_t * KHMAPI \r
+multi_string_next(const wchar_t * str)\r
+{\r
+ size_t cch;\r
+\r
+ if(*str) {\r
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch)))\r
+ return NULL;\r
+ str += cch + 1;\r
+ if(*str)\r
+ return (wchar_t *) str;\r
+ else\r
+ return NULL;\r
+ } else {\r
+ return NULL;\r
+ }\r
+}\r
+\r
+KHMEXP khm_size KHMAPI \r
+multi_string_length_n(const wchar_t * str)\r
+{\r
+ size_t n = 0;\r
+ const wchar_t * c = str;\r
+\r
+ while(c) {\r
+ n++;\r
+ c = multi_string_next(c);\r
+ }\r
+\r
+ return n;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_length_cb(const wchar_t * str, \r
+ khm_size max_cb, \r
+ khm_size * len_cb)\r
+{\r
+ khm_size cch;\r
+ khm_int32 rv;\r
+\r
+ rv = multi_string_length_cch(str, max_cb / sizeof(wchar_t), &cch);\r
+ \r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+ \r
+ if(len_cb)\r
+ *len_cb = cch * sizeof(wchar_t);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_length_cch(const wchar_t * str, \r
+ khm_size max_cch, \r
+ khm_size * len_cch)\r
+{\r
+ const wchar_t * s;\r
+ khm_size cch;\r
+ size_t tcch;\r
+\r
+ if(!str)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ s = str;\r
+ cch = 0;\r
+ while(*s && (cch < max_cch)) {\r
+ if(FAILED(StringCchLength(s, max_cch, &tcch)))\r
+ return KHM_ERROR_TOO_LONG;\r
+ cch += ++tcch;\r
+ s += tcch;\r
+ }\r
+\r
+ if(cch >= max_cch)\r
+ return KHM_ERROR_TOO_LONG;\r
+\r
+ if(len_cch) {\r
+ *len_cch = ++cch;\r
+ }\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_copy_cb(wchar_t * s_dest, \r
+ khm_size max_cb_dest, \r
+ const wchar_t * src)\r
+{\r
+ khm_size cb_dest;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!s_dest)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ rv = multi_string_length_cb(src, max_cb_dest, &cb_dest);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ memmove(s_dest, src, cb_dest);\r
+\r
+ return rv;\r
+}\r
+\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_copy_cch(wchar_t * s_dest, \r
+ khm_size max_cch_dest, \r
+ const wchar_t * src)\r
+{\r
+ khm_size cch_dest;\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+\r
+ if(!s_dest)\r
+ return KHM_ERROR_INVALID_PARM;\r
+\r
+ rv = multi_string_length_cch(src, max_cch_dest, &cch_dest);\r
+ if(KHM_FAILED(rv))\r
+ return rv;\r
+\r
+ memmove(s_dest, src, cch_dest * sizeof(wchar_t));\r
+\r
+ return rv;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_MSTRING_H\r
+#define __KHIMAIRA_MSTRING_H\r
+\r
+#include<khdefs.h>\r
+\r
+/*! \addtogroup util\r
+ @{ */\r
+\r
+/*! \defgroup util_mstring Multi String and CSV functions\r
+ @{*/\r
+\r
+#define KHM_PREFIX 8\r
+\r
+#define KHM_CASE_SENSITIVE 16\r
+\r
+#define KHM_MAXCCH_STRING 16384\r
+\r
+#define KHM_MAXCB_STRING (KHM_MAXCCH_STRING * sizeof(wchar_t))\r
+\r
+/*! \brief Initialize a multi-string\r
+ */\r
+KHMEXP khm_int32 KHMAPI\r
+multi_string_init(wchar_t * ms,\r
+ khm_size cb_ms);\r
+\r
+/*! \brief Prepend a string to a multi string\r
+\r
+ Adds the string \a str to the beginning of multi-string \a ms.\r
+\r
+ \param[in,out] ms The multi-string to be modified.\r
+\r
+ \param[in,out] pcb_ms A pointer to the size of the multistring.\r
+ On entry this specifies the size of the buffer pointed to by\r
+ \a ms. If the call is successful, on exit this will receive\r
+ the new size of the multi string in bytes. If the buffer is\r
+ insufficient, the function will return KHM_ERROR_TOO_LONG and\r
+ set this to the required size of the buffer in bytes.\r
+\r
+ \param[in] str The string to prepend to \a ms. This cannot be\r
+ longer than KHM_MAXCCH_STRING in characters including the\r
+ terminating NULL.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_prepend(wchar_t * ms,\r
+ khm_size * pcb_ms,\r
+ const wchar_t * str);\r
+\r
+/*! \brief Append a string to a multi-string\r
+\r
+ Appends the string specified by \a str to the multi string\r
+ specified by \a ms. The size of the multi string in characters\r
+ including terminating NULLs after appending \a str can not exceed\r
+ KHM_MAXCCH_STRING.\r
+\r
+ \param[in] ms The buffer containing the multi string\r
+\r
+ \param[in,out] pcb_ms Points to a khm_int32 indicating the size of\r
+ the buffer pointed to by \a ms. On entry this contains the\r
+ size (in bytes) of the buffer pointed to by \a ms. On exit,\r
+ contains the new size of the multi string in bytes.\r
+\r
+ \param[in] str The string to append to the multi string. This\r
+ string cannot be NULL or an empty (zero length) string. The\r
+ length of \a str cannot exceed KHM_MAXCCH_STRING in\r
+ characters including terminating NULL.\r
+\r
+ \retval KHM_ERROR_SUCCESS The string was appended to the multi string\r
+\r
+ \retval KHM_ERROR_TOO_LONG The buffer pointed to by \a ms was\r
+ insufficient. The required size of the buffer is in \a pcb_ms\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One of more of the parameters were invalid.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_append(wchar_t * ms,\r
+ khm_size * pcb_ms,\r
+ const wchar_t * str);\r
+\r
+/*! \brief Deletes a string from a multi string\r
+\r
+ Deletes the string specified by \a str from the multi string\r
+ specified by \a ms. How the string is matched to the strings in\r
+ \a ms is determined by \a flags. If more than one match is found,\r
+ then only the first match is deleted.\r
+\r
+ \param[in] ms The multi string to modify. The length of the multi\r
+ string in characters cannot exceed KHM_MAXCCH_STRING.\r
+ \r
+ \param[in] str The string to search for\r
+\r
+ \param[in] flags How \a str is to be matched to existing strings\r
+ in \a ms. This could be a combination of KHM_PREFIX and\r
+ KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is\r
+ searched for a string that begins with \a str. Otherwise, \a\r
+ str must match the an entire string in the multi string. If\r
+ KHM_CASE_SENSITIVE is specified, then a case sensitive match\r
+ is performed. The defualt is to use a case insensitive\r
+ search.\r
+\r
+ \retval KHM_ERROR_SUCCESS A string was matched and deleted from \a ms\r
+\r
+ \retval KHM_ERROR_NOT_FOUND No matches were found\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were incorrect.\r
+\r
+ \note The search for the existing string is done with\r
+ multi_string_find()\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_delete(wchar_t * ms,\r
+ const wchar_t * str,\r
+ const khm_int32 flags);\r
+\r
+/*! \brief Search a multi string for a string\r
+\r
+ Searches the string specified by \a ms for a string that matches\r
+ \a str. How the match is performed is determined by \a flags.\r
+ Returns a poitner to the start of the matched string in \a ms. If\r
+ more than one string in \a ms matches \a str, then only the first\r
+ match is returned.\r
+\r
+ \param[in] ms The multi string to search in. The length of the\r
+ multi string cannot exceed KHM_MAXCCH_STRING in characters.\r
+\r
+ \param[in] str The string to search for\r
+\r
+ \param[in] flags How \a str is to be matched to existing strings\r
+ in \a ms. This could be a combination of KHM_PREFIX and\r
+ KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is\r
+ searched for a string that begins with \a str. Otherwise, \a\r
+ str must match the an entire string in the multi string. If\r
+ KHM_CASE_SENSITIVE is specified, then a case sensitive match\r
+ is performed. The defualt is to use a case insensitive\r
+ search.\r
+\r
+ \return A pointer to the start of the first matched string or\r
+ NULL if no matches were found.\r
+\r
+ */\r
+KHMEXP wchar_t * KHMAPI \r
+multi_string_find(const wchar_t * ms,\r
+ const wchar_t * str,\r
+ const khm_int32 flags);\r
+\r
+/*! \brief Convert a multi string to CSV\r
+\r
+ Converts a multi string to a comma separated value string based on\r
+ the following rules.\r
+\r
+ - Each string in the multi string is treated an individual field \r
+\r
+ - A field is quoted if it has double quotes or commas \r
+\r
+ - Double quotes within quoted fields are escaped by two\r
+ consecutive double quotes.\r
+\r
+ For example:\r
+\r
+ \code\r
+ multi_string = L"foo\0bar\0baz,quux\0ab\"cd\0";\r
+ csv_string = L"foo,bar,\"baz,quux\",\"ab\"\"cd\"";\r
+ \endcode\r
+\r
+ If multi_string_to_csv() is called on \a multi_string above,\r
+ you would obtain \a csv_string.\r
+\r
+ \param[out] csvbuf The buffer to place the CSV string in. Can be\r
+ NULL if only teh size of the needed buffer is required.\r
+\r
+ \param[in,out] pcb_csvbuf On entry, points to a khm_int32 that\r
+ holds the size of the buffer pointed to by \a csvbuf. On\r
+ exit, gets the number of bytes writted to \a csvbuf or the\r
+ required size of \a csvbuf if the buffer is too small or \a\r
+ csvbuf is NULL.\r
+\r
+ \param[in] ms The mutli string to convert to a CSV.\r
+\r
+ \retval KHM_ERROR_SUCCESS The multi string was successfully\r
+ converted to a CSV string. The number of bytes written is in\r
+ \a pcb_csvbuf. The count includes the terminating NULL.\r
+\r
+ \retval KHM_ERROR_TOO_LONG The buffer was too small or \a csvbuf\r
+ was NULL. The required number of bytes in the buffer is in \a\r
+ pcb_csvbuf.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were ivnalid.\r
+\r
+ \see csv_to_multi_string()\r
+*/\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_to_csv(wchar_t * csvbuf,\r
+ khm_size * pcb_csvbuf,\r
+ const wchar_t * ms);\r
+\r
+/*! \brief Converts a CSV to a multi string\r
+\r
+ Undoes what multi_string_to_csv() does.\r
+\r
+ \param[out] ms The buffer that recieves the multi string. This\r
+ can be NULL if only the size of the buffer is requried.\r
+\r
+ \param[in,out] pcb_ms On entry contains the number of bytes ni the\r
+ buffer poitned to by \a ms. On exit contains the number of\r
+ bytes that were copied to \a ms including terminating NULLs,\r
+ or if the buffer was too small or \a ms was NULL, holds the\r
+ size in bytes of the requied buffer.\r
+\r
+ \param[in] csv The CSV string.\r
+\r
+ \retval KHM_ERROR_SUCCESS The CSV string was successfully\r
+ converted. The number of bytes written is in \a pcb_ms.\r
+\r
+ \retval KHM_ERROR_TOO_LONG The provided buffer was too small or \a\r
+ ms was NULL. The required size of the buffer in bytes is in \a\r
+ pcb_ms.\r
+\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.\r
+\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+csv_to_multi_string(wchar_t * ms,\r
+ khm_size * pcb_ms,\r
+ const wchar_t * csv);\r
+\r
+/*! \brief Get the next string in a multi string\r
+\r
+ When \a str is pointing to a string that is in a multi string,\r
+ this function returns a pointer to the next string in the multi\r
+ string.\r
+\r
+ Typically, one would start by having \a str point to the start of\r
+ the multi string (which is the first string in the multi string),\r
+ and then call this function repeatedly, until it returns NULL, at\r
+ which point the end of the multi string has been reached.\r
+\r
+ \param[in] str Pointer to a string in a multi string. Each string\r
+ in a multi string cannot exceed KHM_MAXCCH_STRING in charaters\r
+ including the terminating NULL.\r
+\r
+ \return A pointer to the start of the next string in the multi\r
+ string or NULL if there is no more strings.\r
+ */\r
+KHMEXP wchar_t * KHMAPI \r
+multi_string_next(const wchar_t * str);\r
+\r
+/*! \brief Get the length of a multi string in bytes\r
+\r
+ The returned length includes the trailing double \a NULL and any\r
+ other \a NULL inbetween.\r
+\r
+ \param[in] str Pointer to a multi string.\r
+ \param[in] max_cb Maximum size that the str can be. This can not\r
+ be larger than KHM_MAXCB_STRING.\r
+ \param[out] len_cb The length of the string in bytes if the call\r
+ is successful.\r
+\r
+ \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cb\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TOO_LONG The multi string is longer than \a\r
+ max_cb bytes.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_length_cb(const wchar_t * str, \r
+ khm_size max_cb, \r
+ khm_size * len_cb);\r
+\r
+/*! \brief Get the length of a multi string in characters\r
+\r
+ The returned length includes the trailing double \a NULL and any\r
+ other \a NULL inbetween.\r
+\r
+ \param[in] str Pointer to a multi string.\r
+ \param[in] max_cch Maximum size that the str can be. This can not\r
+ be larger than KHM_MAXCCH_STRING.\r
+ \param[out] len_cch The length of the string in characters if the call\r
+ is successful.\r
+\r
+ \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cch\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid\r
+ \retval KHM_ERROR_TOO_LONG The multi string is longer than \a\r
+ max_cch characters.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_length_cch(const wchar_t * str, \r
+ khm_size max_cch, \r
+ khm_size * len_cch);\r
+\r
+/*! \brief Get the number of strings in a multi string\r
+ */\r
+KHMEXP khm_size KHMAPI \r
+multi_string_length_n(const wchar_t * str);\r
+\r
+/*! \brief Copy a multi string with byte counts\r
+\r
+ Copy a multi string from one location to another.\r
+\r
+ \param[out] s_dest Receives a copy of the multi string\r
+ \param[in] max_cb_dest Number of bytes in the buffer pointed to by\r
+ \a s_dest.\r
+ \param[in] src The source multi string\r
+\r
+ \retval KHM_ERROR_SUCCESS The multi string was copied successfully\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were\r
+ invalid.\r
+ \retval KHM_ERROR_TOO_LONG The size of the destination buffer was\r
+ insufficient.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_copy_cb(wchar_t * s_dest, \r
+ khm_size max_cb_dest, \r
+ const wchar_t * src);\r
+\r
+/*! \brief Copy a multi string with character count\r
+\r
+ Copy a multi string from one location to another.\r
+\r
+ \param[out] s_dest Receives a copy of the multi string\r
+ \param[in] max_cb_dest Number of characters in the buffer pointed\r
+ to by \a s_dest.\r
+ \param[in] src The source multi string\r
+\r
+ \retval KHM_ERROR_SUCCESS The multi string was copied successfully\r
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were\r
+ invalid.\r
+ \retval KHM_ERROR_TOO_LONG The size of the destination buffer was\r
+ insufficient.\r
+ */\r
+KHMEXP khm_int32 KHMAPI \r
+multi_string_copy_cch(wchar_t * s_dest, \r
+ khm_size max_cch_dest, \r
+ const wchar_t * src);\r
+\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#include<windows.h>\r
+#include<sync.h>\r
+#include<assert.h>\r
+\r
+#define LOCK_OPEN 0\r
+#define LOCK_READING 1\r
+#define LOCK_WRITING 2\r
+\r
+KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock)\r
+{\r
+ pLock->locks = 0;\r
+ pLock->status = LOCK_OPEN;\r
+ InitializeCriticalSection(&(pLock->cs));\r
+ pLock->writewx = CreateEvent(NULL, \r
+ FALSE, /* Manual reset */\r
+ TRUE, /* Initial state */\r
+ NULL);\r
+ pLock->readwx = CreateEvent(NULL,\r
+ TRUE, /* Manual reset */\r
+ TRUE, /* Initial state */\r
+ NULL);\r
+}\r
+\r
+KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock)\r
+{\r
+ DeleteCriticalSection(&(pLock->cs));\r
+ CloseHandle(pLock->readwx);\r
+ CloseHandle(pLock->writewx);\r
+}\r
+\r
+KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock)\r
+{\r
+ while(1) {\r
+ WaitForSingleObject(pLock->readwx, INFINITE);\r
+ EnterCriticalSection(&pLock->cs);\r
+ if(pLock->status == LOCK_WRITING) {\r
+ LeaveCriticalSection(&(pLock->cs));\r
+ continue;\r
+ } else\r
+ break;\r
+ }\r
+ pLock->locks ++;\r
+ pLock->status = LOCK_READING;\r
+ ResetEvent(pLock->writewx);\r
+ LeaveCriticalSection(&(pLock->cs));\r
+}\r
+\r
+KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock)\r
+{\r
+ EnterCriticalSection(&(pLock->cs));\r
+ assert(pLock->status == LOCK_READING);\r
+ pLock->locks--;\r
+ if(!pLock->locks) {\r
+ pLock->status = LOCK_OPEN;\r
+ SetEvent(pLock->readwx);\r
+ SetEvent(pLock->writewx);\r
+ }\r
+ LeaveCriticalSection(&(pLock->cs));\r
+}\r
+\r
+KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock)\r
+{\r
+ EnterCriticalSection(&(pLock->cs));\r
+ if(pLock->status == LOCK_WRITING && \r
+ pLock->writer == GetCurrentThreadId()) {\r
+ pLock->locks++;\r
+ LeaveCriticalSection(&(pLock->cs));\r
+ return;\r
+ }\r
+ LeaveCriticalSection(&(pLock->cs));\r
+ while(1) {\r
+ WaitForSingleObject(pLock->writewx, INFINITE);\r
+ EnterCriticalSection(&(pLock->cs));\r
+ if(pLock->status == LOCK_OPEN)\r
+ break;\r
+ LeaveCriticalSection(&(pLock->cs));\r
+ }\r
+ pLock->status = LOCK_WRITING;\r
+ pLock->locks++;\r
+ ResetEvent(pLock->readwx);\r
+ LeaveCriticalSection(&(pLock->cs));\r
+}\r
+\r
+KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock)\r
+{\r
+ EnterCriticalSection(&(pLock->cs));\r
+ assert(pLock->status == LOCK_WRITING);\r
+ pLock->locks--;\r
+ if(!pLock->locks) {\r
+ pLock->status = LOCK_OPEN;\r
+ SetEvent(pLock->readwx);\r
+ SetEvent(pLock->writewx);\r
+ }\r
+ LeaveCriticalSection(&(pLock->cs));\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_SYNC_H\r
+#define __KHIMAIRA_SYNC_H\r
+\r
+#include<khdefs.h>\r
+\r
+/*! \addtogroup util\r
+ @{ */\r
+\r
+/*! \defgroup util_sync Synchronization\r
+ @{*/\r
+\r
+/*! \brief A read/write lock\r
+\r
+ A classic read/write lock. Allows multiple readers or a single\r
+ writer to access a protected object. Readers will wait for any\r
+ pending writer to release the lock, while a writer will wait for\r
+ any pending readers to release the lock.\r
+*/\r
+typedef struct tag_rwlock {\r
+ int locks;\r
+ int status;\r
+ CRITICAL_SECTION cs;\r
+ HANDLE readwx;\r
+ HANDLE writewx;\r
+\r
+ DWORD writer; /* TID of writer thread */\r
+} rw_lock_t;\r
+\r
+typedef rw_lock_t RWLOCK, *PRWLOCK;\r
+\r
+/*! \brief Initialize a read/write lock.\r
+\r
+ A lock <b>must</b> be initialized before it can be used.\r
+ Initializing the lock does not grant the caller any locks on the\r
+ object.\r
+*/\r
+KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock);\r
+\r
+/*! \brief Delete a read/write lock\r
+\r
+ Once the application is done using the read/write lock, it must be\r
+ deleted with a call to DeleteRwLock()\r
+*/\r
+KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock);\r
+\r
+/*! \brief Obtains a read lock on the read/write lock\r
+\r
+ Multiple readers can obtain read locks on the same r/w lock.\r
+ However, if any thread attempts to obtain a write lock on the\r
+ object, it will wait until all readers have released the read\r
+ locks.\r
+\r
+ Call LockReleaseRead() to release the read lock. While the same\r
+ thread may obtain multiple read locks on the same object, each\r
+ call to LockObtainRead() must have a corresponding call to\r
+ LockReleaseRead() to properly relinquish the lock.\r
+\r
+ \see LockReleaseRead()\r
+*/\r
+KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock);\r
+\r
+/*! \brief Relase a read lock obtained on a read/write lock\r
+\r
+ Each call to LockObtainRead() must have a corresponding call to\r
+ LockReleaseRead(). Once all read locks are released, any threads\r
+ waiting on write locks on the object will be woken and assigned a\r
+ write lock.\r
+\r
+ \see LockObtainRead()\r
+*/\r
+KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock);\r
+\r
+/*! \brief Obtains a write lock on the read/write lock\r
+\r
+ Only a single writer is allowed to lock a single r/w lock.\r
+ However, if any thread attempts to obtain a read lock on the\r
+ object, it will wait until the writer has released the lock.\r
+\r
+ Call LockReleaseWrite() to release the write lock. While the same\r
+ thread may obtain multiple write locks on the same object, each\r
+ call to LockObtainWrite() must have a corresponding call to\r
+ LockReleaseWrite() to properly relinquish the lock.\r
+\r
+ \see LockReleaseWrite()\r
+*/\r
+KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock);\r
+\r
+/*! \brief Relase a write lock obtained on a read/write lock\r
+\r
+ Each call to LockObtainWrite() must have a corresponding call to\r
+ LockReleaseWrite(). Once the write lock is released, any threads\r
+ waiting for read or write locks on the object will be woken and\r
+ assigned the proper lock.\r
+\r
+ \see LockObtainWrite()\r
+*/\r
+KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock);\r
+\r
+/*@}*/\r
+/*@}*/\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004 Massachusetts Institute of Technology\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation\r
+ * files (the "Software"), to deal in the Software without\r
+ * restriction, including without limitation the rights to use, copy,\r
+ * modify, merge, publish, distribute, sublicense, and/or sell copies\r
+ * of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+#ifndef __KHIMAIRA_UTIL_H\r
+#define __KHIMAIRA_UTIL_H\r
+\r
+/*! \defgroup util Utilities\r
+ */\r
+#include<hashtable.h>\r
+#include<sync.h>\r
+#include<mstring.h>\r
+\r
+#endif\r