/* all is done. */\r
{\r
khui_new_creds * nc;\r
+ khm_boolean continue_cmdline = FALSE;\r
\r
nc = (khui_new_creds *) m->vparam;\r
\r
*/\r
\r
khm_cred_end_dialog(nc);\r
+ } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) {\r
+\r
+ /* if this is a renewal that was triggered while we\r
+ were processing the commandline, then we need to\r
+ update the pending renewal count. */\r
+\r
+ if (khm_startup.processing) {\r
+ LONG renewals;\r
+ renewals = InterlockedDecrement(&khm_startup.pending_renewals);\r
+\r
+ if (renewals == 0) {\r
+ continue_cmdline = TRUE;\r
+ }\r
+ }\r
}\r
\r
khui_cw_destroy_cred_blob(nc);\r
\r
kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0);\r
\r
- kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
+ if (continue_cmdline)\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
}\r
break;\r
\r
break;\r
\r
case KMSG_CRED_IMPORT:\r
- kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
+ {\r
+ khm_boolean continue_cmdline = FALSE;\r
+ LONG pending_renewals;\r
+\r
+ /* once an import operation ends, we have to trigger a\r
+ renewal so that other plug-ins that didn't participate\r
+ in the import operation can have a chance at getting\r
+ the necessary credentials.\r
+\r
+ If we are in the middle of processing the commandline,\r
+ we have to be a little bit careful. We can't issue a\r
+ commandline conituation message right now because the\r
+ import action is still ongoing (since the renewals are\r
+ part of the action). Once the renewals have completed,\r
+ the completion handler will automatically issue a\r
+ commandline continuation message. However, if there\r
+ were no identities to renew, then we have to issue the\r
+ message ourselves.\r
+ */\r
+\r
+ InterlockedIncrement(&khm_startup.pending_renewals);\r
+\r
+ khm_cred_renew_all_identities();\r
+\r
+ pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals);\r
+\r
+ if (pending_renewals == 0 && khm_startup.processing)\r
+ kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
+ }\r
break;\r
\r
case KMSG_CRED_REFRESH:\r
_end_task();\r
}\r
\r
+void khm_cred_renew_all_identities(void)\r
+{\r
+ khm_size count;\r
+ khm_size cb = 0;\r
+ khm_size n_idents = 0;\r
+ khm_int32 rv;\r
+ wchar_t * ident_names = NULL;\r
+ wchar_t * this_ident;\r
+\r
+ kcdb_credset_get_size(NULL, &count);\r
+\r
+ /* if there are no credentials, we just skip over the renew\r
+ action. */\r
+\r
+ if (count == 0)\r
+ return;\r
+\r
+ ident_names = NULL;\r
+\r
+ while (TRUE) {\r
+ if (ident_names) {\r
+ PFREE(ident_names);\r
+ ident_names = NULL;\r
+ }\r
+\r
+ cb = 0;\r
+ rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
+ NULL,\r
+ &cb, &n_idents);\r
+\r
+ if (n_idents == 0 || rv != KHM_ERROR_TOO_LONG ||\r
+ cb == 0)\r
+ break;\r
+\r
+ ident_names = PMALLOC(cb);\r
+ ident_names[0] = L'\0';\r
+\r
+ rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
+ ident_names,\r
+ &cb, &n_idents);\r
+\r
+ if (KHM_SUCCEEDED(rv))\r
+ break;\r
+ }\r
+\r
+ if (ident_names) {\r
+ for (this_ident = ident_names;\r
+ this_ident && *this_ident;\r
+ this_ident = multi_string_next(this_ident)) {\r
+ khm_handle ident;\r
+\r
+ if (KHM_FAILED(kcdb_identity_create(this_ident, 0,\r
+ &ident)))\r
+ continue;\r
+\r
+ khm_cred_renew_identity(ident);\r
+\r
+ kcdb_identity_release(ident);\r
+ }\r
+\r
+ PFREE(ident_names);\r
+ ident_names = NULL;\r
+ }\r
+}\r
+\r
void khm_cred_renew_identity(khm_handle identity)\r
{\r
khui_new_creds * c;\r
_report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
_describe();\r
\r
+ /* if we are calling this while processing startup actions, we\r
+ need to keep track of how many we have issued. */\r
+ if (khm_startup.processing) {\r
+ InterlockedIncrement(&khm_startup.pending_renewals);\r
+ }\r
+\r
kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
\r
_end_task();\r
_report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
_describe();\r
\r
+ /* if we are calling this while processing startup actions, we\r
+ need to keep track of how many we have issued. */\r
+ if (khm_startup.processing) {\r
+ InterlockedIncrement(&khm_startup.pending_renewals);\r
+ }\r
+\r
kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
\r
_end_task();\r
_report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
_describe();\r
\r
+ /* if we are calling this while processing startup actions, we\r
+ need to keep track of how many we have issued. */\r
+ if (khm_startup.processing) {\r
+ InterlockedIncrement(&khm_startup.pending_renewals);\r
+ }\r
+\r
kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
\r
_end_task();\r
if (khm_startup.import) {\r
khm_cred_import();\r
khm_startup.import = FALSE;\r
+\r
+ /* we also set the renew command to false here because we\r
+ trigger a renewal for all the identities at the end of\r
+ the import operation anyway. */\r
+ khm_startup.renew = FALSE;\r
break;\r
}\r
\r
if (khm_startup.renew) {\r
- khm_size count;\r
- wchar_t * ident_names = NULL;\r
- wchar_t * this_ident;\r
-\r
- kcdb_credset_get_size(NULL, &count);\r
+ LONG pending_renewals;\r
\r
/* if there are no credentials, we just skip over the\r
renew action. */\r
\r
khm_startup.renew = FALSE;\r
\r
- if (count != 0) {\r
- khm_size cb = 0;\r
- khm_size n_idents = 0;\r
- khm_int32 rv;\r
-\r
- ident_names = NULL;\r
-\r
- while (TRUE) {\r
- if (ident_names) {\r
- PFREE(ident_names);\r
- ident_names = NULL;\r
- }\r
-\r
- cb = 0;\r
- rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
- NULL,\r
- &cb, &n_idents);\r
-\r
- if (n_idents == 0 || rv != KHM_ERROR_TOO_LONG ||\r
- cb == 0)\r
- break;\r
-\r
- ident_names = PMALLOC(cb);\r
-\r
- rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
- ident_names,\r
- &cb, &n_idents);\r
+ InterlockedIncrement(&khm_startup.pending_renewals);\r
\r
- if (KHM_SUCCEEDED(rv))\r
- break;\r
- }\r
-\r
- if (ident_names) {\r
- for (this_ident = ident_names;\r
- this_ident && *this_ident;\r
- this_ident = multi_string_next(this_ident)) {\r
- khm_handle ident;\r
-\r
- if (KHM_FAILED(kcdb_identity_create(this_ident, 0,\r
- &ident)))\r
- continue;\r
-\r
- khm_cred_renew_identity(ident);\r
+ khm_cred_renew_all_identities();\r
\r
- kcdb_identity_release(ident);\r
- }\r
+ pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals);\r
\r
- PFREE(ident_names);\r
- ident_names = NULL;\r
- }\r
+ if (pending_renewals != 0)\r
break;\r
- }\r
+\r
+ /* if there were no pending renewals, then we just fall\r
+ through. This means that either there were no\r
+ identities to renew, or all the renewals completed. If\r
+ all the renewals completed, then the commandline\r
+ contiuation message wasn't triggered. Either way, we\r
+ must fall through if the count is zero. */\r
}\r
\r
if (khm_startup.destroy) {\r
KHMEXP khm_ui_4 KHMAPI\r
khm_get_commctl_version(khm_version * pdvi);\r
\r
+/*! \brief UI callback function\r
+\r
+ Used with khui_request_UI_callback().\r
+\r
+ \see khui_request_UI_callback()\r
+ */\r
typedef khm_int32\r
(KHMAPI *khm_ui_callback)(HWND hwnd_main_wnd, void * rock);\r
\r
+/*! \brief Request a UI callback\r
+\r
+ In general, plug-ins in Network Identity Manager run in their own\r
+ thread and will not be able to interact with the user directly by\r
+ creating windows of its own. There are exceptions to this, such\r
+ as when the plug-in is responding to a new credentials request or\r
+ if the plug-in provides configuration panels. However, if a\r
+ plug-in needs to provide a user interface to the user outside of\r
+ the provisions already provided by Network Identity Manager, it\r
+ needs to do so from within the user interface thread.\r
+\r
+ To do so, a plug-in would provide a callback function of the type\r
+ ::khm_ui_callback to this function. The Network Identity Manager\r
+ will then call the callback function from within the user\r
+ interface thread. At this point, the callback function can create\r
+ any windows it wishes to create and interact with the user\r
+ directly.\r
+\r
+ Note that when the plug-in creates any windows, it should specify\r
+ the window handle provided via the \a hwnd_main_wnd parameter as\r
+ the parent window.\r
+\r
+ \see ::khm_ui_callback\r
+ */\r
KHMEXP khm_int32 KHMAPI\r
khui_request_UI_callback(khm_ui_callback cb, void * rock);\r
\r