! KMQ_RCPTTYPE_HWND\r
! KMQ_QUEUE_FLAG_DELETED\r
# Macros not internal\r
+\r
+! khc_value_exists()\r
+# Behavior change with respect to shadowed handles. If a value\r
+# doesn't exist in the top level handle, then each shadowed handle\r
+# will be tried in turn until the value is found.\r
# Version info\r
NETIDMGR_VERSION_MAJOR=1\r
NETIDMGR_VERSION_MINOR=1\r
-NETIDMGR_VERSION_PATCH=10\r
+NETIDMGR_VERSION_PATCH=11\r
NETIDMGR_VERSION_AUX=0\r
NETIDMGR_RELEASEDESC=\r
\r
# Version info\r
NETIDMGR_VERSION_MAJOR=1\r
NETIDMGR_VERSION_MINOR=1\r
-NETIDMGR_VERSION_PATCH=10\r
+NETIDMGR_VERSION_PATCH=11\r
NETIDMGR_VERSION_AUX=0\r
NETIDMGR_RELEASEDESC=\r
\r
#define QNEXT(pe) ((pe)->prev)\r
#define QPREV(pe) ((pe)->next)\r
\r
+#define QINSERT(pt, pre, pe) \\r
+ do { \\r
+ if ((pre) == NULL || \\r
+ QNEXT(pre) == NULL) { QPUT(pt, pe); } \\r
+ else { \\r
+ (pe)->prev = (pre)->prev; \\r
+ (pe)->next = (pre); \\r
+ (pre)->prev->next = (pe); \\r
+ (pre)->prev = (pe); \\r
+ }} while(0)\r
+\r
/* Trees with FIFO child lists */\r
#define TQDCL(type) \\r
LDCL(type); \\r
\r
#define TQINIT(pe) \\r
do { \\r
+ LINIT(pe); \\r
QINIT(pe); \\r
(pe)->parent = NULL; } while(0)\r
\r
-#define TQADDCHILD(pt,pe) \\r
+#define TQPUTCHILD(pt,pe) \\r
do { \\r
QPUT((pt), (pe)); \\r
(pe)->parent = (pt); } while(0)\r
\r
+#define TQINSERT(pt, pre, pe) \\r
+ do { \\r
+ QINSERT(pt, pre, pe); \\r
+ (pe)->parent = (pt); } while(0)\r
+\r
+#define TQGETCHILD(pt,ppe) \\r
+ do { \\r
+ QGET(pt, ppe); \\r
+ if (*(ppe)) { *(ppe)->parent = NULL; } \\r
+ } while(0)\r
+\r
+#define TQDELCHILD(pt, pe) \\r
+ do { \\r
+ QDEL(pt, pe); \\r
+ (pe)->parent = NULL; } while(0)\r
+\r
#define TQFIRSTCHILD(pt) ((pt)?QTOP(pt):NULL)\r
\r
+#define TQNEXTCHILD(pe) QNEXT(pe)\r
+\r
+#define TQPREVCHILD(pe) QPREV(pe)\r
+\r
#define TQPARENT(pe) ((pe)?(pe)->parent:NULL)\r
\r
#endif\r
#define KMSG_ACT_ACTIVATE 6\r
\r
/*! \brief Internal */\r
-#define KMSG_ACT_BEGIN_CMDLINE 128\r
+#define KMSG_ACT_BEGIN_CMDLINE 128\r
\r
/*! \brief Internal */\r
-#define KMSG_ACT_CONTINUE_CMDLINE 129\r
+#define KMSG_ACT_CONTINUE_CMDLINE 129\r
\r
/*! \brief Internal */\r
-#define KMSG_ACT_SYNC_CFG 130\r
+#define KMSG_ACT_SYNC_CFG 130\r
+\r
+/*! \brief Internal */\r
+#define KMSG_ACT_END_CMDLINE 131\r
\r
/*@}*/\r
\r
if(!khc_is_handle(conf))\r
return KHM_ERROR_INVALID_PARAM;\r
\r
- c = khc_space_from_handle(conf);\r
+ do {\r
+ c = khc_space_from_handle(conf);\r
\r
- if (khc_is_user_handle(conf))\r
- hku = khcint_space_open_key(c, KHM_PERM_READ);\r
- if (khc_is_machine_handle(conf))\r
- hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);\r
+ if (khc_is_user_handle(conf))\r
+ hku = khcint_space_open_key(c, KHM_PERM_READ);\r
+ if (khc_is_machine_handle(conf))\r
+ hkm = khcint_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
+ 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 && khc_is_schema_handle(conf)) {\r
- for(i=0; i<c->nSchema; i++) {\r
- if(!wcscmp(c->schema[i].name, value)) {\r
- rv |= KCONF_FLAG_SCHEMA;\r
- break;\r
+ if(c->schema && khc_is_schema_handle(conf)) {\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
+\r
+ /* if the value is not found at this level and the handle is\r
+ shadowed, try the next level down. */\r
+ if (rv == 0 && khc_is_shadowed(conf))\r
+ conf = khc_shadow(conf);\r
+ else\r
+ break;\r
+ } while (conf);\r
\r
return rv;\r
}\r
configuration stores that were specified when opening the\r
configuration space corresponding to \a conf.\r
\r
+ If the specified handle is shadowed (see khc_shadow_space()) and\r
+ the value is not found in any of the visible stores for the\r
+ topmost handle, each of the shadowed handles will be tried in turn\r
+ until the value is found. The return value will correspond to the\r
+ handle where the value is first found.\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
StringCbCopy(id->name, namesize, name);\r
\r
id->flags = (flags & KCDB_IDENT_FLAGMASK_RDWR);\r
- id->flags |= KCDB_IDENT_FLAG_ACTIVE;\r
+ id->flags |= KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY;\r
LINIT(id);\r
\r
EnterCriticalSection(&cs_ident);\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
+DECL_FUNC_PTR(krb5_string_to_deltat);\r
\r
// Krb524 functions\r
DECL_FUNC_PTR(krb524_init_ets);\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_get_integer);\r
DECL_FUNC_PTR(profile_get_values);\r
DECL_FUNC_PTR(profile_get_relation_names);\r
DECL_FUNC_PTR(profile_clear_relation);\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
+ MAKE_FUNC_INFO(krb5_string_to_deltat),\r
END_FUNC_INFO\r
};\r
\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_get_integer),\r
MAKE_FUNC_INFO(profile_get_values),\r
MAKE_FUNC_INFO(profile_get_relation_names),\r
MAKE_FUNC_INFO(profile_clear_relation),\r
/* Dynamic imports */\r
#include<khdefs.h>\r
#include<tlhelp32.h>\r
+\r
+#if _WIN32_WINNT < 0x0501\r
+#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT\r
+#undef _WIN32_WINNT\r
+#define _WIN32_WINNT 0x0501\r
+#endif\r
#include<ntsecapi.h>\r
+#ifdef KHM_SAVE_WIN32_WINNT\r
+#undef _WIN32_WINNT\r
+#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT\r
+#undef KHM_SAVE_WIN32_WINNT\r
+#endif\r
\r
extern HINSTANCE hKrb4;\r
extern HINSTANCE hKrb5;\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
+extern DECL_FUNC_PTR(krb5_string_to_deltat);\r
\r
// Krb524 functions\r
extern DECL_FUNC_PTR(krb524_init_ets);\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_get_integer);\r
extern DECL_FUNC_PTR(profile_get_values);\r
extern DECL_FUNC_PTR(profile_get_relation_names);\r
extern DECL_FUNC_PTR(profile_clear_relation);\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
- if (*cache != NULL)\r
+ if (*cache != NULL) {\r
(*pkrb5_cc_close)(*ctx, *cache);\r
+ *cache = NULL;\r
+ }\r
}\r
return rc;\r
}\r
\r
#define SECURITY_WIN32\r
#include <security.h>\r
-#include <ntsecapi.h>\r
\r
#include <string.h>\r
#include <time.h>\r
#include <windows.h>\r
#define SECURITY_WIN32\r
#include <security.h>\r
-#include <ntsecapi.h>\r
+\r
+#if _WIN32_WINNT < 0x0501\r
+#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT\r
+#undef _WIN32_WINNT\r
+#define _WIN32_WINNT 0x0501\r
+#endif\r
+#include<ntsecapi.h>\r
+#ifdef KHM_SAVE_WIN32_WINNT\r
+#undef _WIN32_WINNT\r
+#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT\r
+#undef KHM_SAVE_WIN32_WINNT\r
+#endif\r
\r
#include <krb5common.h>\r
\r
FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
BEGIN\r
CONTROL "Obtain Kerberos v4 credentials for this identity",IDC_CFG_GETTIX,\r
- "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,7,147,10\r
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,7,165,10\r
END\r
\r
\r
#define K5_CDFLAG_MOD_INC_REALMS 0x00000100
#define K5_CDFLAG_MOD_REALMS 0x00001000
-static const char *const conf_yes[] = {
- "y", "yes", "true", "t", "1", "on",
- 0,
-};
-
-static const char *const conf_no[] = {
- "n", "no", "false", "nil", "0", "off",
- 0,
-};
-
-int
-k5_parse_boolean(const char *s)
-{
- const char *const *p;
-
- for(p=conf_yes; *p; p++) {
- if (!_stricmp(*p,s))
- return 1;
- }
-
- for(p=conf_no; *p; p++) {
- if (!_stricmp(*p,s))
- return 0;
- }
-
- /* Default to "no" */
- return 0;
-}
-
void
k5_init_config_data(k5_config_data * d) {
ZeroMemory(d, sizeof(*d));
rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_kdc",
NULL, NULL, &boolv);
if (!rv && boolv) {
- d->dns_lookup_kdc = k5_parse_boolean(boolv);
+ khm_boolean b;
+
+ if (!khm_krb5_parse_boolean(boolv, &b))
+ d->dns_lookup_kdc = b;
+ else
+ d->dns_lookup_kdc = FALSE;
pprofile_release_string(boolv);
} else
d->dns_lookup_kdc = FALSE;
rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_realm",
NULL, NULL, &boolv);
if (!rv && boolv) {
- d->dns_lookup_realm = k5_parse_boolean(boolv);
+ khm_boolean b;
+
+ if (!khm_krb5_parse_boolean(boolv, &b))
+ d->dns_lookup_realm = b;
+ else
+ d->dns_lookup_realm = FALSE;
pprofile_release_string(boolv);
} else
d->dns_lookup_realm = FALSE;
rv = pprofile_get_string(profile, "libdefaults", "dns_fallback",
NULL, NULL, &boolv);
if (!rv && boolv) {
- d->dns_fallback = k5_parse_boolean(boolv);
+ khm_boolean b;
+
+ if (!khm_krb5_parse_boolean(boolv, &b))
+ d->dns_fallback = b;
+ else
+ d->dns_fallback = FALSE;
pprofile_release_string(boolv);
} else
d->dns_fallback = FALSE;
rv = pprofile_get_string(profile, "libdefaults", "noaddresses",
NULL, NULL, &boolv);
if (!rv && boolv) {
- d->noaddresses = k5_parse_boolean(boolv);
+ khm_boolean b;
+
+ if (!khm_krb5_parse_boolean(boolv, &b))
+ d->noaddresses = b;
+ else
+ d->noaddresses = TRUE;
pprofile_release_string(boolv);
} else
d->noaddresses = TRUE;
rv = pprofile_add_relation(profile, sec_libdefaults,
(d->dns_lookup_kdc)?
- conf_yes[0]:
- conf_no[0]);
+ KRB5_CONF_YES:
+ KRB5_CONF_NO);
d->flags &= ~K5_CDFLAG_MOD_DNS_LOOKUP_KDC;
}
rv = pprofile_add_relation(profile, sec_libdefaults,
(d->dns_lookup_realm)?
- conf_yes[0]:
- conf_no[0]);
+ KRB5_CONF_YES:
+ KRB5_CONF_NO);
d->flags &= ~K5_CDFLAG_MOD_DNS_LOOKUP_RLM;
}
rv = pprofile_add_relation(profile, sec_libdefaults,
(d->dns_fallback)?
- conf_yes[0]:
- conf_no[0]);
+ KRB5_CONF_YES:
+ KRB5_CONF_NO);
d->flags &= ~K5_CDFLAG_MOD_DNS_FALLBACK;
}
rv = pprofile_add_relation(profile, sec_libdefaults,
(d->noaddresses)?
- conf_yes[0]:
- conf_no[0]);
+ KRB5_CONF_YES:
+ KRB5_CONF_NO);
d->flags &= ~K5_CDFLAG_MOD_NOADDRESSES;
}
\r
#define SECURITY_WIN32\r
#include <security.h>\r
-#include <ntsecapi.h>\r
\r
#include <string.h>\r
#include <time.h>\r
krb5_creds my_creds;\r
krb5_data *realm = NULL;\r
wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
- char cidname[KCDB_IDENT_MAXCCH_NAME];\r
khm_size cb;\r
\r
memset(&my_creds, 0, sizeof(krb5_creds));\r
kcdb_identity_get_name(identity, idname, &cb);\r
\r
if (khm_krb5_get_identity_flags(identity) & K5IDFLAG_IMPORTED) {\r
+#ifdef REIMPORT_MSLSA_CREDS\r
/* we are trying to renew the identity that was imported from\r
MSLSA: */\r
BOOL imported;\r
+ char cidname[KCDB_IDENT_MAXCCH_NAME];\r
\r
UnicodeStrToAnsi(cidname, sizeof(cidname), idname);\r
\r
\r
/* if the import failed, then we try to renew the identity via\r
the usual procedure. */\r
+#else\r
+ /* if we are suppressing further imports from MSLSA, we just\r
+ skip renewing this identity. */\r
+ goto cleanup;\r
+#endif\r
}\r
\r
code = khm_krb5_initialize(identity, &ctx, &cc);\r
\r
wname[0] = L'\0';\r
\r
- kcdb_identity_get_config(ident, 0, &idconfig);\r
+ kcdb_identity_get_config(ident, KHM_FLAG_CREATE, &idconfig);\r
if (idconfig == NULL)\r
goto _done_checking_config;\r
\r
- khc_open_space(idconfig, CSNAME_KRB5CRED, 0, &k5config);\r
+ khc_open_space(idconfig, CSNAME_KRB5CRED, KHM_FLAG_CREATE, &k5config);\r
if (k5config == NULL)\r
goto _done_checking_config;\r
\r
\r
return code;\r
}\r
+\r
+/*\r
+\r
+ The configuration information for each identity comes from a\r
+ multitude of layers organized as follows. The ordering is\r
+ decreasing in priority. When looking up a value, the value will be\r
+ looked up in each layer in turn starting at level 0. The first\r
+ instance of the value found will be the effective value.\r
+\r
+ 0 : <identity configuration>\Krb5Cred\r
+\r
+ 0.1: per user\r
+\r
+ 0.2: per machine\r
+\r
+ 1 : <plugin configuration>\Parameters\Realms\<realm of identity>\r
+\r
+ 1.1: per user\r
+\r
+ 1.2: per machine\r
+\r
+ 2 : <plugin configuration>\Parameters\r
+\r
+ 2.1: per user\r
+\r
+ 2.2: per machine\r
+\r
+ 2.3: schema\r
+\r
+ */\r
+khm_int32\r
+khm_krb5_get_identity_config(khm_handle ident,\r
+ khm_int32 flags,\r
+ khm_handle * ret_csp) {\r
+\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle csp_i = NULL;\r
+ khm_handle csp_ik5 = NULL;\r
+ khm_handle csp_realms = NULL;\r
+ khm_handle csp_realm = NULL;\r
+ khm_handle csp_plugins = NULL;\r
+ khm_handle csp_krbcfg = NULL;\r
+ khm_handle csp_rv = NULL;\r
+ wchar_t realm[KCDB_IDENT_MAXCCH_NAME];\r
+\r
+ realm[0] = L'\0';\r
+\r
+ if (ident) {\r
+ wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t * trealm;\r
+ khm_size cb_idname = sizeof(idname);\r
+\r
+ rv = kcdb_identity_get_name(ident, idname, &cb_idname);\r
+ if (KHM_SUCCEEDED(rv) &&\r
+ (trealm = khm_get_realm_from_princ(idname)) != NULL) {\r
+ StringCbCopy(realm, sizeof(realm), trealm);\r
+ }\r
+ }\r
+\r
+ if (ident) {\r
+ rv = kcdb_identity_get_config(ident, flags, &csp_i);\r
+ if (KHM_FAILED(rv))\r
+ goto done;\r
+\r
+ rv = khc_open_space(csp_i, CSNAME_KRB5CRED, flags, &csp_ik5);\r
+ if (KHM_FAILED(rv))\r
+ goto done;\r
+\r
+ if (realm[0] == L'\0')\r
+ goto done_shadow_realm;\r
+\r
+ rv = khc_open_space(csp_params, CSNAME_REALMS, flags, &csp_realms);\r
+ if (KHM_FAILED(rv))\r
+ goto done_shadow_realm;\r
+\r
+ rv = khc_open_space(csp_realms, realm, flags, &csp_realm);\r
+ if (KHM_FAILED(rv))\r
+ goto done_shadow_realm;\r
+\r
+ rv = khc_shadow_space(csp_realm, csp_params);\r
+\r
+ done_shadow_realm:\r
+\r
+ if (csp_realm)\r
+ rv = khc_shadow_space(csp_ik5, csp_realm);\r
+ else\r
+ rv = khc_shadow_space(csp_ik5, csp_params);\r
+\r
+ csp_rv = csp_ik5;\r
+\r
+ } else {\r
+\r
+ /* No valid identity specified. We default to the parameters key. */\r
+ rv = kmm_get_plugins_config(0, &csp_plugins);\r
+ if (KHM_FAILED(rv))\r
+ goto done;\r
+\r
+ rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, flags, &csp_krbcfg);\r
+ if (KHM_FAILED(rv))\r
+ goto done;\r
+\r
+ rv = khc_open_space(csp_krbcfg, CSNAME_PARAMS, flags, &csp_rv);\r
+ }\r
+\r
+ done:\r
+\r
+ *ret_csp = csp_rv;\r
+\r
+ /* leave csp_ik5. If it's non-NULL, then it's the return value */\r
+ /* leave csp_rv. It's the return value. */\r
+ if (csp_i)\r
+ khc_close_space(csp_i);\r
+ if (csp_realms)\r
+ khc_close_space(csp_realms);\r
+ if (csp_realm)\r
+ khc_close_space(csp_realm);\r
+ if (csp_plugins)\r
+ khc_close_space(csp_plugins);\r
+ if (csp_krbcfg)\r
+ khc_close_space(csp_krbcfg);\r
+\r
+ return rv;\r
+}\r
+\r
+khm_int32\r
+khm_krb5_get_identity_params(khm_handle ident, k5_params * p) {\r
+\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle csp_id = NULL;\r
+ khm_int32 regf = 0;\r
+ khm_int32 proff = 0;\r
+ khm_int32 e;\r
+ khm_int32 v;\r
+ CHAR confname[MAX_PATH];\r
+\r
+ ZeroMemory(p, sizeof(*p));\r
+\r
+ rv = khm_krb5_get_identity_config(ident, 0, &csp_id);\r
+ if (KHM_FAILED(rv))\r
+ goto done_reg;\r
+\r
+\r
+#define GETVAL(vname, vfield, flag) \\r
+ do { \\r
+ e = khc_value_exists(csp_id, vname); \\r
+ rv = khc_read_int32(csp_id, vname, &v); \\r
+ if (KHM_FAILED(rv)) goto done_reg; \\r
+ p->vfield = v; \\r
+ if ((e & ~KCONF_FLAG_SCHEMA) != 0) regf |= flag; \\r
+ } while(FALSE)\r
+\r
+ /* Flags */\r
+ GETVAL(L"Renewable", renewable, K5PARAM_F_RENEW);\r
+ GETVAL(L"Forwardable", forwardable, K5PARAM_F_FORW);\r
+ GETVAL(L"Proxiable", proxiable, K5PARAM_F_PROX);\r
+ GETVAL(L"Addressless", addressless, K5PARAM_F_ADDL);\r
+ GETVAL(L"PublicIP", publicIP, K5PARAM_F_PUBIP);\r
+\r
+ /* Lifetime */\r
+ GETVAL(L"DefaultLifetime", lifetime, K5PARAM_F_LIFE);\r
+ GETVAL(L"MaxLifetime", lifetime_max, K5PARAM_F_LIFE_H);\r
+ GETVAL(L"MinLifetime", lifetime_min, K5PARAM_F_LIFE_L);\r
+\r
+ /* Renewable lifetime */\r
+ GETVAL(L"DefaultRenewLifetime", renew_life, K5PARAM_F_RLIFE);\r
+ GETVAL(L"MaxRenewLifetime", renew_life_max, K5PARAM_F_RLIFE_H);\r
+ GETVAL(L"MinRenewLifetime", renew_life_min, K5PARAM_F_RLIFE_L);\r
+\r
+#undef GETVAL\r
+\r
+ done_reg:\r
+\r
+ if (csp_id)\r
+ khc_close_space(csp_id);\r
+\r
+ /* if all the parameters were read from the registry, then we have\r
+ no reason to read from the profile file. */\r
+ if (regf == K5PARAM_FM_ALL) {\r
+ p->source_reg = regf;\r
+ return KHM_ERROR_SUCCESS;\r
+ }\r
+\r
+ if (rv)\r
+ return rv;\r
+\r
+ /* If we get here, then some of the settings we read from the\r
+ configuration actually came from the schema. In other words,\r
+ the values weren't really defined for this identity. So we now\r
+ have to read the values from the krb5 configuration file. */\r
+\r
+ if (!khm_krb5_get_profile_file(confname, sizeof(confname))) {\r
+ profile_t profile;\r
+ const char * filenames[2];\r
+ long retval;\r
+\r
+ filenames[0] = confname;\r
+ filenames[1] = NULL;\r
+\r
+ if (!pprofile_init(filenames, &profile)) {\r
+\r
+ /* default ticket lifetime */\r
+ if (!(regf & K5PARAM_F_LIFE)) {\r
+ char * value = NULL;\r
+ retval = pprofile_get_string(profile, "libdefaults", "ticket_lifetime", 0, 0, &value);\r
+ if (retval == 0 && value) {\r
+ krb5_deltat d;\r
+\r
+ retval = pkrb5_string_to_deltat(value, &d);\r
+ if (retval == KRB5_DELTAT_BADFORMAT) {\r
+ /* Historically some sites use relations of\r
+ the form 'ticket_lifetime = 24000' where\r
+ the unit is left out but is assumed to be\r
+ seconds. Then there are other sites which\r
+ use the form 'ticket_lifetime = 600' where\r
+ the unit is assumed to be minutes. While\r
+ these are technically wrong (a unit needs\r
+ to be specified), we try to accomodate for\r
+ this using the safe assumption that the\r
+ unit is seconds and tack an 's' to the end\r
+ and see if that works. */\r
+\r
+ size_t cch;\r
+ char tmpbuf[256];\r
+ char * buf;\r
+\r
+ do {\r
+ if (FAILED(StringCchLengthA(value, 1024 /* unresonably large size */,\r
+ &cch)))\r
+ break;\r
+\r
+ cch += sizeof(char) * 2; /* NULL and new 's' */\r
+ if (cch > ARRAYLENGTH(tmpbuf))\r
+ buf = PMALLOC(cch * sizeof(char));\r
+ else\r
+ buf = tmpbuf;\r
+\r
+ StringCchCopyA(buf, cch, value);\r
+ StringCchCatA(buf, cch, "s");\r
+\r
+ retval = pkrb5_string_to_deltat(buf, &d);\r
+ if (retval == 0) {\r
+ p->lifetime = d;\r
+ proff |= K5PARAM_F_LIFE;\r
+ }\r
+\r
+ if (buf != tmpbuf)\r
+ PFREE(buf);\r
+\r
+ } while(0);\r
+\r
+ } else if (retval == 0) {\r
+ p->lifetime = d;\r
+ proff |= K5PARAM_F_LIFE;\r
+ }\r
+ pprofile_release_string(value);\r
+ }\r
+ }\r
+\r
+ if (!(regf & K5PARAM_F_RLIFE)) {\r
+ char * value = NULL;\r
+ retval = pprofile_get_string(profile, "libdefaults", "renew_lifetime", 0, 0, &value);\r
+ if (retval == 0 && value) {\r
+ krb5_deltat d;\r
+\r
+ retval = pkrb5_string_to_deltat(value, &d);\r
+ if (retval == 0) {\r
+ p->renew_life = d;\r
+ proff |= K5PARAM_F_RLIFE;\r
+ }\r
+ pprofile_release_string(value);\r
+ }\r
+ }\r
+\r
+ if (!(regf & K5PARAM_F_FORW)) {\r
+ char * value = NULL;\r
+ retval = pprofile_get_string(profile, "libdefaults", "forwardable", 0, 0, &value);\r
+ if (retval == 0 && value) {\r
+ khm_boolean b;\r
+\r
+ if (!khm_krb5_parse_boolean(value, &b))\r
+ p->forwardable = b;\r
+ else\r
+ p->forwardable = FALSE;\r
+ pprofile_release_string(value);\r
+ proff |= K5PARAM_F_FORW;\r
+ }\r
+ }\r
+\r
+ if (!(regf & K5PARAM_F_RENEW)) {\r
+ char * value = NULL;\r
+ retval = pprofile_get_string(profile, "libdefaults", "renewable", 0, 0, &value);\r
+\r
+ if (retval == 0 && value) {\r
+ khm_boolean b;\r
+\r
+ if (!khm_krb5_parse_boolean(value, &b))\r
+ p->renewable = b;\r
+ else\r
+ p->renewable = TRUE;\r
+ pprofile_release_string(value);\r
+ proff |= K5PARAM_F_RENEW;\r
+ }\r
+ }\r
+\r
+ if (!(regf & K5PARAM_F_ADDL)) {\r
+ char * value = NULL;\r
+ retval = pprofile_get_string(profile, "libdefaults", "noaddresses", 0, 0, &value);\r
+\r
+ if (retval == 0 && value) {\r
+ khm_boolean b;\r
+\r
+ if (!khm_krb5_parse_boolean(value, &b))\r
+ p->addressless = b;\r
+ else\r
+ p->addressless = TRUE;\r
+ pprofile_release_string(value);\r
+ proff |= K5PARAM_F_ADDL;\r
+ }\r
+ }\r
+\r
+ if (!(regf & K5PARAM_F_PROX)) {\r
+ char * value = NULL;\r
+ retval = pprofile_get_string(profile, "libdefaults", "proxiable", 0, 0, &value);\r
+\r
+ if (retval == 0 && value) {\r
+ khm_boolean b;\r
+\r
+ if (!khm_krb5_parse_boolean(value, &b))\r
+ p->proxiable = b;\r
+ else\r
+ p->proxiable = FALSE;\r
+ pprofile_release_string(value);\r
+ proff |= K5PARAM_F_PROX;\r
+ }\r
+ }\r
+\r
+ pprofile_release(profile);\r
+ }\r
+ }\r
+\r
+ p->source_reg = regf;\r
+ p->source_prof = proff;\r
+\r
+ return rv;\r
+}\r
+\r
+/* Note that p->source_reg and p->source_prof is used in special ways\r
+ here. All fields that are flagged in source_reg will be written to\r
+ the configuration (if they are different from what\r
+ khm_krb5_get_identity_params() reports). All fields that are\r
+ flagged in source_prof will be removed from the configuration\r
+ (thereby exposing the value defined in the profile file). */\r
+khm_int32\r
+khm_krb5_set_identity_params(khm_handle ident, const k5_params * p) {\r
+ khm_int32 rv = KHM_ERROR_SUCCESS;\r
+ khm_handle csp_id = NULL;\r
+ k5_params p_s;\r
+ khm_int32 source_reg = p->source_reg;\r
+ khm_int32 source_prof = p->source_prof;\r
+\r
+ rv = khm_krb5_get_identity_config(ident,\r
+ KHM_PERM_WRITE | KHM_FLAG_CREATE |\r
+ KCONF_FLAG_WRITEIFMOD,\r
+ &csp_id);\r
+ if (KHM_FAILED(rv))\r
+ goto done_reg;\r
+\r
+ khm_krb5_get_identity_params(ident, &p_s);\r
+\r
+ /* Remove any bits that don't make sense. Not all values can be\r
+ specified in the profile file. */\r
+ source_prof &= K5PARAM_FM_PROF;\r
+\r
+ /* if a flag appears in both source_prof and source_reg, remove\r
+ the flag from source_reg. */\r
+ source_reg &= ~source_prof;\r
+\r
+ /* we only write values that have changed, and that are flagged in\r
+ source_reg */\r
+\r
+ if ((source_reg & K5PARAM_F_RENEW) &&\r
+ !!p_s.renewable != !!p->renewable)\r
+ khc_write_int32(csp_id, L"Renewable", !!p->renewable);\r
+\r
+ if ((source_reg & K5PARAM_F_FORW) &&\r
+ !!p_s.forwardable != !!p->forwardable)\r
+ khc_write_int32(csp_id, L"Forwardable", !!p->forwardable);\r
+\r
+ if ((source_reg & K5PARAM_F_PROX) &&\r
+ !!p_s.proxiable != !!p->proxiable)\r
+ khc_write_int32(csp_id, L"Proxiable", !!p->proxiable);\r
+\r
+ if ((source_reg & K5PARAM_F_ADDL) &&\r
+ !!p_s.addressless != !!p->addressless)\r
+ khc_write_int32(csp_id, L"Addressless", !!p->addressless);\r
+\r
+ if ((source_reg & K5PARAM_F_PUBIP) &&\r
+ p_s.publicIP != p->publicIP)\r
+ khc_write_int32(csp_id, L"PublicIP", p->publicIP);\r
+\r
+ if ((source_reg & K5PARAM_F_LIFE) &&\r
+ p_s.lifetime != p->lifetime)\r
+ khc_write_int32(csp_id, L"DefaultLifetime", p->lifetime);\r
+\r
+ if ((source_reg & K5PARAM_F_LIFE_H) &&\r
+ p_s.lifetime_max != p->lifetime_max)\r
+ khc_write_int32(csp_id, L"MaxLifetime", p->lifetime_max);\r
+\r
+ if ((source_reg & K5PARAM_F_LIFE_L) &&\r
+ p_s.lifetime_min != p->lifetime_min)\r
+ khc_write_int32(csp_id, L"MinLifetime", p->lifetime_min);\r
+\r
+ if ((source_reg & K5PARAM_F_RLIFE) &&\r
+ p_s.renew_life != p->renew_life)\r
+ khc_write_int32(csp_id, L"DefaultRenewLifetime", p->renew_life);\r
+\r
+ if ((source_reg & K5PARAM_F_RLIFE_H) &&\r
+ p_s.renew_life_max != p->renew_life_max)\r
+ khc_write_int32(csp_id, L"MaxRenewLifetime", p->renew_life_max);\r
+\r
+ if ((source_reg & K5PARAM_F_RLIFE_L) &&\r
+ p_s.renew_life_min != p->renew_life_min)\r
+ khc_write_int32(csp_id, L"MinRenewLifetime", p->renew_life_min);\r
+\r
+ /* and now, remove the values that are present in source_prof.\r
+ Not all values are removed since not all values can be\r
+ specified in the profile file. */\r
+ if (source_prof & K5PARAM_F_RENEW)\r
+ khc_remove_value(csp_id, L"Renewable", 0);\r
+\r
+ if (source_prof & K5PARAM_F_FORW)\r
+ khc_remove_value(csp_id, L"Forwardable", 0);\r
+\r
+ if (source_prof & K5PARAM_F_PROX)\r
+ khc_remove_value(csp_id, L"Proxiable", 0);\r
+\r
+ if (source_prof & K5PARAM_F_ADDL)\r
+ khc_remove_value(csp_id, L"Addressless", 0);\r
+\r
+ if (source_prof & K5PARAM_F_LIFE)\r
+ khc_remove_value(csp_id, L"DefaultLifetime", 0);\r
+\r
+ if (source_prof & K5PARAM_F_RLIFE)\r
+ khc_remove_value(csp_id, L"DefaultRenewLifetime", 0);\r
+\r
+ done_reg:\r
+ if (csp_id != NULL)\r
+ khc_close_space(csp_id);\r
+\r
+ return rv;\r
+}\r
+\r
+static const char *const conf_yes[] = {\r
+ "y", "yes", "true", "t", "1", "on",\r
+ 0,\r
+};\r
+\r
+static const char *const conf_no[] = {\r
+ "n", "no", "false", "nil", "0", "off",\r
+ 0,\r
+};\r
+\r
+int\r
+khm_krb5_parse_boolean(const char *s, khm_boolean * b)\r
+{\r
+ const char *const *p;\r
+\r
+ for(p=conf_yes; *p; p++) {\r
+ if (!_stricmp(*p,s)) {\r
+ *b = TRUE;\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ for(p=conf_no; *p; p++) {\r
+ if (!_stricmp(*p,s)) {\r
+ *b = FALSE;\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ /* Default to "no" */\r
+ return KHM_ERROR_INVALID_PARAM;\r
+}\r
#include <windows.h>\r
#define SECURITY_WIN32\r
#include <security.h>\r
-#include <ntsecapi.h>\r
+\r
+#if _WIN32_WINNT < 0x0501\r
+#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT\r
+#undef _WIN32_WINNT\r
+#define _WIN32_WINNT 0x0501\r
+#endif\r
+#include<ntsecapi.h>\r
+#ifdef KHM_SAVE_WIN32_WINNT\r
+#undef _WIN32_WINNT\r
+#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT\r
+#undef KHM_SAVE_WIN32_WINNT\r
+#endif\r
\r
#include <krb5common.h>\r
\r
\r
#define KRB5_MAXCCH_CCNAME 1024\r
\r
-// Function Prototypes.\r
+#define KRB5_CONF_YES "yes"\r
+#define KRB5_CONF_NO "no"\r
+\r
+typedef struct tag_k5params {\r
+\r
+ khm_int32 source_reg; /* flags indicating which fields were\r
+ retrieved using the registry */\r
+ khm_int32 source_prof; /* flags indicating which fields were\r
+ retrieved using krb5.ini */\r
+\r
+ khm_boolean renewable;\r
+ khm_boolean forwardable;\r
+ khm_boolean proxiable;\r
+ khm_boolean addressless;\r
+\r
+ khm_ui_4 publicIP;\r
+\r
+ krb5_deltat lifetime;\r
+ krb5_deltat lifetime_min;\r
+ krb5_deltat lifetime_max;\r
+\r
+ krb5_deltat renew_life;\r
+ krb5_deltat renew_life_min;\r
+ krb5_deltat renew_life_max;\r
+\r
+} k5_params;\r
+\r
+#define K5PARAM_F_RENEW 0x00000001\r
+#define K5PARAM_F_FORW 0x00000002\r
+#define K5PARAM_F_PROX 0x00000004\r
+#define K5PARAM_F_ADDL 0x00000008\r
+#define K5PARAM_F_PUBIP 0x00000010\r
+#define K5PARAM_F_LIFE 0x00000020\r
+#define K5PARAM_F_RLIFE 0x00000040\r
+#define K5PARAM_F_LIFE_L 0x00000080\r
+#define K5PARAM_F_LIFE_H 0x00000100\r
+#define K5PARAM_F_RLIFE_L 0x00000200\r
+#define K5PARAM_F_RLIFE_H 0x00000400\r
+\r
+#define K5PARAM_FM_ALL 0x000007ff\r
+#define K5PARAM_FM_PROF 0x0000007f\r
+ \r
+/* Credential and principal operations */\r
\r
BOOL \r
khm_krb5_ms2mit(char * match_princ,\r
int \r
khm_krb5_renew_ident(khm_handle identity);\r
\r
-wchar_t * \r
-khm_krb5_get_default_realm(void);\r
-\r
-long\r
-khm_krb5_set_default_realm(wchar_t * realm);\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
+khm_krb5_get_temp_ccache(krb5_context ctx,\r
+ krb5_ccache * cc);\r
\r
-int \r
-khm_krb5_cc_name_cmp(const wchar_t * cc_name_1,\r
- const wchar_t * cc_name_2);\r
+khm_int32 KHMAPI\r
+khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy);\r
+\r
+\r
+/* Configuration */\r
\r
BOOL \r
khm_krb5_get_profile_file(LPSTR confname, UINT szConfname);\r
BOOL \r
khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname);\r
\r
-khm_int32 KHMAPI\r
-khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy);\r
+wchar_t * \r
+khm_krb5_get_default_realm(void);\r
+\r
+long\r
+khm_krb5_set_default_realm(wchar_t * realm);\r
+\r
+wchar_t * \r
+khm_krb5_get_realm_list(void);\r
+\r
+khm_int32\r
+khm_krb5_get_identity_config(khm_handle ident,\r
+ khm_int32 flags,\r
+ khm_handle * ret_csp);\r
\r
void\r
khm_krb5_set_identity_flags(khm_handle identity,\r
khm_int32\r
khm_krb5_get_identity_flags(khm_handle identity);\r
\r
+khm_int32\r
+khm_krb5_set_identity_params(khm_handle ident, const k5_params * p);\r
+\r
+khm_int32\r
+khm_krb5_get_identity_params(khm_handle ident, k5_params * p);\r
+\r
+/* Utility */\r
+\r
+wchar_t * \r
+khm_get_realm_from_princ(wchar_t * princ);\r
+\r
long\r
-khm_krb5_get_temp_ccache(krb5_context ctx,\r
- krb5_ccache * cc);\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
+int\r
+khm_krb5_parse_boolean(const char *s, khm_boolean * b);\r
+\r
#endif\r
_reportf(L" g_fjob.valid_principal = %d", (int) g_fjob.valid_principal);\r
#endif\r
\r
+ /* If we don't know if we have a valid principal, we\r
+ restrict the options that are set when we call kinit.\r
+ This way we will be able to use the response from the\r
+ KDC to verify the principal. */\r
+\r
+ g_fjob.retry_if_valid_principal = (g_fjob.forwardable ||\r
+ g_fjob.proxiable ||\r
+ g_fjob.renewable);\r
+\r
+ retry_kinit:\r
g_fjob.code =\r
khm_krb5_kinit(0,\r
g_fjob.principal,\r
g_fjob.password,\r
g_fjob.ccache,\r
g_fjob.lifetime,\r
- g_fjob.valid_principal ? g_fjob.forwardable : 0,\r
- g_fjob.valid_principal ? g_fjob.proxiable : 0,\r
+ g_fjob.valid_principal ? g_fjob.forwardable : 0,\r
+ g_fjob.valid_principal ? g_fjob.proxiable : 0,\r
(g_fjob.valid_principal && 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
+ /* If the principal was found to be valid, and if we\r
+ restricted the options that were being passed to kinit,\r
+ then we need to retry the kinit call. This time we use\r
+ the real options. */\r
+ if (g_fjob.state == FIBER_STATE_RETRY_KINIT) {\r
+#ifdef DEBUG\r
+ assert(g_fjob.valid_principal);\r
+#endif\r
+ g_fjob.state = FIBER_STATE_KINIT;\r
+ goto retry_kinit;\r
+ }\r
}\r
\r
_switch_to_main:\r
#endif\r
\r
/* we got prompts? Then we assume that the principal is valid */\r
- g_fjob.valid_principal = TRUE;\r
+\r
+ if (!g_fjob.valid_principal) {\r
+ g_fjob.valid_principal = TRUE;\r
+\r
+ /* if the flags that were used to call kinit were restricted\r
+ because we didn't know the validity of the principal, then\r
+ we need to go back and retry the call with the correct\r
+ flags. */\r
+ if (g_fjob.retry_if_valid_principal) {\r
+ _reportf(L"Retrying kinit call due to restricted flags on first call.");\r
+ g_fjob.state = FIBER_STATE_RETRY_KINIT;\r
+ return KRB5_LIBOS_PWDINTR;\r
+ }\r
+ }\r
\r
nc = g_fjob.nc;\r
\r
actual acquisition of credentials. */\r
if(g_fjob.command != FIBER_CMD_CONTINUE &&\r
g_fjob.command != FIBER_CMD_KINIT) {\r
- code = -2;\r
+ code = KRB5_LIBOS_PWDINTR;\r
goto _exit;\r
}\r
\r
\r
/* entering a NULL password is equivalent to cancelling out */\r
if (g_fjob.null_password)\r
- return -2;\r
+ return KRB5_LIBOS_PWDINTR;\r
else\r
return code;\r
}\r
\r
-/*\r
-\r
- The configuration information for each identity comes from a\r
- multitude of layers organized as follows. The ordering is\r
- decreasing in priority. When looking up a value, the value will be\r
- looked up in each layer in turn starting at level 0. The first\r
- instance of the value found will be the effective value.\r
-\r
- 0 : <identity configuration>\Krb5Cred\r
-\r
- 0.1: per user\r
-\r
- 0.2: per machine\r
-\r
- 1 : <plugin configuration>\Parameters\Realms\<realm of identity>\r
-\r
- 1.1: per user\r
-\r
- 1.2: per machine\r
-\r
- 2 : <plugin configuration>\Parameters\r
-\r
- 2.1: per user\r
-\r
- 2.2: per machine\r
-\r
- 2.3: schema\r
-\r
- */\r
-khm_int32\r
-k5_open_config_handle(khm_handle ident,\r
- khm_int32 flags,\r
- khm_handle * ret_csp) {\r
-\r
- khm_int32 rv = KHM_ERROR_SUCCESS;\r
- khm_handle csp_i = NULL;\r
- khm_handle csp_ik5 = NULL;\r
- khm_handle csp_realms = NULL;\r
- khm_handle csp_realm = NULL;\r
- khm_handle csp_plugins = NULL;\r
- khm_handle csp_krbcfg = NULL;\r
- khm_handle csp_rv = NULL;\r
- wchar_t realm[KCDB_IDENT_MAXCCH_NAME];\r
-\r
- realm[0] = L'\0';\r
-\r
- if (ident) {\r
- wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
- wchar_t * trealm;\r
- khm_size cb_idname = sizeof(idname);\r
-\r
- rv = kcdb_identity_get_name(ident, idname, &cb_idname);\r
- if (KHM_SUCCEEDED(rv) &&\r
- (trealm = khm_get_realm_from_princ(idname)) != NULL) {\r
- StringCbCopy(realm, sizeof(realm), trealm);\r
- }\r
- }\r
-\r
- if (ident) {\r
- rv = kcdb_identity_get_config(ident, flags, &csp_i);\r
- if (KHM_FAILED(rv))\r
- goto done;\r
-\r
- rv = khc_open_space(csp_i, CSNAME_KRB5CRED, flags, &csp_ik5);\r
- if (KHM_FAILED(rv))\r
- goto done;\r
-\r
- if (realm[0] == L'\0')\r
- goto done_shadow_realm;\r
-\r
- rv = khc_open_space(csp_params, CSNAME_REALMS, flags, &csp_realms);\r
- if (KHM_FAILED(rv))\r
- goto done_shadow_realm;\r
-\r
- rv = khc_open_space(csp_realms, realm, flags, &csp_realm);\r
- if (KHM_FAILED(rv))\r
- goto done_shadow_realm;\r
-\r
- rv = khc_shadow_space(csp_realm, csp_params);\r
\r
- done_shadow_realm:\r
-\r
- if (csp_realm)\r
- rv = khc_shadow_space(csp_ik5, csp_realm);\r
- else\r
- rv = khc_shadow_space(csp_ik5, csp_params);\r
-\r
- csp_rv = csp_ik5;\r
-\r
- } else {\r
-\r
- /* No valid identity specified. We default to the parameters key. */\r
- rv = kmm_get_plugins_config(0, &csp_plugins);\r
- if (KHM_FAILED(rv))\r
- goto done;\r
-\r
- rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, flags, &csp_krbcfg);\r
- if (KHM_FAILED(rv))\r
- goto done;\r
-\r
- rv = khc_open_space(csp_krbcfg, CSNAME_PARAMS, flags, &csp_rv);\r
- }\r
-\r
- done:\r
+void \r
+k5_read_dlg_params(k5_dlg_data * d, khm_handle identity)\r
+{\r
+ k5_params p;\r
\r
- *ret_csp = csp_rv;\r
+ khm_krb5_get_identity_params(identity, &p);\r
\r
- /* leave csp_ik5. If it's non-NULL, then it's the return value */\r
- /* leave csp_rv. It's the return value. */\r
- if (csp_i)\r
- khc_close_space(csp_i);\r
- if (csp_realms)\r
- khc_close_space(csp_realms);\r
- if (csp_realm)\r
- khc_close_space(csp_realm);\r
- if (csp_plugins)\r
- khc_close_space(csp_plugins);\r
- if (csp_krbcfg)\r
- khc_close_space(csp_krbcfg);\r
+ d->renewable = p.renewable;\r
+ d->forwardable = p.forwardable;\r
+ d->proxiable = p.proxiable;\r
+ d->addressless = p.addressless;\r
+ d->publicIP = p.publicIP;\r
\r
- return rv;\r
-}\r
+ d->tc_lifetime.current = p.lifetime;\r
+ d->tc_lifetime.max = p.lifetime_max;\r
+ d->tc_lifetime.min = p.lifetime_min;\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", &i);\r
- d->renewable = i;\r
- khc_read_int32(conf, L"Forwardable", &i);\r
- d->forwardable = i;\r
- khc_read_int32(conf, L"Proxiable", &i);\r
- d->proxiable = i;\r
- khc_read_int32(conf, L"Addressless", &i);\r
- d->addressless = i;\r
- khc_read_int32(conf, L"PublicIP", &i);\r
- d->publicIP = i;\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
+ d->tc_renew.current = p.renew_life;\r
+ d->tc_renew.max = p.renew_life_max;\r
+ d->tc_renew.min = p.renew_life_min;\r
\r
/* however, if this has externally supplied defaults, we have to\r
use them too. */\r
}\r
\r
void \r
-k5_write_dlg_params(khm_handle conf, \r
- k5_dlg_data * d)\r
+k5_write_dlg_params(k5_dlg_data * d, khm_handle identity)\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
- khc_write_int32(conf, L"PublicIP", d->publicIP);\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
+ k5_params p;\r
+\r
+ ZeroMemory(&p, sizeof(p));\r
+\r
+ p.source_reg = K5PARAM_FM_ALL; /* we want to write all the\r
+ settings to the registry, if\r
+ necessary. */\r
+\r
+ p.renewable = d->renewable;\r
+ p.forwardable = d->forwardable;\r
+ p.proxiable = d->proxiable;\r
+ p.addressless = d->addressless;\r
+ p.publicIP = d->publicIP;\r
+\r
+ p.lifetime = (krb5_deltat) d->tc_lifetime.current;\r
+ p.lifetime_max = (krb5_deltat) d->tc_lifetime.max;\r
+ p.lifetime_min = (krb5_deltat) d->tc_lifetime.min;\r
+\r
+ p.renew_life = (krb5_deltat) d->tc_renew.current;\r
+ p.renew_life_max = (krb5_deltat) d->tc_renew.max;\r
+ p.renew_life_min = (krb5_deltat) d->tc_renew.min;\r
+\r
+ khm_krb5_set_identity_params(identity, &p);\r
\r
/* as in k5_read_dlg_params, once we write the data in, the local\r
data is no longer dirty */\r
g_fjob.identity = ident;\r
g_fjob.prompt_set = 0;\r
g_fjob.valid_principal = FALSE;\r
+ g_fjob.retry_if_valid_principal = FALSE;\r
+\r
+ /* the value for\r
+ retry_if_valid_principal is not\r
+ necessarily the correct value here,\r
+ but the correct value will be\r
+ assigned k5_kinit_fiber_proc(). */\r
\r
/* if we have external parameters, we should use them as well */\r
if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) &&\r
}\r
\r
if (nc->subtype == KMSG_CRED_NEW_CREDS) {\r
- k5_read_dlg_params(csp_params, d);\r
+ k5_read_dlg_params(d, NULL);\r
}\r
\r
PostMessage(hwnd, KHUI_WM_NC_NOTIFY, \r
if(/* !d->dirty && */ nc->n_identities > 0 &&\r
nc->subtype == KMSG_CRED_NEW_CREDS) {\r
\r
- khm_handle h_idcfg = NULL;\r
-\r
- do {\r
- if (KHM_FAILED\r
- (k5_open_config_handle(nc->identities[0],\r
- 0, &h_idcfg)))\r
- break;\r
-\r
- k5_read_dlg_params(h_idcfg, d);\r
-\r
- PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, \r
- MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);\r
- } while(FALSE);\r
+ k5_read_dlg_params(d, nc->identities[0]);\r
\r
- if(h_idcfg)\r
- khc_close_space(h_idcfg);\r
+ PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, \r
+ MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);\r
}\r
\r
khui_cw_unlock_nc(nc);\r
if (d->pwd_change)\r
return KHM_ERROR_SUCCESS;\r
\r
- /* At this point, we assume that the current set of\r
- prompts is no longer valid. And since we might not be\r
- able to come up with a set of prompts until the KDC\r
- replies (unless we have cached prompts), we remove the\r
- ones that are already shown. */\r
+#if 0\r
+ /* Clearing the prompts at this point is a bad idea since\r
+ the prompter depends on the prompts to know if this set\r
+ of prompts is the same as the new set and if so, use\r
+ the values entered in the old prompts as responses to\r
+ the new one. */\r
khui_cw_clear_prompts(nc);\r
+#endif\r
\r
/* if the fiber is already in a kinit, cancel it */\r
if(g_fjob.state == FIBER_STATE_KINIT) {\r
NULL)))) {\r
_reportf(L"No password entered, but a valid TGT exists. Continuing");\r
g_fjob.code = 0;\r
- }\r
+ } else if (g_fjob.state == FIBER_STATE_NONE &&\r
+ g_fjob.code == 0 &&\r
+ nc->n_identities > 0 &&\r
+ nc->identities[0] != NULL) {\r
+\r
+ /* we had a password and we used it to get\r
+ tickets. We should reset the IMPORTED flag now\r
+ since the tickets are not imported. */\r
+\r
+ khm_krb5_set_identity_flags(nc->identities[0],\r
+ K5IDFLAG_IMPORTED,\r
+ 0);\r
+ }\r
\r
if(g_fjob.code != 0) {\r
wchar_t tbuf[1024];\r
\r
} else if (nc->result == KHUI_NC_RESULT_PROCESS &&\r
g_fjob.state == FIBER_STATE_NONE) {\r
- khm_handle csp_idcfg = NULL;\r
krb5_context ctx = NULL;\r
\r
_reportf(L"Tickets successfully acquired");\r
assert(nc->n_identities > 0);\r
assert(nc->identities[0]);\r
\r
- if (KHM_SUCCEEDED\r
- (k5_open_config_handle(nc->identities[0],\r
- KHM_FLAG_CREATE |\r
- KCONF_FLAG_WRITEIFMOD,\r
- &csp_idcfg))) {\r
- k5_write_dlg_params(csp_idcfg, d);\r
- }\r
-\r
- if(csp_idcfg != NULL)\r
- khc_close_space(csp_idcfg);\r
+ k5_write_dlg_params(d, nc->identities[0]);\r
\r
/* We should also quickly refresh the credentials\r
so that the identity flags and ccache\r
/* since this was just a password change,\r
we need to load new credentials options\r
from the configuration store. */\r
- \r
- if (KHM_SUCCEEDED\r
- (k5_open_config_handle(nc->identities[0],\r
- KHM_FLAG_CREATE |\r
- KCONF_FLAG_WRITEIFMOD,\r
- &csp_idcfg))) {\r
- k5_read_dlg_params(csp_idcfg, d);\r
- khc_close_space(csp_idcfg);\r
- csp_idcfg = NULL;\r
- }\r
+\r
+ k5_read_dlg_params(d, nc->identities[0]);\r
}\r
\r
/* the password change phase is now done */\r
\r
/* save the settings that we used for\r
obtaining the ticket. */\r
- if (nc->subtype == KMSG_CRED_NEW_CREDS &&\r
- KHM_SUCCEEDED\r
- (k5_open_config_handle(nc->identities[0],\r
- KHM_FLAG_CREATE |\r
- KCONF_FLAG_WRITEIFMOD,\r
- &csp_idcfg))) {\r
- k5_write_dlg_params(csp_idcfg, d);\r
- khc_close_space(csp_idcfg);\r
+ if (nc->subtype == KMSG_CRED_NEW_CREDS) {\r
+\r
+ k5_write_dlg_params(d, nc->identities[0]);\r
\r
/* and then update the LRU too */\r
k5_update_LRU(nc->identities[0]);\r
\r
BOOL null_password;\r
BOOL valid_principal;\r
+ BOOL retry_if_valid_principal;\r
} fiber_job;\r
\r
extern fiber_job g_fjob; /* global fiber job object */\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
+#define FIBER_STATE_NONE 0\r
+#define FIBER_STATE_KINIT 1\r
+#define FIBER_STATE_RETRY_KINIT 2\r
\r
#define K5_SET_CRED_MSG WMNC_USER\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_CREDTEXT_0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Tickets for realm %s</p>"\r
IDS_KRB5_CCNAME_SHORT_DESC "Kerberos v5 CCache"\r
IDS_KEY_ENCTYPE_SHORT_DESC "Session EncType"\r
IDS_TKT_ENCTYPE_SHORT_DESC "Service EncType"\r
/////////////////////////////////////////////////////////////////////////////\r
#endif // not APSTUDIO_INVOKED\r
\r
+\r
shell32.lib \
htmlhelp.lib \
iphlpapi.lib \
- shlwapi.lib
+ shlwapi.lib \
+ msimg32.lib
$(OBJ)\uiconfig.c: uiconfig.csv $(CONFDIR)\csvschema.cfg
$(CCSV) $** $@
BOOL auto_detect_net;\r
BOOL log_to_file;\r
BOOL destroy_creds;\r
+ khm_int32 notif_action;\r
} cfg_data;\r
\r
typedef struct tag_dlg_data {\r
khc_read_int32(csp_cw, L"DestroyCredsOnExit", &t);\r
d->destroy_creds = !!t;\r
\r
+ khc_read_int32(csp_cw, L"NotificationAction", &t);\r
+ d->notif_action = t;\r
+\r
khc_close_space(csp_cw);\r
\r
dd->work = *d;\r
applied = TRUE;\r
}\r
\r
+ if (d->notif_action != s->notif_action) {\r
+ khc_write_int32(csp_cw, L"NotificationAction", d->notif_action);\r
+ applied = TRUE;\r
+ }\r
+\r
khc_close_space(csp_cw);\r
\r
khui_cfg_set_flags(dd->node,\r
!!d->keep_running != !!s->keep_running ||\r
!!d->auto_detect_net != !!s->auto_detect_net ||\r
!!d->log_to_file != !!s->log_to_file ||\r
- !!d->destroy_creds != !!s->destroy_creds) {\r
+ !!d->destroy_creds != !!s->destroy_creds ||\r
+ d->notif_action != s->notif_action) {\r
\r
khui_cfg_set_flags(dd->node,\r
KHUI_CNFLAG_MODIFIED,\r
}\r
}\r
\r
+\r
+static void\r
+strip_ampersands(wchar_t * str) {\r
+ wchar_t *f, *t;\r
+\r
+ for(f = t = str; *f; f++)\r
+ if (*f != L'&')\r
+ *t++ = *f;\r
+\r
+ *t = L'\0';\r
+}\r
+\r
static void\r
refresh_view(HWND hwnd, dlg_data * d) {\r
wchar_t buf[512];\r
+ khm_size i;\r
\r
CheckDlgButton(hwnd, IDC_CFG_AUTOINIT,\r
(d->work.auto_init?BST_CHECKED:BST_UNCHECKED));\r
CheckDlgButton(hwnd, IDC_CFG_DESTROYALL,\r
(d->work.destroy_creds?BST_CHECKED:BST_UNCHECKED));\r
\r
+ /* we need populate the notification action combo box control and\r
+ set the current selection to match the default action. */\r
+\r
+ if (n_khm_notifier_actions != SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION,\r
+ CB_GETCOUNT, 0, 0)) {\r
+\r
+ for (i=0; i < n_khm_notifier_actions; i++) {\r
+ int idx;\r
+\r
+ khm_get_action_caption(khm_notifier_actions[i],\r
+ buf, sizeof(buf));\r
+\r
+ strip_ampersands(buf);\r
+\r
+ idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION,\r
+ CB_INSERTSTRING, i,\r
+ (LPARAM) buf);\r
+\r
+#ifdef DEBUG\r
+ if (idx != (int) i) {\r
+ assert(FALSE);\r
+ }\r
+#endif\r
+ }\r
+ }\r
+\r
+ for (i=0; i < n_khm_notifier_actions; i++) {\r
+ if (khm_notifier_actions[i] == d->work.notif_action)\r
+ break;\r
+ }\r
+\r
+ if (i >= n_khm_notifier_actions) {\r
+ d->work.notif_action = khm_notifier_actions[0];\r
+ i = 0;\r
+ }\r
+\r
+ SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, CB_SETCURSEL, i, 0);\r
+\r
/* in addition, we correct the label on the trace log control to\r
reflect the actual path that is going to get used */\r
if (GetDlgItemText(hwnd, IDC_CFG_LOGPATH, buf,\r
\r
static void\r
refresh_data(HWND hwnd, dlg_data * d) {\r
+ int idx;\r
+\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.destroy_creds = (IsDlgButtonChecked(hwnd, IDC_CFG_DESTROYALL)\r
== BST_CHECKED);\r
+\r
+ idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, CB_GETCURSEL, 0, 0);\r
+ if (idx < 0)\r
+ idx = 0;\r
+ else if (idx >= (int) n_khm_notifier_actions)\r
+ idx = (int) n_khm_notifier_actions - 1;\r
+\r
+ d->work.notif_action = khm_notifier_actions[idx];\r
}\r
\r
INT_PTR CALLBACK\r
refresh_data(hwnd, d);\r
check_for_modification(d);\r
}\r
+ } else if (HIWORD(wParam) == CBN_SELCHANGE) {\r
+ refresh_data(hwnd, d);\r
+ check_for_modification(d);\r
}\r
\r
khm_set_dialog_result(hwnd, 0);\r
static LONG init_dialog = 0;\r
static khm_int32 dialog_result = 0;\r
static wchar_t dialog_identity[KCDB_IDENT_MAXCCH_NAME];\r
+static khui_new_creds * dialog_nc = NULL;\r
\r
static void\r
dialog_sync_init(void) {\r
\r
EnterCriticalSection(&cs_dialog);\r
\r
- if (in_dialog)\r
+ if (in_dialog) {\r
rv = FALSE;\r
- else {\r
+\r
+ /* if a dialog is being displayed and we got a another request\r
+ to show one, we bring the existing one to the\r
+ foreground. */\r
+ if (dialog_nc && dialog_nc->hwnd) {\r
+ khm_int32 t = 0;\r
+\r
+ if (KHM_SUCCEEDED(khc_read_int32(NULL,\r
+ L"CredWindow\\Windows\\NewCred\\ForceToTop",\r
+ &t)) &&\r
+ t != 0) {\r
+\r
+ khm_activate_main_window();\r
+\r
+ SetWindowPos(dialog_nc->hwnd, HWND_TOP, 0, 0, 0, 0,\r
+ (SWP_NOMOVE | SWP_NOSIZE));\r
+ }\r
+ }\r
+\r
+ } else {\r
rv = TRUE;\r
in_dialog = TRUE;\r
ResetEvent(in_dialog_evt);\r
SetEvent(in_dialog_evt);\r
}\r
dialog_result = nc->result;\r
+#ifdef DEBUG\r
+ assert(dialog_nc == nc);\r
+#endif\r
+ dialog_nc = NULL;\r
if (nc->subtype == KMSG_CRED_NEW_CREDS &&\r
nc->n_identities > 0 &&\r
nc->identities[0]) {\r
if(evt->suggestion)\r
khui_alert_set_suggestion(alert, evt->suggestion);\r
\r
+ if (nc->subtype == KMSG_CRED_RENEW_CREDS &&\r
+ nc->ctx.identity != NULL) {\r
+\r
+ khm_int32 n_cmd;\r
+\r
+ n_cmd = khm_get_identity_new_creds_action(nc->ctx.identity);\r
+\r
+ if (n_cmd != 0) {\r
+ khui_alert_add_command(alert, n_cmd);\r
+ khui_alert_add_command(alert, KHUI_PACTION_CLOSE);\r
+\r
+ khui_alert_set_flags(alert, KHUI_ALERT_FLAG_DISPATCH_CMD,\r
+ KHUI_ALERT_FLAG_DISPATCH_CMD);\r
+ }\r
+ }\r
+\r
khui_alert_show(alert);\r
khui_alert_release(alert);\r
\r
\r
khui_cw_create_cred_blob(&nc);\r
nc->subtype = KMSG_CRED_PASSWORD;\r
+ dialog_nc = nc;\r
\r
khui_context_get(&nc->ctx);\r
\r
}\r
}\r
\r
+void\r
+khm_cred_obtain_new_creds_for_ident(khm_handle ident, wchar_t * title)\r
+{\r
+ khui_action_context ctx;\r
+\r
+ if (ident == NULL)\r
+ khm_cred_obtain_new_creds(title);\r
+\r
+ khui_context_get(&ctx);\r
+\r
+ khui_context_set(KHUI_SCOPE_IDENT,\r
+ ident,\r
+ KCDB_CREDTYPE_INVALID,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ NULL);\r
+\r
+ khm_cred_obtain_new_creds(title);\r
+\r
+ khui_context_set_indirect(&ctx);\r
+\r
+ khui_context_release(&ctx);\r
+}\r
+\r
void khm_cred_obtain_new_creds(wchar_t * title)\r
{\r
khui_new_creds * nc;\r
\r
khui_cw_create_cred_blob(&nc);\r
nc->subtype = KMSG_CRED_NEW_CREDS;\r
+ dialog_nc = nc;\r
\r
khui_context_get(&nc->ctx);\r
\r
line stuff */\r
khm_startup.processing = FALSE;\r
khm_startup.remote = FALSE;\r
+\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_END_CMDLINE, 0, 0);\r
} while(FALSE);\r
\r
if (defident)\r
void \r
khm_cred_obtain_new_creds(wchar_t * window_title);\r
\r
+void\r
+khm_cred_obtain_new_creds_for_ident(khm_handle ident, wchar_t * title);\r
+\r
void \r
khm_cred_set_default(void);\r
\r
int i;\r
HDC hdc;\r
LOGFONT log_font;\r
+ khm_int32 t;\r
+ const wchar_t * viewval;\r
\r
tbl->hwnd = hwnd;\r
\r
+ if (khm_main_wnd_mode == KHM_MAIN_WND_MINI)\r
+ viewval = L"DefaultViewMini";\r
+ else\r
+ viewval = L"DefaultView";\r
+\r
if(KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ | KHM_PERM_WRITE,\r
&hc_cw)))\r
return;\r
\r
if(!view) {\r
cbsize = sizeof(buf);\r
- if(KHM_FAILED(khc_read_string(hc_cw, L"DefaultView", buf, &cbsize)))\r
+ if(KHM_FAILED(khc_read_string(hc_cw, viewval, buf, &cbsize)))\r
goto _exit;\r
view = buf;\r
\r
else if (!wcscmp(view, L"Custom_0"))\r
khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT),\r
KHUI_ACTION_LAYOUT_CUST);\r
+ else if (!wcscmp(view, L"CompactIdentity"))\r
+ khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT),\r
+ KHUI_ACTION_LAYOUT_MINI);\r
\r
- kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); \r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0);\r
} else {\r
- khc_write_string(hc_cw, L"DefaultView", view);\r
+ khc_write_string(hc_cw, viewval, view);\r
}\r
\r
if(KHM_FAILED(khc_open_space(hc_vs, view, KHM_PERM_READ, &hc_v)))\r
\r
tbl->flags &= ~(KHUI_CW_TBL_CUSTVIEW | KHUI_CW_TBL_COLSKIP);\r
\r
+ if (KHM_SUCCEEDED(khc_read_int32(hc_v, L"ExpandedIdentity", &t)) && t) {\r
+ tbl->flags |= KHUI_CW_TBL_EXPIDENT;\r
+ } else {\r
+ tbl->flags &= ~KHUI_CW_TBL_EXPIDENT;\r
+ }\r
+\r
+ if (KHM_SUCCEEDED(khc_read_int32(hc_v, L"NoHeader", &t)) && t) {\r
+ tbl->flags |= KHUI_CW_TBL_NOHEADER;\r
+ } else {\r
+ tbl->flags &= ~KHUI_CW_TBL_NOHEADER;\r
+ }\r
+\r
iter = clist;\r
i = 0;\r
while(iter) {\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
+ tbl->cr_hdr_gray = RGB(128,128,128);\r
+ tbl->cr_hdr_gray_sel = RGB(240,240,240);\r
\r
tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 20, 8, 0);\r
{\r
We keep that open until the view is unloaded. */\r
}\r
\r
+khm_int32 KHMAPI\r
+cw_credset_iter_func(khm_handle cred, void * rock) {\r
+ khui_credwnd_tbl * tbl = (khui_credwnd_tbl *) rock;\r
+ khm_handle ident = NULL;\r
+ khm_size i;\r
+ khui_credwnd_ident * cwi = NULL;\r
+\r
+ kcdb_cred_get_identity(cred, &ident);\r
+\r
+ if (ident == NULL)\r
+ goto _cleanup;\r
+\r
+ for (i=0; i < tbl->n_idents; i++) {\r
+ if (kcdb_identity_is_equal(ident, tbl->idents[i].ident))\r
+ break;\r
+ }\r
+\r
+ if (i >= tbl->n_idents) {\r
+ khm_size cb;\r
+\r
+ /* need to add this one */\r
+ if (tbl->n_idents == tbl->nc_idents) {\r
+ tbl->nc_idents = UBOUNDSS(tbl->n_idents + 1,\r
+ CW_IDENT_ALLOC_INCR,\r
+ CW_IDENT_ALLOC_INCR);\r
+#ifdef DEBUG\r
+ assert(tbl->nc_idents > tbl->n_idents);\r
+#endif\r
+ tbl->idents = PREALLOC(tbl->idents, sizeof(tbl->idents[0]) * tbl->nc_idents);\r
+#ifdef DEBUG\r
+ assert(tbl->idents);\r
+#endif\r
+ ZeroMemory(&tbl->idents[tbl->n_idents],\r
+ sizeof(tbl->idents[0]) * (tbl->nc_idents - tbl->n_idents));\r
+ }\r
+\r
+ i = tbl->n_idents;\r
+ cwi = &tbl->idents[tbl->n_idents++];\r
+\r
+ cwi->ident = ident;\r
+ kcdb_identity_hold(ident);\r
+ cb = sizeof(cwi->name);\r
+ kcdb_identity_get_name(ident, cwi->name, &cb);\r
+ kcdb_identity_get_type(&cwi->credtype);\r
+ cb = sizeof(cwi->credtype_name);\r
+ kcdb_credtype_describe(cwi->credtype, cwi->credtype_name, &cb, KCDB_TS_SHORT);\r
+ cwi->credcount = 0;\r
+ }\r
+\r
+ cwi = &tbl->idents[i];\r
+\r
+ /* this is the first time we are seeing this */\r
+ if (cwi->credcount == 0) {\r
+ kcdb_identity_get_flags(cwi->ident, &cwi->ident_flags);\r
+ }\r
+\r
+ cwi->credcount++;\r
+\r
+ _cleanup:\r
+ if (ident)\r
+ kcdb_identity_release(ident);\r
+\r
+ return KHM_ERROR_SUCCESS;\r
+}\r
+\r
void \r
cw_update_creds(khui_credwnd_tbl * tbl)\r
{\r
}\r
}\r
\r
+ /* refresh the per-identity information */\r
+ for (i=0; i < (int) tbl->n_idents; i++) {\r
+ tbl->idents[i].credcount = 0;\r
+ }\r
+\r
+ kcdb_credset_apply(tbl->credset, cw_credset_iter_func, (void *) tbl);\r
+\r
if (fields)\r
PFREE(fields);\r
}\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
+ if ((tbl->flags & KHUI_CW_TBL_EXPIDENT) &&\r
+ tbl->cols[col].attr_id == KCDB_ATTR_ID_NAME)\r
+ tbl->rows[row].flags |= KHUI_CW_ROW_EXPVIEW;\r
}\r
\r
static int \r
ol->flags &= ~KHUI_CW_O_SHOWFLAG;\r
ol->flags &= ~KHUI_CW_O_STICKY;\r
\r
+ if (grouping[j] == tbl->n_cols - 1) {\r
+ ol->flags |= KHUI_CW_O_NOOUTLINE;\r
+ } else {\r
+ ol->flags &= ~KHUI_CW_O_NOOUTLINE;\r
+ }\r
+\r
if(selected) {\r
ol->flags |= KHUI_CW_O_SELECTED;\r
}\r
ol->flags |= KHUI_CW_O_SHOWFLAG;\r
expstate |= flags;\r
}\r
+\r
+ /* if we aren't showing any creds under this outline\r
+ level, we should also show any flags. */\r
+ else if (grouping[j] == tbl->n_cols - 1) {\r
+ ol->flags |= KHUI_CW_O_SHOWFLAG;\r
+ }\r
}\r
}\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
if (ol)\r
\r
flags = cw_get_buf_exp_flags(tbl, thiscred);\r
\r
- if(visible) {\r
+ if(visible && grouping[n_grouping - 1] < tbl->n_cols - 1) {\r
khm_int32 c_flags;\r
\r
cw_set_tbl_row_cred(tbl, n_rows, thiscred, \r
}\r
\r
tbl->cell_height = 0; /* recalculate cell height next time */\r
+\r
+ if (tbl->idents) {\r
+ khm_size i;\r
+\r
+ for (i=0; i < tbl->n_idents; i++) {\r
+ if (tbl->idents[i].ident) {\r
+ kcdb_identity_release(tbl->idents[i].ident);\r
+ }\r
+ }\r
+\r
+ PFREE(tbl->idents);\r
+ tbl->idents = NULL;\r
+ tbl->n_idents = 0;\r
+ tbl->nc_idents = 0;\r
+ }\r
}\r
\r
void \r
tbl->cell_height = height + tbl->vpad * 2;\r
}\r
\r
- ext_y = (int) tbl->n_rows * tbl->cell_height;\r
+ if (tbl->flags & KHUI_CW_TBL_EXPIDENT) {\r
+ ext_y = 0;\r
+\r
+ for (i=0; i < (int) tbl->n_rows; i++) {\r
+ if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW) {\r
+ ext_y += tbl->cell_height * CW_EXP_ROW_MULT;\r
+ } else {\r
+ ext_y += tbl->cell_height;\r
+ }\r
+ }\r
+ } else {\r
+ ext_y = (int) tbl->n_rows * tbl->cell_height;\r
+ }\r
\r
tbl->ext_width = ext_x;\r
tbl->ext_height = ext_y;\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_WOUTLINE) && \r
- tbl->mouse_row == row) {\r
- if(o->flags & KHUI_CW_O_EXPAND) {\r
- khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI,\r
- hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
- } else {\r
- khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI,\r
- 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,\r
- hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
+ } else if (!(o->flags & KHUI_CW_O_NOOUTLINE)) {\r
+ if((tbl->mouse_state & CW_MOUSE_WOUTLINE) && \r
+ tbl->mouse_row == row) {\r
+ if(o->flags & KHUI_CW_O_EXPAND) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI,\r
+ hdc, r->left,\r
+ r->bottom - (KHUI_SMICON_CY +\r
+ (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0);\r
+ } else {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI,\r
+ hdc, r->left,\r
+ r->bottom - (KHUI_SMICON_CY +\r
+ (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0);\r
+ }\r
} else {\r
- khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE,\r
- hdc, r->left, r->bottom - KHUI_SMICON_CY, 0);\r
+ if(o->flags & KHUI_CW_O_EXPAND) {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND,\r
+ hdc, r->left,\r
+ r->bottom - (KHUI_SMICON_CY +\r
+ (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0);\r
+ } else {\r
+ khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE,\r
+ hdc, r->left,\r
+ r->bottom - (KHUI_SMICON_CY +\r
+ (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0);\r
+ }\r
}\r
- }\r
\r
- r->left += KHUI_SMICON_CX * 3 / 2;\r
+ r->left += KHUI_SMICON_CX * 3 / 2;\r
+ }\r
\r
/* try to draw the icon, if there is one */\r
if(colattr == KCDB_ATTR_ID_NAME) {\r
IDB_WDG_STUCK:\r
IDB_WDG_STICK)),\r
hdc,\r
- r->left, r->bottom - KHUI_SMICON_CY,\r
+ r->left,\r
+ r->bottom - (KHUI_SMICON_CY +\r
+ (r->bottom - (r->top + KHUI_SMICON_CY)) / 2),\r
0);\r
\r
r->left += KHUI_SMICON_CX * 3 / 2;\r
IDB_ID_DIS_SM:\r
IDB_ID_SM), \r
hdc, \r
- r->left, r->bottom - KHUI_SMICON_CY, \r
+ r->left,\r
+ r->bottom - (KHUI_SMICON_CY +\r
+ (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), \r
0);\r
r->left += KHUI_SMICON_CX * 3 / 2 ;\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
+ if (!(cr->flags & KHUI_CW_ROW_EXPVIEW)) {\r
+\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
+ if (colattr == KCDB_ATTR_ID_NAME &&\r
+ (idf & KCDB_IDENT_FLAG_DEFAULT)) {\r
+ wchar_t defstr[64];\r
+ SIZE size;\r
+\r
+ LoadString(khm_hInstance, IDS_CW_DEFAULT,\r
+ defstr, ARRAYLENGTH(defstr));\r
+\r
+ GetTextExtentPoint32(hdc, o->header, (int) wcslen(o->header),\r
+ &size);\r
+\r
+ r->left += size.cx + KHUI_SMICON_CX * 2;\r
+\r
+ TextOut(hdc, r->left, r->bottom - tbl->vpad, \r
+ defstr, (int) wcslen(defstr));\r
+ }\r
+ } else {\r
+\r
+ RECT tr;\r
+ int len;\r
+\r
+ /* expanded view */\r
+#ifdef DEBUG\r
+ assert(colattr == KCDB_ATTR_ID_NAME);\r
+#endif\r
+\r
+ CopyRect(&tr, r);\r
+ tr.bottom -= (tr.bottom - tr.top) / 2; /* drawing two lines of text */\r
+\r
+ if (selected)\r
+ SetTextColor(hdc, tbl->cr_hdr_sel);\r
+ else\r
+ SetTextColor(hdc, tbl->cr_hdr_normal);\r
+\r
+ len = (int) wcslen(o->header);\r
+ DrawText(hdc, o->header, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);\r
+\r
+ if ((idf & KCDB_IDENT_FLAG_DEFAULT)) {\r
+ SIZE size;\r
+ int cx_id;\r
+ int cx_def;\r
+ wchar_t defstr[64];\r
+\r
+ LoadString(khm_hInstance, IDS_CW_DEFAULT,\r
+ defstr, ARRAYLENGTH(defstr));\r
+\r
+ GetTextExtentPoint32(hdc, o->header, (int) len, &size);\r
+ cx_id = size.cx;\r
+\r
+ len = (int) wcslen(defstr);\r
+ GetTextExtentPoint32(hdc, defstr, (int) len, &size);\r
+ cx_def = size.cx + KHUI_SMICON_CX / 2;\r
\r
- TextOut(hdc, r->left, r->bottom - tbl->vpad, o->header, (int) wcslen(o->header));\r
+ tr.left = max(tr.right - cx_def, tr.left + cx_id + KHUI_SMICON_CX * 2);\r
+ if (selected)\r
+ SetTextColor(hdc, tbl->cr_hdr_gray_sel);\r
+ else\r
+ SetTextColor(hdc, tbl->cr_hdr_gray);\r
+ DrawText(hdc, defstr, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);\r
+ }\r
+\r
+ CopyRect(&tr, r);\r
+ tr.top += (tr.bottom - tr.top) / 2;\r
\r
- if (colattr == KCDB_ATTR_ID_NAME &&\r
- (idf & KCDB_IDENT_FLAG_DEFAULT)) {\r
- wchar_t defstr[64];\r
- SIZE size;\r
+ if (0) {\r
+ khm_size i;\r
+ wchar_t buf[128];\r
\r
- LoadString(khm_hInstance, IDS_CW_DEFAULT,\r
- defstr, ARRAYLENGTH(defstr));\r
+ for (i = 0; i < tbl->n_idents; i++) {\r
+ if (kcdb_identity_is_equal(o->data, tbl->idents[i].ident))\r
+ break;\r
+ }\r
\r
- GetTextExtentPoint32(hdc, o->header, (int) wcslen(o->header),\r
- &size);\r
+ if (i < tbl->n_idents) {\r
+ khui_credwnd_ident * cwi;\r
+\r
+ cwi = &tbl->idents[i];\r
+\r
+ if (cwi->credcount == 0)\r
+ LoadString(khm_hInstance, IDS_IDEXPDISP_NOCRED,\r
+ buf, ARRAYLENGTH(buf));\r
+ else if (cwi->credcount == 1)\r
+ LoadString(khm_hInstance, IDS_IDEXPDISP_1CRED,\r
+ buf, ARRAYLENGTH(buf));\r
+ else {\r
+ wchar_t fmt[128];\r
+ LoadString(khm_hInstance, IDS_IDEXPDISP_NCRED,\r
+ fmt, ARRAYLENGTH(fmt));\r
+ StringCbPrintf(buf, sizeof(buf), fmt, (int) cwi->credcount);\r
+ }\r
+ }\r
\r
- r->left += size.cx + KHUI_SMICON_CX * 2;\r
+ len = (int) wcslen(buf);\r
\r
- TextOut(hdc, r->left, r->bottom - tbl->vpad, \r
- defstr, (int) wcslen(defstr));\r
+ if (selected)\r
+ SetTextColor(hdc, tbl->cr_hdr_gray_sel);\r
+ else\r
+ SetTextColor(hdc, tbl->cr_hdr_gray);\r
+ DrawText(hdc, buf, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);\r
+ }\r
}\r
}\r
\r
int flag_col = -1;\r
int d_x = -1;\r
int selected = 0;\r
+ int rowheight = 0;\r
BOOL has_dc = FALSE;\r
\r
tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0);\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
+ row_s = 0;\r
+ ys = 0;\r
+ row_e = (int) tbl->n_rows;\r
x = 0;\r
col_s = -1;\r
col_e = -1;\r
y = ys;\r
for(i=row_s; i < row_e; i++) {\r
selected = tbl->rows[i].flags & KHUI_CW_ROW_SELECTED;\r
+ rowheight = (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)? tbl->cell_height * CW_EXP_ROW_MULT : tbl->cell_height;\r
\r
if(tbl->cursor_row == i) {\r
if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER)\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
+ rh.bottom = y + rowheight;\r
if(rh.right > rh.left) {\r
cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK);\r
}\r
\r
x = xs;\r
rh.top = y;\r
- rh.bottom = y + tbl->cell_height;\r
+ rh.bottom = y + rowheight;\r
for(j=col_s; j < col_e; x += tbl->cols[j++].width) {\r
wchar_t buf[256];\r
khm_size cbbuf;\r
SelectFont(hdc, tbl->hf_normal);\r
}\r
\r
- y += tbl->cell_height;\r
+ y += rowheight;\r
\r
}\r
\r
x += tbl->scr_left;\r
y += tbl->scr_top - tbl->header_height;\r
\r
- row = y / tbl->cell_height;\r
+ if (tbl->flags & KHUI_CW_TBL_EXPIDENT) {\r
+ int ty = 0;\r
+\r
+ for (i=0; i < tbl->n_rows; i++) {\r
+ if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)\r
+ ty += tbl->cell_height * CW_EXP_ROW_MULT;\r
+ else\r
+ ty += tbl->cell_height;\r
+\r
+ if (ty > y)\r
+ break;\r
+ }\r
+\r
+ row = i;\r
+ } else {\r
+ row = y / tbl->cell_height;\r
+ }\r
+\r
col = -1;\r
nm_state = CW_MOUSE_NONE;\r
nm_row = nm_col = -1;\r
nm_row = row;\r
nm_col = col;\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
/* 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_WOUTLINE | CW_MOUSE_WIDGET;\r
- } else if (tbl->cols[tbl->rows[row].col].attr_id == \r
- KCDB_ATTR_ID_NAME &&\r
- col == tbl->rows[row].col &&\r
- x >= KHUI_SMICON_CX * 3 / 2 &&\r
- x < KHUI_SMICON_CX * 5 / 2){\r
- nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET;\r
- } else if (tbl->cols[tbl->rows[row].col].attr_id ==\r
- KCDB_ATTR_ID_NAME &&\r
- col == tbl->rows[row].col &&\r
- x >= KHUI_SMICON_CX * 3 &&\r
- x < KHUI_SMICON_CX * 4) {\r
- nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET;\r
+\r
+ if (!(o->flags & KHUI_CW_O_NOOUTLINE)) {\r
+ if(x >= 0 && x < KHUI_SMICON_CX) /* hit */ {\r
+ nm_state |= CW_MOUSE_WOUTLINE | CW_MOUSE_WIDGET;\r
+ } else if (tbl->cols[tbl->rows[row].col].attr_id == \r
+ KCDB_ATTR_ID_NAME &&\r
+ col == tbl->rows[row].col &&\r
+ x >= KHUI_SMICON_CX * 3 / 2 &&\r
+ x < KHUI_SMICON_CX * 5 / 2){\r
+ nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET;\r
+ } else if (tbl->cols[tbl->rows[row].col].attr_id ==\r
+ KCDB_ATTR_ID_NAME &&\r
+ col == tbl->rows[row].col &&\r
+ x >= KHUI_SMICON_CX * 3 &&\r
+ x < KHUI_SMICON_CX * 4) {\r
+ nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET;\r
+ }\r
+ } else if (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME) {\r
+ if (col == tbl->rows[row].col &&\r
+ x >= 0 &&\r
+ x < KHUI_SMICON_CX){\r
+\r
+ nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET;\r
+\r
+ } else if (col == tbl->rows[row].col &&\r
+ x >= KHUI_SMICON_CX * 3 / 2 &&\r
+ x < KHUI_SMICON_CX * 5 / 2) {\r
+ nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET;\r
+ }\r
}\r
}\r
}\r
InvalidateRect(tbl->hwnd, &r, TRUE);\r
}\r
if(tbl->mouse_state & CW_MOUSE_WSTICKY) {\r
- r.left = KHUI_SMICON_CX * 3 / 2 + \r
- tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
- r.top = tbl->mouse_row * tbl->cell_height + \r
- tbl->header_height - tbl->scr_top;\r
- r.right = r.left + KHUI_SMICON_CX;\r
- r.bottom = r.top + tbl->cell_height;\r
+ if (tbl->flags & KHUI_CW_TBL_EXPIDENT) {\r
+ int ty = 0;\r
+\r
+ for (i=0; i < tbl->n_rows && i < tbl->mouse_row; i++) {\r
+ if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)\r
+ ty += tbl->cell_height * CW_EXP_ROW_MULT;\r
+ else\r
+ ty += tbl->cell_height;\r
+ }\r
+\r
+ r.top = ty;\r
+\r
+ if (tbl->mouse_row < tbl->n_rows &&\r
+ (tbl->rows[tbl->mouse_row].flags & KHUI_CW_ROW_EXPVIEW)) {\r
+ r.bottom = r.top + tbl->cell_height * CW_EXP_ROW_MULT;\r
+ } else {\r
+ r.bottom = r.top + tbl->cell_height;\r
+ }\r
+\r
+ if (tbl->mouse_row < tbl->n_rows &&\r
+ (tbl->rows[tbl->mouse_row].flags & KHUI_CW_ROW_HEADER)) {\r
+ khui_credwnd_outline * o;\r
+\r
+ o = (khui_credwnd_outline *) tbl->rows[tbl->mouse_row].data;\r
+\r
+ if (o->flags & KHUI_CW_O_NOOUTLINE) {\r
+ r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ } else {\r
+ r.left = KHUI_SMICON_CX * 3 / 2 + tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ }\r
+ r.right = r.left + KHUI_SMICON_CX;\r
+ } else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+ } else {\r
+ r.left = KHUI_SMICON_CX * 3 / 2 + \r
+ tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ r.top = tbl->mouse_row * tbl->cell_height + \r
+ tbl->header_height - tbl->scr_top;\r
+ r.right = r.left + KHUI_SMICON_CX;\r
+ r.bottom = r.top + tbl->cell_height;\r
+ }\r
InvalidateRect(tbl->hwnd, &r, TRUE);\r
}\r
\r
InvalidateRect(tbl->hwnd, &r, TRUE);\r
}\r
if(tbl->mouse_state & CW_MOUSE_WSTICKY) {\r
- r.left = KHUI_SMICON_CX * 3 / 2 + \r
- tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
- r.top = tbl->mouse_row * tbl->cell_height + \r
- tbl->header_height - tbl->scr_top;\r
- r.right = r.left + KHUI_SMICON_CX;\r
- r.bottom = r.top + tbl->cell_height;\r
+ if (tbl->flags & KHUI_CW_TBL_EXPIDENT) {\r
+ int ty = 0;\r
+\r
+ for (i=0; i < tbl->n_rows && i < tbl->mouse_row; i++) {\r
+ if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)\r
+ ty += tbl->cell_height * CW_EXP_ROW_MULT;\r
+ else\r
+ ty += tbl->cell_height;\r
+ }\r
+\r
+ r.top = ty;\r
+\r
+ if (tbl->mouse_row < tbl->n_rows &&\r
+ (tbl->rows[tbl->mouse_row].flags & KHUI_CW_ROW_EXPVIEW)) {\r
+ r.bottom = r.top + tbl->cell_height * CW_EXP_ROW_MULT;\r
+ } else {\r
+ r.bottom = r.top + tbl->cell_height;\r
+ }\r
+\r
+ if (tbl->mouse_row < tbl->n_rows &&\r
+ (tbl->rows[tbl->mouse_row].flags & KHUI_CW_ROW_HEADER)) {\r
+ khui_credwnd_outline * o;\r
+\r
+ o = (khui_credwnd_outline *) tbl->rows[tbl->mouse_row].data;\r
+\r
+ if (o->flags & KHUI_CW_O_NOOUTLINE) {\r
+ r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ } else {\r
+ r.left = KHUI_SMICON_CX * 3 / 2 + tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ }\r
+ r.right = r.left + KHUI_SMICON_CX;\r
+ } else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ }\r
+ } else {\r
+ r.left = KHUI_SMICON_CX * 3 / 2 + \r
+ tbl->cols[tbl->mouse_col].x - tbl->scr_left;\r
+ r.top = tbl->mouse_row * tbl->cell_height + \r
+ tbl->header_height - tbl->scr_top;\r
+ r.right = r.left + KHUI_SMICON_CX;\r
+ r.bottom = r.top + tbl->cell_height;\r
+ }\r
InvalidateRect(tbl->hwnd, &r, TRUE);\r
}\r
} else if(tbl->mouse_state != nm_state) {\r
}\r
break;\r
\r
+ case KHUI_ACTION_LAYOUT_MINI:\r
+ {\r
+ cw_save_view(tbl, NULL);\r
+ cw_unload_view(tbl);\r
+\r
+ cw_load_view(tbl, NULL, 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
+ break;\r
+\r
case KHUI_PACTION_UP:\r
case KHUI_PACTION_UP_EXTEND:\r
case KHUI_PACTION_UP_TOGGLE:\r
return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
}\r
\r
- row = y / tbl->cell_height;\r
+ if (tbl->flags & KHUI_CW_TBL_EXPIDENT) {\r
+ int i, yt;\r
+\r
+ yt = 0;\r
+ for (i=0; i < tbl->n_rows && yt < y; i++) {\r
+ if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)\r
+ yt += tbl->cell_height * CW_EXP_ROW_MULT;\r
+ else\r
+ yt += tbl->cell_height;\r
+ if (yt > y)\r
+ break;\r
+ }\r
+\r
+ row = i;\r
+\r
+ } else {\r
+ row = y / tbl->cell_height;\r
+ }\r
\r
if(row < 0 || row >= (int) tbl->n_rows)\r
return FALSE;\r
#define KHUI_CW_O_SHOWFLAG 0x00000008\r
#define KHUI_CW_O_SELECTED 0x00000010\r
#define KHUI_CW_O_DATAALLOC 0x00000020\r
+#define KHUI_CW_O_NOOUTLINE 0x00000040\r
\r
typedef struct khui_credwnd_row_t {\r
khm_int32 flags;\r
#define KHUI_CW_ROW_HEADER 0x00000004\r
#define KHUI_CW_ROW_TIMERSET 0x00000008\r
#define KHUI_CW_ROW_SELECTED 0x00000010\r
+#define KHUI_CW_ROW_EXPVIEW 0x00000020\r
\r
/* row allocation */\r
/* initial number of rows to be allocated */\r
\r
#define cw_is_custom_attr(i) ((i)<0)\r
\r
+typedef struct tag_khui_credwnd_ident {\r
+\r
+ khm_handle ident;\r
+ khm_int32 ident_flags;\r
+ khm_int32 credtype;\r
+ wchar_t name[KCDB_IDENT_MAXCCH_NAME];\r
+ wchar_t credtype_name[KCDB_MAXCCH_NAME];\r
+\r
+ khm_size credcount;\r
+\r
+} khui_credwnd_ident;\r
+\r
+#define CW_IDENT_ALLOC_INCR 4\r
+\r
+#define CW_EXP_ROW_MULT 2\r
+\r
typedef struct khui_credwnd_tbl_t {\r
HWND hwnd; /* the window that this table belongs to */\r
\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
+ COLORREF cr_hdr_gray; /* gray header text color */\r
+ COLORREF cr_hdr_gray_sel; /* selected gray 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
\r
/* the credentials set */\r
khm_handle credset;\r
+\r
+ khui_credwnd_ident * idents;\r
+ khm_size n_idents;\r
+ khm_size nc_idents;\r
+\r
} khui_credwnd_tbl;\r
\r
#define KHUI_MAXCB_HEADING 256\r
#define KHUI_CW_TBL_ACTIVE 0x00000100\r
#define KHUI_CW_TBL_CUSTVIEW 0x00000200\r
#define KHUI_CW_TBL_COLSKIP 0x00000400\r
+#define KHUI_CW_TBL_EXPIDENT 0x00000800\r
+#define KHUI_CW_TBL_NOHEADER 0x00001000\r
\r
/* mouse_state constants */\r
#define CW_MOUSE_NONE 0x00000000 /* nothing interesting */\r
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU\r
FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
BEGIN\r
- GROUPBOX "Startup / Shutdown",IDC_CFG_STARTUP_GROUP,7,7,241,50\r
+ GROUPBOX "Startup / Shutdown",IDC_CFG_STARTUP_GROUP,7,7,241,44\r
CONTROL "&Obtain new credentials at startup (if none are present)",IDC_CFG_AUTOINIT,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,22,196,10\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,20,196,10\r
CONTROL "&Destroy all credentials on exit",IDC_CFG_DESTROYALL,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,39,111,10\r
- CONTROL "&Start Network Identity Manager during Windows logon",IDC_CFG_AUTOSTART,\r
- "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,16,48,135,10\r
- GROUPBOX "Other",IDC_CFG_OTHER,7,63,241,85\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,36,111,10\r
+ GROUPBOX "Other",IDC_CFG_OTHER,7,55,241,120\r
CONTROL "&Run Network Identity Manager in system tray after window close",IDC_CFG_KEEPRUNNING,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,78,230,10\r
- CONTROL "Monitor network connectivity",IDC_CFG_NETDETECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,96,106,10\r
- CONTROL "Log trace events to trace log at the following location:",IDC_CFG_LOGTOFILE,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,113,225,10\r
- EDITTEXT IDC_CFG_LOGPATH,16,127,173,14,ES_AUTOHSCROLL | ES_READONLY\r
- PUSHBUTTON "Show log ...",IDC_CFG_SHOWLOG,193,127,50,14\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,68,230,10\r
+ LTEXT "Clicking on the ¬ification icon",IDC_CFG_NOTACT_STATIC,26,87,99,8\r
+ COMBOBOX IDC_CFG_NOTACTION,133,85,110,48,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP\r
+ CONTROL "&Monitor network connectivity",IDC_CFG_NETDETECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,104,106,10\r
+ CONTROL "&Log trace events to trace log at the following location:",IDC_CFG_LOGTOFILE,\r
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,121,225,10\r
+ EDITTEXT IDC_CFG_LOGPATH,16,135,173,14,ES_AUTOHSCROLL | ES_READONLY\r
+ PUSHBUTTON "&Show log",IDC_CFG_SHOWLOG,193,135,50,14\r
CONTROL "A&utomatically import Windows logon identity",IDC_CFG_AUTOIMPORT,\r
- "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,16,158,165,10\r
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,16,156,165,10\r
+ CONTROL "&Start Network Identity Manager during Windows logon",IDC_CFG_AUTOSTART,\r
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,113,165,135,10\r
END\r
\r
IDD_CFG_IDENTITIES DIALOGEX 0, 0, 255, 182\r
PUSHBUTTON "Remove identity ...",IDC_CFG_REMOVE,139,122,78,14\r
END\r
\r
-IDD_ABOUT DIALOGEX 0, 0, 268, 170\r
+IDD_ABOUT DIALOGEX 0, 0, 324, 238\r
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 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-2007 Massachusetts Institute of Technology\n© 2006-2007 Secure Endpoints Inc.",IDC_COPYRIGHT,41,23,220,18,NOT WS_GROUP\r
- LTEXT "BuildInfo",IDC_BUILDINFO,41,43,220,15,NOT WS_GROUP\r
- ICON IDI_MAIN_APP,IDC_STATIC,6,7,20,20\r
- CONTROL "",IDC_MODULES,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,41,72,220,91\r
- LTEXT "Loaded modules",IDC_STATIC,41,60,52,8\r
+ DEFPUSHBUTTON "OK",IDOK,267,7,50,14\r
+ LTEXT "Productname",IDC_PRODUCT,41,7,225,13,NOT WS_GROUP\r
+ LTEXT "© 2005-2007 Massachusetts Institute of Technology\n© 2006-2007 Secure Endpoints Inc.",IDC_COPYRIGHT,41,23,276,23,NOT WS_GROUP\r
+ LTEXT "BuildInfo",IDC_BUILDINFO,41,49,276,20,NOT WS_GROUP\r
+ ICON IDI_MAIN_APP,IDC_STATIC,6,7,21,20\r
+ CONTROL "",IDC_MODULES,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,41,88,276,143\r
+ LTEXT "Loaded modules",IDC_STATIC,41,76,52,8\r
END\r
\r
IDD_CFG_APPEAR DIALOGEX 0, 0, 255, 182\r
IDD_ABOUT, DIALOG\r
BEGIN\r
LEFTMARGIN, 6\r
- RIGHTMARGIN, 261\r
+ RIGHTMARGIN, 317\r
VERTGUIDE, 41\r
- VERTGUIDE, 204\r
+ VERTGUIDE, 266\r
TOPMARGIN, 7\r
- BOTTOMMARGIN, 163\r
+ BOTTOMMARGIN, 231\r
END\r
\r
IDD_CFG_APPEAR, DIALOG\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 Network Identity Manager"\r
+ IDS_ACTION_OPEN_APP "Show Network Identity Manager window"\r
IDS_CTX_NEW_IDENT "Obaining new identity"\r
IDS_CTX_NEW_CREDS "Obtaining new credentials"\r
IDS_CTX_RENEW_CREDS "Renewing credentials"\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 Network Identity Manager window"\r
+ IDS_ACTION_CLOSE_APP "Hide Network Identity Manager window"\r
IDS_NC_FAILED_TITLE "Failed to acquire credentials"\r
IDS_CFG_IDENTITIES_SHORT "Identities"\r
IDS_CFG_IDENTITIES_LONG "Global Identity settings"\r
\r
STRINGTABLE \r
BEGIN\r
- IDS_NC_REN_FAILED_TITLE_I "Failed to renew creds for %s"\r
+ IDS_NC_REN_FAILED_TITLE_I "Failed to renew credentials for %s"\r
IDS_CFG_IDNAME_NON "No identity selected. Please select an identity and try again."\r
IDS_MENU_DESTROY_CRED "Destroy"\r
IDS_MENU_RENEW_CRED "Renew"\r
- IDS_ACTION_DESTROY_ALL "All identities"\r
- IDS_ACTION_RENEW_ALL "All identities"\r
- IDS_IDACTION_RENEW "Renew credentials for %s"\r
- IDS_IDACTION_DESTROY "Destroy credentials for %s"\r
+ IDS_ACTION_DESTROY_ALL "Destroy all identities"\r
+ IDS_ACTION_RENEW_ALL "Renew all identities"\r
+ IDS_IDACTION_RENEW "Renew %s"\r
+ IDS_IDACTION_DESTROY "Destroy %s"\r
IDS_CTX_DESTROY_ID "Destroying identity %1!s!"\r
IDS_NCN_IDENT_INVALID "Identity %s is invalid."\r
IDS_NCN_IDENT_CHECKING "Checking identity %s ..."\r
IDS_NCN_IDENT_UNKNOWN "Validity of identity %s coudn't be determined."\r
IDS_REMOTE_FAIL "The instance of Network Identity Manager that is already running is not responding to the remote request properly. Please check if you are running the latest version of Network Identity Manger software included with MIT Kerberos for Windows."\r
IDS_REMOTE_FAIL_TITLE "Failed to communicate with Network Identity Manager"\r
+ IDS_IDACTION_NEW "Initialize %s"\r
+ IDS_IDACTIONT_NEW "New credentials for %s"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+ IDS_IDACTIONT_RENEW "Renew credentials for %s"\r
+ IDS_IDACTIONT_DESTROY "Destroy credentials for %s"\r
+ IDS_ALERTTYPE_PLUGIN "Failed to load plug-in"\r
+ IDS_ALERTTYPE_EXPIRE "Credential expiration warning"\r
+ IDS_ALERTTYPE_RENEWFAIL "Failed to renew credentials"\r
+ IDS_ALERTTYPE_ACQUIREFAIL "Failed to acquire credentials"\r
+ IDS_ALERTTYPE_CHPW "Failed to change password"\r
+ IDS_ACTION_LAYOUT_MINI "&Advanced"\r
+ IDS_IDEXPDISP_NOCRED "(This identity has no credentials)"\r
+ IDS_IDEXPDISP_1CRED "(This identity has 1 credential)"\r
+ IDS_IDEXPDISP_NCRED "(This identity has %d credentials)"\r
END\r
\r
#endif // English (U.S.) resources\r
if(n_khui_dialogs < MAX_UI_DIALOGS - 1) {\r
khui_dialogs[n_khui_dialogs].hwnd = dlg;\r
khui_dialogs[n_khui_dialogs].hwnd_next = NULL;\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
+ khui_dialogs[n_khui_dialogs].active = TRUE;\r
n_khui_dialogs++;\r
} else {\r
#if DEBUG\r
return i;\r
}\r
\r
+void khm_get_action_caption(khm_int32 action, wchar_t * buf, khm_size cb_buf) {\r
+ khui_action * act;\r
+\r
+ StringCbCopy(buf, cb_buf, L"");\r
+\r
+ khui_action_lock();\r
+ act = khui_find_action(action);\r
+\r
+ if (act == NULL)\r
+ goto done;\r
+\r
+ if (act->caption) {\r
+ StringCbCopy(buf, cb_buf, act->caption);\r
+ } else if (act->is_caption) {\r
+ LoadString(khm_hInstance, act->is_caption,\r
+ buf, (int)(cb_buf / sizeof(wchar_t)));\r
+ }\r
+\r
+ done:\r
+ khui_action_unlock();\r
+}\r
+\r
+void khm_get_action_tooltip(khm_int32 action, wchar_t * buf, khm_size cb_buf) {\r
+ khui_action * act;\r
+\r
+ StringCbCopy(buf, cb_buf, L"");\r
+\r
+ khui_action_lock();\r
+ act = khui_find_action(action);\r
+\r
+ if (act == NULL)\r
+ goto done;\r
+\r
+ if (act->tooltip) {\r
+ StringCbCopy(buf, cb_buf, act->tooltip);\r
+ } else if (act->is_tooltip) {\r
+ LoadString(khm_hInstance, act->is_tooltip,\r
+ buf, (int) (cb_buf / sizeof(wchar_t)));\r
+ }\r
+\r
+ done:\r
+ khui_action_unlock();\r
+}\r
+\r
void add_action_to_menu(HMENU hm, khui_action * act, \r
int idx, int flags) {\r
MENUITEMINFO mii;\r
} else {\r
khui_menu_def * def;\r
\r
- if (act->caption) {\r
- StringCbCopy(buf, sizeof(buf), act->caption);\r
- } else {\r
- LoadString(khm_hInstance, \r
- act->is_caption, \r
- buf, ARRAYLENGTH(buf));\r
- }\r
+ khm_get_action_caption(act->cmd, buf, sizeof(buf));\r
\r
if(khui_get_cmd_accel_string(act->cmd, accel, \r
ARRAYLENGTH(accel))) {\r
}\r
}\r
\r
- if(flags & KHUI_ACTIONREF_DEFAULT)\r
+ if(flags & KHUI_ACTIONREF_DEFAULT) {\r
+ mii.fMask |= MIIM_STATE;\r
mii.fState |= MFS_DEFAULT;\r
+ }\r
}\r
\r
InsertMenuItem(hm,idx,TRUE,&mii);\r
\r
static void refresh_menu(HMENU hm, khui_menu_def * def) {\r
khui_action_ref * act;\r
- int i;\r
+ khm_size i, n;\r
\r
- act = def->items;\r
- i = 0;\r
- while ((def->n_items == -1 && act->action != KHUI_MENU_END) ||\r
- (def->n_items >= 0 && i < (int) def->n_items)) {\r
- refresh_menu_item(hm, khui_find_action(act->action), i, act->flags);\r
- act++; i++;\r
+ for(i = 0, n = khui_menu_get_size(def); i < n; i++) {\r
+ act = khui_menu_get_action(def, i);\r
+ refresh_menu_item(hm, khui_find_action(act->action), (int) i, act->flags);\r
}\r
}\r
\r
static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main) {\r
HMENU hm;\r
khui_action_ref * act;\r
- int i;\r
+ khm_size i, n;\r
\r
if (main)\r
hm = CreateMenu();\r
else\r
hm = CreatePopupMenu();\r
\r
- act = def->items;\r
- i = 0;\r
- while((!(def->state & KHUI_MENUSTATE_ALLOCD) && act->action != KHUI_MENU_END) ||\r
- ((def->state & KHUI_MENUSTATE_ALLOCD) && i < (int) def->n_items)) {\r
- add_action_to_menu(hm,khui_find_action(act->action),i,act->flags);\r
- act++; i++;\r
+ for (i = 0, n = khui_menu_get_size(def); i < n; i++) {\r
+ act = khui_menu_get_action(def, i);\r
+ add_action_to_menu(hm, khui_find_action(act->action), (int) i, act->flags);\r
}\r
\r
return hm;\r
if(act == NULL || (act->is_tooltip == 0 && act->tooltip == NULL))\r
khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL);\r
else {\r
- if (act->tooltip)\r
- StringCbCopy(buf, sizeof(buf), act->tooltip);\r
- else\r
- LoadString(khm_hInstance, \r
- act->is_tooltip, \r
- buf, ARRAYLENGTH(buf));\r
+ khm_get_action_tooltip(act->cmd, buf, sizeof(buf));\r
+\r
khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf);\r
}\r
}\r
khm_handle identity;\r
khm_int32 renew_cmd;\r
khm_int32 destroy_cmd;\r
+ khm_int32 new_cmd;\r
int refreshcycle;\r
};\r
\r
struct identity_action_map * actmap;\r
wchar_t idname[KCDB_IDENT_MAXCCH_NAME];\r
wchar_t fmt[128];\r
+ wchar_t caption[KHUI_MAXCCH_SHORT_DESC];\r
wchar_t tooltip[KHUI_MAXCCH_SHORT_DESC];\r
+ wchar_t actionname[KHUI_MAXCCH_NAME];\r
khm_size cb;\r
\r
if (n_id_action_map + 1 > nc_id_action_map) {\r
actmap->identity = ident;\r
kcdb_identity_hold(ident);\r
\r
- fmt[0] = L'\0';\r
- LoadString(khm_hInstance, IDS_IDACTION_RENEW,\r
- fmt, ARRAYLENGTH(fmt));\r
- StringCbPrintf(tooltip, sizeof(tooltip), fmt, idname);\r
+#define GETFORMAT(I) do { fmt[0] = L'\0'; LoadString(khm_hInstance, I, fmt, ARRAYLENGTH(fmt)); } while(0)\r
+#define EXPFORMAT(d,s) do { StringCbPrintf(d, sizeof(d), fmt, s); } while(0)\r
+ /* renew */\r
+\r
+ GETFORMAT(IDS_IDACTIONT_RENEW);\r
+ EXPFORMAT(tooltip, idname);\r
+\r
+ GETFORMAT(IDS_IDACTION_RENEW);\r
+ EXPFORMAT(caption, idname);\r
+\r
+ StringCbPrintf(actionname, sizeof(actionname), L"R:%s", idname);\r
\r
actmap->renew_cmd =\r
- khui_action_create(NULL, idname, tooltip, NULL,\r
+ khui_action_create(actionname, caption, tooltip, NULL,\r
KHUI_ACTIONTYPE_TRIGGER, NULL);\r
\r
- fmt[0] = L'\0';\r
- LoadString(khm_hInstance, IDS_IDACTION_DESTROY,\r
- fmt, ARRAYLENGTH(fmt));\r
- StringCbPrintf(tooltip, sizeof(tooltip), fmt, idname);\r
+ /* destroy */\r
+\r
+ GETFORMAT(IDS_IDACTIONT_DESTROY);\r
+ EXPFORMAT(tooltip, idname);\r
+\r
+ GETFORMAT(IDS_IDACTION_DESTROY);\r
+ EXPFORMAT(caption, idname);\r
+\r
+ StringCbPrintf(actionname, sizeof(actionname), L"D:%s", idname);\r
\r
actmap->destroy_cmd =\r
- khui_action_create(NULL, idname, tooltip, NULL,\r
+ khui_action_create(actionname, caption, tooltip, NULL,\r
+ KHUI_ACTIONTYPE_TRIGGER, NULL);\r
+\r
+ /* new */\r
+\r
+ GETFORMAT(IDS_IDACTIONT_NEW);\r
+ EXPFORMAT(tooltip, idname);\r
+\r
+ GETFORMAT(IDS_IDACTION_NEW);\r
+ EXPFORMAT(caption, idname);\r
+\r
+ StringCbPrintf(actionname, sizeof(actionname), L"N:%s", idname);\r
+\r
+ actmap->new_cmd =\r
+ khui_action_create(actionname, caption, tooltip, NULL,\r
KHUI_ACTIONTYPE_TRIGGER, NULL);\r
\r
actmap->refreshcycle = idcmd_refreshcycle;\r
\r
+#undef GETFORMAT\r
+#undef EXPFORMAT\r
+\r
return actmap;\r
}\r
\r
}\r
}\r
\r
-static khm_int32\r
-get_identity_renew_command(khm_handle ident) {\r
+khm_int32\r
+khm_get_identity_renew_action(khm_handle ident) {\r
struct identity_action_map * map;\r
\r
map = get_identity_cmd_map(ident);\r
return 0;\r
}\r
\r
-static khm_int32\r
-get_identity_destroy_command(khm_handle ident) {\r
+khm_int32\r
+khm_get_identity_destroy_action(khm_handle ident) {\r
struct identity_action_map * map;\r
\r
map = get_identity_cmd_map(ident);\r
return 0;\r
}\r
\r
+khm_int32\r
+khm_get_identity_new_creds_action(khm_handle ident) {\r
+ struct identity_action_map * map;\r
+\r
+ map = get_identity_cmd_map(ident);\r
+\r
+ if (map)\r
+ return map->new_cmd;\r
+ else\r
+ return 0;\r
+}\r
+\r
void\r
khm_refresh_identity_menus(void) {\r
khui_menu_def * renew_def = NULL;\r
}\r
\r
khui_menu_insert_action(renew_def, 1000,\r
- get_identity_renew_command(identity),\r
+ khm_get_identity_renew_action(identity),\r
0);\r
\r
khui_menu_insert_action(dest_def, 1000,\r
- get_identity_destroy_command(identity),\r
+ khm_get_identity_destroy_action(identity),\r
0);\r
}\r
\r
khm_cred_destroy_identity(id_action_map[i].identity);\r
return TRUE;\r
}\r
+\r
+ if (id_action_map[i].new_cmd == act_id) {\r
+ khm_cred_obtain_new_creds_for_ident(id_action_map[i].identity,\r
+ NULL);\r
+ return TRUE;\r
+ }\r
}\r
}\r
\r
void khm_menu_refresh_items(void);\r
khm_boolean khm_check_identity_menu_action(khm_int32 act_id);\r
void khm_refresh_identity_menus(void);\r
+void khm_get_action_tooltip(khm_int32 action, wchar_t * buf, khm_size cb_buf);\r
+void khm_get_action_caption(khm_int32 action, wchar_t * buf, khm_size cb_buf);\r
+\r
+khm_int32 khm_get_identity_destroy_action(khm_handle ident);\r
+khm_int32 khm_get_identity_renew_action(khm_handle ident);\r
+khm_int32 khm_get_identity_new_creds_action(khm_handle ident);\r
\r
static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main);\r
static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y);\r
HWND khm_hwnd_rebar;\r
HWND khm_hwnd_main_cred;\r
\r
+int khm_main_wnd_mode = KHM_MAIN_WND_NORMAL;\r
+\r
#define MW_RESIZE_TIMER 1\r
#define MW_RESIZE_TIMEOUT 2000\r
#define MW_REFRESH_TIMER 2\r
#endif\r
\r
/* make the call */\r
- pcbdata->rv = (*pcbdata->cb)(khm_hwnd_main, pcbdata->rock);\r
+ if (!IsBadCodePtr(pcbdata->cb))\r
+ pcbdata->rv = (*pcbdata->cb)(khm_hwnd_main, pcbdata->rock);\r
+ else {\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ pcbdata->rv = KHM_ERROR_INVALID_PARAM;\r
+ }\r
}\r
\r
LRESULT CALLBACK \r
khm_ui_cb(lParam);\r
return 0;\r
\r
+ /* layout control */\r
+ case KHUI_ACTION_LAYOUT_MINI:\r
+ if (khm_main_wnd_mode == KHM_MAIN_WND_MINI) {\r
+ khm_set_main_window_mode(KHM_MAIN_WND_NORMAL);\r
+ } else {\r
+ khm_set_main_window_mode(KHM_MAIN_WND_MINI);\r
+ }\r
+ return SendMessage(khm_hwnd_main_cred, uMsg, \r
+ wParam, lParam);\r
+\r
+ case KHUI_ACTION_LAYOUT_ID:\r
+ case KHUI_ACTION_LAYOUT_TYPE:\r
+ case KHUI_ACTION_LAYOUT_LOC:\r
+ case KHUI_ACTION_LAYOUT_CUST:\r
+ case KHUI_ACTION_LAYOUT_RELOAD:\r
+ khm_set_main_window_mode(KHM_MAIN_WND_NORMAL);\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
case KHUI_PACTION_DELETE:\r
\r
case KHUI_PACTION_SELALL:\r
- case KHUI_ACTION_LAYOUT_ID:\r
- case KHUI_ACTION_LAYOUT_TYPE:\r
- case KHUI_ACTION_LAYOUT_LOC:\r
- case KHUI_ACTION_LAYOUT_CUST:\r
- case KHUI_ACTION_LAYOUT_RELOAD:\r
/* otherwise fallthrough and bounce to the creds window */\r
return SendMessage(khm_hwnd_main_cred, uMsg, \r
wParam, lParam);\r
}\r
break;\r
\r
+ case WM_MOVING:\r
+ {\r
+ RECT * r;\r
+\r
+ r = (RECT *) lParam;\r
+ khm_adjust_window_dimensions_for_display(r,\r
+ KHM_DOCK_AUTO | KHM_DOCKF_XBORDER);\r
+ }\r
+ return TRUE;\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
+ const wchar_t * wconfig;\r
+\r
+ if (khm_main_wnd_mode == KHM_MAIN_WND_MINI)\r
+ wconfig = L"Windows\\MainMini";\r
+ else\r
+ wconfig = L"Windows\\Main";\r
\r
KillTimer(hwnd, wParam);\r
\r
KHM_PERM_WRITE,\r
&csp_cw))) {\r
if (KHM_SUCCEEDED(khc_open_space(csp_cw,\r
- L"Windows\\Main",\r
+ wconfig,\r
KHM_PERM_WRITE,\r
&csp_mw))) {\r
+ khm_int32 t;\r
+\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
khc_write_int32(csp_mw, L"Height",\r
r.bottom - r.top);\r
\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Dock", &t)) &&\r
+ t != KHM_DOCK_NONE) {\r
+ khc_write_int32(csp_mw, L"Dock", KHM_DOCK_AUTO);\r
+ }\r
+\r
khc_close_space(csp_mw);\r
}\r
khc_close_space(csp_cw);\r
} else if (m->type == KMSG_ACT &&\r
m->subtype == KMSG_ACT_CONTINUE_CMDLINE) {\r
khm_cred_process_startup_actions();\r
+ } else if (m->type == KMSG_ACT &&\r
+ m->subtype == KMSG_ACT_END_CMDLINE) {\r
+ /* nothing yet */\r
} else if (m->type == KMSG_ACT &&\r
m->subtype == KMSG_ACT_SYNC_CFG) {\r
khm_refresh_config();\r
m->subtype == KMSG_KMM_I_DONE) {\r
kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0);\r
}\r
+\r
return kmq_wm_end(m, rv);\r
}\r
return 0;\r
}\r
\r
void\r
-khm_adjust_window_dimensions_for_display(RECT * pr) {\r
+khm_adjust_window_dimensions_for_display(RECT * pr, int dock) {\r
\r
HMONITOR hmon;\r
RECT rm;\r
if (height > (rm.bottom - rm.top))\r
height = rm.bottom - rm.top;\r
\r
- if (x < rm.left)\r
+ switch (dock & KHM_DOCKF_DOCKHINT) {\r
+ case KHM_DOCK_TOPLEFT:\r
x = rm.left;\r
- if (x + width > rm.right)\r
+ y = rm.top;\r
+ break;\r
+\r
+ case KHM_DOCK_TOPRIGHT:\r
x = rm.right - width;\r
- if (y < rm.top)\r
y = rm.top;\r
- if (y + height > rm.bottom)\r
+ break;\r
+\r
+ case KHM_DOCK_BOTTOMRIGHT:\r
+ x = rm.right - width;\r
y = rm.bottom - height;\r
+ break;\r
+\r
+ case KHM_DOCK_BOTTOMLEFT:\r
+ x = rm.left;\r
+ y = rm.bottom - height;\r
+ break;\r
+\r
+ case KHM_DOCK_AUTO:\r
+ {\r
+ int cxt, cyt;\r
+\r
+ cxt = GetSystemMetrics(SM_CXDRAG);\r
+ cyt = GetSystemMetrics(SM_CYDRAG);\r
+\r
+ if (x > rm.left && (x - rm.left) < cxt)\r
+ x = rm.left;\r
+ else if ((x + width) < rm.right && (rm.right - (x + width)) < cxt)\r
+ x = rm.right - width;\r
+\r
+ if (y > rm.top && (y - rm.top) < cyt)\r
+ y = rm.top;\r
+ else if ((y + height) < rm.bottom && (rm.bottom - (y + height)) < cyt)\r
+ y = rm.bottom - height;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if (!(dock & KHM_DOCKF_XBORDER)) {\r
+ if (x < rm.left)\r
+ x = rm.left;\r
+ if (x + width > rm.right)\r
+ x = rm.right - width;\r
+ if (y < rm.top)\r
+ y = rm.top;\r
+ if (y + height > rm.bottom)\r
+ y = rm.bottom - height;\r
+ }\r
\r
done_with_monitor:\r
pr->left = x;\r
\r
}\r
\r
+void\r
+khm_get_main_window_rect(RECT * pr) {\r
+ khm_handle csp_mw = NULL;\r
+ int x,y,width,height,dock;\r
+ RECT r;\r
+ const wchar_t * wconfig;\r
+\r
+ x = CW_USEDEFAULT;\r
+ y = CW_USEDEFAULT;\r
+ width = CW_USEDEFAULT;\r
+ height = CW_USEDEFAULT;\r
+ dock = KHM_DOCK_NONE;\r
+\r
+ if (khm_main_wnd_mode == KHM_MAIN_WND_MINI)\r
+ wconfig = L"CredWindow\\Windows\\MainMini";\r
+ else\r
+ wconfig = L"CredWindow\\Windows\\Main";\r
+\r
+ if (KHM_SUCCEEDED(khc_open_space(NULL,\r
+ wconfig,\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
+ if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Dock", &t)))\r
+ dock = t;\r
+\r
+ khc_close_space(csp_mw);\r
+ }\r
+\r
+ /* If there were no default values, we default to using 1/4 of the\r
+ work area centered on the primary monitor. If there were any\r
+ docking hints, then the next call to\r
+ khm_adjust_window_dimensions_for_display() will reposition the\r
+ window. */\r
+ if (width == CW_USEDEFAULT || x == CW_USEDEFAULT) {\r
+ RECT wr;\r
+\r
+ SetRectEmpty(&wr);\r
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &wr, 0);\r
+\r
+ if (width == CW_USEDEFAULT) {\r
+ width = (wr.right - wr.left) / 2;\r
+ height = (wr.bottom - wr.top) / 2;\r
+ }\r
+\r
+ if (x == CW_USEDEFAULT) {\r
+ x = (wr.left + wr.right) / 2 - width / 2;\r
+ y = (wr.top + wr.bottom) / 2 - height / 2;\r
+ }\r
+ }\r
+\r
+ /* The saved dimensions might not actually be visible if the user\r
+ has changed the resolution of the display or if it's a multiple\r
+ monitor system where the monitor on which the Network Identity\r
+ Manager window was on previously is no longer connected. We\r
+ have to check for that and adjust the dimensions if needed. */\r
+ SetRect(&r, x, y, x + width, y + height);\r
+ khm_adjust_window_dimensions_for_display(&r, dock);\r
+\r
+ *pr = r;\r
+}\r
+\r
+void\r
+khm_set_main_window_mode(int mode) {\r
+\r
+ RECT r;\r
+\r
+ if (mode == khm_main_wnd_mode)\r
+ return;\r
+\r
+ khui_check_action(KHUI_ACTION_LAYOUT_MINI,\r
+ ((mode == KHM_MAIN_WND_MINI)? FALSE : TRUE));\r
+ khui_enable_action(KHUI_MENU_LAYOUT,\r
+ ((mode == KHM_MAIN_WND_MINI)? FALSE : TRUE));\r
+ khui_enable_action(KHUI_MENU_COLUMNS,\r
+ ((mode == KHM_MAIN_WND_MINI)? FALSE : TRUE));\r
+\r
+ khm_main_wnd_mode = mode;\r
+ if (khm_hwnd_main) {\r
+ khm_get_main_window_rect(&r);\r
+\r
+ SetWindowPos(khm_hwnd_main,\r
+ NULL,\r
+ r.left, r.top,\r
+ r.right - r.left, r.bottom - r.top,\r
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER |\r
+ SWP_NOZORDER);\r
+ }\r
+}\r
\r
void \r
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
RECT r;\r
\r
LoadString(khm_hInstance, IDS_MAIN_WINDOW_TITLE, \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
+ khm_int32 t;\r
+\r
+ if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultWindowMode", &t))) {\r
+ khm_set_main_window_mode(t);\r
}\r
+\r
khc_close_space(csp_cw);\r
}\r
\r
- /* The saved dimensions might not actually be visible if the user\r
- has changed the resolution of the display or if it's a multiple\r
- monitor system where the monitor on which the Network Identity\r
- Manager window was on previously is no longer connected. We\r
- have to check for that and adjust the dimensions if needed. */\r
- SetRect(&r, x, y, x + width, y + height);\r
- khm_adjust_window_dimensions_for_display(&r);\r
+ khm_get_main_window_rect(&r);\r
\r
khm_hwnd_main = \r
CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,\r
extern HWND khm_hwnd_main;\r
extern HWND khm_hwnd_rebar;\r
\r
+#define KHM_MAIN_WND_NORMAL 0\r
+#define KHM_MAIN_WND_MINI 1\r
+\r
+extern int khm_main_wnd_mode;\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_activate_main_window(void);\r
void khm_show_main_window(void);\r
+void khm_set_main_window_mode(int mode);\r
void khm_close_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
+void khm_adjust_window_dimensions_for_display(RECT * pr, int dock);\r
LRESULT khm_rebar_notify(LPNMHDR lpnm);\r
\r
void\r
#define COMMANDLINE_MAP_FMT L"Local\\NetIDMgr_Cmdline_%lu"\r
#define QUERY_APP_VER_MAP_FMT L"Local\\NetIDMgr_QueryVer_%lu"\r
\r
+/* dock values for window positioning */\r
+#define KHM_DOCK_NONE 0\r
+#define KHM_DOCK_TOPLEFT 1\r
+#define KHM_DOCK_TOPRIGHT 2\r
+#define KHM_DOCK_BOTTOMRIGHT 3\r
+#define KHM_DOCK_BOTTOMLEFT 4\r
+#define KHM_DOCK_AUTO 256\r
+#define KHM_DOCKF_DOCKHINT 0x0000ffff\r
+#define KHM_DOCKF_XBORDER 0x00010000\r
#endif\r
\r
#define CW_PARAM DWLP_USER\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
static LRESULT \r
nc_handle_wm_create(HWND hwnd,\r
UINT uMsg,\r
\r
MapDialogRect(ncd->dlg_main, &r);\r
\r
- /* center the new creds window over the main NetIDMgr window */\r
+ /* position the new credentials dialog */\r
width = r.right - r.left;\r
height = r.bottom - r.top;\r
\r
height += (wr.bottom - wr.top) - (cr.bottom - cr.top);\r
}\r
\r
- GetWindowRect(lpc->hwndParent, &r);\r
+ /* if the parent window is visible, we center the new credentials\r
+ dialog over the parent. Otherwise, we center it on the primary\r
+ display. */\r
+\r
+ if (IsWindowVisible(lpc->hwndParent)) {\r
+ GetWindowRect(lpc->hwndParent, &r);\r
+ } else {\r
+ if(!SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID) &r, 0)) {\r
+ /* failover to the window coordinates */\r
+ GetWindowRect(lpc->hwndParent, &r);\r
+ }\r
+ }\r
x = (r.right + r.left)/2 - width / 2;\r
y = (r.top + r.bottom)/2 - height / 2;\r
\r
L"CredWindow\\Windows\\NewCred\\ForceToTop",\r
&t)) &&\r
\r
- t != 0 &&\r
-\r
- !khm_is_dialog_active()) {\r
+ t != 0) {\r
+ /* it used to be that the above condition also called\r
+ !khm_is_dialog_active() to find out whether there\r
+ was a dialog active. If there was, we wouldn't try\r
+ to bring the new cred window to the foreground. But\r
+ that was not the behavior we want. */\r
\r
/* if the main window is not visible, then the SetWindowPos()\r
call is sufficient to bring the new creds window to the\r
if (d->nc->n_prompts > 0 &&\r
d->nc->prompts[0]->hwnd_edit) {\r
\r
- SetFocus(d->nc->prompts[0]->hwnd_edit);\r
+ PostMessage(d->dlg_main, WM_NEXTDLGCTL,\r
+ (WPARAM) d->nc->prompts[0]->hwnd_edit,\r
+ MAKELPARAM(TRUE, 0));\r
\r
}\r
\r
\r
#define KHUI_NOTIFIER_WINDOW L"KhuiNotifierMsgWindow"\r
\r
+\r
+/* The commands that are available as default actions when the user\r
+ clicks the notification icon. */\r
+\r
+khm_int32 khm_notifier_actions[] = {\r
+ KHUI_ACTION_OPEN_APP,\r
+ KHUI_ACTION_NEW_CRED\r
+};\r
+\r
+khm_size n_khm_notifier_actions = ARRAYLENGTH(khm_notifier_actions);\r
+\r
/* notifier message for notification icon */\r
#define KHUI_WM_NOTIFIER WM_COMMAND\r
\r
static khm_int32\r
alert_enqueue(khui_alert * a);\r
\r
+static khm_boolean\r
+alert_is_equal(khui_alert * a1, khui_alert * a2);\r
+\r
static void\r
check_for_queued_alerts(void);\r
\r
+static void\r
+show_queued_alerts(void);\r
+\r
static khm_int32\r
alert_consolidate(alert_list * alist,\r
khui_alert * alert,\r
khm_boolean add_from_queue);\r
\r
+static khm_int32\r
+get_default_notifier_action(void);\r
+\r
/* Globals */\r
\r
/* window class registration atom for message only notifier window\r
break;\r
\r
case KMSG_ALERT_SHOW_QUEUED:\r
- if (!ALERT_DISPLAYED()) {\r
-\r
- /* show next consolidated batch */\r
- alert_list alist;\r
- int n;\r
-\r
- alert_list_init(&alist);\r
- n = alert_consolidate(&alist, NULL, TRUE);\r
-\r
- if (n) {\r
- if (n == 1) {\r
- khui_alert_lock(alist.alerts[0]);\r
-\r
- if (alist.alerts[0]->title) {\r
- alert_list_set_title(&alist, alist.alerts[0]->title);\r
- } else {\r
- wchar_t title[KHUI_MAXCCH_TITLE];\r
- LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
- title, ARRAYLENGTH(title));\r
- alert_list_set_title(&alist, title);\r
- }\r
-\r
- khui_alert_unlock(alist.alerts[0]);\r
- } else {\r
- wchar_t title[KHUI_MAXCCH_TITLE];\r
- LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
- title, ARRAYLENGTH(title));\r
- alert_list_set_title(&alist, title);\r
- }\r
-\r
- alert_show_list(&alist);\r
- }\r
-\r
- alert_list_destroy(&alist);\r
-\r
- check_for_queued_alerts();\r
- }\r
+ show_queued_alerts();\r
break;\r
\r
case KMSG_ALERT_SHOW_MODAL:\r
{\r
POINT pt;\r
int menu_id;\r
+ khui_menu_def * mdef;\r
+ khui_action_ref * act;\r
+ khm_size i, n;\r
+ khm_int32 def_cmd;\r
\r
- GetCursorPos(&pt);\r
+ /* before we show the context menu, we need to make\r
+ sure that the default action for the notification\r
+ icon is present in the menu and that it is marked\r
+ as the default. */\r
\r
- if (khm_is_main_window_visible())\r
+ def_cmd = get_default_notifier_action();\r
+\r
+ if (khm_is_main_window_visible()) {\r
menu_id = KHUI_MENU_ICO_CTX_NORMAL;\r
- else\r
+\r
+ if (def_cmd == KHUI_ACTION_OPEN_APP)\r
+ def_cmd = KHUI_ACTION_CLOSE_APP;\r
+ } else {\r
menu_id = KHUI_MENU_ICO_CTX_MIN;\r
+ }\r
+\r
+ mdef = khui_find_menu(menu_id);\r
+\r
+#ifdef DEBUG\r
+ assert(mdef);\r
+#endif\r
+ n = khui_menu_get_size(mdef);\r
+ for (i=0; i < n; i++) {\r
+ act = khui_menu_get_action(mdef, i);\r
+ if (!(act->flags & KHUI_ACTIONREF_PACTION) &&\r
+ (act->action == def_cmd))\r
+ break;\r
+ }\r
+\r
+ if (i < n) {\r
+ if (!(act->flags & KHUI_ACTIONREF_DEFAULT)) {\r
+ khui_menu_remove_action(mdef, i);\r
+ khui_menu_insert_action(mdef, i, def_cmd, KHUI_ACTIONREF_DEFAULT);\r
+ } else {\r
+ /* we are all set */\r
+ }\r
+ } else {\r
+ /* the default action was not found on the context\r
+ menu */\r
+#ifdef DEBUG\r
+ assert(FALSE);\r
+#endif\r
+ khui_menu_insert_action(mdef, 0, def_cmd, KHUI_ACTIONREF_DEFAULT);\r
+ }\r
\r
SetForegroundWindow(khm_hwnd_main);\r
\r
+ GetCursorPos(&pt);\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
case NIN_SELECT:\r
/* fall through */\r
case NIN_KEYSELECT:\r
- khm_show_main_window();\r
+ /* If there were any alerts waiting to be shown, we show\r
+ them. Otherwise we perform the default action. */\r
+ khm_notify_icon_activate();\r
break;\r
\r
case NIN_BALLOONUSERCLICK:\r
if (balloon_alert) {\r
+ khui_alert * a;\r
+\r
khm_notify_icon_change(KHERR_NONE);\r
\r
- khui_alert_lock(balloon_alert);\r
+ a = balloon_alert;\r
+ balloon_alert = NULL;\r
\r
- if ((balloon_alert->flags & KHUI_ALERT_FLAG_DEFACTION) &&\r
- (balloon_alert->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON) &&\r
- balloon_alert->n_alert_commands > 0) {\r
+ khui_alert_lock(a);\r
+\r
+ if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) &&\r
+ !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) &&\r
+ a->n_alert_commands > 0) {\r
PostMessage(khm_hwnd_main, WM_COMMAND,\r
- MAKEWPARAM(balloon_alert->alert_commands[0], \r
+ MAKEWPARAM(a->alert_commands[0], \r
0),\r
0);\r
- } else if (balloon_alert->flags & \r
+ } else if (a->flags & \r
KHUI_ALERT_FLAG_REQUEST_WINDOW) {\r
khm_show_main_window();\r
- alert_show_normal(balloon_alert);\r
+ alert_show_normal(a);\r
}\r
\r
- khui_alert_unlock(balloon_alert);\r
- khui_alert_release(balloon_alert);\r
- balloon_alert = NULL;\r
+ khui_alert_unlock(a);\r
+ khui_alert_release(a);\r
} else {\r
#ifdef DEBUG\r
assert(FALSE);\r
HWND hwnd_buttons[KHUI_MAX_ALERT_COMMANDS];\r
/* handles for the command buttons */\r
\r
+ HWND hwnd_marker;\r
+ /* handle to the marker window used as\r
+ a tab-stop target when there are\r
+ not buttons associated with the\r
+ alert. */\r
+\r
LDCL(struct tag_alerter_alert_data);\r
} alerter_alert_data;\r
\r
in all the alerts being shown in\r
this dialog. */\r
\r
+ int c_alert; /* current selected alert. */\r
+\r
/* various metrics */\r
/* calculated during WM_CREATE */\r
- SIZE s_button;\r
+ SIZE s_button; /* minimum dimensions for command button */\r
SIZE s_margin;\r
RECT r_text; /* only .left and .right are used. rest are 0 */\r
RECT r_title; /* only .left, .right and .bottom are used. .top=0 */\r
#define NTF_TITLE_WIDTH (NTF_WIDTH - NTF_MARGIN*2)\r
#define NTF_TITLE_HEIGHT 10\r
\r
-#define NTF_ICON_WIDTH 20\r
-#define NTF_ICON_HEIGHT 20\r
-\r
-#define NTF_TEXT_X (NTF_MARGIN + NTF_ICON_WIDTH + NTF_MARGIN)\r
-#define NTF_TEXT_WIDTH ((NTF_WIDTH - NTF_MARGIN) - NTF_TEXT_X)\r
#define NTF_TEXT_PAD 2\r
\r
-#define NTF_BUTTON_WIDTH ((NTF_TEXT_WIDTH - (KHUI_MAX_ALERT_COMMANDS - 1)*NTF_MARGIN) / KHUI_MAX_ALERT_COMMANDS)\r
-#define NTF_BUTTON_HEIGHT 15\r
+#define NTF_BUTTON_HEIGHT 14\r
\r
#define NTF_TIMEOUT 20000\r
\r
#define ALERT_WINDOW_EX_SYLES (WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP)\r
-#define ALERT_WINDOW_STYLES (WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN)\r
+#define ALERT_WINDOW_STYLES (WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN | DS_NOIDLEMSG)\r
\r
/* Control ids */\r
#define IDC_NTF_ALERTBIN 998\r
alert has no commands. */\r
#define ALERT_HAS_CMDS(a) ((a)->n_alert_commands > 1 || ((a)->n_alert_commands == 1 && (a)->alert_commands[0] != KHUI_PACTION_CLOSE))\r
\r
+#define SCROLL_LINE_SIZE(d) ((d)->cy_max_wnd / 12)\r
+\r
static void\r
add_alert_to_wnd_data(alerter_wnd_data * d,\r
khui_alert * a) {\r
- alerter_alert_data * adata;\r
+ alerter_alert_data * aiter;\r
+ khm_boolean exists = 0;\r
\r
- adata = PMALLOC(sizeof(*adata));\r
- ZeroMemory(adata, sizeof(*adata));\r
+ khui_alert_lock(a);\r
\r
- adata->alert = a;\r
- khui_alert_hold(a);\r
+ /* check if the alert is already there */\r
+ aiter = QTOP(d);\r
+ while(aiter && !exists) {\r
+ if (aiter->alert) {\r
+ khui_alert_lock(aiter->alert);\r
\r
- khui_alert_lock(a);\r
+ if (alert_is_equal(aiter->alert, a)) {\r
+ exists = TRUE;\r
+ }\r
+\r
+ khui_alert_unlock(aiter->alert);\r
+ }\r
+\r
+ aiter = QNEXT(aiter);\r
+ }\r
\r
a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW;\r
\r
- a->displayed = TRUE;\r
+ if (!exists)\r
+ a->displayed = TRUE;\r
\r
khui_alert_unlock(a);\r
\r
- QPUT(d, adata);\r
+ if (!exists) {\r
+ alerter_alert_data * adata;\r
+\r
+ adata = PMALLOC(sizeof(*adata));\r
+ ZeroMemory(adata, sizeof(*adata));\r
+\r
+ adata->alert = a;\r
+ khui_alert_hold(a);\r
+\r
+ QPUT(d, adata);\r
+ d->n_alerts ++;\r
+ }\r
}\r
\r
static alerter_wnd_data *\r
d->cx_wnd = DLG2SCNX(NTF_WIDTH);\r
d->cy_max_wnd = DLG2SCNY(NTF_MAXHEIGHT);\r
\r
- d->s_button.cx = DLG2SCNX(NTF_BUTTON_WIDTH);\r
- d->s_button.cy = DLG2SCNY(NTF_BUTTON_HEIGHT);\r
-\r
d->s_margin.cx = DLG2SCNX(NTF_MARGIN);\r
d->s_margin.cy = DLG2SCNY(NTF_MARGIN);\r
\r
- d->r_text.left = DLG2SCNX(NTF_TEXT_X);\r
- d->r_text.right = DLG2SCNX(NTF_TEXT_WIDTH + NTF_TEXT_X);\r
- d->r_text.top = 0;\r
- d->r_text.bottom = 0;\r
-\r
d->r_title.left = DLG2SCNX(NTF_TITLE_X);\r
d->r_title.right = DLG2SCNX(NTF_TITLE_X + NTF_TITLE_WIDTH);\r
d->r_title.top = 0;\r
d->r_title.bottom = DLG2SCNY(NTF_TITLE_HEIGHT);\r
\r
- d->s_icon.cx = DLG2SCNX(NTF_ICON_WIDTH);\r
- d->s_icon.cy = DLG2SCNY(NTF_ICON_HEIGHT);\r
-\r
d->s_pad.cx = DLG2SCNX(NTF_TEXT_PAD);\r
d->s_pad.cy = DLG2SCNY(NTF_TEXT_PAD);\r
\r
+ d->s_icon.cx = GetSystemMetrics(SM_CXICON);\r
+ d->s_icon.cy = GetSystemMetrics(SM_CYICON);\r
+\r
+ d->r_text.left = d->s_margin.cx * 2 + d->s_icon.cx;\r
+ d->r_text.right = d->cx_wnd - d->s_margin.cx;\r
+ d->r_text.top = 0;\r
+ d->r_text.bottom = 0;\r
+\r
+ d->s_button.cx = ((d->r_text.right - d->r_text.left) - (KHUI_MAX_ALERT_COMMANDS - 1) * d->s_margin.cx) / KHUI_MAX_ALERT_COMMANDS;\r
+ d->s_button.cy = DLG2SCNY(NTF_BUTTON_HEIGHT);\r
+\r
#undef DLG2SCNX\r
#undef DLG2SCNY\r
\r
+ d->c_alert = -1;\r
+\r
return d;\r
}\r
\r
\r
y += d->s_margin.cy;\r
\r
+ /* If there is a title and it differs from the title of the\r
+ alerter window, then we have to show the alert title\r
+ separately. */\r
if (adata->alert->title &&\r
wcscmp(adata->alert->title, d->caption)) {\r
\r
\r
if (ALERT_HAS_CMDS(adata->alert)) {\r
khm_int32 i;\r
- int x;\r
+ int x, width;\r
+ wchar_t caption[KHUI_MAXCCH_SHORT_DESC];\r
+ size_t len;\r
+ SIZE s;\r
+ int skip_close;\r
\r
adata->has_commands = TRUE;\r
\r
+ if (d->n_alerts > 1)\r
+ skip_close = TRUE;\r
+ else\r
+ skip_close = FALSE;\r
+\r
x = d->r_text.left;\r
\r
#ifdef DEBUG\r
#endif\r
\r
for (i=0; i < adata->alert->n_alert_commands; i++) {\r
- SetRect(&adata->r_buttons[i], x, y, x + d->s_button.cx, y + d->s_button.cy);\r
\r
- x += d->s_button.cx + d->s_margin.cx;\r
+ if (adata->alert->alert_commands[i] == KHUI_PACTION_CLOSE && skip_close) {\r
+ SetRectEmpty(&adata->r_buttons[i]);\r
+ continue;\r
+ }\r
+\r
+ caption[0] = L'\0';\r
+ len = 0;\r
+ khm_get_action_caption(adata->alert->alert_commands[i],\r
+ caption, sizeof(caption));\r
+ StringCchLength(caption, ARRAYLENGTH(caption), &len);\r
+\r
+ if (!GetTextExtentPoint32(hdc, caption, (int) len, &s)) {\r
+ width = d->s_button.cx;\r
+ } else {\r
+ width = s.cx + d->s_margin.cx * 2;\r
+ }\r
+\r
+ if (width < d->s_button.cx)\r
+ width = d->s_button.cx;\r
+ else if (width > (d->r_text.right - d->r_text.left))\r
+ width = d->r_text.right - d->r_text.left;\r
+\r
+ if (x + width > d->r_text.right) {\r
+ /* new line */\r
+ x = d->r_text.left;\r
+ y += d->s_button.cy + d->s_pad.cy;\r
+ }\r
+\r
+ SetRect(&adata->r_buttons[i], x, y, x + width, y + d->s_button.cy);\r
+\r
+ x += width + d->s_margin.cx;\r
}\r
\r
y += d->s_button.cy + d->s_margin.cy;\r
\r
}\r
\r
+static void\r
+pick_title_for_alerter_window(alerter_wnd_data * d) {\r
+ alerter_alert_data * adata;\r
+ wchar_t caption[KHUI_MAXCCH_TITLE];\r
+ khm_boolean common_caption = TRUE;\r
+ khui_alert_type ctype = KHUI_ALERTTYPE_NONE;\r
+ khm_boolean common_type = TRUE;\r
+\r
+ /* - If all the alerts have the same title, then we use the common\r
+ title.\r
+\r
+ - If all the alerts are of the same type, then we pick a title\r
+ that is suitable for the type.\r
+\r
+ - All else fails, we use a default caption for the window.\r
+ */\r
+\r
+ caption[0] = L'\0';\r
+ adata = QTOP(d);\r
+ while (adata && (common_caption || common_type)) {\r
+\r
+ if (adata->alert) {\r
+ khui_alert_lock(adata->alert);\r
+\r
+ if (common_caption) {\r
+ if (caption[0] == L'\0') {\r
+ if (adata->alert->title)\r
+ StringCbCopy(caption, sizeof(caption), adata->alert->title);\r
+ } else if (adata->alert->title &&\r
+ wcscmp(caption, adata->alert->title)) {\r
+ common_caption = FALSE;\r
+ }\r
+ }\r
+\r
+ if (common_type) {\r
+ if (ctype == KHUI_ALERTTYPE_NONE)\r
+ ctype = adata->alert->alert_type;\r
+ else if (ctype != adata->alert->alert_type)\r
+ common_type = FALSE;\r
+ }\r
+\r
+ khui_alert_unlock(adata->alert);\r
+ }\r
+\r
+ adata = QNEXT(adata);\r
+ }\r
+\r
+ /* just in case someone changes d->caption to a pointer from an\r
+ array */\r
+#ifdef DEBUG\r
+ assert(sizeof(d->caption) > sizeof(wchar_t *));\r
+#endif\r
+\r
+ if (common_caption && caption[0] != L'\0') {\r
+ StringCbCopy(d->caption, sizeof(d->caption), caption);\r
+ } else if (common_type && ctype != KHUI_ALERTTYPE_NONE) {\r
+ switch(ctype) {\r
+ case KHUI_ALERTTYPE_PLUGIN:\r
+ LoadString(khm_hInstance, IDS_ALERTTYPE_PLUGIN,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ break;\r
+\r
+ case KHUI_ALERTTYPE_EXPIRE:\r
+ LoadString(khm_hInstance, IDS_ALERTTYPE_EXPIRE,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ break;\r
+\r
+ case KHUI_ALERTTYPE_RENEWFAIL:\r
+ LoadString(khm_hInstance, IDS_ALERTTYPE_RENEWFAIL,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ break;\r
+\r
+ case KHUI_ALERTTYPE_ACQUIREFAIL:\r
+ LoadString(khm_hInstance, IDS_ALERTTYPE_ACQUIREFAIL,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ break;\r
+\r
+ case KHUI_ALERTTYPE_CHPW:\r
+ LoadString(khm_hInstance, IDS_ALERTTYPE_CHPW,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ break;\r
+\r
+ default:\r
+ LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ }\r
+ } else {\r
+ LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
+ d->caption, ARRAYLENGTH(d->caption));\r
+ }\r
+\r
+ SetWindowText(d->hwnd, d->caption);\r
+}\r
+\r
static void\r
estimate_alerter_wnd_sizes(alerter_wnd_data * d) {\r
HDC hdc;\r
\r
alerter_alert_data * adata;\r
\r
+ pick_title_for_alerter_window(d);\r
+\r
hdc = GetDC(d->hwnd);\r
#ifdef DEBUG\r
assert(hdc);\r
goto done;\r
\r
for (i=0; i < adata->n_cmd_buttons; i++) {\r
- if (IsRectEmpty(&adata->r_buttons[i]) ||\r
- adata->hwnd_buttons[i] == NULL) {\r
-#ifdef DEBUG\r
- assert(FALSE);\r
-#endif\r
+ if (IsRectEmpty(&adata->r_buttons[i])) {\r
+ /* the button is no longer needed */\r
+ if (adata->hwnd_buttons[i] != NULL) {\r
+ DestroyWindow(adata->hwnd_buttons[i]);\r
+ adata->hwnd_buttons[i] = NULL;\r
+ }\r
+\r
+ continue;\r
+ }\r
+\r
+ if (adata->hwnd_buttons[i] == NULL) {\r
continue;\r
}\r
\r
RECT r_client;\r
RECT r_parent;\r
HWND hw_parent;\r
+ HWND hw_focus = NULL;\r
BOOL close_button = FALSE;\r
BOOL scrollbar = FALSE;\r
BOOL redraw_scollbar = FALSE;\r
r_alerts.bottom = d->cy_max_wnd;\r
\r
CopyRect(&r_client, &r_alerts);\r
- r_client.bottom += d->s_margin.cy * 2 + d->s_button.cy;\r
+ r_client.bottom += d->s_margin.cy + d->s_button.cy + d->s_pad.cy;\r
close_button = TRUE;\r
\r
if (d->scroll_top > d->s_alerts.cy - d->cy_max_wnd)\r
if (d->hw_bin == NULL) {\r
d->hw_bin = CreateWindowEx(WS_EX_CONTROLPARENT,\r
MAKEINTATOM(atom_alert_bin),\r
- L"",\r
+ L"Alert Container",\r
WS_CHILD | WS_CLIPCHILDREN |\r
WS_VISIBLE |\r
((scrollbar)? WS_VSCROLL : 0),\r
if (adata->has_commands) {\r
int i;\r
wchar_t caption[KHUI_MAXCCH_SHORT_DESC];\r
- khui_action * action;\r
RECT r;\r
\r
+ if (adata->hwnd_marker) {\r
+ DestroyWindow(adata->hwnd_marker);\r
+ adata->hwnd_marker = NULL;\r
+ }\r
+\r
khui_alert_lock(adata->alert);\r
\r
adata->n_cmd_buttons = adata->alert->n_alert_commands;\r
\r
n_buttons ++;\r
\r
+ if (IsRectEmpty(&adata->r_buttons[i])) {\r
+ /* this button is not necessary */\r
+ if (adata->hwnd_buttons[i]) {\r
+ DestroyWindow(adata->hwnd_buttons[i]);\r
+ adata->hwnd_buttons[i] = NULL;\r
+ }\r
+\r
+ continue;\r
+ }\r
+\r
if (adata->hwnd_buttons[i] != NULL) {\r
/* already there */\r
CopyRect(&r, &adata->r_buttons[i]);\r
\r
last_window = adata->hwnd_buttons[i];\r
\r
- continue;\r
- }\r
-\r
- action = khui_find_action(adata->alert->alert_commands[i]);\r
+ if (hw_focus == NULL)\r
+ hw_focus = adata->hwnd_buttons[i];\r
\r
- if (action == NULL) {\r
-#ifdef DEBUG\r
- assert(FALSE);\r
-#endif\r
continue;\r
}\r
\r
- if (action->caption)\r
- StringCbCopy(caption, sizeof(caption), action->caption);\r
- else if (action->is_caption)\r
- LoadString(khm_hInstance, action->is_caption, caption,\r
- ARRAYLENGTH(caption));\r
- else {\r
-#ifdef DEBUG\r
- assert(FALSE);\r
-#endif\r
- caption[0] = L'\0';\r
- }\r
+ khm_get_action_caption(adata->alert->alert_commands[i],\r
+ caption, sizeof(caption));\r
\r
CopyRect(&r, &adata->r_buttons[i]);\r
OffsetRect(&r, 0, y);\r
CreateWindowEx(0,\r
L"BUTTON",\r
caption,\r
- WS_CHILD | WS_TABSTOP,\r
+ WS_CHILD | WS_TABSTOP | BS_NOTIFY,\r
r.left, r.top,\r
r.right - r.left,\r
r.bottom - r.top,\r
#ifdef DEBUG\r
assert(adata->hwnd_buttons[i]);\r
#endif\r
+\r
+ if (d->hfont) {\r
+ SendMessage(adata->hwnd_buttons[i], WM_SETFONT,\r
+ (WPARAM) d->hfont, FALSE);\r
+ }\r
+\r
SetWindowPos(adata->hwnd_buttons[i], last_window,\r
0, 0, 0, 0,\r
SWP_NOACTIVATE | SWP_NOOWNERZORDER |\r
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);\r
+\r
last_window = adata->hwnd_buttons[i];\r
+\r
+ if (hw_focus == NULL)\r
+ hw_focus = adata->hwnd_buttons[i];\r
}\r
\r
khui_alert_unlock(adata->alert);\r
+ } else {\r
+ int i;\r
+\r
+ /* Destroy any buttons that belong to the alert. We\r
+ might have some left over, if there were command\r
+ belonging to the alert that were ignored.*/\r
+\r
+ for (i=0; i < adata->n_cmd_buttons; i++) {\r
+ if (adata->hwnd_buttons[i]) {\r
+ DestroyWindow(adata->hwnd_buttons[i]);\r
+ adata->hwnd_buttons[i] = NULL;\r
+ }\r
+ }\r
+\r
+ adata->n_cmd_buttons = 0;\r
+\r
+ if (adata->hwnd_marker == NULL) {\r
+ adata->hwnd_marker =\r
+ CreateWindowEx(0,\r
+ L"BUTTON",\r
+ L"Marker",\r
+ WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_NOTIFY,\r
+ -10, 0,\r
+ 5, 5,\r
+ d->hw_bin,\r
+ (HMENU) (INT_PTR) IDC_FROM_IDX(idx, 0),\r
+ khm_hInstance,\r
+ NULL);\r
+#ifdef DEBUG\r
+ assert(adata->hwnd_marker);\r
+#endif\r
+ }\r
+\r
+ SetWindowPos(adata->hwnd_marker, last_window,\r
+ 0, 0, 0, 0,\r
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER |\r
+ SWP_NOMOVE | SWP_NOSIZE);\r
+\r
+ last_window = adata->hwnd_marker;\r
+\r
+ if (hw_focus == NULL)\r
+ hw_focus = adata->hwnd_marker;\r
}\r
\r
y += adata->r_alert.bottom;\r
adata = QNEXT(adata);\r
+ idx++;\r
}\r
\r
d->n_cmd_buttons = n_buttons;\r
\r
if (close_button) {\r
if (d->hw_close == NULL) {\r
- khui_action * close_action;\r
wchar_t caption[256];\r
\r
- close_action = khui_find_action(KHUI_PACTION_CLOSE);\r
-#ifdef DEBUG\r
- assert(close_action);\r
-#endif\r
- if (close_action->caption)\r
- StringCbCopy(caption, sizeof(caption), close_action->caption);\r
- else if (close_action->is_caption)\r
- LoadString(khm_hInstance, close_action->is_caption, caption,\r
- ARRAYLENGTH(caption));\r
- else {\r
-#ifdef DEBUG\r
- assert(FALSE);\r
-#endif\r
- caption[0] = L'\0';\r
- }\r
+ khm_get_action_caption(KHUI_PACTION_CLOSE, caption, sizeof(caption));\r
\r
d->hw_close = CreateWindowEx(0,\r
L"BUTTON",\r
caption,\r
- WS_CHILD | BS_DEFPUSHBUTTON,\r
+ WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP | BS_NOTIFY,\r
0,0,100,100,\r
d->hwnd,\r
(HMENU) IDC_NTF_CLOSE,\r
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER |\r
SWP_SHOWWINDOW);\r
}\r
+\r
+ if (hw_focus == NULL)\r
+ hw_focus = d->hw_close;\r
+\r
+ } else {\r
+ if (d->hw_close != NULL) {\r
+ DestroyWindow(d->hw_close);\r
+ d->hw_close = NULL;\r
+ }\r
}\r
\r
CopyRect(&r_window, &r_client);\r
SWP_SHOWWINDOW | SWP_NOOWNERZORDER);\r
\r
}\r
+\r
+ if (hw_focus != NULL)\r
+ PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw_focus, MAKELPARAM(TRUE, 0));\r
+}\r
+\r
+static void\r
+scroll_to_position(alerter_wnd_data * d, int new_pos, khm_boolean redraw_scrollbar) {\r
+ int delta;\r
+ SCROLLINFO si;\r
+ HWND hwnd = d->hw_bin;\r
+\r
+ if (new_pos < 0)\r
+ new_pos = 0;\r
+ else if (new_pos > d->s_alerts.cy - d->cy_max_wnd)\r
+ new_pos = d->s_alerts.cy - d->cy_max_wnd;\r
+\r
+ if (new_pos == d->scroll_top)\r
+ return;\r
+\r
+ delta = d->scroll_top - new_pos;\r
+\r
+ d->scroll_top -= delta;\r
+\r
+ ScrollWindowEx(hwnd, 0, delta,\r
+ NULL, NULL, NULL, NULL,\r
+ SW_INVALIDATE | SW_ERASE);\r
+\r
+ layout_command_buttons(d);\r
+\r
+ ZeroMemory(&si, sizeof(si));\r
+\r
+ si.fMask = SIF_POS;\r
+ si.nPos = d->scroll_top;\r
+\r
+ SetScrollInfo(hwnd, SB_VERT, &si, redraw_scrollbar);\r
+}\r
+\r
+static void\r
+select_alert(alerter_wnd_data * d, int alert) {\r
+\r
+ int y;\r
+ RECT old_sel, new_sel;\r
+ alerter_alert_data * adata;\r
+ int idx;\r
+\r
+ if (d->n_alerts == 1 ||\r
+ alert < 0 ||\r
+ alert > d->n_alerts ||\r
+ d->c_alert == alert)\r
+ return;\r
+\r
+ SetRectEmpty(&old_sel);\r
+ SetRectEmpty(&new_sel);\r
+ idx = 0; y = -d->scroll_top;\r
+ adata = QTOP(d);\r
+ while(adata && (idx <= d->c_alert || idx <= alert)) {\r
+\r
+ if (idx == d->c_alert) {\r
+ CopyRect(&old_sel, &adata->r_alert);\r
+ OffsetRect(&old_sel, 0, y);\r
+ }\r
+\r
+ if (idx == alert) {\r
+ CopyRect(&new_sel, &adata->r_alert);\r
+ OffsetRect(&new_sel, 0, y);\r
+ }\r
+\r
+ y += adata->r_alert.bottom;\r
+ idx ++;\r
+ adata = QNEXT(adata);\r
+ }\r
+\r
+ d->c_alert = alert;\r
+ if (!IsRectEmpty(&old_sel))\r
+ InvalidateRect(d->hw_bin, &old_sel, TRUE);\r
+ if (!IsRectEmpty(&new_sel))\r
+ InvalidateRect(d->hw_bin, &new_sel, TRUE);\r
+}\r
+\r
+static void\r
+ensure_command_is_visible(alerter_wnd_data * d, int id) {\r
+ int alert_idx;\r
+ int y = 0;\r
+ alerter_alert_data * adata;\r
+ int new_pos = 0;\r
+\r
+ alert_idx = ALERT_FROM_IDC(id);\r
+\r
+#ifdef DEBUG\r
+ assert(alert_idx >= 0 && alert_idx < d->n_alerts);\r
+#endif\r
+ if (alert_idx >= d->n_alerts || alert_idx < 0)\r
+ return;\r
+\r
+ adata = QTOP(d);\r
+ while(adata && alert_idx > 0) {\r
+ y += adata->r_alert.bottom;\r
+ alert_idx--;\r
+ adata = QNEXT(adata);\r
+ }\r
+\r
+#ifdef DEBUG\r
+ assert(alert_idx == 0);\r
+ assert(adata);\r
+ assert(adata->alert);\r
+#endif\r
+ if (adata == NULL || alert_idx != 0)\r
+ return;\r
+\r
+ new_pos = d->scroll_top;\r
+ if (y < d->scroll_top) {\r
+ new_pos = y;\r
+ } else if (y + adata->r_alert.bottom > d->scroll_top + d->cy_max_wnd) {\r
+ new_pos = y + adata->r_alert.bottom - d->cy_max_wnd;\r
+ }\r
+\r
+ if (new_pos != d->scroll_top)\r
+ scroll_to_position(d, new_pos, TRUE);\r
+\r
+ select_alert(d, ALERT_FROM_IDC(id));\r
+}\r
+\r
+static void\r
+handle_mouse_select(alerter_wnd_data * d, int mouse_x, int mouse_y) {\r
+ int y;\r
+ alerter_alert_data * adata;\r
+\r
+ y = -d->scroll_top;\r
+ adata = QTOP(d);\r
+ while(adata) {\r
+ if (y <= mouse_y && (y + adata->r_alert.bottom) > mouse_y) {\r
+ HWND hw = NULL;\r
+\r
+ if (adata->n_cmd_buttons > 0)\r
+ hw = adata->hwnd_buttons[0];\r
+ else\r
+ hw = adata->hwnd_marker;\r
+\r
+ if (hw && !IsWindowEnabled(hw))\r
+ hw = GetNextDlgTabItem(d->hwnd, hw, FALSE);\r
+\r
+ if (hw)\r
+ PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw, MAKELPARAM(TRUE, 0));\r
+\r
+ return;\r
+ }\r
+\r
+ y += adata->r_alert.bottom;\r
+ adata = QNEXT(adata);\r
+ }\r
+}\r
+\r
+static void\r
+process_command_button(alerter_wnd_data * d, int id) {\r
+ int alert_idx;\r
+ int cmd_idx;\r
+ khm_int32 flags = 0;\r
+ khm_int32 cmd = 0;\r
+ alerter_alert_data * adata;\r
+ int i;\r
+\r
+ alert_idx = ALERT_FROM_IDC(id);\r
+ cmd_idx = BUTTON_FROM_IDC(id);\r
+\r
+#ifdef DEBUG\r
+ assert(alert_idx >= 0 && alert_idx < d->n_alerts);\r
+#endif\r
+ if (alert_idx >= d->n_alerts || alert_idx < 0)\r
+ return;\r
+\r
+ adata = QTOP(d);\r
+ while(adata && alert_idx > 0) {\r
+ alert_idx--;\r
+ adata = QNEXT(adata);\r
+ }\r
+\r
+#ifdef DEBUG\r
+ assert(alert_idx == 0);\r
+ assert(adata);\r
+ assert(adata->alert);\r
+#endif\r
+ if (adata == NULL || alert_idx != 0)\r
+ return;\r
+\r
+ khui_alert_lock(adata->alert);\r
+#ifdef DEBUG\r
+ assert(cmd_idx >= 0 && cmd_idx < adata->alert->n_alert_commands);\r
+#endif\r
+\r
+ if (cmd_idx >= 0 && cmd_idx < adata->alert->n_alert_commands) {\r
+ cmd = adata->alert->alert_commands[cmd_idx];\r
+ }\r
+\r
+ flags = adata->alert->flags;\r
+\r
+ adata->alert->response = cmd;\r
+\r
+ khui_alert_unlock(adata->alert);\r
+\r
+ /* if we were supposed to dispatch the command, do so */\r
+ if (cmd != 0 &&\r
+ cmd != KHUI_PACTION_CLOSE &&\r
+ (flags & KHUI_ALERT_FLAG_DISPATCH_CMD)) {\r
+ PostMessage(khm_hwnd_main, WM_COMMAND,\r
+ MAKEWPARAM(cmd, 0), 0);\r
+ }\r
+\r
+ /* if this was the only alert in the alert group and its close\r
+ button was clicked, we close the alert window. Otherwise, the\r
+ alert window creates its own close button that closes the\r
+ window. */\r
+ if (d->n_alerts == 1) {\r
+ PostMessage(d->hwnd, WM_CLOSE, 0, 0);\r
+ }\r
+\r
+ /* While we are at it, we should disable the buttons for this\r
+ alert since we have already dispatched the command for it. */\r
+ if (cmd != 0) {\r
+ HWND hw_focus = GetFocus();\r
+ khm_boolean focus_trapped = FALSE;\r
+\r
+ for (i=0; i < adata->n_cmd_buttons; i++) {\r
+ if (adata->hwnd_buttons[i]) {\r
+ if (hw_focus == adata->hwnd_buttons[i])\r
+ focus_trapped = TRUE;\r
+\r
+ EnableWindow(adata->hwnd_buttons[i], FALSE);\r
+ }\r
+ }\r
+\r
+ if (focus_trapped) {\r
+ hw_focus = GetNextDlgTabItem(d->hwnd, hw_focus, FALSE);\r
+ if (hw_focus)\r
+ PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw_focus, MAKELPARAM(TRUE,0));\r
+ }\r
+ }\r
}\r
\r
static void\r
\r
khui_alert_lock(adata->alert);\r
\r
- adata->alert->flags &= ~KHUI_ALERT_FLAG_DISPLAY_WINDOW;\r
-\r
adata->alert->displayed = FALSE;\r
\r
khui_alert_unlock(adata->alert);\r
return FALSE;\r
}\r
\r
+/* both a1 and a2 must be locked */\r
+static khm_boolean\r
+alert_is_equal(khui_alert * a1, khui_alert * a2) {\r
+ khm_int32 i;\r
+\r
+ if ((a1->severity != a2->severity) ||\r
+ (a1->n_alert_commands != a2->n_alert_commands) ||\r
+ (a1->title && (!a2->title || wcscmp(a1->title, a2->title))) ||\r
+ (!a1->title && a2->title) ||\r
+ (a1->message && (!a2->message || wcscmp(a1->message, a2->message))) ||\r
+ (!a1->message && a2->message) ||\r
+ (a1->suggestion && (!a2->suggestion || wcscmp(a1->suggestion, a2->suggestion))) ||\r
+ (!a1->suggestion && a2->suggestion)) {\r
+\r
+ return FALSE;\r
+\r
+ }\r
+\r
+ for (i=0; i < a1->n_alert_commands; i++) {\r
+ if (a1->alert_commands[i] != a2->alert_commands[i])\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
/* the return value is the number of alerts added to alist */\r
static khm_int32\r
alert_consolidate(alert_list * alist,\r
\r
if (n_added == 0 && add_from_queue) {\r
khui_alert * q;\r
- int s, i;\r
+ int i;\r
\r
- s = alert_queue_get_size();\r
- for (i=0; i < s && n_added == 0; i++) {\r
+ queue_size = alert_queue_get_size();\r
+ for (i=0; i < queue_size && n_added == 0; i++) {\r
q = alert_queue_get_alert_by_pos(i);\r
if (q) {\r
khui_alert_lock(q);\r
alert_queue_delete_alert(a);\r
alert_list_add_alert(alist, a);\r
n_added ++;\r
- queue_size = alert_queue_get_size();\r
+\r
+ queue_size--;\r
+ i--;\r
+#ifdef DEBUG\r
+ assert(alert_queue_get_size() == queue_size);\r
+#endif\r
}\r
khui_alert_unlock(a);\r
khui_alert_release(a);\r
return KHM_ERROR_SUCCESS;\r
}\r
\r
+static void\r
+show_queued_alerts(void) {\r
+\r
+ if (!ALERT_DISPLAYED()) {\r
+\r
+ /* show next consolidated batch */\r
+ alert_list alist;\r
+ int n;\r
+\r
+ alert_list_init(&alist);\r
+ n = alert_consolidate(&alist, NULL, TRUE);\r
+\r
+ if (n) {\r
+ if (n == 1) {\r
+ khui_alert_lock(alist.alerts[0]);\r
+\r
+ if (alist.alerts[0]->title) {\r
+ alert_list_set_title(&alist, alist.alerts[0]->title);\r
+ } else {\r
+ wchar_t title[KHUI_MAXCCH_TITLE];\r
+ LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
+ title, ARRAYLENGTH(title));\r
+ alert_list_set_title(&alist, title);\r
+ }\r
+\r
+ khui_alert_unlock(alist.alerts[0]);\r
+ } else {\r
+ wchar_t title[KHUI_MAXCCH_TITLE];\r
+ LoadString(khm_hInstance, IDS_ALERT_DEFAULT,\r
+ title, ARRAYLENGTH(title));\r
+ alert_list_set_title(&alist, title);\r
+ }\r
+\r
+ alert_show_list(&alist);\r
+ }\r
+\r
+ alert_list_destroy(&alist);\r
+\r
+ check_for_queued_alerts();\r
+ }\r
+}\r
+\r
+\r
static void\r
check_for_queued_alerts(void) {\r
if (!is_alert_queue_empty()) {\r
khm_statusbar_set_part(KHUI_SBPART_NOTICE,\r
hi,\r
a->title);\r
+ } else {\r
+ khm_statusbar_set_part(KHUI_SBPART_NOTICE,\r
+ NULL, NULL);\r
+#ifdef DEBUG\r
+ DebugBreak();\r
+#endif\r
}\r
\r
khui_alert_unlock(a);\r
}\r
break;\r
\r
-#if 0\r
- case WM_PAINT:\r
- {\r
- RECT r_update;\r
- PAINTSTRUCT ps;\r
- HDC hdc;\r
- alerter_wnd_data * d;\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
- hdc = BeginPaint(hwnd, &ps);\r
-\r
- EndPaint(hwnd, &ps);\r
-\r
- return FALSE;\r
- }\r
- break; /* not reached */\r
-#endif\r
-\r
case WM_COMMAND:\r
{\r
alerter_wnd_data * d;\r
\r
DestroyWindow(hwnd);\r
\r
-#ifdef FORLATER\r
- if (LOWORD(wParam) == KHUI_PACTION_NEXT) {\r
- kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW_QUEUED, 0, 0);\r
- }\r
-#endif\r
return 0;\r
}\r
}\r
}\r
break;\r
+\r
+ case WM_CLOSE:\r
+ {\r
+ khm_leave_modal();\r
+\r
+ DestroyWindow(hwnd);\r
+\r
+ return 0;\r
+ }\r
}\r
\r
+ /* Since this is a custom built dialog, we use DefDlgProc instead\r
+ of DefWindowProc. */\r
return DefDlgProc(hwnd, uMsg, wParam, lParam);\r
- //return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
}\r
\r
static LRESULT CALLBACK \r
}\r
return 0;\r
\r
+ case WM_ERASEBKGND:\r
+ /* we erase the background when we are drawing the alerts\r
+ anyway. */\r
+ return 0;\r
+\r
case WM_PRINTCLIENT:\r
in_printclient = TRUE;\r
/* fallthrough */\r
alerter_wnd_data * d;\r
alerter_alert_data * adata;\r
size_t len;\r
+ int idx;\r
\r
d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
#ifdef DEBUG\r
assert(d->hfont);\r
#endif\r
\r
+#ifdef ALERT_STATIC_BACKGROUND\r
if (in_printclient || ps.fErase) {\r
HBRUSH hb_background;\r
\r
GetClientRect(hwnd, &r);\r
FillRect(hdc, &r, hb_background);\r
}\r
+#endif\r
\r
SetBkMode(hdc, TRANSPARENT);\r
\r
hf_old = SelectFont(hdc, d->hfont);\r
\r
y = -d->scroll_top;\r
-\r
+ idx = 0;\r
/* go through the alerts and display them */\r
adata = QTOP(d);\r
while(adata) {\r
khui_alert * a;\r
\r
+#ifndef ALERT_STATIC_BACKGROUND\r
+#define MIX_C(v1, v2, p) (((int)v1) * p + (((int) v2) * (256 - p)))\r
+#define ALPHA 50\r
+ if (in_printclient || ps.fErase) {\r
+ TRIVERTEX v[2];\r
+ GRADIENT_RECT gr;\r
+ COLORREF clr;\r
+ COLORREF clr2;\r
+\r
+ CopyRect(&r, &adata->r_alert);\r
+ OffsetRect(&r, 0, y);\r
+\r
+ v[0].x = r.left;\r
+ v[0].y = r.top;\r
+ v[0].Alpha = 0;\r
+\r
+ v[1].x = r.right;\r
+ v[1].y = r.bottom;\r
+ v[1].Alpha = 0;\r
+\r
+ if (idx == d->c_alert) {\r
+ clr = GetSysColor(COLOR_HOTLIGHT);\r
+\r
+ clr2 = GetSysColor(COLOR_BTNHIGHLIGHT);\r
+ v[0].Red = MIX_C(GetRValue(clr), GetRValue(clr2), ALPHA);\r
+ v[0].Green = MIX_C(GetGValue(clr), GetGValue(clr2), ALPHA);\r
+ v[0].Blue = MIX_C(GetBValue(clr), GetBValue(clr2), ALPHA);\r
+\r
+ clr2 = GetSysColor(COLOR_BTNFACE);\r
+ v[1].Red = MIX_C(GetRValue(clr), GetRValue(clr2), ALPHA);\r
+ v[1].Green = MIX_C(GetGValue(clr), GetGValue(clr2), ALPHA);\r
+ v[1].Blue = MIX_C(GetBValue(clr), GetBValue(clr2), ALPHA);\r
+ } else {\r
+ clr = GetSysColor(COLOR_BTNHIGHLIGHT);\r
+ v[0].Red = ((int)GetRValue(clr)) << 8;\r
+ v[0].Green = ((int)GetGValue(clr)) << 8;\r
+ v[0].Blue = ((int)GetBValue(clr)) << 8;\r
+\r
+ clr = GetSysColor(COLOR_BTNFACE);\r
+ v[1].Red = ((int)GetRValue(clr)) << 8;\r
+ v[1].Green = ((int)GetGValue(clr)) << 8;\r
+ v[1].Blue = ((int)GetBValue(clr)) << 8;\r
+ }\r
+\r
+ gr.UpperLeft = 0;\r
+ gr.LowerRight = 1;\r
+ GradientFill(hdc, v, 2, &gr, 1, GRADIENT_FILL_RECT_V);\r
+ }\r
+#undef ALPHA\r
+#undef MIX_C\r
+#endif\r
+\r
a = adata->alert;\r
#ifdef DEBUG\r
assert(a != NULL);\r
#endif\r
khui_alert_lock(a);\r
\r
- /* if the alert has a title and it's different from\r
- the original caption for the alert dialog, we have\r
- to display the title. */\r
- if (a->title &&\r
- wcscmp(a->title, d->caption)) {\r
+ if (!IsRectEmpty(&adata->r_title)) {\r
\r
CopyRect(&r, &adata->r_title);\r
OffsetRect(&r, 0, y);\r
khui_alert_unlock(a);\r
\r
y += adata->r_alert.bottom;\r
+ idx++;\r
\r
adata = QNEXT(adata);\r
}\r
\r
case WM_VSCROLL:\r
{\r
+ alerter_wnd_data * d;\r
+ int new_pos = 0;\r
+ SCROLLINFO si;\r
+\r
+ d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ if (d == NULL)\r
+ break; /* we can't handle the message */\r
+\r
+ ZeroMemory(&si, sizeof(si));\r
+\r
+ switch(LOWORD(wParam)) {\r
+ case SB_BOTTOM:\r
+ new_pos = d->s_alerts.cy - d->cy_max_wnd;\r
+ break;\r
+\r
+ case SB_LINEDOWN:\r
+ new_pos = d->scroll_top + SCROLL_LINE_SIZE(d);\r
+ break;\r
+\r
+ case SB_LINEUP:\r
+ new_pos = d->scroll_top - SCROLL_LINE_SIZE(d);\r
+ break;\r
+\r
+ case SB_PAGEDOWN:\r
+ new_pos = d->scroll_top + d->cy_max_wnd;\r
+ break;\r
+\r
+ case SB_PAGEUP:\r
+ new_pos = d->scroll_top - d->cy_max_wnd;\r
+ break;\r
+\r
+ case SB_THUMBPOSITION:\r
+ case SB_THUMBTRACK:\r
+ si.fMask = SIF_TRACKPOS;\r
+ GetScrollInfo(hwnd, SB_VERT, &si);\r
+ new_pos = si.nTrackPos;\r
+ break;\r
+\r
+ case SB_TOP:\r
+ new_pos = 0;\r
+ break;\r
+\r
+ case SB_ENDSCROLL:\r
+ si.fMask = SIF_POS;\r
+ si.nPos = d->scroll_top;\r
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);\r
+ return 0;\r
+\r
+ default:\r
+ return 0;\r
+ }\r
+\r
+ scroll_to_position(d, new_pos, FALSE);\r
}\r
return 0;\r
\r
case WM_COMMAND:\r
{\r
+ alerter_wnd_data * d;\r
+\r
+ d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ if (d == NULL)\r
+ break;\r
+\r
+ if (HIWORD(wParam) == BN_CLICKED) {\r
+ process_command_button(d, LOWORD(wParam));\r
+ return 0;\r
+ } else if (HIWORD(wParam) == BN_SETFOCUS) {\r
+ ensure_command_is_visible(d, LOWORD(wParam));\r
+ return 0;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WM_LBUTTONUP:\r
+ {\r
+ alerter_wnd_data * d;\r
+ int x,y;\r
+\r
+ d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
+#ifdef DEBUG\r
+ assert(d);\r
+#endif\r
+ if (d == NULL)\r
+ break;\r
+\r
+ x = GET_X_LPARAM(lParam);\r
+ y = GET_Y_LPARAM(lParam);\r
+\r
+ handle_mouse_select(d, x, y);\r
}\r
break;\r
\r
case WM_DESTROY:\r
{\r
+ /* nothing needs to be done here */\r
}\r
return 0;\r
}\r
\r
Shell_NotifyIcon(NIM_ADD, &ni);\r
\r
+ DestroyIcon(ni.hIcon);\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
Shell_NotifyIcon(NIM_DELETE, &ni);\r
}\r
\r
+static khm_int32\r
+get_default_notifier_action(void) {\r
+ khm_int32 def_cmd = KHUI_ACTION_OPEN_APP;\r
+ khm_handle csp_cw = NULL;\r
+ khm_size i;\r
+\r
+ if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ,\r
+ &csp_cw)))\r
+ def_cmd;\r
+\r
+ khc_read_int32(csp_cw, L"NotificationAction", &def_cmd);\r
+\r
+ khc_close_space(csp_cw);\r
+\r
+ for (i=0; i < n_khm_notifier_actions; i++) {\r
+ if (khm_notifier_actions[i] == def_cmd)\r
+ break;\r
+ }\r
+\r
+ if (i < n_khm_notifier_actions)\r
+ return def_cmd;\r
+ else\r
+ return KHUI_ACTION_OPEN_APP;\r
+}\r
+\r
+void khm_notify_icon_activate(void) {\r
+ /* if there are any notifications waiting to be shown and there\r
+ are no alerts already being shown, we show them. Otherwise we\r
+ execute the default action. */\r
+\r
+ khm_notify_icon_change(KHERR_NONE);\r
+\r
+ if (!is_alert_queue_empty() && !ALERT_DISPLAYED()) {\r
+\r
+ khm_show_main_window();\r
+ show_queued_alerts();\r
+\r
+ } else if (balloon_alert != NULL && khui_alert_windows == NULL) {\r
+\r
+ khui_alert * a;\r
+\r
+ a = balloon_alert;\r
+ balloon_alert = NULL;\r
+\r
+ khui_alert_lock(a);\r
+ if (balloon_alert->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) {\r
+ alert_show_normal(a);\r
+ }\r
+ khui_alert_unlock(a);\r
+ khui_alert_release(a);\r
+\r
+ } else {\r
+ khm_int32 cmd = 0;\r
+\r
+ cmd = get_default_notifier_action();\r
+\r
+ if (cmd == KHUI_ACTION_OPEN_APP) {\r
+ if (khm_is_main_window_visible()) {\r
+ khm_hide_main_window();\r
+ } else {\r
+ khm_show_main_window();\r
+ }\r
+ } else {\r
+ khui_action_trigger(cmd, NULL);\r
+ }\r
+\r
+ check_for_queued_alerts();\r
+ }\r
+}\r
+\r
/*********************************************************************\r
Initialization\r
**********************************************************************/\r
\r
notifier_ready = FALSE;\r
}\r
+\r
+/***** testing *****/\r
+\r
+void\r
+create_test_alerts(void) {\r
+\r
+ khui_alert * a;\r
+ int i;\r
+\r
+ for (i=0; i < 50; i++) {\r
+ wchar_t buf[128];\r
+\r
+ StringCbPrintf(buf, sizeof(buf), L"Foo bar baz. This is alert number %d", i);\r
+ khui_alert_create_simple(L"Title", buf, KHERR_INFO, &a);\r
+ khui_alert_set_type(a, KHUI_ALERTTYPE_PLUGIN);\r
+\r
+ khui_alert_add_command(a, KHUI_ACTION_NEW_CRED);\r
+ khui_alert_add_command(a, KHUI_ACTION_CLOSE_APP);\r
+ khui_alert_add_command(a, KHUI_ACTION_PROPERTIES);\r
+ khui_alert_add_command(a, KHUI_ACTION_OPEN_APP);\r
+ khui_alert_add_command(a, KHUI_ACTION_VIEW_REFRESH);\r
+\r
+ khui_alert_show(a);\r
+ khui_alert_release(a);\r
+ }\r
+}\r
KHM_NOTIF_EXP\r
};\r
\r
+extern khm_int32 khm_notifier_actions[];\r
+extern khm_size n_khm_notifier_actions;\r
+\r
void \r
khm_init_notifier(void);\r
\r
void\r
khm_notify_icon_expstate(enum khm_notif_expstate expseverity);\r
\r
+void\r
+khm_notify_icon_activate(void);\r
+\r
#endif\r
#define IDS_NCN_IDENT_UNKNOWN 299\r
#define IDS_REMOTE_FAIL 300\r
#define IDS_REMOTE_FAIL_TITLE 301\r
+#define IDS_NOTIFICATION_ACTIONS 302\r
+#define IDS_IDACTION_NEW 302\r
+#define IDS_IDACTIONT_NEW 303\r
+#define IDS_IDACTIONT_RENEW 304\r
+#define IDS_IDACTIONT_DESTROY 305\r
+#define IDS_ALERTTYPE_PLUGIN 306\r
+#define IDS_ALERTTYPE_EXPIRE 307\r
+#define IDS_ALERTTYPE_RENEWFAIL 308\r
+#define IDS_ALERTTYPE_ACQUIREFAIL 309\r
+#define IDS_ALERTTYPE_CHPW 310\r
+#define IDS_ACTION_LAYOUT_MINI 311\r
+#define IDS_IDEXPDISP_NOCRED 312\r
+#define IDS_IDEXPDISP_1CRED 313\r
+#define IDS_IDEXPDISP_NCRED 314\r
#define IDC_NC_USERNAME 1007\r
#define IDC_NC_PASSWORD 1008\r
#define IDC_NC_CREDTEXT_LABEL 1009\r
#define IDC_SM_LBL 1137\r
#define IDC_MED_LBL 1138\r
#define IDC_LG_LBL 1139\r
+#define IDC_CFG_NOTACTION 1141\r
+#define IDC_CFG_NOTACT_STATIC 1142\r
#define IDA_ACTIVATE_MENU 40003\r
#define IDA_UP 40004\r
#define IDA_DOWN 40005\r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
#define _APS_NEXT_RESOURCE_VALUE 212\r
#define _APS_NEXT_COMMAND_VALUE 40010\r
-#define _APS_NEXT_CONTROL_VALUE 1140\r
+#define _APS_NEXT_CONTROL_VALUE 1143\r
#define _APS_NEXT_SYMED_VALUE 101\r
#endif\r
#endif\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
+\r
+ if (eff_ident != NULL) {\r
+ khm_int32 cmd;\r
+\r
+ cmd = khm_get_identity_new_creds_action(eff_ident);\r
+\r
+ if (cmd) {\r
+ khui_alert_add_command(alert, cmd);\r
+ khui_alert_add_command(alert, KHUI_PACTION_CLOSE);\r
+ }\r
+ }\r
+\r
khui_alert_show(alert);\r
khui_alert_release(alert);\r
}\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
+ DefaultViewMini,KC_STRING,CompactIdentity,\r
ViewList,KC_STRING,"ByIdentity,ByLocation,ByType",\r
PaddingHorizontal,KC_INT32,4,\r
PaddingVertical,KC_INT32,2,\r
MinThreshold,KC_INT32,10,Min value for a threshold (0)\r
LogToFile,KC_INT32,0,Boolean. If true logs trace events to a nidmdbg.log in the temp folder\r
DestroyCredsOnExit,KC_INT32,0,Boolean. If true; all credentials will be destroyed when NetIDMgr exits.\r
+ NotificationAction,KC_INT32,50025,Action to perform when the user clicks on the notification icon.\r
+ DefaultWindowMode,KC_INT32,1,(0-normal; 1-mini)\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
+ Dock,KC_INT32,0,Dock on window corner (0-none; 1-top left; 2-top right; 3-bottom right; 4-bottom left)\r
_Schema,KC_ENDSPACE,0,\r
Main,KC_SPACE,0,Main window\r
Main,KC_ENDSPACE,0,\r
+ MainMini,KC_SPACE,0,Main window (mini mode)\r
+ Width,KC_INT32,470,\r
+ Height,KC_INT32,500,\r
+ Dock,KC_INT32,3,\r
+ MainMini,KC_ENDSPACE,0,\r
NewCred,KC_SPACE,0,New credentials window\r
ForceToTop,KC_INT32,1,Force new creds window to the top\r
AnimateSizeChanges,KC_INT32,1,Animate the new creds window when the size needs changing.\r
TimeLeft,KC_ENDSPACE,0\r
Columns,KC_ENDSPACE,0\r
ByLocation,KC_ENDSPACE,0\r
+ CompactIdentity,KC_SPACE,0,Default Compact View by Identity\r
+ Description,KC_STRING,Compact view of identities\r
+ ColumnList,KC_STRING,"IdentityName",\r
+ ExpandedIdentity,KC_INT32,1,Use expanded display of identity headers\r
+ NoHeader,KC_INT32,1,Suppress the column header\r
+ Columns,KC_SPACE,0,\r
+ IdentityName,KC_SPACE,0,\r
+ Width,KC_INT32,415,\r
+ SortIndex,KC_INT32,0,\r
+ Flags,KC_INT32,11\r
+ IdentityName,KC_ENDSPACE,0,\r
+ Columns,KC_ENDSPACE,0,\r
+ CompactIdentity,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
KHUI_ACTION_RENEW_CRED,FCONTROL|FVIRTKEY,\'R\',KHUI_ACCEL_SCOPE_GLOBAL\r
KHUI_ACTION_IMPORT,FCONTROL|FVIRTKEY,\'I\',KHUI_ACCEL_SCOPE_GLOBAL\r
KHUI_ACTION_DESTROY_CRED,FCONTROL|FVIRTKEY,\'D\',KHUI_ACCEL_SCOPE_GLOBAL\r
+KHUI_ACTION_LAYOUT_MINI,FVIRTKEY,VK_F7,KHUI_ACCEL_SCOPE_GLOBAL\r
KHUI_PACTION_SELALL,FCONTROL|FVIRTKEY,\'A\',KHUI_ACCEL_SCOPE_GLOBAL\r
};\r
\r
khui_action_ref khui_menu_view[] = {\r
+ MENU_ACTION(KHUI_ACTION_LAYOUT_MINI),\r
MENU_SUBMENU(KHUI_MENU_COLUMNS),\r
MENU_SUBMENU(KHUI_MENU_LAYOUT),\r
#if 0\r
int i;\r
size_t s;\r
\r
- if (!caption ||\r
+ if ((name && FAILED(StringCchLength(name, KHUI_MAXCCH_NAME, &s))) ||\r
+ !caption ||\r
FAILED(StringCchLength(caption, KHUI_MAXCCH_SHORT_DESC, &s)) ||\r
(tooltip && FAILED(StringCchLength(tooltip, KHUI_MAXCCH_SHORT_DESC, &s))) ||\r
(type != KHUI_ACTIONTYPE_TRIGGER && type != KHUI_ACTIONTYPE_TOGGLE)) {\r
KHMEXP void KHMAPI\r
khui_menu_insert_action(khui_menu_def * d, khm_size idx, khm_int32 action, khm_int32 flags)\r
{\r
+ khm_size i;\r
\r
EnterCriticalSection(&cs_actions);\r
\r
\r
d->n_items++;\r
\r
+ /* only one action is allowed to have the KHUI_ACTIONREF_DEFAULT\r
+ flag */\r
+ if (flags & KHUI_ACTIONREF_DEFAULT) {\r
+ for (i=0; i < d->n_items; i++) {\r
+ if (i != idx && (d->items[i].flags & KHUI_ACTIONREF_DEFAULT))\r
+ d->items[i].flags &= ~KHUI_ACTIONREF_DEFAULT;\r
+ }\r
+ }\r
+\r
LeaveCriticalSection(&cs_actions);\r
}\r
\r
KHMEXP void KHMAPI\r
khui_menu_insert_paction(khui_menu_def * d, khm_size idx, khui_action * paction, int flags)\r
{\r
+ khm_size i;\r
\r
if (paction == NULL)\r
return;\r
\r
d->n_items++;\r
\r
+ /* only one action is allowed to have the KHUI_ACTIONREF_DEFAULT\r
+ flag */\r
+ if (flags & KHUI_ACTIONREF_DEFAULT) {\r
+ for (i=0; i < d->n_items; i++) {\r
+ if (i != idx && (d->items[i].flags & KHUI_ACTIONREF_DEFAULT))\r
+ d->items[i].flags &= ~KHUI_ACTIONREF_DEFAULT;\r
+ }\r
+ }\r
+\r
LeaveCriticalSection(&cs_actions);\r
}\r
\r
ap = L"F10";\r
break;\r
\r
+ case VK_F11:\r
+ ap = L"F11";\r
+ break;\r
+\r
+ case VK_F12:\r
+ ap = L"F12";\r
+ break;\r
+\r
case VK_DELETE:\r
ap = L"Del";\r
break;\r
KHUI_ACTION_LAYOUT_TYPE,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_TYPE,0,0,0\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_LAYOUT_CUST,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_CUST,0,0,0\r
+KHUI_ACTION_LAYOUT_MINI,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_MINI,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|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,IDS_ACTIONT_VIEW_REFRESH,IDH_ACTION_VIEW_REFRESH,0\r
context menus. In general, it is good practice to place the\r
default item at the top of a menu, although the UI library does\r
not enforce this. This is purely meant as a rendering hint.\r
+\r
+ Only one action is allowed to have this flag set. When an action\r
+ is added to a menu using khui_menu_insert_action() or\r
+ khui_menu_insert_paction() and this flag is set, all other menu\r
+ items will be stripped of this flag.\r
*/\r
#define KHUI_ACTIONREF_DEFAULT 0x20\r
\r
that are valid for this function are: ::KHUI_ACTIONREF_SEP,\r
::KHUI_ACTIONREF_SUBMENU, ::KHUI_ACTIONREF_DEFAULT.\r
::KHUI_ACTIONREF_SEP will be automatically added if the\r
- command is ::KHUI_MENU_SEP.\r
-\r
- \note The ::khui_menu_def structure is not thread safe. Multiple\r
- threads modifying the same ::khui_menu_def structure may cause\r
- thread safety issues.\r
+ command is ::KHUI_MENU_SEP. If ::KHUI_ACTIONREF_DEFAULT is\r
+ specified, then all other items in the menu will be stripped\r
+ of that flag leaving this action as the only one with that\r
+ flag set.\r
*/\r
KHMEXP void KHMAPI\r
khui_menu_insert_action(khui_menu_def * d, khm_size idx, khm_int32 cmd, khm_int32 flags);\r
::KHUI_ACTIONREF_SUBMENU, ::KHUI_ACTIONREF_DEFAULT. For this\r
function, ::KHUI_ACTIONREF_PACTION will automatically be aded\r
when adding the action. ::KHUI_ACTIONREF_SEP will be\r
- automatically added if the command is ::KHUI_MENU_SEP.\r
-\r
- \note The ::khui_menu_def structure is not thread safe. Multiple\r
- threads modifying the same ::khui_menu_def structure may cause\r
- thread safety issues.\r
+ automatically added if the command is ::KHUI_MENU_SEP. If\r
+ ::KHUI_ACTIONREF_DEFAULT is specified, then all other items in\r
+ the menu will be stripped of that flag leaving this action as\r
+ the only one with that flag set.\r
*/\r
KHMEXP void KHMAPI\r
khui_menu_insert_paction(khui_menu_def * d, khm_size idx, khui_action * act, khm_int32 flags);\r
If the specified index is out of bounds, then the function returns\r
NULL.\r
\r
- \note The ::khui_menu_def structure is not thread safe. Multiple\r
- threads modifying the same ::khui_menu_def structure may cause\r
- thread safety issues.\r
*/\r
KHMEXP khui_action_ref *\r
khui_menu_get_action(khui_menu_def * d, khm_size idx);\r
#define KHUI_ACTION_RENEW_ALL (KHUI_ACTION_BASE + 33)\r
#define KHUI_ACTION_DESTROY_ALL (KHUI_ACTION_BASE + 34)\r
#define KHUI_ACTION_UICB (KHUI_ACTION_BASE + 35)\r
+#define KHUI_ACTION_LAYOUT_MINI (KHUI_ACTION_BASE + 36)\r
/*@}*/\r
\r
/*! \name Pseudo actions \r
are no actions or if ::KHUI_ALERT_FLAG_REQUEST_WINDOW is\r
specified.*/\r
\r
+ KHUI_ALERT_FLAG_DISPATCH_CMD =0x00000020,\r
+ /*!< If the message has commands, when the user clicks on one of\r
+ the command buttons, the corresponding command will be\r
+ immediately dispatched as if khui_action_trigger() is called\r
+ with a NULL UI context. Otherwise, the selected command will be\r
+ stored in the alert and can be retrieved via a call to\r
+ khui_alert_get_response(). */\r
+\r
KHUI_ALERT_FLAG_VALID_TARGET =0x00010000,\r
- /*!< There is a valid target for the alert */\r
+ /*!< Internal. 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
+ /*!< Internal. 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
/*!< The alert should be displayed in a balloon */\r
\r
KHUI_ALERT_FLAG_MODAL =0x10000000,\r
- /*!< Modal alert. Do not set direclty. */\r
+ /*!< Internal. Modal alert. Do not set direclty. */\r
\r
- KHUI_ALERT_FLAGMASK_RDWR =0x0C000010,\r
+ KHUI_ALERT_FLAGMASK_RDWR =0x0C000030,\r
/*!< Bit mask of flags that can be set by khui_alert_set_flags() */\r
};\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
+ necessary). Clicking on the balloon will cause the first command\r
+ in the command list to be performed.\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
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
+ User interaction with the alert will be as follows:\r
+\r
+ - If the alert contains no commands, then the alert will be\r
+ displayed to the user as described above. A 'close' button will\r
+ be added to the alert if the alert is being displayed in a\r
+ window.\r
+\r
+ - If the alert contains commands, has the\r
+ ::KHUI_ALERT_FLAG_DEFACTION flag set and is displayed in a\r
+ balloon and the user clicks on it, the first command in the\r
+ command list will be executed.\r
+\r
+ - If the alert contains commands and does not have the\r
+ ::KHUI_ALERT_FLAG_DEFACTION and has the\r
+ ::KHUI_ALERT_FLAG_DISPATCH_CMD flag set, then when the user\r
+ selects one of the command buttons, the corresponding command\r
+ will immediately be dispatched. (see\r
+ ::KHUI_ALERT_FLAG_DISPATCH_CMD).\r
+\r
+ - If the alert contains command and have neither\r
+ ::KHUI_ALERT_FLAG_DEFACTION nor ::KHUI_ALERT_FLAG_DISPATCH_CMD,\r
+ then when the user selects one of the command buttons, the\r
+ selected command will be stored along with the alert. It can be\r
+ retrieved via a call to khui_alert_get_response().\r
+\r
*/\r
KHMEXP khm_int32 KHMAPI \r
khui_alert_show(khui_alert * alert);\r