From 17999a7c872911216e17f20b1135923283138153 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Fri, 30 Mar 2007 18:38:54 +0000 Subject: [PATCH] pull up r19306 from trunk r19306@cathode-dark-space: jaltman | 2007-03-29 13:24:34 -0400 ticket: new subject: NIM commits for KFW 3.2 Beta 1 component: windows (NetIDMgr 1.2.0.0) netidmgr.exe - Simplify credential window UI element placement calculations. - Add the Custom_1 view to the UI schema. This is used to store customizations to the basic view. - Extended styles for toolbars have to be set via TB_SETEXTENDEDSTYLE messages instead of the EX_STYLE parameter to CreateWindowEx(). Also, set the extended style to support detached arrows. - Support drop down menus in the standard toolbar. - The per-identity commands that are added to expiration dialogs are now flagged for automatic dispatch. - Remove unnecessary status bar parts and display the status bar icons at the correct size. - The notification alerts now display the info balloon at the correct size. - Increase the height of the height of the dialog button bar to 190 from 181 dialog units. - Lock the action tables when refreshing the per-identity actions. Perform the necessary notification after refreshing the per-identity actions. - "Initialize " -> "Obtain new credentials for " - Add a button to go back to the Basic view from the Advanced view in the new credentials dialog. - Cache the extents of each row since we now support rows of variable heights. - Selecting a credential row or a header should select all the credentials that are represented by the row. - Update the selection state after loading a new view. - Display the expiration times in the second line of an expanded identity header. - Checks for expiration flags in the credentials window now take into account that the each flag may occupy more than one bit position. - Calculate the expiration flags for the identity before assigning it to a header, so that the header can display accurate expiration data. - Kill unnecessary timers in the credentials view and make sure taht the KHUI_CW_ROW_TIMERSET flag is consistent with whether there is an active timer for the row. - In addition to rows that hold credentials, timers can also be assigned to headers for identities in the basic view. This allows the headers to display expiration times. - The credentials view keeps track of the count of credentials, the count of identity credentials (credentials which belong to the credentials type that the identity belongs to) and the number of initial credentials. - Configuration spaces that hold credential view definitions now include an additional value "_AppVersion" which contains the version of NIM used to create the data. If the current version is greater than the stated version, NIM will failover to using the schema instead of using the saved data. This is because view definitions are version dependent. - The app_version global variable is now a const. - The renew and destroy icons in the standard toolbar are now drop down buttons. If the drop down arrow is clicked, they display a menu with the list of identities that the operation can target. - The renew and destroy actions on the credential menu have been replaced by submenus that allow the user to select the identity which would be the target of the operation. - Consistently update the 'displayed' field of an alert so that plug-ins can keep track of which alerts are being displayed. - If the currently displayed balloon alert has KHUI_ALERT_FLAG_DEFACTION flag, then dispatch the defualt command when the user clicks the notification icon, or display the expanded alert if necessary. - Reduce flicker when drawing the credentials display by clipping the header control from the device context. - The state of Advanced mode is now preserved between NIM sessions. - The credential display layout is kept track of separately for the Basic and Advanced views. Any customization done on either view (e.g.: changing sort order) will only affect that view. Customizations for the Advanced view will be saved in the Custom_0 view, while customizations for the Basic view will be saved in Custom_1. - New color scheme. - Selecting a credential or identity will no longer mask the expiration state. The selection rectangle is now alpha blended. - In Basic view, the width of the Identity column changes with the width of the window so that the credentials display always fills the width of the window. - The colors for the highlight, text color, highlighted text color, window background and other elements are now obtained via Windows so that NetIDMgr will be more consistent with any themes that have been applied. - Correctly determine whether a column can be dragged or resized based on the KHUI_CW_COL_FIXED_WIDTH and KHUI_CW_COL_FIXED_POS flags. - Correctly update the scroll bars when switching between views. - The "marker" button for a displayed alert should not perform any action and it should not be the default control. Selecting it should no longer cause an assertion to be thrown. - Don't display the "... Click here for more." message when displaying a balloon alert if the operating system involved does not provide a reliable means of detecting that the user clicked on a balloon. - When attempting to display queued alerts, if the alert at the top of the queue is of a type that cannot be consolidated, then show it by itself. - If the size of the alert window changes, it should be redrawn properly. krb5creds.dll - Allow setting an identity as the default even if there are no credentials or credential caches associated with it. We generate the name of the ccache we would use if we were getting new credentials for the identity and then set that as the default cache. - Controls in the per-identity configuration panels resized to fit their contents. - Set the credentials type and type name attributes for identities for which we have a TGT. - Use khm_krb5_get_identity_params() when retrieving parameters for the identity global configuration panel. - Add UI elements for setting the global values for forwardable, renewable and addressless flags. - Make the schema default to issue forwardable tickets for identities that have no configuration and when krb5.ini does not define 'forwardable'. - When updating the identity properties, take all the active identities into account, so that we won't orphan any identities with Krb5 properties but no credentials associated with them. - If there is no TGT associated with an identity, then strip it of any Krb5 provided properties. - Associate identities that have a valid TGT with Krb5 by setting KCDB_ATTR_TYPE to the Krb5 credentials type. - Don't attempt to renew an identity if the TGT is not renewable or is expired. - When opening the configuration handle for an identity, if the identity does not have any configuration information, failover to using the per-realm configuration or the identity global configuration. - When opening the configuration handle, don't return a handle that can't safely be closed. - Add code from get_in_tkt.c that correctly handles per-realm settings when obtaining libdefaults settings from the profile. ticket: 5495 version_fixed: 1.6.1 git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-6@19341 dc483132-0cff-0310-8789-dd5450dbe970 --- src/windows/identity/config/Makefile.w2k | 4 +- src/windows/identity/config/Makefile.w32 | 4 +- .../identity/plugins/krb5/krb5configids.c | 75 +- src/windows/identity/plugins/krb5/krb5funcs.c | 400 +++++++-- .../identity/plugins/krb5/krb5identpro.c | 32 +- .../identity/plugins/krb5/krbconfig.csv | 2 +- .../plugins/krb5/lang/en_us/langres.rc | 35 +- src/windows/identity/plugins/krb5/langres.h | 3 +- src/windows/identity/ui/appglobal.h | 4 +- src/windows/identity/ui/credwnd.c | 810 ++++++++++++++---- src/windows/identity/ui/credwnd.h | 49 +- src/windows/identity/ui/lang/en_us/khapp.rc | 13 +- src/windows/identity/ui/main.c | 8 +- src/windows/identity/ui/mainmenu.c | 119 ++- src/windows/identity/ui/mainwnd.c | 9 + src/windows/identity/ui/newcredwnd.c | 25 +- src/windows/identity/ui/newcredwnd.h | 2 +- src/windows/identity/ui/notifier.c | 126 ++- src/windows/identity/ui/resource.h | 8 +- src/windows/identity/ui/statusbar.c | 25 +- src/windows/identity/ui/statusbar.h | 1 + src/windows/identity/ui/timer.c | 5 +- src/windows/identity/ui/toolbar.c | 47 +- src/windows/identity/ui/toolbar.h | 12 +- src/windows/identity/ui/uiconfig.csv | 15 +- src/windows/identity/uilib/action.c | 8 +- src/windows/identity/uilib/khnewcred.h | 3 +- 27 files changed, 1435 insertions(+), 409 deletions(-) diff --git a/src/windows/identity/config/Makefile.w2k b/src/windows/identity/config/Makefile.w2k index a0632065c..e8da2fc17 100644 --- a/src/windows/identity/config/Makefile.w2k +++ b/src/windows/identity/config/Makefile.w2k @@ -46,8 +46,8 @@ KHIMAIRA_WIN32_CONFIG=1 # Version info NETIDMGR_VERSION_MAJOR=1 -NETIDMGR_VERSION_MINOR=1 -NETIDMGR_VERSION_PATCH=11 +NETIDMGR_VERSION_MINOR=2 +NETIDMGR_VERSION_PATCH=0 NETIDMGR_VERSION_AUX=0 NETIDMGR_RELEASEDESC= diff --git a/src/windows/identity/config/Makefile.w32 b/src/windows/identity/config/Makefile.w32 index 3a87ba6ff..d65d45d73 100644 --- a/src/windows/identity/config/Makefile.w32 +++ b/src/windows/identity/config/Makefile.w32 @@ -46,8 +46,8 @@ KHIMAIRA_WIN32_CONFIG=1 # Version info NETIDMGR_VERSION_MAJOR=1 -NETIDMGR_VERSION_MINOR=1 -NETIDMGR_VERSION_PATCH=11 +NETIDMGR_VERSION_MINOR=2 +NETIDMGR_VERSION_PATCH=0 NETIDMGR_VERSION_AUX=0 NETIDMGR_RELEASEDESC= diff --git a/src/windows/identity/plugins/krb5/krb5configids.c b/src/windows/identity/plugins/krb5/krb5configids.c index afd86e541..5f4729253 100644 --- a/src/windows/identity/plugins/krb5/krb5configids.c +++ b/src/windows/identity/plugins/krb5/krb5configids.c @@ -31,6 +31,11 @@ #include #include +typedef struct tag_k5_ids_opts { + khm_int32 renewable; + khm_int32 forwardable; + khm_int32 addressless; +} k5_ids_opts; typedef struct tag_k5_ids_dlg_data { khui_config_init_data cfg; @@ -48,6 +53,10 @@ typedef struct tag_k5_ids_dlg_data { time_t life_max; time_t renew_min; time_t renew_max; + + k5_ids_opts opt; + k5_ids_opts opt_saved; + } k5_ids_dlg_data; static khm_boolean @@ -57,7 +66,10 @@ k5_ids_is_mod(k5_ids_dlg_data * d) { d->life_max != d->tc_life_max.current || d->life_min != d->tc_life_min.current || d->renew_max != d->tc_renew_max.current || - d->renew_min != d->tc_renew_min.current) + d->renew_min != d->tc_renew_min.current || + !!d->opt.renewable != !!d->opt_saved.renewable || + !!d->opt.forwardable != !!d->opt_saved.forwardable || + !!d->opt.addressless != !!d->opt_saved.addressless) return TRUE; return FALSE; } @@ -96,6 +108,9 @@ k5_ids_write_params(k5_ids_dlg_data * d) { WRITEPARAM(d->life_min,d->tc_life_min.current, L"MinLifetime"); WRITEPARAM(d->renew_max,d->tc_renew_max.current, L"MaxRenewLifetime"); WRITEPARAM(d->renew_min,d->tc_renew_min.current, L"MinRenewLifetime"); + WRITEPARAM(d->opt_saved.renewable, d->opt.renewable, L"Renewable"); + WRITEPARAM(d->opt_saved.forwardable, d->opt.forwardable, L"Forwardable"); + WRITEPARAM(d->opt_saved.addressless, d->opt.addressless, L"Addressless"); #undef WRITEPARAM @@ -106,36 +121,23 @@ k5_ids_write_params(k5_ids_dlg_data * d) { static void k5_ids_read_params(k5_ids_dlg_data * d) { - khm_int32 t; - khm_int32 rv; - -#ifdef DEBUG - assert(csp_params); -#endif + k5_params p; - rv = khc_read_int32(csp_params, L"DefaultLifetime", &t); - assert(KHM_SUCCEEDED(rv)); - d->life = t; + khm_krb5_get_identity_params(NULL, &p); - rv = khc_read_int32(csp_params, L"DefaultRenewLifetime", &t); - assert(KHM_SUCCEEDED(rv)); - d->renew_life = t; + d->life = p.lifetime; + d->life_max = p.lifetime_max; + d->life_min = p.lifetime_min; - rv = khc_read_int32(csp_params, L"MaxLifetime", &t); - assert(KHM_SUCCEEDED(rv)); - d->life_max = t; + d->renew_life = p.renew_life; + d->renew_max = p.renew_life_max; + d->renew_min = p.renew_life_min; - rv = khc_read_int32(csp_params, L"MinLifetime", &t); - assert(KHM_SUCCEEDED(rv)); - d->life_min = t; + d->opt_saved.forwardable = p.forwardable; + d->opt_saved.renewable = p.renewable; + d->opt_saved.addressless = p.addressless; - rv = khc_read_int32(csp_params, L"MaxRenewLifetime", &t); - assert(KHM_SUCCEEDED(rv)); - d->renew_max = t; - - rv = khc_read_int32(csp_params, L"MinRenewLifetime", &t); - assert(KHM_SUCCEEDED(rv)); - d->renew_min = t; + d->opt = d->opt_saved; khui_tracker_initialize(&d->tc_life); d->tc_life.current = d->life; @@ -209,6 +211,10 @@ k5_ids_tab_dlgproc(HWND hwnd, khui_tracker_refresh(&d->tc_renew); khui_tracker_refresh(&d->tc_renew_min); khui_tracker_refresh(&d->tc_renew_max); + + CheckDlgButton(hwnd, IDC_CFG_RENEW, (d->opt.renewable ? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_FORWARD, (d->opt.forwardable ? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_ADDRESSLESS, (d->opt.addressless ? BST_CHECKED: BST_UNCHECKED)); break; case WM_COMMAND: @@ -216,6 +222,22 @@ k5_ids_tab_dlgproc(HWND hwnd, GetWindowLongPtr(hwnd, DWLP_USER); if (HIWORD(wParam) == EN_CHANGE) { + k5_ids_check_mod(d); + } else if (HIWORD(wParam) == BN_CLICKED) { + switch (LOWORD(wParam)) { + case IDC_CFG_RENEW: + d->opt.renewable = (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED); + break; + + case IDC_CFG_FORWARD: + d->opt.forwardable = (IsDlgButtonChecked(hwnd, IDC_CFG_FORWARD) == BST_CHECKED); + break; + + case IDC_CFG_ADDRESSLESS: + d->opt.addressless = (IsDlgButtonChecked(hwnd, IDC_CFG_ADDRESSLESS) == BST_CHECKED); + break; + } + k5_ids_check_mod(d); } break; @@ -245,3 +267,4 @@ k5_ids_tab_dlgproc(HWND hwnd, return FALSE; } + diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c index bab9ba4cd..bc0170d8f 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.c +++ b/src/windows/identity/plugins/krb5/krb5funcs.c @@ -228,9 +228,91 @@ typedef struct tag_identlist { static void tc_prep_idlist(identlist * idlist) { + khm_int32 rv; + khm_size cb_ids = 0; + khm_size n_ids = 0; + khm_size i; + wchar_t * ids = NULL; + wchar_t *thisid; + idlist->list = NULL; idlist->n_list = 0; idlist->nc_list = 0; + + do { + + if (ids) { + PFREE(ids); + ids = NULL; + } + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE, + KCDB_IDENT_FLAG_ACTIVE, + NULL, + &cb_ids, + &n_ids); + + if (rv != KHM_ERROR_TOO_LONG) + break; /* something else is wrong */ + + if (n_ids == 0 || cb_ids == 0) + break; /* no identities to process */ + +#ifdef DEBUG + assert(cb_ids > 0); +#endif + + ids = PMALLOC(cb_ids); +#ifdef DEBUG + assert(ids != NULL); +#endif + if (ids == NULL) + break; + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE, + KCDB_IDENT_FLAG_ACTIVE, + ids, + &cb_ids, + &n_ids); + + if (KHM_SUCCEEDED(rv)) + break; + + } while (TRUE); + + if (ids == NULL) + return; + + if (KHM_FAILED(rv) || n_ids == 0) { + if (ids) + PFREE(ids); + return; + } + + idlist->nc_list = UBOUNDSS(n_ids, IDLIST_ALLOC_INCR, IDLIST_ALLOC_INCR); + + idlist->list = PCALLOC(idlist->nc_list, sizeof(idlist->list[0])); + + for (i = 0, thisid = ids; + thisid && thisid[0]; + thisid = multi_string_next(thisid)) { + + khm_handle ident; + + rv = kcdb_identity_create(thisid, 0, &ident); + + if (KHM_FAILED(rv)) + continue; + + idlist->list[i].ident = ident; + idlist->list[i].count = 0; + + i++; + } + + idlist->n_list = i; + + PFREE(ids); } static ident_data * @@ -286,42 +368,102 @@ tc_add_ident_to_list(identlist * idlist, khm_handle ident) { static void tc_set_ident_data(identlist * idlist) { khm_size i; + wchar_t k5idtype[KCDB_MAXCCH_NAME]; + + k5idtype[0] = L'\0'; + LoadString(hResModule, IDS_KRB5_NC_NAME, + k5idtype, ARRAYLENGTH(k5idtype)); for (i=0; i < idlist->n_list; i++) { #ifdef DEBUG assert(idlist->list[i].ident); #endif - kcdb_identity_set_attr(idlist->list[i].ident, - attr_id_krb5_ccname, - idlist->list[i].ccname, - KCDB_CBSIZE_AUTO); + if (idlist->list[i].count > 0) { + khm_int32 t; - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_EXPIRE, - &idlist->list[i].ft_expire, - sizeof(idlist->list[i].ft_expire)); + t = credtype_id_krb5; + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE, + &t, + sizeof(t)); + + /* We need to manually add the type name if we want the + name to show up in the property list for the identity. + The type name is only automatically calculated for + credentials. */ + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE_NAME, + k5idtype, + KCDB_CBSIZE_AUTO); - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_ISSUE, - &idlist->list[i].ft_issue, - sizeof(idlist->list[i].ft_issue)); + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_ccname, + idlist->list[i].ccname, + KCDB_CBSIZE_AUTO); - kcdb_identity_set_attr(idlist->list[i].ident, - attr_id_krb5_flags, - &idlist->list[i].krb5_flags, - sizeof(idlist->list[i].krb5_flags)); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_EXPIRE, + &idlist->list[i].ft_expire, + sizeof(idlist->list[i].ft_expire)); - if (idlist->list[i].ft_renewexpire.dwLowDateTime == 0 && - idlist->list[i].ft_renewexpire.dwHighDateTime == 0) { kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_RENEW_EXPIRE, - NULL, 0); - } else { + KCDB_ATTR_ISSUE, + &idlist->list[i].ft_issue, + sizeof(idlist->list[i].ft_issue)); + kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_RENEW_EXPIRE, - &idlist->list[i].ft_renewexpire, - sizeof(idlist->list[i].ft_renewexpire)); + attr_id_krb5_flags, + &idlist->list[i].krb5_flags, + sizeof(idlist->list[i].krb5_flags)); + + if (idlist->list[i].ft_renewexpire.dwLowDateTime == 0 && + idlist->list[i].ft_renewexpire.dwHighDateTime == 0) { + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } else { + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, + &idlist->list[i].ft_renewexpire, + sizeof(idlist->list[i].ft_renewexpire)); + } + + } else { + /* We didn't see any TGTs for this identity. We have to + remove all the Krb5 supplied properties. */ + + khm_int32 t; + khm_size cb; + + cb = sizeof(t); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE, NULL, + &t, + &cb)) && + t == credtype_id_krb5) { + + /* disown this and remove all our properties. the + system will GC this identity if nobody claims it.*/ + + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE_NAME, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_ccname, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_EXPIRE, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_ISSUE, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_flags, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, NULL, 0); + } else { + /* otherwise, this identity doesn't belong to us. We + should leave it as is. */ + } } } } @@ -918,7 +1060,7 @@ khm_krb5_renew_cred(khm_handle cred) #endif if (strlen("krbtgt") != krb5_princ_name(ctx, server)->length || - strncmp("krbtgt", krb5_princ_name(ctx, server)->data, krb5_princ_name(ctx, server)->length)) + strncmp("krbtgt", krb5_princ_name(ctx, server)->data, krb5_princ_name(ctx, server)->length)) { code = pkrb5_get_renewed_creds(ctx, &cc_creds, me, cc, name); if (code) { @@ -1004,6 +1146,7 @@ khm_krb5_renew_ident(khm_handle identity) krb5_data *realm = NULL; wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; khm_size cb; + khm_int32 k5_flags; memset(&my_creds, 0, sizeof(krb5_creds)); @@ -1036,6 +1179,37 @@ khm_krb5_renew_ident(khm_handle identity) #endif } + cb = sizeof(k5_flags); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(identity, + attr_id_krb5_flags, + NULL, + &k5_flags, + &cb)) && + !(k5_flags & TKT_FLG_RENEWABLE)) { + + code = KRB5KDC_ERR_BADOPTION; + goto cleanup; + } + + { + FILETIME ft_now; + FILETIME ft_exp; + + cb = sizeof(ft_exp); + GetSystemTimeAsFileTime(&ft_now); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(identity, + KCDB_ATTR_EXPIRE, + NULL, + &ft_exp, + &cb)) && + CompareFileTime(&ft_exp, &ft_now) < 0) { + + code = KRB5KRB_AP_ERR_TKT_EXPIRED; + goto cleanup; + + } + } + code = khm_krb5_initialize(identity, &ctx, &cc); if (code) goto cleanup; @@ -2580,7 +2754,7 @@ khm_krb5_set_identity_flags(khm_handle identity, } t &= ~flag_mask; - t |= flag_value | flag_mask; + t |= (flag_value & flag_mask); kcdb_identity_set_attr(identity, attr_id_krb5_idflags, @@ -2679,11 +2853,13 @@ khm_krb5_get_identity_config(khm_handle ident, if (ident) { rv = kcdb_identity_get_config(ident, flags, &csp_i); if (KHM_FAILED(rv)) - goto done; + goto try_realm; rv = khc_open_space(csp_i, CSNAME_KRB5CRED, flags, &csp_ik5); if (KHM_FAILED(rv)) - goto done; + goto try_realm; + + try_realm: if (realm[0] == L'\0') goto done_shadow_realm; @@ -2700,16 +2876,31 @@ khm_krb5_get_identity_config(khm_handle ident, done_shadow_realm: - if (csp_realm) - rv = khc_shadow_space(csp_ik5, csp_realm); - else - rv = khc_shadow_space(csp_ik5, csp_params); + if (csp_ik5) { + if (csp_realm) + rv = khc_shadow_space(csp_ik5, csp_realm); + else + rv = khc_shadow_space(csp_ik5, csp_params); - csp_rv = csp_ik5; + csp_rv = csp_ik5; + } else { + if (csp_realm) + csp_rv = csp_realm; + } + } - } else { + if (csp_rv == NULL) { + + /* No valid identity specified or the specified identity + doesn't have any configuration. We default to the + parameters key. */ + + /* we don't just return csp_params since that's a global + handle that we shouldn't close until the plugin is + unloaded. The caller is going to close the returned handle + when it is done. So we need to create a new csp_params + that can safely be closed. */ - /* No valid identity specified. We default to the parameters key. */ rv = kmm_get_plugins_config(0, &csp_plugins); if (KHM_FAILED(rv)) goto done; @@ -2731,8 +2922,11 @@ khm_krb5_get_identity_config(khm_handle ident, khc_close_space(csp_i); if (csp_realms) khc_close_space(csp_realms); - if (csp_realm) + + /* csp_realm can also be a return value if csp_ik5 was NULL */ + if (csp_realm && csp_realm != csp_rv) khc_close_space(csp_realm); + if (csp_plugins) khc_close_space(csp_plugins); if (csp_krbcfg) @@ -2741,6 +2935,82 @@ khm_krb5_get_identity_config(khm_handle ident, return rv; } +/* from get_in_tkt.c */ +static krb5_error_code +get_libdefault_string(profile_t profile, const char * realm, + const char * option, char ** ret_val) { + char realmstr[K5_MAXCCH_REALM]; + char **nameval = NULL; + const char * names[4]; + krb5_error_code code = 0; + + names[0] = "libdefaults"; + + if (!realm || !realm[0]) + goto try_number_two; + + StringCbCopyA(realmstr, sizeof(realmstr), realm); + + /* + * Try number one: + * + * [libdefaults] + * REALM = { + * option = + * } + */ + + names[1] = realmstr; + names[2] = option; + names[3] = 0; + code = pprofile_get_values(profile, names, &nameval); + if (code == 0 && nameval && nameval[0]) + goto goodbye; + + try_number_two: + + /* + * Try number two: + * + * [libdefaults] + * option = + */ + + names[1] = option; + names[2] = 0; + code = pprofile_get_values(profile, names, &nameval); + if (code == 0 && nameval && nameval[0]) + goto goodbye; + + goodbye: + if (!nameval) + return(ENOENT); + + if (!nameval[0]) { + code = ENOENT; + } else { + size_t cb; + + if (FAILED(StringCbLengthA(nameval[0], K5_MAXCCH_REALM * sizeof(char), &cb))) { + code = ENOMEM; + } else { + cb += sizeof(char); + *ret_val = PMALLOC(cb); + + if (!*ret_val) + code = ENOMEM; + else { + StringCbCopyA(*ret_val, cb, nameval[0]); + code = 0; + } + } + } + + pprofile_free_list(nameval); + + return code; +} + khm_int32 khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { @@ -2751,6 +3021,7 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { khm_int32 e; khm_int32 v; CHAR confname[MAX_PATH]; + CHAR realmname[K5_MAXCCH_REALM]; ZeroMemory(p, sizeof(*p)); @@ -2802,6 +3073,28 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { if (rv) return rv; + /* we need to figure out the realm name, since there might be + per-realm configuration in the profile file. */ + + realmname[0] = '\0'; + + if (ident) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + idname[0] = L'\0'; + cb = sizeof(idname); + rv = kcdb_identity_get_name(ident, idname, &cb); + if (KHM_SUCCEEDED(rv)) { + wchar_t * wrealm; + + wrealm = khm_get_realm_from_princ(idname); + if (wrealm) { + UnicodeStrToAnsi(realmname, sizeof(realmname), wrealm); + } + } + } + /* If we get here, then some of the settings we read from the configuration actually came from the schema. In other words, the values weren't really defined for this identity. So we now @@ -2820,7 +3113,9 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { /* default ticket lifetime */ if (!(regf & K5PARAM_F_LIFE)) { char * value = NULL; - retval = pprofile_get_string(profile, "libdefaults", "ticket_lifetime", 0, 0, &value); + retval = get_libdefault_string(profile, realmname, + "ticket_lifetime", &value); + if (retval == 0 && value) { krb5_deltat d; @@ -2871,13 +3166,15 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { p->lifetime = d; proff |= K5PARAM_F_LIFE; } - pprofile_release_string(value); + + PFREE(value); } } if (!(regf & K5PARAM_F_RLIFE)) { char * value = NULL; - retval = pprofile_get_string(profile, "libdefaults", "renew_lifetime", 0, 0, &value); + retval = get_libdefault_string(profile, realmname, + "renew_lifetime", &value); if (retval == 0 && value) { krb5_deltat d; @@ -2886,13 +3183,14 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { p->renew_life = d; proff |= K5PARAM_F_RLIFE; } - pprofile_release_string(value); + PFREE(value); } } if (!(regf & K5PARAM_F_FORW)) { char * value = NULL; - retval = pprofile_get_string(profile, "libdefaults", "forwardable", 0, 0, &value); + retval = get_libdefault_string(profile, realmname, + "forwardable", &value); if (retval == 0 && value) { khm_boolean b; @@ -2900,15 +3198,15 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { p->forwardable = b; else p->forwardable = FALSE; - pprofile_release_string(value); + PFREE(value); proff |= K5PARAM_F_FORW; } } if (!(regf & K5PARAM_F_RENEW)) { char * value = NULL; - retval = pprofile_get_string(profile, "libdefaults", "renewable", 0, 0, &value); - + retval = get_libdefault_string(profile, realmname, + "renewable", &value); if (retval == 0 && value) { khm_boolean b; @@ -2916,15 +3214,15 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { p->renewable = b; else p->renewable = TRUE; - pprofile_release_string(value); + PFREE(value); proff |= K5PARAM_F_RENEW; } } if (!(regf & K5PARAM_F_ADDL)) { char * value = NULL; - retval = pprofile_get_string(profile, "libdefaults", "noaddresses", 0, 0, &value); - + retval = get_libdefault_string(profile, realmname, + "noaddresses", &value); if (retval == 0 && value) { khm_boolean b; @@ -2932,15 +3230,15 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { p->addressless = b; else p->addressless = TRUE; - pprofile_release_string(value); + PFREE(value); proff |= K5PARAM_F_ADDL; } } if (!(regf & K5PARAM_F_PROX)) { char * value = NULL; - retval = pprofile_get_string(profile, "libdefaults", "proxiable", 0, 0, &value); - + retval = get_libdefault_string(profile, realmname, + "proxiable", &value); if (retval == 0 && value) { khm_boolean b; @@ -2948,7 +3246,7 @@ khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { p->proxiable = b; else p->proxiable = FALSE; - pprofile_release_string(value); + PFREE(value); proff |= K5PARAM_F_PROX; } } diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c index c036eb976..bc77b26f0 100644 --- a/src/windows/identity/plugins/krb5/krb5identpro.c +++ b/src/windows/identity/plugins/krb5/krb5identpro.c @@ -846,9 +846,37 @@ k5_ident_set_default(khm_int32 msg_type, NULL, id_ccname, &cb))) { + khm_handle csp_ident = NULL; + khm_handle csp_k5 = NULL; + _reportf(L"The specified identity does not have the Krb5CCName property"); - _end_task(); - return KHM_ERROR_NOT_FOUND; + + cb = sizeof(id_ccname); + if (KHM_SUCCEEDED(kcdb_identity_get_config(def_ident, 0, &csp_ident)) && + KHM_SUCCEEDED(khc_open_space(csp_ident, CSNAME_KRB5CRED, 0, &csp_k5)) && + KHM_SUCCEEDED(khc_read_string(csp_k5, L"DefaultCCName", + id_ccname, &cb))) { + + _reportf(L"Found CC name in configuration [%s]", id_ccname); + } else { + /* last resort, use the name of the identity as the cc + name */ + cb = sizeof(id_ccname); + if (KHM_FAILED(kcdb_identity_get_name(def_ident, id_ccname, &cb))) { + _reportf(L"Can't use name of identity as CCName"); + _end_task(); + + id_ccname[0] = L'\0'; + } + } + + if (csp_k5) + khc_close_space(csp_k5); + if (csp_ident) + khc_close_space(csp_ident); + + if (id_ccname[0] == L'\0') + return KHM_ERROR_INVALID_PARAM; } khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); diff --git a/src/windows/identity/plugins/krb5/krbconfig.csv b/src/windows/identity/plugins/krb5/krbconfig.csv index 205cbcb42..4dc5b7d72 100644 --- a/src/windows/identity/plugins/krb5/krbconfig.csv +++ b/src/windows/identity/plugins/krb5/krbconfig.csv @@ -13,7 +13,7 @@ Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider DefaultLifetime,KC_INT32,36000,Default ticket lifetime MaxLifetime,KC_INT32,86400,Maximum lifetime MinLifetime,KC_INT32,60,Minimum lifetime - Forwardable,KC_INT32,0,Obtain forwardable tickets (boolean) + Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean) Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) Addressless,KC_INT32,1,Obtain addressless tickets (boolean) PublicIP,KC_INT32,0,Additional public IP address to use (int32) diff --git a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc index 4d98fd314..1bdae10e2 100644 --- a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc +++ b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc @@ -156,20 +156,23 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Credential lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 - EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL - LTEXT "Credential renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80,8 - EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL - GROUPBOX "Credential lifetime range",IDC_CFG_LIFEGRP,7,43,221,49 - LTEXT "Minimum",IDC_STATIC,13,56,28,8 - EDITTEXT IDC_CFG_LRNG_MIN,91,53,131,14,ES_AUTOHSCROLL - LTEXT "Maximum",IDC_STATIC,13,75,30,8 - EDITTEXT IDC_CFG_LRNG_MAX,91,72,131,14,ES_AUTOHSCROLL - GROUPBOX "Credential renewable lifetime range",IDC_STATIC,7,95,221,49 - LTEXT "Minimum",IDC_STATIC,13,108,28,8 - EDITTEXT IDC_CFG_RLRNG_MIN,91,105,131,14,ES_AUTOHSCROLL - LTEXT "Maximum",IDC_STATIC,13,128,30,8 - EDITTEXT IDC_CFG_RLRNG_MAX,91,125,131,14,ES_AUTOHSCROLL + LTEXT "Ticket &lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,94,7,134,14,ES_AUTOHSCROLL + LTEXT "Ticket re&newable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80,8 + EDITTEXT IDC_CFG_DEFRLIFE,94,26,134,14,ES_AUTOHSCROLL + CONTROL "&Renewable",IDC_CFG_RENEW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,51,10 + CONTROL "&Forwardable",IDC_CFG_FORWARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,94,47,56,10 + CONTROL "&Addressless",IDC_CFG_ADDRESSLESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,63,54,10 + GROUPBOX "Credential lifetime range",IDC_CFG_LIFEGRP,7,79,221,31 + LTEXT "From",IDC_STATIC,13,93,17,8 + EDITTEXT IDC_CFG_LRNG_MIN,38,90,79,14,ES_AUTOHSCROLL + LTEXT "To",IDC_STATIC,125,93,9,8 + EDITTEXT IDC_CFG_LRNG_MAX,143,90,79,14,ES_AUTOHSCROLL + GROUPBOX "Credential renewable lifetime range",IDC_STATIC,7,113,221,31 + LTEXT "From",IDC_STATIC,13,128,17,8 + EDITTEXT IDC_CFG_RLRNG_MIN,38,125,79,14,ES_AUTOHSCROLL + LTEXT "To",IDC_STATIC,125,128,9,8 + EDITTEXT IDC_CFG_RLRNG_MAX,143,125,79,14,ES_AUTOHSCROLL END IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151 @@ -177,7 +180,7 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Credential lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + LTEXT "Credential lifetime",IDC_CFG_LBL_DEFLIFE,7,10,58,8 EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL CONTROL "Renewable for",IDC_CFG_RENEW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,41,63,10 EDITTEXT IDC_CFG_DEFRLIFE,91,39,137,14,ES_AUTOHSCROLL @@ -280,7 +283,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 228 VERTGUIDE, 13 - VERTGUIDE, 91 + VERTGUIDE, 94 VERTGUIDE, 222 TOPMARGIN, 7 BOTTOMMARGIN, 144 diff --git a/src/windows/identity/plugins/krb5/langres.h b/src/windows/identity/plugins/krb5/langres.h index 9381b99ee..0e62ecda1 100644 --- a/src/windows/identity/plugins/krb5/langres.h +++ b/src/windows/identity/plugins/krb5/langres.h @@ -201,6 +201,7 @@ #define IDC_CHECK3 1077 #define IDC_CFG_ADDRESSLESS 1077 #define IDC_CFG_FORWARD 1078 +#define IDC_CHECK1 1079 #define ID_FOO_BAR 40001 // Next default values for new objects @@ -209,7 +210,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 219 #define _APS_NEXT_COMMAND_VALUE 40002 -#define _APS_NEXT_CONTROL_VALUE 1079 +#define _APS_NEXT_CONTROL_VALUE 1080 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/windows/identity/ui/appglobal.h b/src/windows/identity/ui/appglobal.h index b25d38247..3e44282d1 100644 --- a/src/windows/identity/ui/appglobal.h +++ b/src/windows/identity/ui/appglobal.h @@ -36,7 +36,7 @@ extern int khm_nCmdShow; extern const wchar_t * khm_facility; extern kconf_schema schema_uiconfig[]; extern khm_ui_4 khm_commctl_version; -extern khm_version app_version; +extern const khm_version app_version; #define IS_COMMCTL6() (khm_commctl_version >= 0x60000) @@ -134,6 +134,8 @@ HWND khm_html_help(HWND hwnd, wchar_t * suffix, UINT command, DWORD_PTR data); WPARAM khm_message_loop_int(khm_boolean * p_exit); +int khm_compare_version(const khm_version * v1, const khm_version * v2); + #define MAX_RES_STRING 1024 #define ELLIPSIS L"..." diff --git a/src/windows/identity/ui/credwnd.c b/src/windows/identity/ui/credwnd.c index 474bfa9aa..b4982218e 100644 --- a/src/windows/identity/ui/credwnd.c +++ b/src/windows/identity/ui/credwnd.c @@ -289,8 +289,15 @@ cw_save_view(khui_credwnd_tbl * tbl, wchar_t * view_name) { multi_string_init(col_list, cb_col_list); + /* if we aren't saving to a specific view, and the view has been + customized, then we save it to "Custom_0", unless we are in the + mini mode, in which case we save it to "Custom_1" */ if (!view_name && (tbl->flags & KHUI_CW_TBL_CUSTVIEW)) { - view_name = L"Custom_0"; + if (!(tbl->flags & KHUI_CW_TBL_EXPIDENT)) { + view_name = L"Custom_0"; + } else { + view_name = L"Custom_1"; + } } if (view_name) { @@ -309,7 +316,9 @@ cw_save_view(khui_credwnd_tbl * tbl, wchar_t * view_name) { /* if we are switching to a custom view, then we should mark that as the default. */ if (tbl->flags & KHUI_CW_TBL_CUSTVIEW) { - khc_write_string(csp_cw, L"DefaultView", L"Custom_0"); + khc_write_string(csp_cw, ((!(tbl->flags & KHUI_CW_TBL_EXPIDENT))? + L"DefaultView": + L"DefaultViewMini"), view_name); } } else { @@ -319,6 +328,22 @@ cw_save_view(khui_credwnd_tbl * tbl, wchar_t * view_name) { if (!csp_view) goto _cleanup; + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + khc_write_int32(csp_view, L"ExpandedIdentity", 1); + } else { + khm_int32 t; + if (KHM_SUCCEEDED(khc_read_int32(csp_view, L"ExpandedIdentity", &t)) && t) + khc_write_int32(csp_view, L"ExpandedIdentity", 0); + } + + if (tbl->flags & KHUI_CW_TBL_NOHEADER) { + khc_write_int32(csp_view, L"NoHeader", 1); + } else { + khm_int32 t; + if (KHM_SUCCEEDED(khc_read_int32(csp_view, L"NoHeader", &t)) && t) + khc_write_int32(csp_view, L"NoHeader", 0); + } + if (KHM_FAILED(khc_open_space(csp_view, L"Columns", KHM_PERM_WRITE | KHM_FLAG_CREATE, &csp_cols))) @@ -369,6 +394,12 @@ cw_save_view(khui_credwnd_tbl * tbl, wchar_t * view_name) { khc_write_multi_string(csp_view, L"ColumnList", col_list); + { + khm_version v = app_version; + + khc_write_binary(csp_view, L"_AppVersion", &v, sizeof(v)); + } + _cleanup: if (view_name) { @@ -389,6 +420,19 @@ cw_save_view(khui_credwnd_tbl * tbl, wchar_t * view_name) { PFREE(col_list); } +static COLORREF +cw_mix_colors(COLORREF c1, COLORREF c2, int alpha) { + int r = (GetRValue(c1) * alpha + GetRValue(c2) * (255 - alpha)) / 255; + int g = (GetGValue(c1) * alpha + GetGValue(c2) * (255 - alpha)) / 255; + int b = (GetBValue(c1) * alpha + GetBValue(c2) * (255 - alpha)) / 255; + +#ifdef DEBUG + assert(alpha >= 0 && alpha < 256); +#endif + + return RGB(r,g,b); +} + void cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { khm_handle hc_cw = NULL; @@ -405,6 +449,7 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { LOGFONT log_font; khm_int32 t; const wchar_t * viewval; + khm_boolean reopen_csp = FALSE; tbl->hwnd = hwnd; @@ -450,12 +495,39 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { khc_write_string(hc_cw, viewval, view); } - if(KHM_FAILED(khc_open_space(hc_vs, view, KHM_PERM_READ, &hc_v))) + if(KHM_FAILED(khc_open_space(hc_vs, view, 0, &hc_v))) goto _exit; + /* view data is very sensitive to version changes. We need to + check if this configuration data was created with this version + of NetIDMgr. If not, we switch to using a schema handle. */ + { + khm_version this_v = app_version; + khm_version cfg_v; + + cbsize = sizeof(cfg_v); + if (KHM_FAILED(khc_read_binary(hc_v, L"_AppVersion", &cfg_v, &cbsize)) || + khm_compare_version(&cfg_v, &this_v) != 0) { + + khc_close_space(hc_v); + + if (KHM_FAILED(khc_open_space(hc_vs, view, KCONF_FLAG_SCHEMA, + &hc_v)) && + (wcscmp(view, L"Custom_1") || + KHM_FAILED(khc_open_space(hc_vs, L"CompactIdentity", + KCONF_FLAG_SCHEMA, &hc_v)))) { + goto _exit; + } + + reopen_csp = TRUE; + } + } + tbl->csp_view = hc_v; - if(KHM_FAILED(khc_open_space(hc_v, L"Columns", KHM_PERM_READ, &hc_cs))) + if(KHM_FAILED(khc_open_space(hc_v, L"Columns", + KHM_PERM_READ | (reopen_csp ? KCONF_FLAG_SCHEMA : 0), + &hc_cs))) goto _exit; cbsize = 0; @@ -525,7 +597,9 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { tbl->cols[i].attr_id = attr_id; - if(KHM_SUCCEEDED(khc_open_space(hc_cs, iter, KHM_PERM_READ, &hc_c))) { + if(KHM_SUCCEEDED(khc_open_space(hc_cs, iter, + KHM_PERM_READ | (reopen_csp ? KCONF_FLAG_SCHEMA : 0), + &hc_c))) { if(KHM_FAILED(khc_read_int32(hc_c, L"Flags", &(tbl->cols[i].flags)))) tbl->cols[i].flags = 0; if(KHM_FAILED(khc_read_int32(hc_c, L"Width", &(tbl->cols[i].width)))) @@ -601,23 +675,47 @@ _skip_col: 0, LR_DEFAULTCOLOR)); - tbl->hb_normal = CreateSolidBrush(RGB(255,255,255)); - tbl->hb_grey = CreateSolidBrush(RGB(240,240,240)); - tbl->hb_sel = CreateSolidBrush(RGB(230,230,255)); - tbl->hb_hdr_bg = CreateSolidBrush(RGB(230,230,230)); - tbl->hb_hdr_bg_sel = CreateSolidBrush(RGB(0,0,255)); - tbl->hb_hdr_bg_crit = CreateSolidBrush(RGB(240,133,117)); - tbl->hb_hdr_bg_warn = CreateSolidBrush(RGB(251,199,77)); - tbl->hb_hdr_bg_exp = CreateSolidBrush(RGB(255,144,144)); - tbl->hb_hdr_bg_def = CreateSolidBrush(RGB(186,254,184)); - - tbl->cr_normal = RGB(0,0,0); - tbl->cr_sel = RGB(0,0,0); - tbl->cr_hdr_outline = RGB(0,0,0); - tbl->cr_hdr_normal = RGB(0,0,0); - tbl->cr_hdr_sel = RGB(255,255,255); - tbl->cr_hdr_gray = RGB(128,128,128); - tbl->cr_hdr_gray_sel = RGB(240,240,240); + { +#define SEL_ALPHA 50 + + COLORREF bg_s = GetSysColor(COLOR_HIGHLIGHT); + COLORREF bg_normal = GetSysColor(COLOR_WINDOW); + COLORREF bg_gray = RGB(240,240,240); + COLORREF bg_hdr = RGB(240,240,240); + COLORREF bg_hdr_warn = RGB(235,235,134); + COLORREF bg_hdr_crit = RGB(235,184,134); + COLORREF bg_hdr_exp = RGB(235,134,134); + COLORREF bg_hdr_def = RGB(184,235,134); + + tbl->cr_normal = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_s = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_hdr_outline = RGB(0,0,0); + tbl->cr_hdr_normal = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_hdr_s = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_hdr_gray = GetSysColor(COLOR_GRAYTEXT); + tbl->cr_hdr_gray_s = GetSysColor(COLOR_HIGHLIGHTTEXT); + + if (khm_main_wnd_mode == KHM_MAIN_WND_MINI) { + bg_hdr = bg_normal; + tbl->cr_hdr_outline = bg_gray; + } + + tbl->hb_normal = CreateSolidBrush(bg_normal); + tbl->hb_grey = CreateSolidBrush(bg_gray); + tbl->hb_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_normal, SEL_ALPHA)); + + tbl->hb_hdr_bg = CreateSolidBrush(bg_hdr); + tbl->hb_hdr_bg_warn = CreateSolidBrush(bg_hdr_warn); + tbl->hb_hdr_bg_crit = CreateSolidBrush(bg_hdr_crit); + tbl->hb_hdr_bg_exp = CreateSolidBrush(bg_hdr_exp); + tbl->hb_hdr_bg_def = CreateSolidBrush(bg_hdr_def); + + tbl->hb_hdr_bg_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr, SEL_ALPHA)); + tbl->hb_hdr_bg_warn_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_warn, SEL_ALPHA)); + tbl->hb_hdr_bg_crit_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_crit, SEL_ALPHA)); + tbl->hb_hdr_bg_exp_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_exp, SEL_ALPHA)); + tbl->hb_hdr_bg_def_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_def, SEL_ALPHA)); + } tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 20, 8, 0); { @@ -657,12 +755,30 @@ _skip_col: #undef ADD_BITMAP } + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + tbl->hi_lg_ident = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + LR_DEFAULTCOLOR); + } + tbl->cursor_row = -1; tbl->scr_left = 0; tbl->scr_top = 0; tbl->ext_height = 0; tbl->ext_width = 0; + if (reopen_csp) { + khc_close_space(hc_v); + + hc_v = NULL; + + khc_open_space(hc_vs, view, 0, &hc_v); + + tbl->csp_view = hc_v; + } + _exit: if(hc_cw) khc_close_space(hc_cw); @@ -676,12 +792,29 @@ _exit: We keep that open until the view is unloaded. */ } +khui_credwnd_ident * +cw_find_ident(khui_credwnd_tbl * tbl, khm_handle ident) { + khm_size i; + + for (i=0; i < tbl->n_idents; i++) { + if (kcdb_identity_is_equal(ident, tbl->idents[i].ident)) + break; + } + + if (i < tbl->n_idents) + return &tbl->idents[i]; + else + return NULL; +} + khm_int32 KHMAPI cw_credset_iter_func(khm_handle cred, void * rock) { khui_credwnd_tbl * tbl = (khui_credwnd_tbl *) rock; khm_handle ident = NULL; khm_size i; khui_credwnd_ident * cwi = NULL; + khm_int32 cred_credtype = KCDB_CREDTYPE_INVALID; + khm_int32 cred_flags = 0; kcdb_cred_get_identity(cred, &ident); @@ -715,25 +848,59 @@ cw_credset_iter_func(khm_handle cred, void * rock) { i = tbl->n_idents; cwi = &tbl->idents[tbl->n_idents++]; + ZeroMemory(cwi, sizeof(*cwi)); + cwi->ident = ident; kcdb_identity_hold(ident); + cb = sizeof(cwi->name); kcdb_identity_get_name(ident, cwi->name, &cb); - kcdb_identity_get_type(&cwi->credtype); - cb = sizeof(cwi->credtype_name); - kcdb_credtype_describe(cwi->credtype, cwi->credtype_name, &cb, KCDB_TS_SHORT); - cwi->credcount = 0; } cwi = &tbl->idents[i]; - /* this is the first time we are seeing this */ + /* this is the first time we are seeing this identity. */ if (cwi->credcount == 0) { + khm_size cb; + + cb = sizeof(cwi->credtype); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, KCDB_ATTR_TYPE, NULL, + &cwi->credtype, &cb))) { + cwi->credtype_name[0] = L'\0'; + + cb = sizeof(cwi->credtype_name); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_TYPE_NAME, NULL, + &cwi->credtype, &cb))) { + cb = sizeof(cwi->credtype_name); + kcdb_credtype_describe(cwi->credtype, cwi->credtype_name, + &cb, KCDB_TS_SHORT); + } + } else { + cwi->credtype = KCDB_CREDTYPE_INVALID; + cwi->credtype_name[0] = L'\0'; + } + + cb = sizeof(cwi->ft_expire); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, + &cwi->ft_expire, &cb))) { + cwi->ft_expire = IntToFt(0); + } + kcdb_identity_get_flags(cwi->ident, &cwi->ident_flags); } cwi->credcount++; + kcdb_cred_get_type(cred, &cred_credtype); + if (cred_credtype >= 0 && cred_credtype == cwi->credtype) { + cwi->id_credcount++; + + kcdb_cred_get_flags(cred, &cred_flags); + if (cred_flags & KCDB_CRED_FLAG_INITIAL) { + cwi->init_credcount++; + } + } + _cleanup: if (ident) kcdb_identity_release(ident); @@ -843,6 +1010,8 @@ cw_update_creds(khui_credwnd_tbl * tbl) /* refresh the per-identity information */ for (i=0; i < (int) tbl->n_idents; i++) { tbl->idents[i].credcount = 0; + tbl->idents[i].id_credcount = 0; + tbl->idents[i].init_credcount = 0; } kcdb_credset_apply(tbl->credset, cw_credset_iter_func, (void *) tbl); @@ -935,6 +1104,9 @@ cw_get_buf_exp_flags(khui_credwnd_tbl * tbl, khm_handle buf) void cw_update_outline(khui_credwnd_tbl * tbl); +static void +cw_update_selection_state(khui_credwnd_tbl * tbl); + VOID CALLBACK cw_timer_proc(HWND hwnd, UINT uMsg, @@ -948,46 +1120,96 @@ cw_timer_proc(HWND hwnd, long ms; FILETIME ft; khm_size cbsize; + int timer_set = 0; + + KillTimer(hwnd, idEvent); tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); r = (khui_credwnd_row *) idEvent; + r->flags &= ~KHUI_CW_ROW_TIMERSET; nr = (int)(r - tbl->rows); if(nr < 0 || nr >= tbl->n_rows) return; - if(!(r->flags & KHUI_CW_ROW_CRED)) - return; /* we only know what to do with cred rows */ + if(r->flags & KHUI_CW_ROW_CRED) { + + nflags = cw_get_buf_exp_flags(tbl, (khm_handle) r->data); + if((r->flags & CW_EXPSTATE_MASK) != nflags) { + /* flags have changed */ + /* the outline needs to be updated */ + cw_update_outline(tbl); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } else { + /* just invalidate the row */ + RECT rc,rr,ri; + + GetClientRect(tbl->hwnd, &rc); + rc.top += tbl->header_height; + + rr = r->r_ext; + OffsetRect(&rr, 0, tbl->header_height - tbl->scr_top); + + if(IntersectRect(&ri, &rc, &rr)) + InvalidateRect(tbl->hwnd, &ri, FALSE); + + cbsize = sizeof(ft); + if(KHM_SUCCEEDED(kcdb_cred_get_attr((khm_handle) r->data, + KCDB_ATTR_TIMELEFT, NULL, + &ft, &cbsize))) { + ms = FtIntervalMsToRepChange(&ft); + if(ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); + timer_set = 1; + } + } - nflags = cw_get_buf_exp_flags(tbl, (khm_handle) r->data); - if((r->flags & CW_EXPSTATE_MASK) != nflags) { - /* flags have changed */ - /* the outline needs to be updated */ - cw_update_outline(tbl); - InvalidateRect(tbl->hwnd, NULL, FALSE); + if (timer_set) + r->flags |= KHUI_CW_ROW_TIMERSET; + } } else { - /* just invalidate the row */ - RECT r,rr,ri; + khui_credwnd_outline * o; + khui_credwnd_ident * cwi; + FILETIME ft_now; - GetClientRect(tbl->hwnd, &r); - r.top += tbl->header_height; - rr.top = r.top + (long)nr * tbl->cell_height - tbl->scr_top; - rr.bottom = rr.top + tbl->cell_height; - rr.left = r.left; - rr.right = r.right; - - if(IntersectRect(&ri, &r, &rr)) - InvalidateRect(tbl->hwnd, &ri, FALSE); - } + o = (khui_credwnd_outline *) r->data; +#ifdef DEBUG + assert(r->flags & KHUI_CW_ROW_EXPVIEW); + assert(o->attr_id == KCDB_ATTR_ID); + assert(tbl->flags & KHUI_CW_TBL_EXPIDENT); +#endif - cbsize = sizeof(ft); - if(KHM_SUCCEEDED(kcdb_cred_get_attr((khm_handle) r->data, - KCDB_ATTR_TIMELEFT, NULL, - &ft, &cbsize))) { - ms = FtIntervalMsToRepChange(&ft); - if(ms > 0) { - SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); + nflags = cw_get_buf_exp_flags(tbl, (khm_handle) o->data); + if ((o->flags & CW_EXPSTATE_MASK) != nflags) { + cw_update_outline(tbl); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } else { + RECT rc, rr, ri; + + GetClientRect(tbl->hwnd, &rc); + rc.top += tbl->header_height; + + rr = r->r_ext; + OffsetRect(&rr, 0, tbl->header_height - tbl->scr_top); + + if (IntersectRect(&ri, &rc, &rr)) + InvalidateRect(tbl->hwnd, &ri, FALSE); + + cwi = cw_find_ident(tbl, o->data); + + GetSystemTimeAsFileTime(&ft_now); + if (CompareFileTime(&cwi->ft_expire, &ft_now) > 0) { + ft = FtSub(&cwi->ft_expire, &ft_now); + ms = FtIntervalMsToRepChange(&ft); + if (ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); + timer_set = 1; + } + } + + if (timer_set) + r->flags |= KHUI_CW_ROW_TIMERSET; } } } @@ -1053,9 +1275,38 @@ cw_set_tbl_row_header(khui_credwnd_tbl * tbl, tbl->rows[row].flags = KHUI_CW_ROW_HEADER; if(o->flags & KHUI_CW_O_SELECTED) tbl->rows[row].flags |= KHUI_CW_ROW_SELECTED; + + /* if we are showing expanded identity information, we need to set + a timer so that we can update the identity row when the + identity changes. */ if ((tbl->flags & KHUI_CW_TBL_EXPIDENT) && - tbl->cols[col].attr_id == KCDB_ATTR_ID_NAME) + tbl->cols[col].attr_id == KCDB_ATTR_ID_NAME) { + + khui_credwnd_ident * cwi; + tbl->rows[row].flags |= KHUI_CW_ROW_EXPVIEW; + + cwi = cw_find_ident(tbl, o->data); + if (cwi && FtToInt(&cwi->ft_expire) != 0) { + FILETIME ft; + FILETIME ft_now; + + ft = cwi->ft_expire; + GetSystemTimeAsFileTime(&ft_now); + + if (CompareFileTime(&ft, &ft_now) > 0) { + long ms; + + ft = FtSub(&ft, &ft_now); + ms = FtIntervalMsToRepChange(&ft); + if (ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, + cw_timer_proc); + tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET; + } + } + } + } } static int @@ -1329,25 +1580,6 @@ cw_update_outline(khui_credwnd_tbl * tbl) ol->flags &= ~KHUI_CW_O_SHOWFLAG; ol->flags &= ~KHUI_CW_O_STICKY; - if (grouping[j] == tbl->n_cols - 1) { - ol->flags |= KHUI_CW_O_NOOUTLINE; - } else { - ol->flags &= ~KHUI_CW_O_NOOUTLINE; - } - - if(selected) { - ol->flags |= KHUI_CW_O_SELECTED; - } - if(visible) { - cw_set_tbl_row_header(tbl, n_rows, grouping[j], ol); - n_rows ++; - ol->flags |= KHUI_CW_O_VISIBLE; - } else { - ol->flags &= ~KHUI_CW_O_VISIBLE; - } - visible = visible && (ol->flags & KHUI_CW_O_EXPAND); - selected = (selected || (ol->flags & KHUI_CW_O_SELECTED)); - /* if the outline node is for an identity, then we have to check the expiration state for the identity. */ @@ -1368,6 +1600,26 @@ cw_update_outline(khui_credwnd_tbl * tbl) ol->flags |= KHUI_CW_O_SHOWFLAG; } } + + if (grouping[j] == tbl->n_cols - 1) { + ol->flags |= KHUI_CW_O_NOOUTLINE; + } else { + ol->flags &= ~KHUI_CW_O_NOOUTLINE; + } + + if(selected) { + ol->flags |= KHUI_CW_O_SELECTED; + } + if(visible) { + cw_set_tbl_row_header(tbl, n_rows, grouping[j], ol); + n_rows ++; + ol->flags |= KHUI_CW_O_VISIBLE; + } else { + ol->flags &= ~KHUI_CW_O_VISIBLE; + } + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + selected = (selected || (ol->flags & KHUI_CW_O_SELECTED)); + } /* we need to do this here too just in case we were already at @@ -1375,20 +1627,23 @@ cw_update_outline(khui_credwnd_tbl * tbl) if (ol) visible = visible && (ol->flags & KHUI_CW_O_EXPAND); - flags = cw_get_buf_exp_flags(tbl, thiscred); - if(visible && grouping[n_grouping - 1] < tbl->n_cols - 1) { khm_int32 c_flags; cw_set_tbl_row_cred(tbl, n_rows, thiscred, grouping[n_grouping-1]); - kcdb_cred_get_flags(thiscred, &c_flags); + + flags = cw_get_buf_exp_flags(tbl, thiscred); if(flags) { tbl->rows[n_rows].flags |= flags; } + + kcdb_cred_get_flags(thiscred, &c_flags); if(selected || - (c_flags & KCDB_CRED_FLAG_SELECTED)) + (c_flags & KCDB_CRED_FLAG_SELECTED)) { tbl->rows[n_rows].flags |= KHUI_CW_ROW_SELECTED; + } + tbl->rows[n_rows].idx_start = i; tbl->rows[n_rows].idx_end = i; @@ -1519,10 +1774,10 @@ _exit: * we have expiration states set for any active identities */ if (n_creds == 0) khm_notify_icon_expstate(KHM_NOTIF_EMPTY); - else if (expstate & CW_EXPSTATE_EXPIRED) + else if ((expstate & CW_EXPSTATE_EXPIRED) == CW_EXPSTATE_EXPIRED) khm_notify_icon_expstate(KHM_NOTIF_EXP); - else if ((expstate & CW_EXPSTATE_WARN) || - (expstate & CW_EXPSTATE_CRITICAL)) + else if ((expstate & CW_EXPSTATE_WARN) == CW_EXPSTATE_WARN || + (expstate & CW_EXPSTATE_CRITICAL) == CW_EXPSTATE_CRITICAL) khm_notify_icon_expstate(KHM_NOTIF_WARN); else khm_notify_icon_expstate(KHM_NOTIF_OK); @@ -1543,18 +1798,30 @@ cw_unload_view(khui_credwnd_tbl * tbl) SafeDeleteObject(tbl->hf_normal); SafeDeleteObject(tbl->hf_bold); SafeDeleteObject(tbl->hf_bold_header); + SafeDeleteObject(tbl->hb_grey); SafeDeleteObject(tbl->hb_normal); - SafeDeleteObject(tbl->hb_sel); + SafeDeleteObject(tbl->hb_s); + SafeDeleteObject(tbl->hb_hdr_bg); - SafeDeleteObject(tbl->hb_hdr_bg_sel); SafeDeleteObject(tbl->hb_hdr_bg_crit); SafeDeleteObject(tbl->hb_hdr_bg_exp); SafeDeleteObject(tbl->hb_hdr_bg_warn); SafeDeleteObject(tbl->hb_hdr_bg_def); + SafeDeleteObject(tbl->hb_hdr_bg_s); + SafeDeleteObject(tbl->hb_hdr_bg_crit_s); + SafeDeleteObject(tbl->hb_hdr_bg_exp_s); + SafeDeleteObject(tbl->hb_hdr_bg_warn_s); + SafeDeleteObject(tbl->hb_hdr_bg_def_s); + #undef SafeDeleteObject + if (tbl->hi_lg_ident) { + DestroyIcon(tbl->hi_lg_ident); + tbl->hi_lg_ident = NULL; + } + if(tbl->credset) { kcdb_credset_delete(tbl->credset); tbl->credset = NULL; @@ -1679,19 +1946,71 @@ cw_get_cell_height(HDC hdc, HFONT hf) { return size.cy; } +int +cw_update_header_column_width(khui_credwnd_tbl * tbl, int c) { + int idx; + HDITEM hi; + +#ifdef DEBUG + assert(c >= 0 && c < tbl->n_cols); +#endif + + if (tbl->hwnd_header == NULL) + return 0; + + idx = Header_OrderToIndex(tbl->hwnd_header, c); + ZeroMemory(&hi, sizeof(hi)); + hi.mask = HDI_WIDTH; + hi.cxy = tbl->cols[c].width; + return Header_SetItem(tbl->hwnd_header, idx, &hi); +} + /* returns a bitmask indicating which measures were changed */ int cw_update_extents(khui_credwnd_tbl * tbl, khm_boolean update_scroll) { - int ext_x, ext_y; + int ext_x = 0; + int ext_y = 0; int i; + int filler_col = -1; + int fill_adjusted = 0; + + recompute_columns: ext_x = 0; for(i=0; i < (int) tbl->n_cols; i++) { tbl->cols[i].x = ext_x; + if (tbl->cols[i].flags & KHUI_CW_COL_FILLER) { + if (filler_col == -1) + filler_col = i; + } ext_x += tbl->cols[i].width; } + if (filler_col != -1 && !fill_adjusted) { + RECT r; + int delta; + + GetClientRect(tbl->hwnd, &r); + + /* we decrement the width so that the width data area is + strictly less than the width of the client area. Windows + doesn't disable a scrollbar unless the range is strictly + less than the page size. */ + delta = ((r.right - r.left) - 1) - ext_x; + + if (tbl->cols[filler_col].width + delta <= GetSystemMetrics(SM_CXSMICON)) { + tbl->cols[filler_col].width = GetSystemMetrics(SM_CXICON); + } else { + tbl->cols[filler_col].width += delta; + } + + cw_update_header_column_width(tbl, filler_col); + + fill_adjusted = 1; + goto recompute_columns; + } + if(!tbl->cell_height) { HDC dc; int maxheight = 0; @@ -1716,16 +2035,35 @@ cw_update_extents(khui_credwnd_tbl * tbl, } if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + RECT r; + ext_y = 0; + r.left = 0; + r.right = ext_x; for (i=0; i < (int) tbl->n_rows; i++) { + r.top = ext_y; if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW) { ext_y += tbl->cell_height * CW_EXP_ROW_MULT; } else { ext_y += tbl->cell_height; } + r.bottom = ext_y; + tbl->rows[i].r_ext = r; } } else { + RECT r; + + r.left = 0; + r.right = ext_x; + + for (i=0; i < (int) tbl->n_rows; i++) { + r.top = i * tbl->cell_height; + r.bottom = r.top + tbl->cell_height; + + tbl->rows[i].r_ext = r; + } + ext_y = (int) tbl->n_rows * tbl->cell_height; } @@ -1848,7 +2186,7 @@ cw_erase_rect(HDC hdc, break; case CW_ER_SEL: - hbr = tbl->hb_sel; + hbr = tbl->hb_s; break; default: @@ -1936,18 +2274,30 @@ cw_draw_header(HDC hdc, { HBRUSH hbr; - if(selected) - hbr = tbl->hb_hdr_bg_sel; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) - hbr = tbl->hb_hdr_bg_exp; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) - hbr = tbl->hb_hdr_bg_crit; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) - hbr = tbl->hb_hdr_bg_warn; - else if (idf & KCDB_IDENT_FLAG_DEFAULT) - hbr = tbl->hb_hdr_bg_def; - else - hbr = tbl->hb_hdr_bg; + + if(selected) { + if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) + hbr = tbl->hb_hdr_bg_exp_s; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) + hbr = tbl->hb_hdr_bg_crit_s; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) + hbr = tbl->hb_hdr_bg_warn_s; + else if (idf & KCDB_IDENT_FLAG_DEFAULT) + hbr = tbl->hb_hdr_bg_def_s; + else + hbr = tbl->hb_hdr_bg_s; + } else { + if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) + hbr = tbl->hb_hdr_bg_exp; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) + hbr = tbl->hb_hdr_bg_crit; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) + hbr = tbl->hb_hdr_bg_warn; + else if (idf & KCDB_IDENT_FLAG_DEFAULT) + hbr = tbl->hb_hdr_bg_def; + else + hbr = tbl->hb_hdr_bg; + } FillRect(hdc, r, hbr); } @@ -1968,25 +2318,21 @@ cw_draw_header(HDC hdc, if(o->flags & KHUI_CW_O_EXPAND) { khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI, hdc, r->left, - r->bottom - (KHUI_SMICON_CY + - (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0); + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); } else { khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI, hdc, r->left, - r->bottom - (KHUI_SMICON_CY + - (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0); + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); } } else { if(o->flags & KHUI_CW_O_EXPAND) { khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND, hdc, r->left, - r->bottom - (KHUI_SMICON_CY + - (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0); + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); } else { khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE, hdc, r->left, - r->bottom - (KHUI_SMICON_CY + - (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), 0); + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); } } @@ -2007,22 +2353,30 @@ cw_draw_header(HDC hdc, IDB_WDG_STICK)), hdc, r->left, - r->bottom - (KHUI_SMICON_CY + - (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), - 0); + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); r->left += KHUI_SMICON_CX * 3 / 2; - khui_ilist_draw_id(tbl->ilist, - ((o->flags & KHUI_CW_O_STICKY)? - IDB_ID_DIS_SM: - IDB_ID_SM), - hdc, - r->left, - r->bottom - (KHUI_SMICON_CY + - (r->bottom - (r->top + KHUI_SMICON_CY)) / 2), - 0); - r->left += KHUI_SMICON_CX * 3 / 2 ; + /* the TRUE part of the 'if' is for drawing large icons. It's + disabled for now until we have new icons. */ + if ((cr->flags & KHUI_CW_ROW_EXPVIEW) && FALSE) { + int cx = GetSystemMetrics(SM_CXICON); + int cy = GetSystemMetrics(SM_CYICON); + + DrawIcon(hdc, r->left, (r->top + r->bottom - cy) / 2, tbl->hi_lg_ident); + + r->left += cx + KHUI_SMICON_CX / 2; + + } else { + khui_ilist_draw_id(tbl->ilist, + ((o->flags & KHUI_CW_O_STICKY)? + IDB_ID_DIS_SM: + IDB_ID_SM), + hdc, + r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + r->left += KHUI_SMICON_CX * 3 / 2 ; + } } @@ -2031,7 +2385,7 @@ cw_draw_header(HDC hdc, SetTextAlign(hdc, TA_BOTTOM | TA_LEFT); if(selected) - SetTextColor(hdc, tbl->cr_hdr_sel); + SetTextColor(hdc, tbl->cr_hdr_s); else SetTextColor(hdc, tbl->cr_hdr_normal); @@ -2057,64 +2411,81 @@ cw_draw_header(HDC hdc, RECT tr; int len; + wchar_t typestr[128]; + int cx_id; + SIZE size; + khui_credwnd_ident * cwi; /* expanded view */ #ifdef DEBUG assert(colattr == KCDB_ATTR_ID_NAME); #endif + cwi = cw_find_ident(tbl, o->data); + CopyRect(&tr, r); tr.bottom -= (tr.bottom - tr.top) / 2; /* drawing two lines of text */ if (selected) - SetTextColor(hdc, tbl->cr_hdr_sel); + SetTextColor(hdc, tbl->cr_hdr_s); else SetTextColor(hdc, tbl->cr_hdr_normal); len = (int) wcslen(o->header); DrawText(hdc, o->header, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + GetTextExtentPoint32(hdc, o->header, (int) len, &size); + cx_id = size.cx; + + typestr[0] = L'\0'; if ((idf & KCDB_IDENT_FLAG_DEFAULT)) { - SIZE size; - int cx_id; - int cx_def; - wchar_t defstr[64]; + if (cwi && cwi->credtype_name[0]) { + wchar_t fmt[64]; - LoadString(khm_hInstance, IDS_CW_DEFAULT, - defstr, ARRAYLENGTH(defstr)); + LoadString(khm_hInstance, IDS_CW_DEFAULTTF, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(typestr, sizeof(typestr), fmt, + cwi->credtype_name); + } else { + LoadString(khm_hInstance, IDS_CW_DEFAULT, + typestr, ARRAYLENGTH(typestr)); + } + } else if (cwi && cwi->credtype_name[0]) { + wchar_t fmt[64]; - GetTextExtentPoint32(hdc, o->header, (int) len, &size); - cx_id = size.cx; + LoadString(khm_hInstance, IDS_CW_TYPEF, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(typestr, sizeof(typestr), fmt, + cwi->credtype_name); + } + + if (typestr[0]) { + int cx_str; - len = (int) wcslen(defstr); - GetTextExtentPoint32(hdc, defstr, (int) len, &size); - cx_def = size.cx + KHUI_SMICON_CX / 2; + len = (int) wcslen(typestr); + GetTextExtentPoint32(hdc, typestr, (int) len, &size); + cx_str = size.cx + KHUI_SMICON_CX / 2; - tr.left = max(tr.right - cx_def, tr.left + cx_id + KHUI_SMICON_CX * 2); + tr.left = max(tr.right - cx_str, tr.left + cx_id + KHUI_SMICON_CX * 2); if (selected) - SetTextColor(hdc, tbl->cr_hdr_gray_sel); + SetTextColor(hdc, tbl->cr_hdr_gray_s); else SetTextColor(hdc, tbl->cr_hdr_gray); - DrawText(hdc, defstr, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + DrawText(hdc, typestr, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } CopyRect(&tr, r); tr.top += (tr.bottom - tr.top) / 2; - if (0) { - khm_size i; + if (1) { wchar_t buf[128]; + khui_credwnd_ident * cwi; - for (i = 0; i < tbl->n_idents; i++) { - if (kcdb_identity_is_equal(o->data, tbl->idents[i].ident)) - break; - } - - if (i < tbl->n_idents) { - khui_credwnd_ident * cwi; - - cwi = &tbl->idents[i]; + buf[0] = L'\0'; + cwi = cw_find_ident(tbl, o->data); + if (cwi) { +#ifdef SHOW_CREDENTIAL_COUNTS if (cwi->credcount == 0) LoadString(khm_hInstance, IDS_IDEXPDISP_NOCRED, buf, ARRAYLENGTH(buf)); @@ -2127,15 +2498,40 @@ cw_draw_header(HDC hdc, fmt, ARRAYLENGTH(fmt)); StringCbPrintf(buf, sizeof(buf), fmt, (int) cwi->credcount); } - } +#else + if (FtToInt(&cwi->ft_expire) != 0) { + FILETIME ft_now; + + GetSystemTimeAsFileTime(&ft_now); + if (CompareFileTime(&cwi->ft_expire, &ft_now) > 0) { + wchar_t fmt[64]; + wchar_t intstr[128]; + FILETIME ft; + khm_size cb; + + ft = FtSub(&cwi->ft_expire, &ft_now); + intstr[0] = L'\0'; + cb = sizeof(intstr); + FtIntervalToString(&ft, intstr, &cb); + + LoadString(khm_hInstance, IDS_CW_EXPIREF, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, intstr); + } else { + LoadString(khm_hInstance, IDS_CW_EXPIRED, + buf, ARRAYLENGTH(buf)); + } + } +#endif - len = (int) wcslen(buf); + len = (int) wcslen(buf); - if (selected) - SetTextColor(hdc, tbl->cr_hdr_gray_sel); - else - SetTextColor(hdc, tbl->cr_hdr_gray); - DrawText(hdc, buf, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + if (selected) + SetTextColor(hdc, tbl->cr_hdr_gray_s); + else + SetTextColor(hdc, tbl->cr_hdr_gray); + DrawText(hdc, buf, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + } } } } @@ -2160,6 +2556,8 @@ cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { } case HDN_TRACK: + return FALSE; + case HDN_ENDTRACK: { int width; @@ -2182,7 +2580,7 @@ cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { hi.mask = HDI_ORDER; Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); - if (tbl->cols[hi.iOrder].flags & KHUI_CW_COL_FIXED_WIDTH) { + if (tbl->cols[hi.iOrder].flags & KHUI_CW_COL_FIXED_POS) { return TRUE; } else { return FALSE; @@ -2215,7 +2613,7 @@ cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { /* we don't allow dragging in to the "fixed" area. */ for (i=0; i < tbl->n_cols; i++) { - if (tbl->cols[i].attr_id >= 0) + if (!(tbl->cols[i].flags & KHUI_CW_COL_FIXED_POS)) break; } @@ -2305,7 +2703,10 @@ cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); idx = hi.iOrder; - if (idx == 0 || idx >= tbl->n_cols) + if (idx < 0 || idx >= tbl->n_cols) + return FALSE; + + if (tbl->cols[idx].flags & KHUI_CW_COL_META) return FALSE; if (tbl->cols[idx].flags & @@ -2511,6 +2912,7 @@ cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); + cw_update_selection_state(tbl); cw_update_extents(tbl, FALSE); { @@ -2685,9 +3087,9 @@ cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_draw_header(hdc, tbl, i, &rh); } - + if(selected) - SetTextColor(hdc, tbl->cr_sel); + SetTextColor(hdc, tbl->cr_s); else SetTextColor(hdc, tbl->cr_normal); @@ -2955,6 +3357,7 @@ cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); + cw_update_selection_state(tbl); cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); @@ -3121,6 +3524,51 @@ cw_select_outline(khui_credwnd_outline * o, o->flags &= ~KHUI_CW_O_SELECTED; } +static void +cw_select_cred_row(khui_credwnd_tbl * tbl, int row, int selected) { + + khm_size j; + khm_size idx_start, idx_end; + +#ifdef DEBUG + assert(row >= 0 && row < tbl->n_rows); +#endif + + if (row >= tbl->n_rows) + return; + + if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[row].data; + if (o->col == tbl->n_cols - 1) { + /* this is a special case where the outline column is the + last displayed column. In this case, the credentials + do not occupy any rows, and this header row acts as a + group credential row. */ + idx_start = o->idx_start; + idx_end = o->idx_end; + } else { + return; + } + } else { + idx_start = tbl->rows[row].idx_start; + idx_end = tbl->rows[row].idx_end; + } + + for (j = idx_start; j <= idx_end; j++) { + khm_handle cred = NULL; + + kcdb_credset_get_cred(tbl->credset, (khm_int32) j, &cred); + + if (cred) { + kcdb_cred_set_flags(cred, ((selected)?KCDB_CRED_FLAG_SELECTED:0), + KCDB_CRED_FLAG_SELECTED); + kcdb_cred_release(cred); + } + } +} + static void cw_unselect_all(khui_credwnd_tbl * tbl) { @@ -3128,10 +3576,10 @@ cw_unselect_all(khui_credwnd_tbl * tbl) for(i=0; in_rows; i++) { tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; - if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) - kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, - 0, - KCDB_CRED_FLAG_SELECTED); + + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + cw_select_cred_row(tbl, i, FALSE); + } } cw_select_outline_level(tbl->outline, FALSE); @@ -3352,9 +3800,7 @@ cw_select_all(khui_credwnd_tbl * tbl) for(i=0; in_rows; i++) { tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) - kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, - KCDB_CRED_FLAG_SELECTED, - KCDB_CRED_FLAG_SELECTED); + cw_select_cred_row(tbl, i, TRUE); } cw_select_outline_level(tbl->outline, TRUE); @@ -3410,11 +3856,7 @@ cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) for (i = group_begin; i <= group_end; i++) { tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; - if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { - kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, - KCDB_CRED_FLAG_SELECTED, - KCDB_CRED_FLAG_SELECTED); - } + cw_select_cred_row(tbl, i, TRUE); } } else if (toggle) { BOOL select; @@ -3430,11 +3872,7 @@ cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) else tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; - if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { - kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, - (select)?KCDB_CRED_FLAG_SELECTED:0, - KCDB_CRED_FLAG_SELECTED); - } + cw_select_cred_row(tbl, i, select); } } else if (extend) { int range_begin; @@ -3448,11 +3886,7 @@ cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) for (i = range_begin; i <= range_end; i++) { tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; - if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { - kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, - KCDB_CRED_FLAG_SELECTED, - KCDB_CRED_FLAG_SELECTED); - } + cw_select_cred_row(tbl, i, TRUE); } tbl->cursor_row = row; @@ -4549,6 +4983,7 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); + cw_update_selection_state(tbl); cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); @@ -4565,7 +5000,8 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); - cw_update_extents(tbl, FALSE); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); @@ -4584,7 +5020,8 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); - cw_update_extents(tbl, FALSE); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); @@ -4604,7 +5041,8 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); - cw_update_extents(tbl, FALSE); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); @@ -4624,7 +5062,8 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); - cw_update_extents(tbl, FALSE); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); @@ -4644,7 +5083,8 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_update_creds(tbl); cw_update_outline(tbl); - cw_update_extents(tbl, FALSE); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); InvalidateRect(tbl->hwnd, NULL, TRUE); } @@ -5040,7 +5480,7 @@ khm_create_credwnd(HWND parent) { (0, MAKEINTATOM(khui_credwnd_cls), L"", - WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN, r.left, r.top, r.right - r.left, diff --git a/src/windows/identity/ui/credwnd.h b/src/windows/identity/ui/credwnd.h index 3d39ebc4f..42edf2842 100644 --- a/src/windows/identity/ui/credwnd.h +++ b/src/windows/identity/ui/credwnd.h @@ -75,6 +75,7 @@ typedef struct khui_credwnd_row_t { khm_handle data; khm_size idx_start; khm_size idx_end; + RECT r_ext; /* extents of this row */ } khui_credwnd_row; #define KHUI_CW_ROW_CRED 0x00000002 @@ -111,6 +112,7 @@ typedef struct khui_credwnd_col_t { #define KHUI_CW_COL_FIXED_WIDTH 0x00000010 #define KHUI_CW_COL_FIXED_POS 0x00000020 #define KHUI_CW_COL_META 0x00000040 +#define KHUI_CW_COL_FILLER 0x00000080 /* Custom column attributes (are not kcdb attributes) */ #define CW_CA_FLAGS -1 @@ -129,7 +131,12 @@ typedef struct tag_khui_credwnd_ident { wchar_t name[KCDB_IDENT_MAXCCH_NAME]; wchar_t credtype_name[KCDB_MAXCCH_NAME]; - khm_size credcount; + khm_size credcount; /* count of all credentials */ + khm_size id_credcount; /* count of identity credentials + (credentials that are of the + identity type */ + khm_size init_credcount; /* count of initial credentials */ + FILETIME ft_expire; } khui_credwnd_ident; @@ -181,25 +188,37 @@ typedef struct khui_credwnd_tbl_t { HFONT hf_header; /* header text */ HFONT hf_bold; /* bold text */ HFONT hf_bold_header; /* bold header text */ + HBRUSH hb_normal; /* normal background brush */ - HBRUSH hb_grey; /* normal grey background brush */ - HBRUSH hb_sel; /* selected background brush */ + HBRUSH hb_grey; /* normal background brush (greyed) */ + HBRUSH hb_s; /* normal background brush (selected) */ + + HBRUSH hb_hdr_bg; /* header background brush (normal) */ + HBRUSH hb_hdr_bg_exp; /* header background brush (expired) */ + HBRUSH hb_hdr_bg_warn; /* header background brush (warn) */ + HBRUSH hb_hdr_bg_crit; /* header background brush (critical) */ + HBRUSH hb_hdr_bg_def; /* header background brush (default) */ + + HBRUSH hb_hdr_bg_s; /* header background brush (selected) */ + HBRUSH hb_hdr_bg_exp_s; /* header background brush (expired,selected) */ + HBRUSH hb_hdr_bg_warn_s;/* header background brush (warn,selected) */ + HBRUSH hb_hdr_bg_crit_s;/* header background brush (critical,selected) */ + HBRUSH hb_hdr_bg_def_s; /* header background brush (default,selected) */ + + COLORREF cr_normal; /* text color (normal) */ + COLORREF cr_s; /* text color (selected) */ + COLORREF cr_hdr_normal; /* header text color (normal) */ + COLORREF cr_hdr_s; /* header text color (selected) */ + COLORREF cr_hdr_gray; /* header text color (greyed) */ + COLORREF cr_hdr_gray_s; /* header text color (greyed,selected) */ + COLORREF cr_hdr_outline;/* header outline color */ - COLORREF cr_normal; /* normal text color */ - COLORREF cr_sel; /* selected text color */ - COLORREF cr_hdr_normal; /* normal header text color */ - COLORREF cr_hdr_sel; /* selected header text color */ - COLORREF cr_hdr_gray; /* gray header text color */ - COLORREF cr_hdr_gray_sel; /* selected gray header text color */ - HBRUSH hb_hdr_bg; /* header background color (normal) */ - HBRUSH hb_hdr_bg_exp; /* header background color (expired) */ - HBRUSH hb_hdr_bg_warn; /* header background color (warn) */ - HBRUSH hb_hdr_bg_crit; /* header background color (critical) */ - HBRUSH hb_hdr_bg_sel; /* header background color (selected) */ - HBRUSH hb_hdr_bg_def; /* header background color (default) */ + HCURSOR hc_hand; /* the HAND cursor */ khui_ilist * ilist; /* image list */ + HICON hi_lg_ident; /* large identity icon */ + #if 0 /* icon indices */ int idx_expand; /* index of 'expanded' icon in image list */ diff --git a/src/windows/identity/ui/lang/en_us/khapp.rc b/src/windows/identity/ui/lang/en_us/khapp.rc index b8e2e3d2a..74255fb02 100644 --- a/src/windows/identity/ui/lang/en_us/khapp.rc +++ b/src/windows/identity/ui/lang/en_us/khapp.rc @@ -181,14 +181,15 @@ BEGIN PUSHBUTTON "&>>",IDC_NC_ADVANCED,260,142,34,18 END -IDD_NC_BBAR DIALOGEX 0, 0, 66, 181 +IDD_NC_BBAR DIALOGEX 0, 0, 66, 190 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "&Ok",IDOK,7,7,52,41,WS_DISABLED PUSHBUTTON "&Cancel",IDCANCEL,7,58,52,19 - PUSHBUTTON "&Help",IDC_NC_HELP,7,155,52,19 + PUSHBUTTON "<<",IDC_NC_BASIC,7,144,52,14 + PUSHBUTTON "&Help",IDC_NC_HELP,7,164,52,19 END IDD_PP_IDENT DIALOGEX 0, 0, 235, 156 @@ -412,7 +413,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 59 TOPMARGIN, 7 - BOTTOMMARGIN, 174 + BOTTOMMARGIN, 183 END IDD_PP_IDENT, DIALOG @@ -790,7 +791,7 @@ BEGIN IDS_NCN_IDENT_UNKNOWN "Validity of identity %s coudn't be determined." 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." IDS_REMOTE_FAIL_TITLE "Failed to communicate with Network Identity Manager" - IDS_IDACTION_NEW "Initialize %s" + IDS_IDACTION_NEW "Obtain new credentials for %s" IDS_IDACTIONT_NEW "New credentials for %s" END @@ -807,6 +808,10 @@ BEGIN IDS_IDEXPDISP_NOCRED "(This identity has no credentials)" IDS_IDEXPDISP_1CRED "(This identity has 1 credential)" IDS_IDEXPDISP_NCRED "(This identity has %d credentials)" + IDS_CW_DEFAULTTF "(Default, %s)" + IDS_CW_TYPEF "(%s)" + IDS_CW_EXPIREF "Expires in %s" + IDS_CW_EXPIRED "(Expired)" END #endif // English (U.S.) resources diff --git a/src/windows/identity/ui/main.c b/src/windows/identity/ui/main.c index 82d0fb75d..e7d59eddb 100644 --- a/src/windows/identity/ui/main.c +++ b/src/windows/identity/ui/main.c @@ -45,7 +45,7 @@ khm_ui_4 khm_commctl_version = 0; khm_startup_options khm_startup; -khm_version app_version = {KH_VERSION_LIST}; +const khm_version app_version = {KH_VERSION_LIST}; void khm_init_gui(void) { khui_init_actions(); @@ -522,7 +522,7 @@ void khm_load_default_modules(void) { kmm_load_default_modules(); } -int version_compare(const khm_version * v1, const khm_version * v2) { +int khm_compare_version(const khm_version * v1, const khm_version * v2) { if (v1->major != v2->major) return ((int)v1->major) - ((int)v2->major); @@ -744,8 +744,8 @@ int WINAPI WinMain(HINSTANCE hInstance, v.patch = 0; v.aux = 0; - if (version_compare(&query_app_version.ver_remote, &app_version) == 0 || - version_compare(&query_app_version.ver_remote, &v) > 0) + if (khm_compare_version(&query_app_version.ver_remote, &app_version) == 0 || + khm_compare_version(&query_app_version.ver_remote, &v) > 0) use_cmd_v2 = TRUE; else use_cmd_v2 = FALSE; diff --git a/src/windows/identity/ui/mainmenu.c b/src/windows/identity/ui/mainmenu.c index 70913f472..5d9e4d997 100644 --- a/src/windows/identity/ui/mainmenu.c +++ b/src/windows/identity/ui/mainmenu.c @@ -190,62 +190,99 @@ void add_action_to_menu(HMENU hm, khui_action * act, static void refresh_menu(HMENU hm, khui_menu_def * def); -static void refresh_menu_item(HMENU hm, khui_action * act, - int idx, int flags) { +static int refresh_menu_item(HMENU hm, khui_action * act, + int idx, int flags) { MENUITEMINFO mii; + khui_menu_def * def; mii.cbSize = sizeof(mii); mii.fMask = 0; - if (act == NULL) - return; - else { - khui_menu_def * def; - - /* first check if the menu item is there. Otherwise we need - to add it. */ - mii.fMask = MIIM_STATE; - if (!GetMenuItemInfo(hm, act->cmd, FALSE, &mii)) { - add_action_to_menu(hm, act, idx, flags); - return; + if (flags & KHUI_ACTIONREF_END) { + /* we have been asked to assert that the menu doesn't have + more than idx items */ + mii.fMask = MIIM_FTYPE; + while (GetMenuItemInfo(hm, idx, TRUE, &mii)) { + RemoveMenu(hm, idx, MF_BYPOSITION); + mii.fMask = MIIM_FTYPE; } - mii.fMask = 0; + return 0; + } - if(act->state & KHUI_ACTIONSTATE_DISABLED) { - mii.fMask |= MIIM_STATE; - mii.fState = MFS_DISABLED; - } else { + /* Check if the menu item is there. Otherwise we need to add + it. */ + mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; + if (!GetMenuItemInfo(hm, idx, TRUE, &mii) || + ((flags & KHUI_ACTIONREF_SEP) && !(mii.fType & MFT_SEPARATOR)) || + (!(flags & KHUI_ACTIONREF_SEP) && mii.wID != act->cmd)) { + add_action_to_menu(hm, ((flags & KHUI_ACTIONREF_SEP)? NULL : act), + idx, flags); + return 0; + } + + if (flags & KHUI_ACTIONREF_SEP) + return 0; + +#ifdef DEBUG + assert(act); +#endif + if (!act) + return 0; + + if (flags & KHUI_ACTIONREF_DEFAULT) { + if (!(mii.fState & MFS_DEFAULT)) { mii.fMask |= MIIM_STATE; - mii.fState = MFS_ENABLED; + mii.fState |= MFS_DEFAULT; + } + } else { + if (mii.fState & MFS_DEFAULT) { + RemoveMenu(hm, idx, MF_BYPOSITION); + add_action_to_menu(hm, act, idx, flags); + return 0; } + } - if(act->type & KHUI_ACTIONTYPE_TOGGLE) { - mii.fMask |= MIIM_STATE; - if (act->state & KHUI_ACTIONSTATE_CHECKED) { - mii.fState |= MFS_CHECKED; - } else { - mii.fState |= MFS_UNCHECKED; - } + mii.fMask = 0; + + if(act->state & KHUI_ACTIONSTATE_DISABLED) { + mii.fMask |= MIIM_STATE; + mii.fState &= ~MFS_ENABLED; + mii.fState |= MFS_DISABLED; + } else { + mii.fMask |= MIIM_STATE; + mii.fState &= ~MFS_DISABLED; + mii.fState |= MFS_ENABLED; + } + + if(act->type & KHUI_ACTIONTYPE_TOGGLE) { + mii.fMask |= MIIM_STATE; + if (act->state & KHUI_ACTIONSTATE_CHECKED) { + mii.fState |= MFS_CHECKED; + } else { + mii.fState |= MFS_UNCHECKED; } + } - SetMenuItemInfo(hm, act->cmd, FALSE, &mii); + SetMenuItemInfo(hm, act->cmd, FALSE, &mii); - def = khui_find_menu(act->cmd); + def = khui_find_menu(act->cmd); - if(def) { - MENUITEMINFO mii2; + if(def) { + MENUITEMINFO mii2; - mii2.cbSize = sizeof(mii2); - mii2.fMask = MIIM_SUBMENU; + mii2.cbSize = sizeof(mii2); + mii2.fMask = MIIM_SUBMENU; - if (GetMenuItemInfo(hm, act->cmd, FALSE, &mii2)) { - refresh_menu(mii2.hSubMenu, def); - } + if (GetMenuItemInfo(hm, act->cmd, FALSE, &mii2)) { + refresh_menu(mii2.hSubMenu, def); } } + + return 0; } + static void refresh_menu(HMENU hm, khui_menu_def * def) { khui_action_ref * act; khm_size i, n; @@ -254,6 +291,8 @@ static void refresh_menu(HMENU hm, khui_menu_def * def) { act = khui_menu_get_action(def, i); refresh_menu_item(hm, khui_find_action(act->action), (int) i, act->flags); } + + refresh_menu_item(hm, NULL, (int) i, KHUI_ACTIONREF_END); } static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main) { @@ -778,6 +817,8 @@ khm_refresh_identity_menus(void) { khm_size t; khm_int32 rv = KHM_ERROR_SUCCESS; + khui_action_lock(); + idcmd_refreshcycle++; do { @@ -867,6 +908,10 @@ khm_refresh_identity_menus(void) { PFREE(idlist); purge_identity_cmd_map(); + + khui_action_unlock(); + + khui_refresh_actions(); } khm_boolean @@ -929,10 +974,14 @@ void khm_menu_refresh_items(void) { if (!khui_hmenu_main) return; + khui_action_lock(); + def = khui_find_menu(KHUI_MENU_MAIN); refresh_menu(khui_hmenu_main, def); + khui_action_unlock(); + DrawMenuBar(khm_hwnd_main); } diff --git a/src/windows/identity/ui/mainwnd.c b/src/windows/identity/ui/mainwnd.c index 494ef4bb6..128be085c 100644 --- a/src/windows/identity/ui/mainwnd.c +++ b/src/windows/identity/ui/mainwnd.c @@ -1093,6 +1093,7 @@ void khm_set_main_window_mode(int mode) { RECT r; + khm_handle csp_cw; if (mode == khm_main_wnd_mode) return; @@ -1115,6 +1116,14 @@ khm_set_main_window_mode(int mode) { SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); } + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, + &csp_cw))) { + + khc_write_int32(csp_cw, L"DefaultWindowMode", mode); + khc_close_space(csp_cw); + + } } void diff --git a/src/windows/identity/ui/newcredwnd.c b/src/windows/identity/ui/newcredwnd.c index 72c58a0a1..4e4e5e116 100644 --- a/src/windows/identity/ui/newcredwnd.c +++ b/src/windows/identity/ui/newcredwnd.c @@ -1570,9 +1570,9 @@ nc_handle_wm_create(HWND hwnd, SendMessage(ncd->dlg_main, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); } else { - /* we don't call this if the dialog is expanded because - posting WMNC_DIALOG_EXPAND to the main panel results in - this getting called anyway. */ + /* we don't call nc_layout_main_panel() if the dialog is + expanded because posting WMNC_DIALOG_EXPAND to the main + panel results in it getting called anyway. */ nc_layout_main_panel(ncd); } @@ -1759,6 +1759,7 @@ nc_handle_wm_command(HWND hwnd, khm_html_help(hwnd, NULL, HH_HELP_CONTEXT, IDH_ACTION_NEW_ID); return FALSE; + case IDC_NC_BASIC: case IDC_NC_ADVANCED: /* the Options button in the main window was clicked. we respond by expanding the dialog. */ @@ -1919,15 +1920,19 @@ static LRESULT nc_handle_wm_nc_notify(HWND hwnd, /* fallthrough */ case WMNC_DIALOG_EXPAND: - /* we are expanding the dialog box */ + /* we are switching from basic to advanced or vice versa */ - /* nothing to do? */ - if (d->nc->mode == KHUI_NC_MODE_EXPANDED) - break; - - d->nc->mode = KHUI_NC_MODE_EXPANDED; + if (d->nc->mode == KHUI_NC_MODE_EXPANDED) { + d->nc->mode = KHUI_NC_MODE_MINI; + } else { + d->nc->mode = KHUI_NC_MODE_EXPANDED; + } - nc_notify_clear(d); + /* if we are switching to the advanced mode, we clear any + notifications because we now have a credential text area + for that. */ + if (d->nc->mode == KHUI_NC_MODE_EXPANDED) + nc_notify_clear(d); nc_layout_main_panel(d); diff --git a/src/windows/identity/ui/newcredwnd.h b/src/windows/identity/ui/newcredwnd.h index 46ac83169..939cf0141 100644 --- a/src/windows/identity/ui/newcredwnd.h +++ b/src/windows/identity/ui/newcredwnd.h @@ -140,7 +140,7 @@ void khm_show_newcredwnd(HWND hwnd); /* Width of the button bar in dialog units */ #define NCDLG_BBAR_WIDTH 66 /* Height of the button bar in dialog units */ -#define NCDLG_BBAR_HEIGHT 181 +#define NCDLG_BBAR_HEIGHT 190 /* Control identifier for the tab control in the new credentials dialog. We declare this here since we will be creating the control diff --git a/src/windows/identity/ui/notifier.c b/src/windows/identity/ui/notifier.c index 530c22b56..e0582eb94 100644 --- a/src/windows/identity/ui/notifier.c +++ b/src/windows/identity/ui/notifier.c @@ -118,7 +118,7 @@ alerter_wnd_data * khui_alert_windows = NULL; int iid_normal = IDI_NOTIFY_NONE; /* The alert currently being displayed in a balloon */ -khui_alert * balloon_alert; +khui_alert * balloon_alert = NULL; /********************************************************************** Alert Queue @@ -488,6 +488,7 @@ notifier_wnd_proc(HWND hwnd, balloon_alert = NULL; khui_alert_lock(a); + a->displayed = FALSE; if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) && !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) && @@ -515,8 +516,15 @@ notifier_wnd_proc(HWND hwnd, case NIN_BALLOONTIMEOUT: khm_notify_icon_change(KHERR_NONE); if (balloon_alert) { - khui_alert_release(balloon_alert); + khui_alert * a; + a = balloon_alert; balloon_alert = NULL; + + khui_alert_lock(a); + a->displayed = FALSE; + khui_alert_unlock(a); + + khui_alert_release(a); } break; } @@ -681,9 +689,9 @@ typedef struct tag_alerter_wnd_data { #define IDC_NTF_CLOSE 999 #define IDC_NTF_CMDBUTTONS 1001 -#define IDC_FROM_IDX(alert, bn) ((alert) * KHUI_MAX_ALERT_COMMANDS + (bn) + IDC_NTF_CMDBUTTONS) -#define ALERT_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) / KHUI_MAX_ALERT_COMMANDS) -#define BUTTON_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) % KHUI_MAX_ALERT_COMMANDS) +#define IDC_FROM_IDX(alert, bn) ((alert) * (KHUI_MAX_ALERT_COMMANDS + 1) + (bn) + 1 + IDC_NTF_CMDBUTTONS) +#define ALERT_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) / (KHUI_MAX_ALERT_COMMANDS + 1)) +#define BUTTON_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) % (KHUI_MAX_ALERT_COMMANDS + 1) - 1) /* if the only command in an alert is "Close", we assume that the alert has no commands. */ @@ -717,8 +725,9 @@ add_alert_to_wnd_data(alerter_wnd_data * d, a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW; - if (!exists) + if (!exists) { a->displayed = TRUE; + } khui_alert_unlock(a); @@ -1376,7 +1385,7 @@ setup_alerter_window_controls(alerter_wnd_data * d) { -10, 0, 5, 5, d->hw_bin, - (HMENU) (INT_PTR) IDC_FROM_IDX(idx, 0), + (HMENU) (INT_PTR) IDC_FROM_IDX(idx, -1), khm_hInstance, NULL); #ifdef DEBUG @@ -1391,8 +1400,13 @@ setup_alerter_window_controls(alerter_wnd_data * d) { last_window = adata->hwnd_marker; - if (hw_focus == NULL) - hw_focus = adata->hwnd_marker; + if (scrollbar) { + EnableWindow(adata->hwnd_marker, TRUE); + if (hw_focus == NULL) + hw_focus = adata->hwnd_marker; + } else { + EnableWindow(adata->hwnd_marker, FALSE); + } } y += adata->r_alert.bottom; @@ -1441,7 +1455,7 @@ setup_alerter_window_controls(alerter_wnd_data * d) { SWP_SHOWWINDOW); } - if (hw_focus == NULL) + if (hw_focus == NULL || d->n_cmd_buttons == 0) hw_focus = d->hw_close; } else { @@ -1473,7 +1487,6 @@ setup_alerter_window_controls(alerter_wnd_data * d) { r_window.right - r_window.left, r_window.bottom - r_window.top, SWP_SHOWWINDOW | SWP_NOOWNERZORDER); - } if (hw_focus != NULL) @@ -1645,6 +1658,11 @@ process_command_button(alerter_wnd_data * d, int id) { if (alert_idx >= d->n_alerts || alert_idx < 0) return; + if (cmd_idx < 0) { + /* the user selected a marker button. Nothing to do. */ + return; + } + adata = QTOP(d); while(adata && alert_idx > 0) { alert_idx--; @@ -2011,15 +2029,22 @@ alert_show_minimized(khui_alert * a) { a->flags |= KHUI_ALERT_FLAG_DISPLAY_BALLOON; -#if (_WIN32_IE >= 0x0501) +#ifdef DEBUG + assert(balloon_alert == NULL); +#endif + if (balloon_alert) { + khui_alert_lock(balloon_alert); + balloon_alert->displayed = FALSE; + khui_alert_unlock(balloon_alert); khui_alert_release(balloon_alert); balloon_alert = NULL; } balloon_alert = a; khui_alert_hold(a); -#endif + + a->displayed = TRUE; khm_notify_icon_balloon(a->severity, tbuf, @@ -2205,6 +2230,21 @@ show_queued_alerts(void) { alert_list_destroy(&alist); + if (n == 0) { + khui_alert * a; + + /* no alerts were shown above. This maybe because none of + the alerts were consolidatable or they were requested + to be shown in a balloon. In this case, we just take + the first alert from the queue and show it manually. */ + + a = alert_queue_get_alert(); + if (a) { + alert_show(a); + khui_alert_release(a); + } + } + check_for_queued_alerts(); } } @@ -2550,6 +2590,7 @@ alert_bin_wnd_proc(HWND hwnd, if (a->suggestion) { HICON hicon; + SIZE sz; CopyRect(&r, &adata->r_suggestion); OffsetRect(&r, 0, y); @@ -2558,14 +2599,18 @@ alert_bin_wnd_proc(HWND hwnd, InflateRect(&r, -d->s_pad.cx, -d->s_pad.cy); + sz.cx = GetSystemMetrics(SM_CXSMICON); + sz.cy = GetSystemMetrics(SM_CYSMICON); + hicon = (HICON) LoadImage(NULL, MAKEINTRESOURCE(OIC_NOTE), IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), + sz.cx, + sz.cy, LR_SHARED); - DrawIcon(hdc, r.left, r.top, hicon); + DrawIconEx(hdc, r.left, r.top, hicon, sz.cx, sz.cy, 0, NULL, + DI_NORMAL); r.left += d->s_pad.cx + GetSystemMetrics(SM_CXSMICON); @@ -2691,6 +2736,12 @@ alert_bin_wnd_proc(HWND hwnd, } break; + case WM_SIZE: + { + InvalidateRect(hwnd, NULL, TRUE); + } + break; + case WM_DESTROY: { /* nothing needs to be done here */ @@ -2944,26 +2995,52 @@ void khm_notify_icon_activate(void) { khm_notify_icon_change(KHERR_NONE); - if (!is_alert_queue_empty() && !ALERT_DISPLAYED()) { - - khm_show_main_window(); - show_queued_alerts(); - - } else if (balloon_alert != NULL && khui_alert_windows == NULL) { + if (balloon_alert != NULL && khui_alert_windows == NULL) { khui_alert * a; + khm_boolean alert_done = FALSE; a = balloon_alert; balloon_alert = NULL; khui_alert_lock(a); - if (balloon_alert->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) { + + a->displayed = FALSE; + + if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) && + (a->n_alert_commands > 0)) { + + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(a->alert_commands[0], + 0), + 0); + alert_done = TRUE; + + } else if (a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) { + alert_show_normal(a); + alert_done = TRUE; + } khui_alert_unlock(a); khui_alert_release(a); - } else { + if (alert_done) + return; + } + + if (!is_alert_queue_empty() && !ALERT_DISPLAYED()) { + + khm_show_main_window(); + show_queued_alerts(); + + return; + } + + + /* if none of the above applied, then we perform the default + action for the notification icon. */ + { khm_int32 cmd = 0; cmd = get_default_notifier_action(); @@ -3069,6 +3146,7 @@ create_test_alerts(void) { StringCbPrintf(buf, sizeof(buf), L"Foo bar baz. This is alert number %d", i); khui_alert_create_simple(L"Title", buf, KHERR_INFO, &a); khui_alert_set_type(a, KHUI_ALERTTYPE_PLUGIN); + khui_alert_set_suggestion(a, L"This is a suggestion. It is kinda long to see if the word wrapping actually works as we expect it to. Just in case, here's a line feed.\n\nDoes this show up on a different line? Cool!"); khui_alert_add_command(a, KHUI_ACTION_NEW_CRED); khui_alert_add_command(a, KHUI_ACTION_CLOSE_APP); diff --git a/src/windows/identity/ui/resource.h b/src/windows/identity/ui/resource.h index d7c9f27a6..31df1fe7e 100644 --- a/src/windows/identity/ui/resource.h +++ b/src/windows/identity/ui/resource.h @@ -319,6 +319,10 @@ #define IDS_IDEXPDISP_NOCRED 312 #define IDS_IDEXPDISP_1CRED 313 #define IDS_IDEXPDISP_NCRED 314 +#define IDS_CW_DEFAULTTF 315 +#define IDS_CW_TYPEF 316 +#define IDS_CW_EXPIREF 317 +#define IDS_CW_EXPIRED 318 #define IDC_NC_USERNAME 1007 #define IDC_NC_PASSWORD 1008 #define IDC_NC_CREDTEXT_LABEL 1009 @@ -425,6 +429,8 @@ #define IDC_LG_LBL 1139 #define IDC_CFG_NOTACTION 1141 #define IDC_CFG_NOTACT_STATIC 1142 +#define IDC_BUTTON1 1143 +#define IDC_NC_BASIC 1143 #define IDA_ACTIVATE_MENU 40003 #define IDA_UP 40004 #define IDA_DOWN 40005 @@ -439,7 +445,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 212 #define _APS_NEXT_COMMAND_VALUE 40010 -#define _APS_NEXT_CONTROL_VALUE 1143 +#define _APS_NEXT_CONTROL_VALUE 1144 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/windows/identity/ui/statusbar.c b/src/windows/identity/ui/statusbar.c index 5bcf2c2a5..e5f7e2009 100644 --- a/src/windows/identity/ui/statusbar.c +++ b/src/windows/identity/ui/statusbar.c @@ -30,9 +30,13 @@ #endif khm_statusbar_part khm_statusbar_parts[] = { - {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER}, - {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE}, - {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE} + {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER, NULL}, + {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE, NULL}, +#if 0 + /* Not implemented. This was originally intended to provide + location information. */ + {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE, NULL} +#endif }; int khm_n_statusbar_parts = sizeof(khm_statusbar_parts) / sizeof(khm_statusbar_part); @@ -178,10 +182,22 @@ void khm_statusbar_set_part(int id, HICON icon, wchar_t * text) { if(idx < 0) return; + if (khm_statusbar_parts[idx].hIcon != NULL) { + DestroyIcon(khm_statusbar_parts[idx].hIcon); + khm_statusbar_parts[idx].hIcon = NULL; + } + + if (icon) { + khm_statusbar_parts[idx].hIcon = CopyImage(icon, IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_COPYFROMRESOURCE); + } + SendMessage(khm_hwnd_statusbar, SB_SETICON, idx, - (LPARAM) icon); + (LPARAM) (khm_statusbar_parts[idx].hIcon ? khm_statusbar_parts[idx].hIcon:icon)); SendMessage(khm_hwnd_statusbar, SB_SETTEXT, @@ -189,3 +205,4 @@ void khm_statusbar_set_part(int id, HICON icon, wchar_t * text) { (LPARAM) text); } + diff --git a/src/windows/identity/ui/statusbar.h b/src/windows/identity/ui/statusbar.h index 2fd267e9e..6a2b3ddfb 100644 --- a/src/windows/identity/ui/statusbar.h +++ b/src/windows/identity/ui/statusbar.h @@ -31,6 +31,7 @@ typedef struct khm_statusbar_part_t { int id; int width; int wtype; /* one of KHUI_SB_WTYPE_* */ + HICON hIcon; } khm_statusbar_part; #define KHUI_SB_WTYPE_RELATIVE 1 diff --git a/src/windows/identity/ui/timer.c b/src/windows/identity/ui/timer.c index 77fa6c161..7024481c4 100644 --- a/src/windows/identity/ui/timer.c +++ b/src/windows/identity/ui/timer.c @@ -256,8 +256,9 @@ tmr_fire_timer(void) { wtitle, ARRAYLENGTH(wtitle)); khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert); - khui_alert_set_flags(alert, KHUI_ALERT_FLAG_REQUEST_BALLOON, - KHUI_ALERT_FLAG_REQUEST_BALLOON); + khui_alert_set_flags(alert, + KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD, + KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD); if (eff_ident != NULL) { khm_int32 cmd; diff --git a/src/windows/identity/ui/toolbar.c b/src/windows/identity/ui/toolbar.c index f3781b930..a464009fc 100644 --- a/src/windows/identity/ui/toolbar.c +++ b/src/windows/identity/ui/toolbar.c @@ -106,6 +106,28 @@ LRESULT khm_toolbar_notify(LPNMHDR notice) { } break; + case TBN_DROPDOWN: + { + LPNMTOOLBAR nmtb = (LPNMTOOLBAR) notice; + RECT r; + + GetWindowRect(khui_hwnd_standard_toolbar, &r); + if (nmtb->iItem == KHUI_ACTION_DESTROY_CRED) { + khm_menu_show_panel(KHUI_MENU_DESTROY_CRED, + r.left + nmtb->rcButton.left, + r.top + nmtb->rcButton.bottom); + } else if (nmtb->iItem == KHUI_ACTION_RENEW_CRED) { + khm_menu_show_panel(KHUI_MENU_RENEW_CRED, + r.left + nmtb->rcButton.left, + r.top + nmtb->rcButton.bottom); + } else { + return TBDDRET_NODEFAULT; + } + + return TBDDRET_DEFAULT; + } + break; + case NM_CUSTOMDRAW: { LPNMTBCUSTOMDRAW nmcd = (LPNMTBCUSTOMDRAW) notice; @@ -156,11 +178,14 @@ LRESULT khm_toolbar_notify(LPNMHDR notice) { return CDRF_DODEFAULT; CopyRect(&r, &(nmcd->nmcd.rc)); - r.left += ((r.right - r.left) - - KHUI_TOOLBAR_IMAGE_WIDTH) / 2; + r.left += ((r.bottom - r.top) - + KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; r.top += ((r.bottom - r.top) - KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; - +#if 0 + r.left += ((r.right - r.left) - + KHUI_TOOLBAR_IMAGE_WIDTH) / 2; +#endif khui_ilist_draw(ilist_toolbar, iidx, nmcd->nmcd.hdc, @@ -317,17 +342,12 @@ void khm_create_standard_toolbar(HWND rebar) { return; } - hwtb = CreateWindowEx(0 -#if (_WIN32_IE >= 0x0501) - | TBSTYLE_EX_MIXEDBUTTONS -#endif - , + hwtb = CreateWindowEx(0 , TOOLBARCLASSNAME, (LPWSTR) NULL, WS_CHILD | TBSTYLE_FLAT | TBSTYLE_AUTOSIZE | - TBSTYLE_LIST | TBSTYLE_TOOLTIPS | CCS_NORESIZE | CCS_NOPARENTALIGN | @@ -344,6 +364,11 @@ void khm_create_standard_toolbar(HWND rebar) { return; } +#if (_WIN32_IE >= 0x0501) + SendMessage(hwtb, TB_SETEXTENDEDSTYLE, 0, + TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_DRAWDDARROWS); +#endif + hiList = ImageList_Create( KHUI_TOOLBAR_IMAGE_WIDTH, KHUI_TOOLBAR_IMAGE_HEIGHT, @@ -395,7 +420,9 @@ void khm_create_standard_toolbar(HWND rebar) { act = khui_find_action(aref->action); khui_add_action_to_toolbar(hwtb, act, - KHUI_TOOLBAR_ADD_BITMAP, + KHUI_TOOLBAR_ADD_BITMAP | + ((aref->flags & KHUI_ACTIONREF_SUBMENU)? + KHUI_TOOLBAR_ADD_DROPDOWN: 0), hiList); } aref ++; diff --git a/src/windows/identity/ui/toolbar.h b/src/windows/identity/ui/toolbar.h index 89700f2e4..8068a6be2 100644 --- a/src/windows/identity/ui/toolbar.h +++ b/src/windows/identity/ui/toolbar.h @@ -37,12 +37,12 @@ void khui_add_action_to_toolbar(HWND toolbar, khui_action * act, int opt, HIMAGE void khm_update_standard_toolbar(void); /* options for khui_add_action_to_toolbar */ -#define KHUI_TOOLBAR_ADD_TEXT 1 -#define KHUI_TOOLBAR_ADD_BITMAP 2 -#define KHUI_TOOLBAR_ADD_LONGTEXT 5 -#define KHUI_TOOLBAR_ADD_DROPDOWN 8 -#define KHUI_TOOLBAR_ADD_SEP 16 -#define KHUI_TOOLBAR_VARSIZE 32 +#define KHUI_TOOLBAR_ADD_TEXT 0x00000001 +#define KHUI_TOOLBAR_ADD_BITMAP 0x00000002 +#define KHUI_TOOLBAR_ADD_LONGTEXT 0x00000005 +#define KHUI_TOOLBAR_ADD_DROPDOWN 0x00000008 +#define KHUI_TOOLBAR_ADD_SEP 0x00000010 +#define KHUI_TOOLBAR_VARSIZE 0x00000020 #define KHUI_TOOLBAR_IMAGE_WIDTH 29 #define KHUI_TOOLBAR_IMAGE_HEIGHT 27 diff --git a/src/windows/identity/ui/uiconfig.csv b/src/windows/identity/ui/uiconfig.csv index 7056fce6e..20130489f 100644 --- a/src/windows/identity/ui/uiconfig.csv +++ b/src/windows/identity/ui/uiconfig.csv @@ -187,10 +187,23 @@ CredWindow,KC_SPACE,0,Options for the credentials window IdentityName,KC_SPACE,0, Width,KC_INT32,415, SortIndex,KC_INT32,0, - Flags,KC_INT32,11 + Flags,KC_INT32,171 IdentityName,KC_ENDSPACE,0, Columns,KC_ENDSPACE,0, CompactIdentity,KC_ENDSPACE,0 + Custom_1,KC_SPACE,0,Default Compact View by Identity + Description,KC_STRING,Compact view of identities + ColumnList,KC_STRING,"IdentityName", + ExpandedIdentity,KC_INT32,1,Use expanded display of identity headers + NoHeader,KC_INT32,1,Suppress the column header + Columns,KC_SPACE,0, + IdentityName,KC_SPACE,0, + Width,KC_INT32,415, + SortIndex,KC_INT32,0, + Flags,KC_INT32,171 + IdentityName,KC_ENDSPACE,0, + Columns,KC_ENDSPACE,0, + Custom_1,KC_ENDSPACE,0 Views,KC_ENDSPACE,0 Notices,KC_SPACE,0,Notices and alerts MinimizeWarning,KC_INT32,1,Show the minimize warning? diff --git a/src/windows/identity/uilib/action.c b/src/windows/identity/uilib/action.c index 8ec98f8cd..00902eec9 100644 --- a/src/windows/identity/uilib/action.c +++ b/src/windows/identity/uilib/action.c @@ -52,9 +52,9 @@ khui_action_ref khui_menu_file[] = { khui_action_ref khui_menu_cred[] = { MENU_ACTION(KHUI_ACTION_NEW_CRED), MENU_SEP(), - MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_SUBMENU(KHUI_MENU_RENEW_CRED), + MENU_SUBMENU(KHUI_MENU_DESTROY_CRED), MENU_ACTION(KHUI_ACTION_IMPORT), - MENU_ACTION(KHUI_ACTION_DESTROY_CRED), MENU_SEP(), MENU_ACTION(KHUI_ACTION_SET_DEF_ID), #if 0 @@ -119,9 +119,9 @@ khui_action_ref khui_menu_help[] = { khui_action_ref khui_toolbar_standard[] = { MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_SUBMENU(KHUI_ACTION_RENEW_CRED), MENU_ACTION(KHUI_ACTION_IMPORT), - MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SUBMENU(KHUI_ACTION_DESTROY_CRED), MENU_SEP(), MENU_ACTION(KHUI_ACTION_PASSWD_ID), MENU_SEP(), diff --git a/src/windows/identity/uilib/khnewcred.h b/src/windows/identity/uilib/khnewcred.h index 45a565cde..e22e1f77f 100644 --- a/src/windows/identity/uilib/khnewcred.h +++ b/src/windows/identity/uilib/khnewcred.h @@ -69,7 +69,8 @@ */ enum khui_wm_nc_notifications { WMNC_DIALOG_EXPAND = 1, - /*!< The dialog is getting expanded. + /*!< The dialog is switching from basic to advanced mode or vice + versa. This message is sent to the new creds dialog to set the dialog to expanded mode. In expanded mode, all credentials type panels -- 2.26.2