Initial Commit Network Identity Manager for Windows
authorJeffrey Altman <jaltman@secure-endpoints.com>
Wed, 2 Nov 2005 01:14:30 +0000 (01:14 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Wed, 2 Nov 2005 01:14:30 +0000 (01:14 +0000)
  Initial commit of Network Identity Manager for KFW 3.0 Beta 1

ticket: new
tags: pullup
component: windows

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17476 dc483132-0cff-0310-8789-dd5450dbe970

307 files changed:
src/windows/Makefile.in
src/windows/identity/Makefile [new file with mode: 0644]
src/windows/identity/config/Makefile [new file with mode: 0644]
src/windows/identity/config/Makefile.w32 [new file with mode: 0644]
src/windows/identity/config/ccsv.pl [new file with mode: 0644]
src/windows/identity/config/csvschema.cfg [new file with mode: 0644]
src/windows/identity/doc/Makefile [new file with mode: 0644]
src/windows/identity/doc/cred_aquisition.h [new file with mode: 0644]
src/windows/identity/doc/cred_data_types.h [new file with mode: 0644]
src/windows/identity/doc/cred_main.h [new file with mode: 0644]
src/windows/identity/doc/cred_msgs.h [new file with mode: 0644]
src/windows/identity/doc/cred_prop_pages.h [new file with mode: 0644]
src/windows/identity/doc/doxyfile.cfg [new file with mode: 0644]
src/windows/identity/doc/footer.html [new file with mode: 0644]
src/windows/identity/doc/header.html [new file with mode: 0644]
src/windows/identity/doc/images/Thumbs.db [new file with mode: 0644]
src/windows/identity/doc/images/credview-select-outline.jpg [new file with mode: 0644]
src/windows/identity/doc/images/khimaira_logo.png [new file with mode: 0644]
src/windows/identity/doc/images/khimaira_logo_old.jpg [new file with mode: 0644]
src/windows/identity/doc/images/khimaira_logo_small.png [new file with mode: 0644]
src/windows/identity/doc/images/khimaira_logo_small_old.jpg [new file with mode: 0644]
src/windows/identity/doc/main_page.h [new file with mode: 0644]
src/windows/identity/doc/plugin_framework.h [new file with mode: 0644]
src/windows/identity/doc/plugin_locale.h [new file with mode: 0644]
src/windows/identity/doc/plugin_main.h [new file with mode: 0644]
src/windows/identity/doc/plugin_structure.h [new file with mode: 0644]
src/windows/identity/doc/stylesheet.css [new file with mode: 0644]
src/windows/identity/doc/ui_actions.h [new file with mode: 0644]
src/windows/identity/doc/ui_context.h [new file with mode: 0644]
src/windows/identity/doc/ui_main.h [new file with mode: 0644]
src/windows/identity/doc/ui_menus.h [new file with mode: 0644]
src/windows/identity/help/Index.hhk [new file with mode: 0644]
src/windows/identity/help/Makefile [new file with mode: 0644]
src/windows/identity/help/html/images/Thumbs.db [new file with mode: 0644]
src/windows/identity/help/html/images/link.GIF [new file with mode: 0644]
src/windows/identity/help/html/khm.css [new file with mode: 0644]
src/windows/identity/help/html/menu_exit.htm [new file with mode: 0644]
src/windows/identity/help/html/menu_file.htm [new file with mode: 0644]
src/windows/identity/help/html/menu_properties.htm [new file with mode: 0644]
src/windows/identity/help/html/template.htm [new file with mode: 0644]
src/windows/identity/help/html/welcome.htm [new file with mode: 0644]
src/windows/identity/help/khhelp.h [new file with mode: 0644]
src/windows/identity/help/netidmgr.hhp [new file with mode: 0644]
src/windows/identity/help/toc.hhc [new file with mode: 0644]
src/windows/identity/include/Makefile [new file with mode: 0644]
src/windows/identity/include/khdefs.h [new file with mode: 0644]
src/windows/identity/include/kherror.h [new file with mode: 0644]
src/windows/identity/include/khlist.h [new file with mode: 0644]
src/windows/identity/include/khmsgtypes.h [new file with mode: 0644]
src/windows/identity/include/khthread.h [new file with mode: 0644]
src/windows/identity/kconfig/Makefile [new file with mode: 0644]
src/windows/identity/kconfig/api.c [new file with mode: 0644]
src/windows/identity/kconfig/kconfig.h [new file with mode: 0644]
src/windows/identity/kconfig/kconfiginternal.h [new file with mode: 0644]
src/windows/identity/kconfig/kconfigmain.c [new file with mode: 0644]
src/windows/identity/kconfig/registry.c [new file with mode: 0644]
src/windows/identity/kconfig/test/utiltest.c [new file with mode: 0644]
src/windows/identity/kcreddb/Makefile [new file with mode: 0644]
src/windows/identity/kcreddb/attrib.c [new file with mode: 0644]
src/windows/identity/kcreddb/attrib.h [new file with mode: 0644]
src/windows/identity/kcreddb/buf.c [new file with mode: 0644]
src/windows/identity/kcreddb/buf.h [new file with mode: 0644]
src/windows/identity/kcreddb/credential.c [new file with mode: 0644]
src/windows/identity/kcreddb/credential.h [new file with mode: 0644]
src/windows/identity/kcreddb/credset.c [new file with mode: 0644]
src/windows/identity/kcreddb/credset.h [new file with mode: 0644]
src/windows/identity/kcreddb/credtype.c [new file with mode: 0644]
src/windows/identity/kcreddb/credtype.h [new file with mode: 0644]
src/windows/identity/kcreddb/identity.c [new file with mode: 0644]
src/windows/identity/kcreddb/identity.h [new file with mode: 0644]
src/windows/identity/kcreddb/init.c [new file with mode: 0644]
src/windows/identity/kcreddb/kcdbconfig.csv [new file with mode: 0644]
src/windows/identity/kcreddb/kcreddb.h [new file with mode: 0644]
src/windows/identity/kcreddb/kcreddbinternal.h [new file with mode: 0644]
src/windows/identity/kcreddb/kcreddbmain.c [new file with mode: 0644]
src/windows/identity/kcreddb/lang/en_us/kcredres.rc [new file with mode: 0644]
src/windows/identity/kcreddb/langres.h [new file with mode: 0644]
src/windows/identity/kcreddb/resource.h [new file with mode: 0644]
src/windows/identity/kcreddb/type.c [new file with mode: 0644]
src/windows/identity/kcreddb/type.h [new file with mode: 0644]
src/windows/identity/kherr/Makefile [new file with mode: 0644]
src/windows/identity/kherr/kherr.c [new file with mode: 0644]
src/windows/identity/kherr/kherr.h [new file with mode: 0644]
src/windows/identity/kherr/kherrinternal.h [new file with mode: 0644]
src/windows/identity/kherr/kherrmain.c [new file with mode: 0644]
src/windows/identity/kmm/Makefile [new file with mode: 0644]
src/windows/identity/kmm/kmm.c [new file with mode: 0644]
src/windows/identity/kmm/kmm.h [new file with mode: 0644]
src/windows/identity/kmm/kmm_module.c [new file with mode: 0644]
src/windows/identity/kmm/kmm_plugin.c [new file with mode: 0644]
src/windows/identity/kmm/kmm_reg.c [new file with mode: 0644]
src/windows/identity/kmm/kmm_registrar.c [new file with mode: 0644]
src/windows/identity/kmm/kmmconfig.csv [new file with mode: 0644]
src/windows/identity/kmm/kmminternal.h [new file with mode: 0644]
src/windows/identity/kmm/kmmmain.c [new file with mode: 0644]
src/windows/identity/kmm/kplugin.h [new file with mode: 0644]
src/windows/identity/kmm/lang/kmm_msgs.mc [new file with mode: 0644]
src/windows/identity/kmq/Makefile [new file with mode: 0644]
src/windows/identity/kmq/consumer.c [new file with mode: 0644]
src/windows/identity/kmq/init.c [new file with mode: 0644]
src/windows/identity/kmq/kmq.h [new file with mode: 0644]
src/windows/identity/kmq/kmqconfig.csv [new file with mode: 0644]
src/windows/identity/kmq/kmqinternal.h [new file with mode: 0644]
src/windows/identity/kmq/kmqmain.c [new file with mode: 0644]
src/windows/identity/kmq/msgtype.c [new file with mode: 0644]
src/windows/identity/kmq/publisher.c [new file with mode: 0644]
src/windows/identity/nidmgrdll/Makefile [new file with mode: 0644]
src/windows/identity/nidmgrdll/dllmain.c [new file with mode: 0644]
src/windows/identity/nidmgrdll/nidmgrdll.rc [new file with mode: 0644]
src/windows/identity/plugins/common/Makefile [new file with mode: 0644]
src/windows/identity/plugins/common/dynimport.c [new file with mode: 0644]
src/windows/identity/plugins/common/dynimport.h [new file with mode: 0644]
src/windows/identity/plugins/common/krb5common.c [new file with mode: 0644]
src/windows/identity/plugins/common/krb5common.h [new file with mode: 0644]
src/windows/identity/plugins/krb4/Makefile [new file with mode: 0644]
src/windows/identity/plugins/krb4/datarep.h [new file with mode: 0644]
src/windows/identity/plugins/krb4/errorfuncs.c [new file with mode: 0644]
src/windows/identity/plugins/krb4/errorfuncs.h [new file with mode: 0644]
src/windows/identity/plugins/krb4/krb4configdlg.c [new file with mode: 0644]
src/windows/identity/plugins/krb4/krb4funcs.c [new file with mode: 0644]
src/windows/identity/plugins/krb4/krb4funcs.h [new file with mode: 0644]
src/windows/identity/plugins/krb4/krb4plugin.c [new file with mode: 0644]
src/windows/identity/plugins/krb4/krbconfig.csv [new file with mode: 0644]
src/windows/identity/plugins/krb4/krbcred.h [new file with mode: 0644]
src/windows/identity/plugins/krb4/lang/en_us/langres.rc [new file with mode: 0644]
src/windows/identity/plugins/krb4/langres.h [new file with mode: 0644]
src/windows/identity/plugins/krb4/main.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/Makefile [new file with mode: 0644]
src/windows/identity/plugins/krb5/datarep.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/datarep.h [new file with mode: 0644]
src/windows/identity/plugins/krb5/errorfuncs.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/errorfuncs.h [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5configdlg.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5funcs.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5funcs.h [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5identpro.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5newcreds.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5plugin.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5props.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krb5util.c [new file with mode: 0644]
src/windows/identity/plugins/krb5/krbconfig.csv [new file with mode: 0644]
src/windows/identity/plugins/krb5/krbcred.h [new file with mode: 0644]
src/windows/identity/plugins/krb5/lang/en_us/langres.rc [new file with mode: 0644]
src/windows/identity/plugins/krb5/lang/krb5_msgs.mc [new file with mode: 0644]
src/windows/identity/plugins/krb5/langres.h [new file with mode: 0644]
src/windows/identity/plugins/krb5/main.c [new file with mode: 0644]
src/windows/identity/ui/Makefile [new file with mode: 0644]
src/windows/identity/ui/aboutwnd.c [new file with mode: 0644]
src/windows/identity/ui/aboutwnd.h [new file with mode: 0644]
src/windows/identity/ui/appglobal.h [new file with mode: 0644]
src/windows/identity/ui/cfg_general_wnd.c [new file with mode: 0644]
src/windows/identity/ui/cfg_identities_wnd.c [new file with mode: 0644]
src/windows/identity/ui/cfg_notif_wnd.c [new file with mode: 0644]
src/windows/identity/ui/cfg_plugins_wnd.c [new file with mode: 0644]
src/windows/identity/ui/configwnd.c [new file with mode: 0644]
src/windows/identity/ui/configwnd.h [new file with mode: 0644]
src/windows/identity/ui/credfuncs.c [new file with mode: 0644]
src/windows/identity/ui/credfuncs.h [new file with mode: 0644]
src/windows/identity/ui/credwnd.c [new file with mode: 0644]
src/windows/identity/ui/credwnd.h [new file with mode: 0644]
src/windows/identity/ui/htmlwnd.h [new file with mode: 0644]
src/windows/identity/ui/htwnd.c [new file with mode: 0644]
src/windows/identity/ui/htwnd.h [new file with mode: 0644]
src/windows/identity/ui/images/Thumbs.db [new file with mode: 0644]
src/windows/identity/ui/images/app_notify_error.ico [new file with mode: 0644]
src/windows/identity/ui/images/app_notify_info.ico [new file with mode: 0644]
src/windows/identity/ui/images/app_notify_none.ico [new file with mode: 0644]
src/windows/identity/ui/images/app_notify_warn.ico [new file with mode: 0644]
src/windows/identity/ui/images/bitmap1.bmp [new file with mode: 0644]
src/windows/identity/ui/images/cfg_applied.ico [new file with mode: 0644]
src/windows/identity/ui/images/cfg_default.ico [new file with mode: 0644]
src/windows/identity/ui/images/cfg_deleted.ico [new file with mode: 0644]
src/windows/identity/ui/images/cfg_mod.ico [new file with mode: 0644]
src/windows/identity/ui/images/chpw-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/chpw-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/chpw-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/chpw.bmp [new file with mode: 0644]
src/windows/identity/ui/images/disabled.ico [new file with mode: 0644]
src/windows/identity/ui/images/enabled.ico [new file with mode: 0644]
src/windows/identity/ui/images/flag-critical.bmp [new file with mode: 0644]
src/windows/identity/ui/images/flag-warning.bmp [new file with mode: 0644]
src/windows/identity/ui/images/flag_expired.bmp [new file with mode: 0644]
src/windows/identity/ui/images/help-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/help.bmp [new file with mode: 0644]
src/windows/identity/ui/images/icon1.ico [new file with mode: 0644]
src/windows/identity/ui/images/id-delete-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-delete-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-delete-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-delete.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-new-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-new-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-new-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-new.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-refresh-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-refresh-sm-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-refresh-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-refresh.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id.bmp [new file with mode: 0644]
src/windows/identity/ui/images/id.ico [new file with mode: 0644]
src/windows/identity/ui/images/ident.png [new file with mode: 0644]
src/windows/identity/ui/images/import-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/import-sm-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/import-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/import.bmp [new file with mode: 0644]
src/windows/identity/ui/images/khimaira-cfg.bmp [new file with mode: 0644]
src/windows/identity/ui/images/logo_shade.bmp [new file with mode: 0644]
src/windows/identity/ui/images/main_app.ico [new file with mode: 0644]
src/windows/identity/ui/images/main_app_old.ico [new file with mode: 0644]
src/windows/identity/ui/images/tb-blank-small.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tb-blank.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tb-space.bmp [new file with mode: 0644]
src/windows/identity/ui/images/text1138.png [new file with mode: 0644]
src/windows/identity/ui/images/tk-delete-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-delete-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-delete-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-delete.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-new-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-new-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-new-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-new.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-refresh-dis-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-refresh-dis.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-refresh-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-refresh.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/tk.bmp [new file with mode: 0644]
src/windows/identity/ui/images/vw-refresh-sm.bmp [new file with mode: 0644]
src/windows/identity/ui/images/vw-refresh.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wdg_collapsed.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wdg_collapsed_hi.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wdg_credtype.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wdg_expanded.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wdg_expanded_hi.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wdg_flag.bmp [new file with mode: 0644]
src/windows/identity/ui/images/wgt_arrow_collapse.ico [new file with mode: 0644]
src/windows/identity/ui/images/wgt_arrow_expand.ico [new file with mode: 0644]
src/windows/identity/ui/khmapp.h [new file with mode: 0644]
src/windows/identity/ui/lang/en_us/khapp.rc [new file with mode: 0644]
src/windows/identity/ui/main.c [new file with mode: 0644]
src/windows/identity/ui/mainmenu.c [new file with mode: 0644]
src/windows/identity/ui/mainmenu.h [new file with mode: 0644]
src/windows/identity/ui/mainwnd.c [new file with mode: 0644]
src/windows/identity/ui/mainwnd.h [new file with mode: 0644]
src/windows/identity/ui/makeacceldef.pl [new file with mode: 0644]
src/windows/identity/ui/makeactiondef.pl [new file with mode: 0644]
src/windows/identity/ui/netidmgr.exe.manifest.i386 [new file with mode: 0644]
src/windows/identity/ui/netidmgr.manifest.i386.vc7 [new file with mode: 0644]
src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug [new file with mode: 0644]
src/windows/identity/ui/netidmgr.manifest.i386.vc8 [new file with mode: 0644]
src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug [new file with mode: 0644]
src/windows/identity/ui/newcredwnd.c [new file with mode: 0644]
src/windows/identity/ui/newcredwnd.h [new file with mode: 0644]
src/windows/identity/ui/notifier.c [new file with mode: 0644]
src/windows/identity/ui/notifier.h [new file with mode: 0644]
src/windows/identity/ui/passwnd.c [new file with mode: 0644]
src/windows/identity/ui/passwnd.h [new file with mode: 0644]
src/windows/identity/ui/propertywnd.c [new file with mode: 0644]
src/windows/identity/ui/propertywnd.h [new file with mode: 0644]
src/windows/identity/ui/reqdaemon.c [new file with mode: 0644]
src/windows/identity/ui/reqdaemon.h [new file with mode: 0644]
src/windows/identity/ui/resource.h [new file with mode: 0644]
src/windows/identity/ui/statusbar.c [new file with mode: 0644]
src/windows/identity/ui/statusbar.h [new file with mode: 0644]
src/windows/identity/ui/timer.c [new file with mode: 0644]
src/windows/identity/ui/timer.h [new file with mode: 0644]
src/windows/identity/ui/toolbar.c [new file with mode: 0644]
src/windows/identity/ui/toolbar.h [new file with mode: 0644]
src/windows/identity/ui/uiconfig.csv [new file with mode: 0644]
src/windows/identity/uilib/Makefile [new file with mode: 0644]
src/windows/identity/uilib/accel.csv [new file with mode: 0644]
src/windows/identity/uilib/acceldef.cfg [new file with mode: 0644]
src/windows/identity/uilib/action.c [new file with mode: 0644]
src/windows/identity/uilib/actiondef.cfg [new file with mode: 0644]
src/windows/identity/uilib/actions.csv [new file with mode: 0644]
src/windows/identity/uilib/alert.c [new file with mode: 0644]
src/windows/identity/uilib/configui.c [new file with mode: 0644]
src/windows/identity/uilib/configui.h [new file with mode: 0644]
src/windows/identity/uilib/creddlg.c [new file with mode: 0644]
src/windows/identity/uilib/khaction.h [new file with mode: 0644]
src/windows/identity/uilib/khactiondef.h [new file with mode: 0644]
src/windows/identity/uilib/khalerts.h [new file with mode: 0644]
src/windows/identity/uilib/khconfigui.h [new file with mode: 0644]
src/windows/identity/uilib/khhtlink.h [new file with mode: 0644]
src/windows/identity/uilib/khnewcred.h [new file with mode: 0644]
src/windows/identity/uilib/khprops.h [new file with mode: 0644]
src/windows/identity/uilib/khremote.h [new file with mode: 0644]
src/windows/identity/uilib/khrescache.h [new file with mode: 0644]
src/windows/identity/uilib/khtracker.h [new file with mode: 0644]
src/windows/identity/uilib/khuidefs.h [new file with mode: 0644]
src/windows/identity/uilib/propsheet.c [new file with mode: 0644]
src/windows/identity/uilib/propwnd.c [new file with mode: 0644]
src/windows/identity/uilib/rescache.c [new file with mode: 0644]
src/windows/identity/uilib/trackerwnd.c [new file with mode: 0644]
src/windows/identity/uilib/uilibmain.c [new file with mode: 0644]
src/windows/identity/util/Makefile [new file with mode: 0644]
src/windows/identity/util/hashtable.c [new file with mode: 0644]
src/windows/identity/util/hashtable.h [new file with mode: 0644]
src/windows/identity/util/mstring.c [new file with mode: 0644]
src/windows/identity/util/mstring.h [new file with mode: 0644]
src/windows/identity/util/sync.c [new file with mode: 0644]
src/windows/identity/util/sync.h [new file with mode: 0644]
src/windows/identity/util/utils.h [new file with mode: 0644]

index ebfc6e3a7ece25a4fb826055069f667e60b02fee..ae3c48f120a660cd89035dbddee2a1c71e71d1ec 100644 (file)
@@ -23,6 +23,11 @@ all-windows::
        @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::
@@ -44,4 +49,9 @@ 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 ..
diff --git a/src/windows/identity/Makefile b/src/windows/identity/Makefile
new file mode 100644 (file)
index 0000000..3a79ee5
--- /dev/null
@@ -0,0 +1,179 @@
+#\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
diff --git a/src/windows/identity/config/Makefile b/src/windows/identity/config/Makefile
new file mode 100644 (file)
index 0000000..686a044
--- /dev/null
@@ -0,0 +1,133 @@
+#\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
diff --git a/src/windows/identity/config/Makefile.w32 b/src/windows/identity/config/Makefile.w32
new file mode 100644 (file)
index 0000000..1b862a9
--- /dev/null
@@ -0,0 +1,278 @@
+#\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
diff --git a/src/windows/identity/config/ccsv.pl b/src/windows/identity/config/ccsv.pl
new file mode 100644 (file)
index 0000000..c6c8281
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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
diff --git a/src/windows/identity/config/csvschema.cfg b/src/windows/identity/config/csvschema.cfg
new file mode 100644 (file)
index 0000000..ba3bf9b
--- /dev/null
@@ -0,0 +1,67 @@
+#\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
diff --git a/src/windows/identity/doc/Makefile b/src/windows/identity/doc/Makefile
new file mode 100644 (file)
index 0000000..71e9f0f
--- /dev/null
@@ -0,0 +1,68 @@
+#\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
diff --git a/src/windows/identity/doc/cred_aquisition.h b/src/windows/identity/doc/cred_aquisition.h
new file mode 100644 (file)
index 0000000..1adb3b8
--- /dev/null
@@ -0,0 +1,208 @@
+/*\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
diff --git a/src/windows/identity/doc/cred_data_types.h b/src/windows/identity/doc/cred_data_types.h
new file mode 100644 (file)
index 0000000..3257520
--- /dev/null
@@ -0,0 +1,246 @@
+/*\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
diff --git a/src/windows/identity/doc/cred_main.h b/src/windows/identity/doc/cred_main.h
new file mode 100644 (file)
index 0000000..e8f7d29
--- /dev/null
@@ -0,0 +1,35 @@
+/*\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
diff --git a/src/windows/identity/doc/cred_msgs.h b/src/windows/identity/doc/cred_msgs.h
new file mode 100644 (file)
index 0000000..a1b2c2c
--- /dev/null
@@ -0,0 +1,47 @@
+/*\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
diff --git a/src/windows/identity/doc/cred_prop_pages.h b/src/windows/identity/doc/cred_prop_pages.h
new file mode 100644 (file)
index 0000000..5e84483
--- /dev/null
@@ -0,0 +1,83 @@
+/*\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
diff --git a/src/windows/identity/doc/doxyfile.cfg b/src/windows/identity/doc/doxyfile.cfg
new file mode 100644 (file)
index 0000000..7aac802
--- /dev/null
@@ -0,0 +1,1000 @@
+# 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
diff --git a/src/windows/identity/doc/footer.html b/src/windows/identity/doc/footer.html
new file mode 100644 (file)
index 0000000..13314c2
--- /dev/null
@@ -0,0 +1,19 @@
+<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&nbsp;<a href="http://www.doxygen.org/index.html">Doxygen</a> $doxygenversion<br>\r
+       &copy; 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
diff --git a/src/windows/identity/doc/header.html b/src/windows/identity/doc/header.html
new file mode 100644 (file)
index 0000000..4235468
--- /dev/null
@@ -0,0 +1,5 @@
+<!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
diff --git a/src/windows/identity/doc/images/Thumbs.db b/src/windows/identity/doc/images/Thumbs.db
new file mode 100644 (file)
index 0000000..371f5d6
Binary files /dev/null and b/src/windows/identity/doc/images/Thumbs.db differ
diff --git a/src/windows/identity/doc/images/credview-select-outline.jpg b/src/windows/identity/doc/images/credview-select-outline.jpg
new file mode 100644 (file)
index 0000000..d06ca9f
Binary files /dev/null and b/src/windows/identity/doc/images/credview-select-outline.jpg differ
diff --git a/src/windows/identity/doc/images/khimaira_logo.png b/src/windows/identity/doc/images/khimaira_logo.png
new file mode 100644 (file)
index 0000000..26c3380
Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo.png differ
diff --git a/src/windows/identity/doc/images/khimaira_logo_old.jpg b/src/windows/identity/doc/images/khimaira_logo_old.jpg
new file mode 100644 (file)
index 0000000..10e8fde
Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo_old.jpg differ
diff --git a/src/windows/identity/doc/images/khimaira_logo_small.png b/src/windows/identity/doc/images/khimaira_logo_small.png
new file mode 100644 (file)
index 0000000..26c3380
Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo_small.png differ
diff --git a/src/windows/identity/doc/images/khimaira_logo_small_old.jpg b/src/windows/identity/doc/images/khimaira_logo_small_old.jpg
new file mode 100644 (file)
index 0000000..94d8d19
Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo_small_old.jpg differ
diff --git a/src/windows/identity/doc/main_page.h b/src/windows/identity/doc/main_page.h
new file mode 100644 (file)
index 0000000..545e9ee
--- /dev/null
@@ -0,0 +1,108 @@
+/*\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
+    &copy; 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 &copy; 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
diff --git a/src/windows/identity/doc/plugin_framework.h b/src/windows/identity/doc/plugin_framework.h
new file mode 100644 (file)
index 0000000..dbf1600
--- /dev/null
@@ -0,0 +1,131 @@
+/*\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
diff --git a/src/windows/identity/doc/plugin_locale.h b/src/windows/identity/doc/plugin_locale.h
new file mode 100644 (file)
index 0000000..3cb65a4
--- /dev/null
@@ -0,0 +1,107 @@
+/*\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
diff --git a/src/windows/identity/doc/plugin_main.h b/src/windows/identity/doc/plugin_main.h
new file mode 100644 (file)
index 0000000..ed8d038
--- /dev/null
@@ -0,0 +1,126 @@
+/*\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
diff --git a/src/windows/identity/doc/plugin_structure.h b/src/windows/identity/doc/plugin_structure.h
new file mode 100644 (file)
index 0000000..8c57b03
--- /dev/null
@@ -0,0 +1,50 @@
+/*\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
diff --git a/src/windows/identity/doc/stylesheet.css b/src/windows/identity/doc/stylesheet.css
new file mode 100644 (file)
index 0000000..fc3e062
--- /dev/null
@@ -0,0 +1,271 @@
+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
diff --git a/src/windows/identity/doc/ui_actions.h b/src/windows/identity/doc/ui_actions.h
new file mode 100644 (file)
index 0000000..ab3848e
--- /dev/null
@@ -0,0 +1,29 @@
+/*\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
diff --git a/src/windows/identity/doc/ui_context.h b/src/windows/identity/doc/ui_context.h
new file mode 100644 (file)
index 0000000..8ef3250
--- /dev/null
@@ -0,0 +1,187 @@
+/*\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
diff --git a/src/windows/identity/doc/ui_main.h b/src/windows/identity/doc/ui_main.h
new file mode 100644 (file)
index 0000000..0f9ab66
--- /dev/null
@@ -0,0 +1,34 @@
+/*\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
diff --git a/src/windows/identity/doc/ui_menus.h b/src/windows/identity/doc/ui_menus.h
new file mode 100644 (file)
index 0000000..c7a95a3
--- /dev/null
@@ -0,0 +1,29 @@
+/*\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
diff --git a/src/windows/identity/help/Index.hhk b/src/windows/identity/help/Index.hhk
new file mode 100644 (file)
index 0000000..2e24f6f
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">\r
+<HTML>\r
+<HEAD>\r
+<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">\r
+<!-- Sitemap 1.0 -->\r
+</HEAD><BODY>\r
+<UL>\r
+</UL>\r
+</BODY></HTML>\r
diff --git a/src/windows/identity/help/Makefile b/src/windows/identity/help/Makefile
new file mode 100644 (file)
index 0000000..2b823d8
--- /dev/null
@@ -0,0 +1,36 @@
+#\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
diff --git a/src/windows/identity/help/html/images/Thumbs.db b/src/windows/identity/help/html/images/Thumbs.db
new file mode 100644 (file)
index 0000000..01828e4
Binary files /dev/null and b/src/windows/identity/help/html/images/Thumbs.db differ
diff --git a/src/windows/identity/help/html/images/link.GIF b/src/windows/identity/help/html/images/link.GIF
new file mode 100644 (file)
index 0000000..1af792f
Binary files /dev/null and b/src/windows/identity/help/html/images/link.GIF differ
diff --git a/src/windows/identity/help/html/khm.css b/src/windows/identity/help/html/khm.css
new file mode 100644 (file)
index 0000000..82c4d57
--- /dev/null
@@ -0,0 +1,13 @@
+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
diff --git a/src/windows/identity/help/html/menu_exit.htm b/src/windows/identity/help/html/menu_exit.htm
new file mode 100644 (file)
index 0000000..2130df1
--- /dev/null
@@ -0,0 +1,9 @@
+<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
diff --git a/src/windows/identity/help/html/menu_file.htm b/src/windows/identity/help/html/menu_file.htm
new file mode 100644 (file)
index 0000000..021f71f
--- /dev/null
@@ -0,0 +1,18 @@
+<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
diff --git a/src/windows/identity/help/html/menu_properties.htm b/src/windows/identity/help/html/menu_properties.htm
new file mode 100644 (file)
index 0000000..2130df1
--- /dev/null
@@ -0,0 +1,9 @@
+<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
diff --git a/src/windows/identity/help/html/template.htm b/src/windows/identity/help/html/template.htm
new file mode 100644 (file)
index 0000000..2130df1
--- /dev/null
@@ -0,0 +1,9 @@
+<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
diff --git a/src/windows/identity/help/html/welcome.htm b/src/windows/identity/help/html/welcome.htm
new file mode 100644 (file)
index 0000000..32d7d05
--- /dev/null
@@ -0,0 +1,24 @@
+<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
diff --git a/src/windows/identity/help/khhelp.h b/src/windows/identity/help/khhelp.h
new file mode 100644 (file)
index 0000000..4ffa6d8
--- /dev/null
@@ -0,0 +1,23 @@
+\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
diff --git a/src/windows/identity/help/netidmgr.hhp b/src/windows/identity/help/netidmgr.hhp
new file mode 100644 (file)
index 0000000..8e0d5a5
--- /dev/null
@@ -0,0 +1,21 @@
+[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
diff --git a/src/windows/identity/help/toc.hhc b/src/windows/identity/help/toc.hhc
new file mode 100644 (file)
index 0000000..cde5119
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">\r
+<HTML>\r
+<HEAD>\r
+<meta name="GENERATOR" content="Microsoft&reg; 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
diff --git a/src/windows/identity/include/Makefile b/src/windows/identity/include/Makefile
new file mode 100644 (file)
index 0000000..17182d5
--- /dev/null
@@ -0,0 +1,37 @@
+#\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
diff --git a/src/windows/identity/include/khdefs.h b/src/windows/identity/include/khdefs.h
new file mode 100644 (file)
index 0000000..4279263
--- /dev/null
@@ -0,0 +1,235 @@
+/*\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
diff --git a/src/windows/identity/include/kherror.h b/src/windows/identity/include/kherror.h
new file mode 100644 (file)
index 0000000..d56fa7d
--- /dev/null
@@ -0,0 +1,177 @@
+/*\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
diff --git a/src/windows/identity/include/khlist.h b/src/windows/identity/include/khlist.h
new file mode 100644 (file)
index 0000000..330cfc4
--- /dev/null
@@ -0,0 +1,173 @@
+/*\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
diff --git a/src/windows/identity/include/khmsgtypes.h b/src/windows/identity/include/khmsgtypes.h
new file mode 100644 (file)
index 0000000..8348bbf
--- /dev/null
@@ -0,0 +1,700 @@
+/*\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
diff --git a/src/windows/identity/include/khthread.h b/src/windows/identity/include/khthread.h
new file mode 100644 (file)
index 0000000..b7354c4
--- /dev/null
@@ -0,0 +1,42 @@
+/*\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
diff --git a/src/windows/identity/kconfig/Makefile b/src/windows/identity/kconfig/Makefile
new file mode 100644 (file)
index 0000000..26619c0
--- /dev/null
@@ -0,0 +1,51 @@
+#\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
diff --git a/src/windows/identity/kconfig/api.c b/src/windows/identity/kconfig/api.c
new file mode 100644 (file)
index 0000000..3d69c99
--- /dev/null
@@ -0,0 +1,2098 @@
+/*\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
diff --git a/src/windows/identity/kconfig/kconfig.h b/src/windows/identity/kconfig/kconfig.h
new file mode 100644 (file)
index 0000000..22d923b
--- /dev/null
@@ -0,0 +1,823 @@
+/*\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
diff --git a/src/windows/identity/kconfig/kconfiginternal.h b/src/windows/identity/kconfig/kconfiginternal.h
new file mode 100644 (file)
index 0000000..1b4b701
--- /dev/null
@@ -0,0 +1,114 @@
+/*\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
diff --git a/src/windows/identity/kconfig/kconfigmain.c b/src/windows/identity/kconfig/kconfigmain.c
new file mode 100644 (file)
index 0000000..8a9d657
--- /dev/null
@@ -0,0 +1,37 @@
+/*\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
diff --git a/src/windows/identity/kconfig/registry.c b/src/windows/identity/kconfig/registry.c
new file mode 100644 (file)
index 0000000..4a7b466
--- /dev/null
@@ -0,0 +1,28 @@
+/*\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
diff --git a/src/windows/identity/kconfig/test/utiltest.c b/src/windows/identity/kconfig/test/utiltest.c
new file mode 100644 (file)
index 0000000..0652c63
--- /dev/null
@@ -0,0 +1,207 @@
+#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
diff --git a/src/windows/identity/kcreddb/Makefile b/src/windows/identity/kcreddb/Makefile
new file mode 100644 (file)
index 0000000..24cc033
--- /dev/null
@@ -0,0 +1,52 @@
+#\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
diff --git a/src/windows/identity/kcreddb/attrib.c b/src/windows/identity/kcreddb/attrib.c
new file mode 100644 (file)
index 0000000..e43540d
--- /dev/null
@@ -0,0 +1,853 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/attrib.h b/src/windows/identity/kcreddb/attrib.h
new file mode 100644 (file)
index 0000000..5199aec
--- /dev/null
@@ -0,0 +1,55 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/buf.c b/src/windows/identity/kcreddb/buf.c
new file mode 100644 (file)
index 0000000..0f50be2
--- /dev/null
@@ -0,0 +1,391 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/buf.h b/src/windows/identity/kcreddb/buf.h
new file mode 100644 (file)
index 0000000..3ff1f04
--- /dev/null
@@ -0,0 +1,78 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/credential.c b/src/windows/identity/kcreddb/credential.c
new file mode 100644 (file)
index 0000000..1fe1dcd
--- /dev/null
@@ -0,0 +1,1047 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/credential.h b/src/windows/identity/kcreddb/credential.h
new file mode 100644 (file)
index 0000000..8104f68
--- /dev/null
@@ -0,0 +1,70 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/credset.c b/src/windows/identity/kcreddb/credset.c
new file mode 100644 (file)
index 0000000..3a39d48
--- /dev/null
@@ -0,0 +1,1132 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/credset.h b/src/windows/identity/kcreddb/credset.h
new file mode 100644 (file)
index 0000000..c192465
--- /dev/null
@@ -0,0 +1,75 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/credtype.c b/src/windows/identity/kcreddb/credtype.c
new file mode 100644 (file)
index 0000000..dc2b7b8
--- /dev/null
@@ -0,0 +1,411 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/credtype.h b/src/windows/identity/kcreddb/credtype.h
new file mode 100644 (file)
index 0000000..6e46db3
--- /dev/null
@@ -0,0 +1,55 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/identity.c b/src/windows/identity/kcreddb/identity.c
new file mode 100644 (file)
index 0000000..d6ae129
--- /dev/null
@@ -0,0 +1,1537 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/identity.h b/src/windows/identity/kcreddb/identity.h
new file mode 100644 (file)
index 0000000..6c7e26e
--- /dev/null
@@ -0,0 +1,62 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/init.c b/src/windows/identity/kcreddb/init.c
new file mode 100644 (file)
index 0000000..2df3f3e
--- /dev/null
@@ -0,0 +1,91 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/kcdbconfig.csv b/src/windows/identity/kcreddb/kcdbconfig.csv
new file mode 100644 (file)
index 0000000..bd1fc6f
--- /dev/null
@@ -0,0 +1,15 @@
+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
diff --git a/src/windows/identity/kcreddb/kcreddb.h b/src/windows/identity/kcreddb/kcreddb.h
new file mode 100644 (file)
index 0000000..e5be0f4
--- /dev/null
@@ -0,0 +1,3212 @@
+/*\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 &lt; \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 &gt; \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
diff --git a/src/windows/identity/kcreddb/kcreddbinternal.h b/src/windows/identity/kcreddb/kcreddbinternal.h
new file mode 100644 (file)
index 0000000..699954c
--- /dev/null
@@ -0,0 +1,60 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/kcreddbmain.c b/src/windows/identity/kcreddb/kcreddbmain.c
new file mode 100644 (file)
index 0000000..796084a
--- /dev/null
@@ -0,0 +1,40 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/lang/en_us/kcredres.rc b/src/windows/identity/kcreddb/lang/en_us/kcredres.rc
new file mode 100644 (file)
index 0000000..2f73319
--- /dev/null
@@ -0,0 +1,130 @@
+// 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
diff --git a/src/windows/identity/kcreddb/langres.h b/src/windows/identity/kcreddb/langres.h
new file mode 100644 (file)
index 0000000..ab6620c
--- /dev/null
@@ -0,0 +1,49 @@
+//{{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
diff --git a/src/windows/identity/kcreddb/resource.h b/src/windows/identity/kcreddb/resource.h
new file mode 100644 (file)
index 0000000..dfb47e0
--- /dev/null
@@ -0,0 +1,27 @@
+//{{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
diff --git a/src/windows/identity/kcreddb/type.c b/src/windows/identity/kcreddb/type.c
new file mode 100644 (file)
index 0000000..e416945
--- /dev/null
@@ -0,0 +1,1295 @@
+/*\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
diff --git a/src/windows/identity/kcreddb/type.h b/src/windows/identity/kcreddb/type.h
new file mode 100644 (file)
index 0000000..9d8b52e
--- /dev/null
@@ -0,0 +1,216 @@
+/*\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
diff --git a/src/windows/identity/kherr/Makefile b/src/windows/identity/kherr/Makefile
new file mode 100644 (file)
index 0000000..84f9da5
--- /dev/null
@@ -0,0 +1,43 @@
+#\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
diff --git a/src/windows/identity/kherr/kherr.c b/src/windows/identity/kherr/kherr.c
new file mode 100644 (file)
index 0000000..04b4523
--- /dev/null
@@ -0,0 +1,1164 @@
+/*\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
diff --git a/src/windows/identity/kherr/kherr.h b/src/windows/identity/kherr/kherr.h
new file mode 100644 (file)
index 0000000..7ccc6e5
--- /dev/null
@@ -0,0 +1,965 @@
+/*\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
diff --git a/src/windows/identity/kherr/kherrinternal.h b/src/windows/identity/kherr/kherrinternal.h
new file mode 100644 (file)
index 0000000..e91cc3d
--- /dev/null
@@ -0,0 +1,67 @@
+/*\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
diff --git a/src/windows/identity/kherr/kherrmain.c b/src/windows/identity/kherr/kherrmain.c
new file mode 100644 (file)
index 0000000..b108609
--- /dev/null
@@ -0,0 +1,52 @@
+/*\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
diff --git a/src/windows/identity/kmm/Makefile b/src/windows/identity/kmm/Makefile
new file mode 100644 (file)
index 0000000..6135cdc
--- /dev/null
@@ -0,0 +1,54 @@
+#\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
diff --git a/src/windows/identity/kmm/kmm.c b/src/windows/identity/kmm/kmm.c
new file mode 100644 (file)
index 0000000..af8419f
--- /dev/null
@@ -0,0 +1,167 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmm.h b/src/windows/identity/kmm/kmm.h
new file mode 100644 (file)
index 0000000..8e487be
--- /dev/null
@@ -0,0 +1,1010 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmm_module.c b/src/windows/identity/kmm/kmm_module.c
new file mode 100644 (file)
index 0000000..e1f5292
--- /dev/null
@@ -0,0 +1,338 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmm_plugin.c b/src/windows/identity/kmm/kmm_plugin.c
new file mode 100644 (file)
index 0000000..f37eaa1
--- /dev/null
@@ -0,0 +1,377 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmm_reg.c b/src/windows/identity/kmm/kmm_reg.c
new file mode 100644 (file)
index 0000000..ea13fc1
--- /dev/null
@@ -0,0 +1,291 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmm_registrar.c b/src/windows/identity/kmm/kmm_registrar.c
new file mode 100644 (file)
index 0000000..3c690f3
--- /dev/null
@@ -0,0 +1,836 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmmconfig.csv b/src/windows/identity/kmm/kmmconfig.csv
new file mode 100644 (file)
index 0000000..93444bd
--- /dev/null
@@ -0,0 +1,52 @@
+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
diff --git a/src/windows/identity/kmm/kmminternal.h b/src/windows/identity/kmm/kmminternal.h
new file mode 100644 (file)
index 0000000..662eff2
--- /dev/null
@@ -0,0 +1,215 @@
+/*\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
diff --git a/src/windows/identity/kmm/kmmmain.c b/src/windows/identity/kmm/kmmmain.c
new file mode 100644 (file)
index 0000000..8ec4bc0
--- /dev/null
@@ -0,0 +1,157 @@
+/*\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
diff --git a/src/windows/identity/kmm/kplugin.h b/src/windows/identity/kmm/kplugin.h
new file mode 100644 (file)
index 0000000..f7489bf
--- /dev/null
@@ -0,0 +1,146 @@
+/*\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
diff --git a/src/windows/identity/kmm/lang/kmm_msgs.mc b/src/windows/identity/kmm/lang/kmm_msgs.mc
new file mode 100644 (file)
index 0000000..5e88121
--- /dev/null
@@ -0,0 +1,146 @@
+; // ** 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
diff --git a/src/windows/identity/kmq/Makefile b/src/windows/identity/kmq/Makefile
new file mode 100644 (file)
index 0000000..1f11e0f
--- /dev/null
@@ -0,0 +1,48 @@
+#\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
diff --git a/src/windows/identity/kmq/consumer.c b/src/windows/identity/kmq/consumer.c
new file mode 100644 (file)
index 0000000..32072cf
--- /dev/null
@@ -0,0 +1,423 @@
+/*\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
diff --git a/src/windows/identity/kmq/init.c b/src/windows/identity/kmq/init.c
new file mode 100644 (file)
index 0000000..cb50c54
--- /dev/null
@@ -0,0 +1,251 @@
+/*\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
diff --git a/src/windows/identity/kmq/kmq.h b/src/windows/identity/kmq/kmq.h
new file mode 100644 (file)
index 0000000..3d596d7
--- /dev/null
@@ -0,0 +1,743 @@
+/*\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
diff --git a/src/windows/identity/kmq/kmqconfig.csv b/src/windows/identity/kmq/kmqconfig.csv
new file mode 100644 (file)
index 0000000..c6d5ca4
--- /dev/null
@@ -0,0 +1,5 @@
+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
diff --git a/src/windows/identity/kmq/kmqinternal.h b/src/windows/identity/kmq/kmqinternal.h
new file mode 100644 (file)
index 0000000..c82fb92
--- /dev/null
@@ -0,0 +1,111 @@
+/*\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
diff --git a/src/windows/identity/kmq/kmqmain.c b/src/windows/identity/kmq/kmqmain.c
new file mode 100644 (file)
index 0000000..d93403a
--- /dev/null
@@ -0,0 +1,47 @@
+/*\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
diff --git a/src/windows/identity/kmq/msgtype.c b/src/windows/identity/kmq/msgtype.c
new file mode 100644 (file)
index 0000000..eb44eec
--- /dev/null
@@ -0,0 +1,357 @@
+/*\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
diff --git a/src/windows/identity/kmq/publisher.c b/src/windows/identity/kmq/publisher.c
new file mode 100644 (file)
index 0000000..5391844
--- /dev/null
@@ -0,0 +1,470 @@
+/*\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
diff --git a/src/windows/identity/nidmgrdll/Makefile b/src/windows/identity/nidmgrdll/Makefile
new file mode 100644 (file)
index 0000000..5d48c2d
--- /dev/null
@@ -0,0 +1,106 @@
+#\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
diff --git a/src/windows/identity/nidmgrdll/dllmain.c b/src/windows/identity/nidmgrdll/dllmain.c
new file mode 100644 (file)
index 0000000..f54d4ef
--- /dev/null
@@ -0,0 +1,114 @@
+/*\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
diff --git a/src/windows/identity/nidmgrdll/nidmgrdll.rc b/src/windows/identity/nidmgrdll/nidmgrdll.rc
new file mode 100644 (file)
index 0000000..10870e8
--- /dev/null
@@ -0,0 +1,74 @@
+/*\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
diff --git a/src/windows/identity/plugins/common/Makefile b/src/windows/identity/plugins/common/Makefile
new file mode 100644 (file)
index 0000000..cbadbc6
--- /dev/null
@@ -0,0 +1,42 @@
+#\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
diff --git a/src/windows/identity/plugins/common/dynimport.c b/src/windows/identity/plugins/common/dynimport.c
new file mode 100644 (file)
index 0000000..cd33813
--- /dev/null
@@ -0,0 +1,420 @@
+/*\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
diff --git a/src/windows/identity/plugins/common/dynimport.h b/src/windows/identity/plugins/common/dynimport.h
new file mode 100644 (file)
index 0000000..b3ba225
--- /dev/null
@@ -0,0 +1,338 @@
+/*\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
diff --git a/src/windows/identity/plugins/common/krb5common.c b/src/windows/identity/plugins/common/krb5common.c
new file mode 100644 (file)
index 0000000..5501a12
--- /dev/null
@@ -0,0 +1,156 @@
+/*\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
diff --git a/src/windows/identity/plugins/common/krb5common.h b/src/windows/identity/plugins/common/krb5common.h
new file mode 100644 (file)
index 0000000..7d99821
--- /dev/null
@@ -0,0 +1,43 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/Makefile b/src/windows/identity/plugins/krb4/Makefile
new file mode 100644 (file)
index 0000000..d6b7491
--- /dev/null
@@ -0,0 +1,78 @@
+#\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
diff --git a/src/windows/identity/plugins/krb4/datarep.h b/src/windows/identity/plugins/krb4/datarep.h
new file mode 100644 (file)
index 0000000..9c7048e
--- /dev/null
@@ -0,0 +1,37 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/errorfuncs.c b/src/windows/identity/plugins/krb4/errorfuncs.c
new file mode 100644 (file)
index 0000000..9feaad2
--- /dev/null
@@ -0,0 +1,264 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/errorfuncs.h b/src/windows/identity/plugins/krb4/errorfuncs.h
new file mode 100644 (file)
index 0000000..be8f4e7
--- /dev/null
@@ -0,0 +1,80 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/krb4configdlg.c b/src/windows/identity/plugins/krb4/krb4configdlg.c
new file mode 100644 (file)
index 0000000..9ad3406
--- /dev/null
@@ -0,0 +1,88 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/krb4funcs.c b/src/windows/identity/plugins/krb4/krb4funcs.c
new file mode 100644 (file)
index 0000000..8fda720
--- /dev/null
@@ -0,0 +1,505 @@
+/*\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, &sections);\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
diff --git a/src/windows/identity/plugins/krb4/krb4funcs.h b/src/windows/identity/plugins/krb4/krb4funcs.h
new file mode 100644 (file)
index 0000000..ea97358
--- /dev/null
@@ -0,0 +1,190 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/krb4plugin.c b/src/windows/identity/plugins/krb4/krb4plugin.c
new file mode 100644 (file)
index 0000000..106feba
--- /dev/null
@@ -0,0 +1,164 @@
+/*\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(&reg, 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, &reg);\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
diff --git a/src/windows/identity/plugins/krb4/krbconfig.csv b/src/windows/identity/plugins/krb4/krbconfig.csv
new file mode 100644 (file)
index 0000000..bed0d1c
--- /dev/null
@@ -0,0 +1,23 @@
+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
diff --git a/src/windows/identity/plugins/krb4/krbcred.h b/src/windows/identity/plugins/krb4/krbcred.h
new file mode 100644 (file)
index 0000000..e56d114
--- /dev/null
@@ -0,0 +1,114 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb4/lang/en_us/langres.rc b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc
new file mode 100644 (file)
index 0000000..a5d62a2
--- /dev/null
@@ -0,0 +1,141 @@
+// 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
diff --git a/src/windows/identity/plugins/krb4/langres.h b/src/windows/identity/plugins/krb4/langres.h
new file mode 100644 (file)
index 0000000..2096ade
--- /dev/null
@@ -0,0 +1,78 @@
+//{{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
diff --git a/src/windows/identity/plugins/krb4/main.c b/src/windows/identity/plugins/krb4/main.c
new file mode 100644 (file)
index 0000000..60ceb7f
--- /dev/null
@@ -0,0 +1,191 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/Makefile b/src/windows/identity/plugins/krb5/Makefile
new file mode 100644 (file)
index 0000000..9bf9ef0
--- /dev/null
@@ -0,0 +1,91 @@
+#\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
diff --git a/src/windows/identity/plugins/krb5/datarep.c b/src/windows/identity/plugins/krb5/datarep.c
new file mode 100644 (file)
index 0000000..f8cc4cc
--- /dev/null
@@ -0,0 +1,269 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/datarep.h b/src/windows/identity/plugins/krb5/datarep.h
new file mode 100644 (file)
index 0000000..e5388f0
--- /dev/null
@@ -0,0 +1,37 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/errorfuncs.c b/src/windows/identity/plugins/krb5/errorfuncs.c
new file mode 100644 (file)
index 0000000..ab64889
--- /dev/null
@@ -0,0 +1,260 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/errorfuncs.h b/src/windows/identity/plugins/krb5/errorfuncs.h
new file mode 100644 (file)
index 0000000..46d68f9
--- /dev/null
@@ -0,0 +1,75 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krb5configdlg.c b/src/windows/identity/plugins/krb5/krb5configdlg.c
new file mode 100644 (file)
index 0000000..c3b00e1
--- /dev/null
@@ -0,0 +1,421 @@
+/*\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(&reg, 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, &reg);\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(&reg, 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, &reg);\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(&reg, 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, &reg);\r
+\r
+    ZeroMemory(&reg, 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, &reg);\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
diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c
new file mode 100644 (file)
index 0000000..d3c97ff
--- /dev/null
@@ -0,0 +1,1889 @@
+/*\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
+                                                       &sections);\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
diff --git a/src/windows/identity/plugins/krb5/krb5funcs.h b/src/windows/identity/plugins/krb5/krb5funcs.h
new file mode 100644 (file)
index 0000000..79ca956
--- /dev/null
@@ -0,0 +1,121 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c
new file mode 100644 (file)
index 0000000..c568e49
--- /dev/null
@@ -0,0 +1,1108 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c
new file mode 100644 (file)
index 0000000..968e0e2
--- /dev/null
@@ -0,0 +1,2167 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krb5plugin.c b/src/windows/identity/plugins/krb5/krb5plugin.c
new file mode 100644 (file)
index 0000000..4b53ed3
--- /dev/null
@@ -0,0 +1,230 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krb5props.c b/src/windows/identity/plugins/krb5/krb5props.c
new file mode 100644 (file)
index 0000000..9134de2
--- /dev/null
@@ -0,0 +1,117 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krb5util.c b/src/windows/identity/plugins/krb5/krb5util.c
new file mode 100644 (file)
index 0000000..b892531
--- /dev/null
@@ -0,0 +1,1362 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/krbconfig.csv b/src/windows/identity/plugins/krb5/krbconfig.csv
new file mode 100644 (file)
index 0000000..c577eec
--- /dev/null
@@ -0,0 +1,34 @@
+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
diff --git a/src/windows/identity/plugins/krb5/krbcred.h b/src/windows/identity/plugins/krb5/krbcred.h
new file mode 100644 (file)
index 0000000..08978f1
--- /dev/null
@@ -0,0 +1,182 @@
+/*\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
diff --git a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc
new file mode 100644 (file)
index 0000000..087b93e
--- /dev/null
@@ -0,0 +1,406 @@
+// 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
diff --git a/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc
new file mode 100644 (file)
index 0000000..22f973f
--- /dev/null
@@ -0,0 +1,151 @@
+; // ** 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
diff --git a/src/windows/identity/plugins/krb5/langres.h b/src/windows/identity/plugins/krb5/langres.h
new file mode 100644 (file)
index 0000000..87f74f5
--- /dev/null
@@ -0,0 +1,127 @@
+//{{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
diff --git a/src/windows/identity/plugins/krb5/main.c b/src/windows/identity/plugins/krb5/main.c
new file mode 100644 (file)
index 0000000..db996d9
--- /dev/null
@@ -0,0 +1,387 @@
+/*\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
diff --git a/src/windows/identity/ui/Makefile b/src/windows/identity/ui/Makefile
new file mode 100644 (file)
index 0000000..402fc5d
--- /dev/null
@@ -0,0 +1,81 @@
+#\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
diff --git a/src/windows/identity/ui/aboutwnd.c b/src/windows/identity/ui/aboutwnd.c
new file mode 100644 (file)
index 0000000..2dde601
--- /dev/null
@@ -0,0 +1,147 @@
+/*\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
diff --git a/src/windows/identity/ui/aboutwnd.h b/src/windows/identity/ui/aboutwnd.h
new file mode 100644 (file)
index 0000000..a427b7d
--- /dev/null
@@ -0,0 +1,33 @@
+/*\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
diff --git a/src/windows/identity/ui/appglobal.h b/src/windows/identity/ui/appglobal.h
new file mode 100644 (file)
index 0000000..41fca2d
--- /dev/null
@@ -0,0 +1,74 @@
+/*\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
diff --git a/src/windows/identity/ui/cfg_general_wnd.c b/src/windows/identity/ui/cfg_general_wnd.c
new file mode 100644 (file)
index 0000000..37c7ba7
--- /dev/null
@@ -0,0 +1,227 @@
+/*\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
diff --git a/src/windows/identity/ui/cfg_identities_wnd.c b/src/windows/identity/ui/cfg_identities_wnd.c
new file mode 100644 (file)
index 0000000..1cef2d7
--- /dev/null
@@ -0,0 +1,1256 @@
+/*\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, &reg);\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, &reg);\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, &reg);\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
diff --git a/src/windows/identity/ui/cfg_notif_wnd.c b/src/windows/identity/ui/cfg_notif_wnd.c
new file mode 100644 (file)
index 0000000..aafa12d
--- /dev/null
@@ -0,0 +1,313 @@
+/*\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
diff --git a/src/windows/identity/ui/cfg_plugins_wnd.c b/src/windows/identity/ui/cfg_plugins_wnd.c
new file mode 100644 (file)
index 0000000..16a3442
--- /dev/null
@@ -0,0 +1,318 @@
+/*\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
diff --git a/src/windows/identity/ui/configwnd.c b/src/windows/identity/ui/configwnd.c
new file mode 100644 (file)
index 0000000..22a41ee
--- /dev/null
@@ -0,0 +1,839 @@
+/*\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, &reg);\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, &reg);\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, &reg);\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(&reg, 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
+                              &reg);\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, &reg);\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, &reg);\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, &reg);\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, &reg);\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, &reg);\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, &reg);\r
+}\r
+\r
+void khm_exit_config(void) {\r
+}\r
diff --git a/src/windows/identity/ui/configwnd.h b/src/windows/identity/ui/configwnd.h
new file mode 100644 (file)
index 0000000..64da771
--- /dev/null
@@ -0,0 +1,80 @@
+/*\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
diff --git a/src/windows/identity/ui/credfuncs.c b/src/windows/identity/ui/credfuncs.c
new file mode 100644 (file)
index 0000000..b92e5d4
--- /dev/null
@@ -0,0 +1,827 @@
+/*\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
diff --git a/src/windows/identity/ui/credfuncs.h b/src/windows/identity/ui/credfuncs.h
new file mode 100644 (file)
index 0000000..b25b663
--- /dev/null
@@ -0,0 +1,72 @@
+/*\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
diff --git a/src/windows/identity/ui/credwnd.c b/src/windows/identity/ui/credwnd.c
new file mode 100644 (file)
index 0000000..784a7f9
--- /dev/null
@@ -0,0 +1,3223 @@
+/*\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 = &rect;\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
diff --git a/src/windows/identity/ui/credwnd.h b/src/windows/identity/ui/credwnd.h
new file mode 100644 (file)
index 0000000..66fc3d2
--- /dev/null
@@ -0,0 +1,237 @@
+/*\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
diff --git a/src/windows/identity/ui/htmlwnd.h b/src/windows/identity/ui/htmlwnd.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/windows/identity/ui/htwnd.c b/src/windows/identity/ui/htwnd.c
new file mode 100644 (file)
index 0000000..9acbac7
--- /dev/null
@@ -0,0 +1,1070 @@
+/*\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, &param_start, &param_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
diff --git a/src/windows/identity/ui/htwnd.h b/src/windows/identity/ui/htwnd.h
new file mode 100644 (file)
index 0000000..9e74788
--- /dev/null
@@ -0,0 +1,55 @@
+/*\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
diff --git a/src/windows/identity/ui/images/Thumbs.db b/src/windows/identity/ui/images/Thumbs.db
new file mode 100644 (file)
index 0000000..a80265f
Binary files /dev/null and b/src/windows/identity/ui/images/Thumbs.db differ
diff --git a/src/windows/identity/ui/images/app_notify_error.ico b/src/windows/identity/ui/images/app_notify_error.ico
new file mode 100644 (file)
index 0000000..8dcb29e
Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_error.ico differ
diff --git a/src/windows/identity/ui/images/app_notify_info.ico b/src/windows/identity/ui/images/app_notify_info.ico
new file mode 100644 (file)
index 0000000..8dcb29e
Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_info.ico differ
diff --git a/src/windows/identity/ui/images/app_notify_none.ico b/src/windows/identity/ui/images/app_notify_none.ico
new file mode 100644 (file)
index 0000000..8dcb29e
Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_none.ico differ
diff --git a/src/windows/identity/ui/images/app_notify_warn.ico b/src/windows/identity/ui/images/app_notify_warn.ico
new file mode 100644 (file)
index 0000000..8dcb29e
Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_warn.ico differ
diff --git a/src/windows/identity/ui/images/bitmap1.bmp b/src/windows/identity/ui/images/bitmap1.bmp
new file mode 100644 (file)
index 0000000..1f07309
Binary files /dev/null and b/src/windows/identity/ui/images/bitmap1.bmp differ
diff --git a/src/windows/identity/ui/images/cfg_applied.ico b/src/windows/identity/ui/images/cfg_applied.ico
new file mode 100644 (file)
index 0000000..4fcdf84
Binary files /dev/null and b/src/windows/identity/ui/images/cfg_applied.ico differ
diff --git a/src/windows/identity/ui/images/cfg_default.ico b/src/windows/identity/ui/images/cfg_default.ico
new file mode 100644 (file)
index 0000000..d6e7f24
Binary files /dev/null and b/src/windows/identity/ui/images/cfg_default.ico differ
diff --git a/src/windows/identity/ui/images/cfg_deleted.ico b/src/windows/identity/ui/images/cfg_deleted.ico
new file mode 100644 (file)
index 0000000..2ef11c7
Binary files /dev/null and b/src/windows/identity/ui/images/cfg_deleted.ico differ
diff --git a/src/windows/identity/ui/images/cfg_mod.ico b/src/windows/identity/ui/images/cfg_mod.ico
new file mode 100644 (file)
index 0000000..65e3691
Binary files /dev/null and b/src/windows/identity/ui/images/cfg_mod.ico differ
diff --git a/src/windows/identity/ui/images/chpw-dis-sm.bmp b/src/windows/identity/ui/images/chpw-dis-sm.bmp
new file mode 100644 (file)
index 0000000..230ad36
Binary files /dev/null and b/src/windows/identity/ui/images/chpw-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/chpw-dis.bmp b/src/windows/identity/ui/images/chpw-dis.bmp
new file mode 100644 (file)
index 0000000..43468cb
Binary files /dev/null and b/src/windows/identity/ui/images/chpw-dis.bmp differ
diff --git a/src/windows/identity/ui/images/chpw-sm.bmp b/src/windows/identity/ui/images/chpw-sm.bmp
new file mode 100644 (file)
index 0000000..309a917
Binary files /dev/null and b/src/windows/identity/ui/images/chpw-sm.bmp differ
diff --git a/src/windows/identity/ui/images/chpw.bmp b/src/windows/identity/ui/images/chpw.bmp
new file mode 100644 (file)
index 0000000..688da40
Binary files /dev/null and b/src/windows/identity/ui/images/chpw.bmp differ
diff --git a/src/windows/identity/ui/images/disabled.ico b/src/windows/identity/ui/images/disabled.ico
new file mode 100644 (file)
index 0000000..6b6a907
Binary files /dev/null and b/src/windows/identity/ui/images/disabled.ico differ
diff --git a/src/windows/identity/ui/images/enabled.ico b/src/windows/identity/ui/images/enabled.ico
new file mode 100644 (file)
index 0000000..22821a8
Binary files /dev/null and b/src/windows/identity/ui/images/enabled.ico differ
diff --git a/src/windows/identity/ui/images/flag-critical.bmp b/src/windows/identity/ui/images/flag-critical.bmp
new file mode 100644 (file)
index 0000000..0b4c920
Binary files /dev/null and b/src/windows/identity/ui/images/flag-critical.bmp differ
diff --git a/src/windows/identity/ui/images/flag-warning.bmp b/src/windows/identity/ui/images/flag-warning.bmp
new file mode 100644 (file)
index 0000000..f5be298
Binary files /dev/null and b/src/windows/identity/ui/images/flag-warning.bmp differ
diff --git a/src/windows/identity/ui/images/flag_expired.bmp b/src/windows/identity/ui/images/flag_expired.bmp
new file mode 100644 (file)
index 0000000..2815fb4
Binary files /dev/null and b/src/windows/identity/ui/images/flag_expired.bmp differ
diff --git a/src/windows/identity/ui/images/help-sm.bmp b/src/windows/identity/ui/images/help-sm.bmp
new file mode 100644 (file)
index 0000000..49e560f
Binary files /dev/null and b/src/windows/identity/ui/images/help-sm.bmp differ
diff --git a/src/windows/identity/ui/images/help.bmp b/src/windows/identity/ui/images/help.bmp
new file mode 100644 (file)
index 0000000..d7d4eaf
Binary files /dev/null and b/src/windows/identity/ui/images/help.bmp differ
diff --git a/src/windows/identity/ui/images/icon1.ico b/src/windows/identity/ui/images/icon1.ico
new file mode 100644 (file)
index 0000000..c2746b0
Binary files /dev/null and b/src/windows/identity/ui/images/icon1.ico differ
diff --git a/src/windows/identity/ui/images/id-delete-dis-sm.bmp b/src/windows/identity/ui/images/id-delete-dis-sm.bmp
new file mode 100644 (file)
index 0000000..68850ab
Binary files /dev/null and b/src/windows/identity/ui/images/id-delete-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id-delete-dis.bmp b/src/windows/identity/ui/images/id-delete-dis.bmp
new file mode 100644 (file)
index 0000000..11aedd5
Binary files /dev/null and b/src/windows/identity/ui/images/id-delete-dis.bmp differ
diff --git a/src/windows/identity/ui/images/id-delete-sm.bmp b/src/windows/identity/ui/images/id-delete-sm.bmp
new file mode 100644 (file)
index 0000000..3447d57
Binary files /dev/null and b/src/windows/identity/ui/images/id-delete-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id-delete.bmp b/src/windows/identity/ui/images/id-delete.bmp
new file mode 100644 (file)
index 0000000..5b1b680
Binary files /dev/null and b/src/windows/identity/ui/images/id-delete.bmp differ
diff --git a/src/windows/identity/ui/images/id-dis-sm.bmp b/src/windows/identity/ui/images/id-dis-sm.bmp
new file mode 100644 (file)
index 0000000..ff0c38e
Binary files /dev/null and b/src/windows/identity/ui/images/id-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id-dis.bmp b/src/windows/identity/ui/images/id-dis.bmp
new file mode 100644 (file)
index 0000000..3c04aa2
Binary files /dev/null and b/src/windows/identity/ui/images/id-dis.bmp differ
diff --git a/src/windows/identity/ui/images/id-new-dis-sm.bmp b/src/windows/identity/ui/images/id-new-dis-sm.bmp
new file mode 100644 (file)
index 0000000..d2a151c
Binary files /dev/null and b/src/windows/identity/ui/images/id-new-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id-new-dis.bmp b/src/windows/identity/ui/images/id-new-dis.bmp
new file mode 100644 (file)
index 0000000..61c2fd2
Binary files /dev/null and b/src/windows/identity/ui/images/id-new-dis.bmp differ
diff --git a/src/windows/identity/ui/images/id-new-sm.bmp b/src/windows/identity/ui/images/id-new-sm.bmp
new file mode 100644 (file)
index 0000000..9fb17b9
Binary files /dev/null and b/src/windows/identity/ui/images/id-new-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id-new.bmp b/src/windows/identity/ui/images/id-new.bmp
new file mode 100644 (file)
index 0000000..54830c1
Binary files /dev/null and b/src/windows/identity/ui/images/id-new.bmp differ
diff --git a/src/windows/identity/ui/images/id-refresh-dis.bmp b/src/windows/identity/ui/images/id-refresh-dis.bmp
new file mode 100644 (file)
index 0000000..7d79343
Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh-dis.bmp differ
diff --git a/src/windows/identity/ui/images/id-refresh-sm-dis.bmp b/src/windows/identity/ui/images/id-refresh-sm-dis.bmp
new file mode 100644 (file)
index 0000000..c9d9add
Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh-sm-dis.bmp differ
diff --git a/src/windows/identity/ui/images/id-refresh-sm.bmp b/src/windows/identity/ui/images/id-refresh-sm.bmp
new file mode 100644 (file)
index 0000000..11d1893
Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id-refresh.bmp b/src/windows/identity/ui/images/id-refresh.bmp
new file mode 100644 (file)
index 0000000..6357fde
Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh.bmp differ
diff --git a/src/windows/identity/ui/images/id-sm.bmp b/src/windows/identity/ui/images/id-sm.bmp
new file mode 100644 (file)
index 0000000..e507a62
Binary files /dev/null and b/src/windows/identity/ui/images/id-sm.bmp differ
diff --git a/src/windows/identity/ui/images/id.bmp b/src/windows/identity/ui/images/id.bmp
new file mode 100644 (file)
index 0000000..72a93c6
Binary files /dev/null and b/src/windows/identity/ui/images/id.bmp differ
diff --git a/src/windows/identity/ui/images/id.ico b/src/windows/identity/ui/images/id.ico
new file mode 100644 (file)
index 0000000..1f0f676
Binary files /dev/null and b/src/windows/identity/ui/images/id.ico differ
diff --git a/src/windows/identity/ui/images/ident.png b/src/windows/identity/ui/images/ident.png
new file mode 100644 (file)
index 0000000..904f023
Binary files /dev/null and b/src/windows/identity/ui/images/ident.png differ
diff --git a/src/windows/identity/ui/images/import-dis.bmp b/src/windows/identity/ui/images/import-dis.bmp
new file mode 100644 (file)
index 0000000..4257a1a
Binary files /dev/null and b/src/windows/identity/ui/images/import-dis.bmp differ
diff --git a/src/windows/identity/ui/images/import-sm-dis.bmp b/src/windows/identity/ui/images/import-sm-dis.bmp
new file mode 100644 (file)
index 0000000..b9398c3
Binary files /dev/null and b/src/windows/identity/ui/images/import-sm-dis.bmp differ
diff --git a/src/windows/identity/ui/images/import-sm.bmp b/src/windows/identity/ui/images/import-sm.bmp
new file mode 100644 (file)
index 0000000..0c99168
Binary files /dev/null and b/src/windows/identity/ui/images/import-sm.bmp differ
diff --git a/src/windows/identity/ui/images/import.bmp b/src/windows/identity/ui/images/import.bmp
new file mode 100644 (file)
index 0000000..6a428c9
Binary files /dev/null and b/src/windows/identity/ui/images/import.bmp differ
diff --git a/src/windows/identity/ui/images/khimaira-cfg.bmp b/src/windows/identity/ui/images/khimaira-cfg.bmp
new file mode 100644 (file)
index 0000000..d20b9eb
Binary files /dev/null and b/src/windows/identity/ui/images/khimaira-cfg.bmp differ
diff --git a/src/windows/identity/ui/images/logo_shade.bmp b/src/windows/identity/ui/images/logo_shade.bmp
new file mode 100644 (file)
index 0000000..2e36b9b
Binary files /dev/null and b/src/windows/identity/ui/images/logo_shade.bmp differ
diff --git a/src/windows/identity/ui/images/main_app.ico b/src/windows/identity/ui/images/main_app.ico
new file mode 100644 (file)
index 0000000..8dcb29e
Binary files /dev/null and b/src/windows/identity/ui/images/main_app.ico differ
diff --git a/src/windows/identity/ui/images/main_app_old.ico b/src/windows/identity/ui/images/main_app_old.ico
new file mode 100644 (file)
index 0000000..e3222e7
Binary files /dev/null and b/src/windows/identity/ui/images/main_app_old.ico differ
diff --git a/src/windows/identity/ui/images/tb-blank-small.bmp b/src/windows/identity/ui/images/tb-blank-small.bmp
new file mode 100644 (file)
index 0000000..0718d12
Binary files /dev/null and b/src/windows/identity/ui/images/tb-blank-small.bmp differ
diff --git a/src/windows/identity/ui/images/tb-blank.bmp b/src/windows/identity/ui/images/tb-blank.bmp
new file mode 100644 (file)
index 0000000..01adca9
Binary files /dev/null and b/src/windows/identity/ui/images/tb-blank.bmp differ
diff --git a/src/windows/identity/ui/images/tb-space.bmp b/src/windows/identity/ui/images/tb-space.bmp
new file mode 100644 (file)
index 0000000..d85cc5c
Binary files /dev/null and b/src/windows/identity/ui/images/tb-space.bmp differ
diff --git a/src/windows/identity/ui/images/text1138.png b/src/windows/identity/ui/images/text1138.png
new file mode 100644 (file)
index 0000000..cf5ee37
Binary files /dev/null and b/src/windows/identity/ui/images/text1138.png differ
diff --git a/src/windows/identity/ui/images/tk-delete-dis-sm.bmp b/src/windows/identity/ui/images/tk-delete-dis-sm.bmp
new file mode 100644 (file)
index 0000000..00adcf4
Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-delete-dis.bmp b/src/windows/identity/ui/images/tk-delete-dis.bmp
new file mode 100644 (file)
index 0000000..844fb23
Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete-dis.bmp differ
diff --git a/src/windows/identity/ui/images/tk-delete-sm.bmp b/src/windows/identity/ui/images/tk-delete-sm.bmp
new file mode 100644 (file)
index 0000000..0ac2d6a
Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-delete.bmp b/src/windows/identity/ui/images/tk-delete.bmp
new file mode 100644 (file)
index 0000000..501ff6e
Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete.bmp differ
diff --git a/src/windows/identity/ui/images/tk-dis-sm.bmp b/src/windows/identity/ui/images/tk-dis-sm.bmp
new file mode 100644 (file)
index 0000000..9100d9a
Binary files /dev/null and b/src/windows/identity/ui/images/tk-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-dis.bmp b/src/windows/identity/ui/images/tk-dis.bmp
new file mode 100644 (file)
index 0000000..558ba90
Binary files /dev/null and b/src/windows/identity/ui/images/tk-dis.bmp differ
diff --git a/src/windows/identity/ui/images/tk-new-dis-sm.bmp b/src/windows/identity/ui/images/tk-new-dis-sm.bmp
new file mode 100644 (file)
index 0000000..d2e1fcd
Binary files /dev/null and b/src/windows/identity/ui/images/tk-new-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-new-dis.bmp b/src/windows/identity/ui/images/tk-new-dis.bmp
new file mode 100644 (file)
index 0000000..c6abc4e
Binary files /dev/null and b/src/windows/identity/ui/images/tk-new-dis.bmp differ
diff --git a/src/windows/identity/ui/images/tk-new-sm.bmp b/src/windows/identity/ui/images/tk-new-sm.bmp
new file mode 100644 (file)
index 0000000..f2bf279
Binary files /dev/null and b/src/windows/identity/ui/images/tk-new-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-new.bmp b/src/windows/identity/ui/images/tk-new.bmp
new file mode 100644 (file)
index 0000000..e0e7bc0
Binary files /dev/null and b/src/windows/identity/ui/images/tk-new.bmp differ
diff --git a/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp b/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp
new file mode 100644 (file)
index 0000000..2745af1
Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-refresh-dis.bmp b/src/windows/identity/ui/images/tk-refresh-dis.bmp
new file mode 100644 (file)
index 0000000..45f8099
Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh-dis.bmp differ
diff --git a/src/windows/identity/ui/images/tk-refresh-sm.bmp b/src/windows/identity/ui/images/tk-refresh-sm.bmp
new file mode 100644 (file)
index 0000000..acf3361
Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk-refresh.bmp b/src/windows/identity/ui/images/tk-refresh.bmp
new file mode 100644 (file)
index 0000000..6e39f87
Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh.bmp differ
diff --git a/src/windows/identity/ui/images/tk-sm.bmp b/src/windows/identity/ui/images/tk-sm.bmp
new file mode 100644 (file)
index 0000000..c89285c
Binary files /dev/null and b/src/windows/identity/ui/images/tk-sm.bmp differ
diff --git a/src/windows/identity/ui/images/tk.bmp b/src/windows/identity/ui/images/tk.bmp
new file mode 100644 (file)
index 0000000..e689cb8
Binary files /dev/null and b/src/windows/identity/ui/images/tk.bmp differ
diff --git a/src/windows/identity/ui/images/vw-refresh-sm.bmp b/src/windows/identity/ui/images/vw-refresh-sm.bmp
new file mode 100644 (file)
index 0000000..aabd10e
Binary files /dev/null and b/src/windows/identity/ui/images/vw-refresh-sm.bmp differ
diff --git a/src/windows/identity/ui/images/vw-refresh.bmp b/src/windows/identity/ui/images/vw-refresh.bmp
new file mode 100644 (file)
index 0000000..76b68dd
Binary files /dev/null and b/src/windows/identity/ui/images/vw-refresh.bmp differ
diff --git a/src/windows/identity/ui/images/wdg_collapsed.bmp b/src/windows/identity/ui/images/wdg_collapsed.bmp
new file mode 100644 (file)
index 0000000..f4d8297
Binary files /dev/null and b/src/windows/identity/ui/images/wdg_collapsed.bmp differ
diff --git a/src/windows/identity/ui/images/wdg_collapsed_hi.bmp b/src/windows/identity/ui/images/wdg_collapsed_hi.bmp
new file mode 100644 (file)
index 0000000..90ab26d
Binary files /dev/null and b/src/windows/identity/ui/images/wdg_collapsed_hi.bmp differ
diff --git a/src/windows/identity/ui/images/wdg_credtype.bmp b/src/windows/identity/ui/images/wdg_credtype.bmp
new file mode 100644 (file)
index 0000000..3bac3fe
Binary files /dev/null and b/src/windows/identity/ui/images/wdg_credtype.bmp differ
diff --git a/src/windows/identity/ui/images/wdg_expanded.bmp b/src/windows/identity/ui/images/wdg_expanded.bmp
new file mode 100644 (file)
index 0000000..c590722
Binary files /dev/null and b/src/windows/identity/ui/images/wdg_expanded.bmp differ
diff --git a/src/windows/identity/ui/images/wdg_expanded_hi.bmp b/src/windows/identity/ui/images/wdg_expanded_hi.bmp
new file mode 100644 (file)
index 0000000..6b2affc
Binary files /dev/null and b/src/windows/identity/ui/images/wdg_expanded_hi.bmp differ
diff --git a/src/windows/identity/ui/images/wdg_flag.bmp b/src/windows/identity/ui/images/wdg_flag.bmp
new file mode 100644 (file)
index 0000000..c563c56
Binary files /dev/null and b/src/windows/identity/ui/images/wdg_flag.bmp differ
diff --git a/src/windows/identity/ui/images/wgt_arrow_collapse.ico b/src/windows/identity/ui/images/wgt_arrow_collapse.ico
new file mode 100644 (file)
index 0000000..b248bd9
Binary files /dev/null and b/src/windows/identity/ui/images/wgt_arrow_collapse.ico differ
diff --git a/src/windows/identity/ui/images/wgt_arrow_expand.ico b/src/windows/identity/ui/images/wgt_arrow_expand.ico
new file mode 100644 (file)
index 0000000..485b537
Binary files /dev/null and b/src/windows/identity/ui/images/wgt_arrow_expand.ico differ
diff --git a/src/windows/identity/ui/khmapp.h b/src/windows/identity/ui/khmapp.h
new file mode 100644 (file)
index 0000000..bd53bde
--- /dev/null
@@ -0,0 +1,69 @@
+/*\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
diff --git a/src/windows/identity/ui/lang/en_us/khapp.rc b/src/windows/identity/ui/lang/en_us/khapp.rc
new file mode 100644 (file)
index 0000000..a1b03b4
--- /dev/null
@@ -0,0 +1,728 @@
+// 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
diff --git a/src/windows/identity/ui/main.c b/src/windows/identity/ui/main.c
new file mode 100644 (file)
index 0000000..b92c540
--- /dev/null
@@ -0,0 +1,442 @@
+/*\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
diff --git a/src/windows/identity/ui/mainmenu.c b/src/windows/identity/ui/mainmenu.c
new file mode 100644 (file)
index 0000000..6115204
--- /dev/null
@@ -0,0 +1,566 @@
+/*\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
diff --git a/src/windows/identity/ui/mainmenu.h b/src/windows/identity/ui/mainmenu.h
new file mode 100644 (file)
index 0000000..7cd8e01
--- /dev/null
@@ -0,0 +1,58 @@
+/*\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
diff --git a/src/windows/identity/ui/mainwnd.c b/src/windows/identity/ui/mainwnd.c
new file mode 100644 (file)
index 0000000..0f5c7e0
--- /dev/null
@@ -0,0 +1,679 @@
+/*\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
diff --git a/src/windows/identity/ui/mainwnd.h b/src/windows/identity/ui/mainwnd.h
new file mode 100644 (file)
index 0000000..cdaac1e
--- /dev/null
@@ -0,0 +1,60 @@
+/*\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
diff --git a/src/windows/identity/ui/makeacceldef.pl b/src/windows/identity/ui/makeacceldef.pl
new file mode 100644 (file)
index 0000000..f13a3ec
--- /dev/null
@@ -0,0 +1,29 @@
+#\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
diff --git a/src/windows/identity/ui/makeactiondef.pl b/src/windows/identity/ui/makeactiondef.pl
new file mode 100644 (file)
index 0000000..a83325b
--- /dev/null
@@ -0,0 +1,29 @@
+#\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
diff --git a/src/windows/identity/ui/netidmgr.exe.manifest.i386 b/src/windows/identity/ui/netidmgr.exe.manifest.i386
new file mode 100644 (file)
index 0000000..5e83258
--- /dev/null
@@ -0,0 +1,22 @@
+<?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
diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc7 b/src/windows/identity/ui/netidmgr.manifest.i386.vc7
new file mode 100644 (file)
index 0000000..5e83258
--- /dev/null
@@ -0,0 +1,22 @@
+<?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
diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug b/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug
new file mode 100644 (file)
index 0000000..5e83258
--- /dev/null
@@ -0,0 +1,22 @@
+<?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
diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc8 b/src/windows/identity/ui/netidmgr.manifest.i386.vc8
new file mode 100644 (file)
index 0000000..84d91a3
--- /dev/null
@@ -0,0 +1,31 @@
+<?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
diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug b/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug
new file mode 100644 (file)
index 0000000..84d91a3
--- /dev/null
@@ -0,0 +1,31 @@
+<?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
diff --git a/src/windows/identity/ui/newcredwnd.c b/src/windows/identity/ui/newcredwnd.c
new file mode 100644 (file)
index 0000000..4b6ce08
--- /dev/null
@@ -0,0 +1,1694 @@
+/*\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
diff --git a/src/windows/identity/ui/newcredwnd.h b/src/windows/identity/ui/newcredwnd.h
new file mode 100644 (file)
index 0000000..d0b6764
--- /dev/null
@@ -0,0 +1,101 @@
+/*\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
diff --git a/src/windows/identity/ui/notifier.c b/src/windows/identity/ui/notifier.c
new file mode 100644 (file)
index 0000000..0ebdbd4
--- /dev/null
@@ -0,0 +1,1079 @@
+/*\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
diff --git a/src/windows/identity/ui/notifier.h b/src/windows/identity/ui/notifier.h
new file mode 100644 (file)
index 0000000..bfe9656
--- /dev/null
@@ -0,0 +1,45 @@
+/*\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
diff --git a/src/windows/identity/ui/passwnd.c b/src/windows/identity/ui/passwnd.c
new file mode 100644 (file)
index 0000000..4084ede
--- /dev/null
@@ -0,0 +1,133 @@
+#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
diff --git a/src/windows/identity/ui/passwnd.h b/src/windows/identity/ui/passwnd.h
new file mode 100644 (file)
index 0000000..f8c17f6
--- /dev/null
@@ -0,0 +1,39 @@
+/*\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
diff --git a/src/windows/identity/ui/propertywnd.c b/src/windows/identity/ui/propertywnd.c
new file mode 100644 (file)
index 0000000..fe603c0
--- /dev/null
@@ -0,0 +1,248 @@
+/*\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
diff --git a/src/windows/identity/ui/propertywnd.h b/src/windows/identity/ui/propertywnd.h
new file mode 100644 (file)
index 0000000..67250c9
--- /dev/null
@@ -0,0 +1,36 @@
+/*\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
diff --git a/src/windows/identity/ui/reqdaemon.c b/src/windows/identity/ui/reqdaemon.c
new file mode 100644 (file)
index 0000000..b73ec48
--- /dev/null
@@ -0,0 +1,396 @@
+/*\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
diff --git a/src/windows/identity/ui/reqdaemon.h b/src/windows/identity/ui/reqdaemon.h
new file mode 100644 (file)
index 0000000..13b0ebd
--- /dev/null
@@ -0,0 +1,42 @@
+/*\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
diff --git a/src/windows/identity/ui/resource.h b/src/windows/identity/ui/resource.h
new file mode 100644 (file)
index 0000000..a58cebb
--- /dev/null
@@ -0,0 +1,313 @@
+//{{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
diff --git a/src/windows/identity/ui/statusbar.c b/src/windows/identity/ui/statusbar.c
new file mode 100644 (file)
index 0000000..75f520c
--- /dev/null
@@ -0,0 +1,149 @@
+/*\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
diff --git a/src/windows/identity/ui/statusbar.h b/src/windows/identity/ui/statusbar.h
new file mode 100644 (file)
index 0000000..b4f2a6e
--- /dev/null
@@ -0,0 +1,53 @@
+/*\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
diff --git a/src/windows/identity/ui/timer.c b/src/windows/identity/ui/timer.c
new file mode 100644 (file)
index 0000000..bd5b30e
--- /dev/null
@@ -0,0 +1,637 @@
+/*\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
diff --git a/src/windows/identity/ui/timer.h b/src/windows/identity/ui/timer.h
new file mode 100644 (file)
index 0000000..921b9dc
--- /dev/null
@@ -0,0 +1,100 @@
+/*\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
diff --git a/src/windows/identity/ui/toolbar.c b/src/windows/identity/ui/toolbar.c
new file mode 100644 (file)
index 0000000..d1a84e2
--- /dev/null
@@ -0,0 +1,366 @@
+/*\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
diff --git a/src/windows/identity/ui/toolbar.h b/src/windows/identity/ui/toolbar.h
new file mode 100644 (file)
index 0000000..65598de
--- /dev/null
@@ -0,0 +1,52 @@
+/*\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
diff --git a/src/windows/identity/ui/uiconfig.csv b/src/windows/identity/ui/uiconfig.csv
new file mode 100644 (file)
index 0000000..eeb44bb
--- /dev/null
@@ -0,0 +1,111 @@
+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
diff --git a/src/windows/identity/uilib/Makefile b/src/windows/identity/uilib/Makefile
new file mode 100644 (file)
index 0000000..4e65600
--- /dev/null
@@ -0,0 +1,61 @@
+#\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
diff --git a/src/windows/identity/uilib/accel.csv b/src/windows/identity/uilib/accel.csv
new file mode 100644 (file)
index 0000000..80b6ad0
--- /dev/null
@@ -0,0 +1,17 @@
+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
diff --git a/src/windows/identity/uilib/acceldef.cfg b/src/windows/identity/uilib/acceldef.cfg
new file mode 100644 (file)
index 0000000..5dc72e6
--- /dev/null
@@ -0,0 +1,50 @@
+#\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
diff --git a/src/windows/identity/uilib/action.c b/src/windows/identity/uilib/action.c
new file mode 100644 (file)
index 0000000..cc383c6
--- /dev/null
@@ -0,0 +1,1019 @@
+/*\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
diff --git a/src/windows/identity/uilib/actiondef.cfg b/src/windows/identity/uilib/actiondef.cfg
new file mode 100644 (file)
index 0000000..14600b0
--- /dev/null
@@ -0,0 +1,64 @@
+#\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
diff --git a/src/windows/identity/uilib/actions.csv b/src/windows/identity/uilib/actions.csv
new file mode 100644 (file)
index 0000000..e317c7c
--- /dev/null
@@ -0,0 +1,37 @@
+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
diff --git a/src/windows/identity/uilib/alert.c b/src/windows/identity/uilib/alert.c
new file mode 100644 (file)
index 0000000..69ef01f
--- /dev/null
@@ -0,0 +1,350 @@
+/*\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
diff --git a/src/windows/identity/uilib/configui.c b/src/windows/identity/uilib/configui.c
new file mode 100644 (file)
index 0000000..5c97c70
--- /dev/null
@@ -0,0 +1,1001 @@
+/*\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
diff --git a/src/windows/identity/uilib/configui.h b/src/windows/identity/uilib/configui.h
new file mode 100644 (file)
index 0000000..37d5e97
--- /dev/null
@@ -0,0 +1,74 @@
+/*\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
diff --git a/src/windows/identity/uilib/creddlg.c b/src/windows/identity/uilib/creddlg.c
new file mode 100644 (file)
index 0000000..ccc27b4
--- /dev/null
@@ -0,0 +1,671 @@
+/*\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
diff --git a/src/windows/identity/uilib/khaction.h b/src/windows/identity/uilib/khaction.h
new file mode 100644 (file)
index 0000000..7b7c22a
--- /dev/null
@@ -0,0 +1,566 @@
+/*\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
diff --git a/src/windows/identity/uilib/khactiondef.h b/src/windows/identity/uilib/khactiondef.h
new file mode 100644 (file)
index 0000000..d01eb2a
--- /dev/null
@@ -0,0 +1,134 @@
+/*\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
diff --git a/src/windows/identity/uilib/khalerts.h b/src/windows/identity/uilib/khalerts.h
new file mode 100644 (file)
index 0000000..c41dddf
--- /dev/null
@@ -0,0 +1,372 @@
+/*\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
diff --git a/src/windows/identity/uilib/khconfigui.h b/src/windows/identity/uilib/khconfigui.h
new file mode 100644 (file)
index 0000000..9a96d41
--- /dev/null
@@ -0,0 +1,588 @@
+/*\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
diff --git a/src/windows/identity/uilib/khhtlink.h b/src/windows/identity/uilib/khhtlink.h
new file mode 100644 (file)
index 0000000..dcbf328
--- /dev/null
@@ -0,0 +1,58 @@
+/*\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
diff --git a/src/windows/identity/uilib/khnewcred.h b/src/windows/identity/uilib/khnewcred.h
new file mode 100644 (file)
index 0000000..1742f4a
--- /dev/null
@@ -0,0 +1,896 @@
+/*\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
diff --git a/src/windows/identity/uilib/khprops.h b/src/windows/identity/uilib/khprops.h
new file mode 100644 (file)
index 0000000..b772690
--- /dev/null
@@ -0,0 +1,202 @@
+/*\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
diff --git a/src/windows/identity/uilib/khremote.h b/src/windows/identity/uilib/khremote.h
new file mode 100644 (file)
index 0000000..a5b9d67
--- /dev/null
@@ -0,0 +1,84 @@
+/*\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
diff --git a/src/windows/identity/uilib/khrescache.h b/src/windows/identity/uilib/khrescache.h
new file mode 100644 (file)
index 0000000..96bec88
--- /dev/null
@@ -0,0 +1,100 @@
+/*\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
diff --git a/src/windows/identity/uilib/khtracker.h b/src/windows/identity/uilib/khtracker.h
new file mode 100644 (file)
index 0000000..f03d2b4
--- /dev/null
@@ -0,0 +1,113 @@
+/*\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
diff --git a/src/windows/identity/uilib/khuidefs.h b/src/windows/identity/uilib/khuidefs.h
new file mode 100644 (file)
index 0000000..d92eb64
--- /dev/null
@@ -0,0 +1,58 @@
+/*\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
diff --git a/src/windows/identity/uilib/propsheet.c b/src/windows/identity/uilib/propsheet.c
new file mode 100644 (file)
index 0000000..749aa53
--- /dev/null
@@ -0,0 +1,188 @@
+/*\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
diff --git a/src/windows/identity/uilib/propwnd.c b/src/windows/identity/uilib/propwnd.c
new file mode 100644 (file)
index 0000000..4d5d548
--- /dev/null
@@ -0,0 +1,37 @@
+/*\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
diff --git a/src/windows/identity/uilib/rescache.c b/src/windows/identity/uilib/rescache.c
new file mode 100644 (file)
index 0000000..57ff309
--- /dev/null
@@ -0,0 +1,301 @@
+/*\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
diff --git a/src/windows/identity/uilib/trackerwnd.c b/src/windows/identity/uilib/trackerwnd.c
new file mode 100644 (file)
index 0000000..04de096
--- /dev/null
@@ -0,0 +1,453 @@
+/*\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
diff --git a/src/windows/identity/uilib/uilibmain.c b/src/windows/identity/uilib/uilibmain.c
new file mode 100644 (file)
index 0000000..65fa7af
--- /dev/null
@@ -0,0 +1,41 @@
+/*\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
diff --git a/src/windows/identity/util/Makefile b/src/windows/identity/util/Makefile
new file mode 100644 (file)
index 0000000..b9fc80e
--- /dev/null
@@ -0,0 +1,46 @@
+#\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
diff --git a/src/windows/identity/util/hashtable.c b/src/windows/identity/util/hashtable.c
new file mode 100644 (file)
index 0000000..41f785a
--- /dev/null
@@ -0,0 +1,167 @@
+/*\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
diff --git a/src/windows/identity/util/hashtable.h b/src/windows/identity/util/hashtable.h
new file mode 100644 (file)
index 0000000..179d311
--- /dev/null
@@ -0,0 +1,223 @@
+/*\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 &lt; \a key2\r
+    - \b Positive if \a key1 &gt; \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
diff --git a/src/windows/identity/util/mstring.c b/src/windows/identity/util/mstring.c
new file mode 100644 (file)
index 0000000..e9120d6
--- /dev/null
@@ -0,0 +1,516 @@
+/*\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
diff --git a/src/windows/identity/util/mstring.h b/src/windows/identity/util/mstring.h
new file mode 100644 (file)
index 0000000..9b4e380
--- /dev/null
@@ -0,0 +1,361 @@
+/*\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
diff --git a/src/windows/identity/util/sync.c b/src/windows/identity/util/sync.c
new file mode 100644 (file)
index 0000000..b50d484
--- /dev/null
@@ -0,0 +1,121 @@
+/*\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
diff --git a/src/windows/identity/util/sync.h b/src/windows/identity/util/sync.h
new file mode 100644 (file)
index 0000000..5410d0e
--- /dev/null
@@ -0,0 +1,128 @@
+/*\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
diff --git a/src/windows/identity/util/utils.h b/src/windows/identity/util/utils.h
new file mode 100644 (file)
index 0000000..2e3b6b7
--- /dev/null
@@ -0,0 +1,36 @@
+/*\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