summaryrefslogtreecommitdiffstats
path: root/src/windows/identity/kmq/kmq.h
blob: db6d5b26221c175bdd10868def2cd1c1a850ddee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
/*
 * Copyright (c) 2005 Massachusetts Institute of Technology
 *
 * Copyright (c) 2007 Secure Endpoints Inc.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/* $Id$ */

#ifndef __KHIMAIRA_KMQ_H__
#define __KHIMAIRA_KMQ_H__

/*! \defgroup kmq NetIDMgr Message Queue 

    The Network Identity Manager Message Queue handles all the
    messaging within the application and all loaded plug-ins.

    For information about the messaging system and how it is used,
    please see \ref pi_fw_pnm_msg .
*/
/*@{*/

#include<khdefs.h>
#include<khlist.h>
#include<kherr.h>

/* general */
#ifdef _WIN32
typedef DWORD kmq_thread_id;
typedef DWORD kmq_timer;
#endif

#ifdef _WIN32
/*! \brief Window message for kmq

   This message is sent to the window procedure of a window if that
   window is a subscriber to KMQ messages.

    \see kmq_subscribe_hwnd() for more information about handling this
        window message
 */
#define KMQ_WM_DISPATCH (WM_APP+0x100)
#endif

/* callback */

/*! \brief A message callback

    Should return TRUE if the message is properly handled.  Otherwise
    return FALSE */
typedef khm_int32 (KHMAPI *kmq_callback_t)(khm_int32 msg_type, 
                                           khm_int32 msg_sub_type, 
                                           khm_ui_4 uparam, 
                                           void * vparam);

/* message */

/*! \brief A single response.

    Certain broadcast messages may user scatter-gather type
    notification and result gathering.  Individual subscribers to a
    message attach their individual responses to a ::kmq_response
    object and attach that to the message which can later be read by
    the sender of the message.
 */
typedef struct tag_kmq_response {
    kmq_thread_id thread;
    void * response;

    LDCL(struct tag_kmq_response);
} kmq_response;

/*! \brief A single message
 */
typedef struct tag_kmq_message {
    khm_int32 type;             /*!< Type of message */
    khm_int32 subtype;          /*!< Subtype of message */

    khm_ui_4 uparam;             /*!< Integer parameter */
    void * vparam;            /*!< Pointer to parameter blob */
	
    khm_int32 nSent;            /*!< Number of instances of message
                                  sent (for broadcast messages) */

    khm_int32 nCompleted;       /*!< Number of instances that have
                                  completed processing (for broadcast
                                  messages) */

    khm_int32 nFailed;          /*!< Number of instances that failed
                                  to process (for broadcast
                                  messages) */

    kmq_response * responses;   /*!< List of responses */
    HANDLE wait_o;              /*!< Event to wait on (only valid if
                                  the publisher of the message
                                  requested a handle to the call) */

    kmq_timer timeSent;         /*!< Time at which the message was
                                  sent */
    kmq_timer timeExpire;       /*!< Time at which the message
                                  expires */

    kherr_context * err_ctx;    /*!< Error context for the message */

    khm_boolean aborted;        /*!< TRUE if the message has been
                                  aborted. */

    khm_int32 refcount;         /*!< Internal use */

    LDCL(struct tag_kmq_message); /*!< Internal use */
} kmq_message;

/*! \brief A handle to a call
 */
typedef kmq_message *kmq_call;

/* publishers */

/*! \brief A completion handler for a message

    Each message type can have a completion handler.  Once a message
    of this a specific type has been broadcast and handled by all the
    subscripbers, the message will be passed down to the completion
    handler before the associated data structures are freed.  This
    allows applications that define message type to also define clean
    up for each message.  For example, the completion handler can
    initiate another message if the messages form a sequence or free
    up blocks of memory that was passed as the parameter to the
    message.
 */
typedef void (KHMAPI *kmq_msg_completion_handler)(kmq_message *);

#ifdef NOEXPORT

KHMEXP khm_int32 KHMAPI kmq_init(void);

KHMEXP khm_int32 KHMAPI kmq_exit(void);

#endif

/*! \brief Register a message type

    Registers a custom message type.  The \a name parameter specifies
    a language independent name for the message type and must be
    unique and must be less than ::KMQ_MAXCCH_TYPE_NAME characters.

    \param[in] name Name of the message type.  Upto
        ::KMQ_MAXCCH_TYPE_NAME characters including terminating NULL.
        The \a name cannot be a zero length string.

    \param[out] new_id Receives the new message type ID.  Specify NULL
        if the new message type is not required.

    \see kmq_find_type() and kmq_unregister_type()

    \retval KHM_ERROR_INVALID_PARAM The \a name parameter was invalid.
    \retval KHM_ERROR_EXISTS A message type with that name already exists.
    \retval KHM_ERROR_NO_RESOURCES Can't register any more message types.
    \retval KHM_ERROR_SUCCESS The operation succeeded.
 */
KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, khm_int32 * new_id);

/*! \brief Find a message type

    Find the message type with the given name.  If found, the type ID
    is returned in \a id.

    \retval KHM_ERROR_SUCCESS A message type with the given name was
        found.
    \retval KHM_ERROR_NOT_FOUND A message type with the given name was
        not found.
 */
KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id);

/*! \brief Unregister a message type

    Unregisters a message type that was registered using
    kmq_register_type().

    \retval KHM_ERROR_SUCCESS The specified message type was
        successfully unregistered.

    \retval KHM_ERROR_NOT_FOUND The message type was not found.
 */
KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id);

/*! \brief Subscribte to a message type.

    Adds a subscription to messages of type \a type.  Subscriptions
    are managed per thread.  Therefore the subscription is actually
    added to the subscription list for the current thread (the thread
    which calls kmq_subscribe()).

    When a message of type \a type is received by the thread, it is
    dispatched to the callback function identified by \a cb within the
    context of this thread.

    \note Calling kmq_subscribe() from within multiple threads with
        the same \a type and \a cb will result in multiple
        subscriptions.

    \see kmq_unsubscribe()
    \see kmq_dispatch()
*/
KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb);

/*! \brief Subscribe a window to a message type

    Adds the window specified by \a hwnd to the subscription list for
    the message type \a type.  When a message of this type is posted,
    then the window procedure of the window \a hwnd receives a message
    ::KMQ_WM_DISPATCH.

    When a window receives a ::KMQ_WM_DISPATCH message, it means that
    a message has been posted which is of a type that the window has
    subscribed for.  Because of the way Windows handles window
    messages and the way NetIDMgr message queues work, a thread which
    has a window (or thread) procedure can not call kmq_dispatch() to
    handle these messages.  For threads that have window or thread
    message loops, they must call kmq_subscribe_hwnd() to subscribe a
    particular window (for thread message loops, this would be the
    HWND of the message window for the thread) to NetIDMgr messages.

    There are two supported ways of handling the ::KMQ_WM_DISPATCH
    message.  Examples of both are provided below.

    Handling the message inline:

    \code
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    kmq_message * m;
    khm_int32 rv;
    ...
    switch(uMsg) {
    case WM_CREATE:
       ...
       kmq_subscribe_hwnd(KMSG_CRED, hwnd);
       ...
       break;

    case WM_DESTROY:
       ...
       kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);
       ...
       break;

    ...
    case KMQ_WM_DISPATCH:
        kmq_wm_begin(lParam,&m);

	if(m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) {
	// do something
        rv = KHM_ERROR_SUCCESS;
	}

	return kmq_wm_end(m, rv);
    ...
    };
    ...
    }
    \endcode

    The other method is to dispatch the ::KMQ_WM_DISPATCH message to a
    secondary callback function:

    \code
    khm_int32 msg_handler(khm_int32 t, khm_int32 st, khm_ui_4 up, void * pb) {
        khm_int32 rv = KHM_ERROR_SUCCESS;

        //handle message

	return rv;
    }

    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    kmq_message * m;
    khm_int32 rv;
    ...
    switch(uMsg) {
    ...

    case WM_CREATE:
       ...
       kmq_subscribe_hwnd(KMSG_CRED, hwnd);
       ...
       break;

    case WM_DESTROY:
       ...
       kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);
       ...
       break;

    ...
    case KMQ_WM_DISPATCH:
        return kmq_wm_dispatch(lParam, msg_handler);
    ...
    };
    ...
    }
    \endcode

    \note Make sure you unsubscribe from the message type when the
        window is destroyed.

    \see kmq_unsubscribe_hwnd()
    \see kmq_wm_begin()
    \see kmq_wm_end()
    \see kmq_wm_dispatch()
 */
KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd);

#ifdef _WIN32
/*! \brief Begins handling a KMQ_WM_DISPATCH message

    \return The return value of this function should be ignored.

    \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH
 */
KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m);

/*! \brief Ends handling a KMQ_WM_DISPATCH message

    \return The return value of this function should be the return
        value of the window procedure.  See kmq_subscribe_hwnd()
        documentation for example

    \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH
 */
KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv);

/*! \brief Dispatches a KMQ_WM_DISPATCH message to a callback

    \return The return value of this function should be the return
        value of the window procedure.  See kmq_subscribe_hwnd()
        documentation for example.

    \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH
 */
KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb);
#endif

/*! \brief Unsubscribe a callback from a message type

    Removes the subscription for message type \a type for callback
    function \a cb from the subscription list for the current thread
    (the thread that calls kmq_unsubscribe()).

    \note kmq_unsubscribe() can only remove subscriptions for the subscription
        list for the current thread.

    \see kmq_subscribe()
    \see kmq_dispatch()
*/
KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb);

/*! \brief Unsubscribe a window from a message type

    Removes the specific window from the subsription list for message
    type \a type.

    \see kmq_subscribe_hwnd()
*/
KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd);

/*! \brief Create an ad-hoc subscription

    An ad-hoc subscription describes a callback point in a thread that
    can be dispatched messages to individually without broadcasting.

    \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(),
        kmq_send_sub_msg(), kmq_post_subs_msg(),
        kmq_post_subs_msg_ex(), kmq_send_subs_msg(),
        kmq_delete_subscription()
*/
KHMEXP khm_int32 KHMAPI kmq_create_subscription(
    kmq_callback_t cb, 
    khm_handle * result);

/*! \brief Create an ad-hoc subscription for a window

    An ad-hoc subscription describes a window that will be dispatched
    messages individually without broadcasting.

    \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(),
        kmq_send_sub_msg(), kmq_post_subs_msg(),
        kmq_post_subs_msg_ex(), kmq_send_subs_msg(),
        kmq_delete_subscription()
 */
KHMEXP khm_int32 KHMAPI kmq_create_hwnd_subscription(HWND hw,
                                                     khm_handle * result);

/*! \brief Delete an ad-hoc subscription

    Deletes a subscriptoin that was created using
    kmq_create_subscription()
 */
KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub);

/*! \brief Post a message to a subscription

    Equivalent of kmq_post_msg() but only posts the message to the
    specified subscription.
 */
KHMEXP khm_int32 KHMAPI kmq_post_sub_msg(
    khm_handle sub, 
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * vparam);

/*! \brief Post a message to a subscription and acquire a handle to the call
 */
KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex(
    khm_handle sub, 
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * vparam, 
    kmq_call * call);

/*! \brief Send a synchronous message to a subscription

    \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors
    \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors
 */
KHMEXP khm_int32 KHMAPI kmq_send_sub_msg(
    khm_handle sub, 
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * vparam);

/*! \brief Post a message to a group of subscriptions

    The block of memory pointed to by \a subs should be an array of
    subscriptions.  The number of elements in that array should be \a
    n_subs.  A message as specified by the remaining parameters will
    be dispatched to all of the subscription points in the array.
 */
KHMEXP khm_int32 KHMAPI kmq_post_subs_msg(
    khm_handle * subs, 
    khm_size  n_subs, 
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * vparam);

/*! \brief Post a message to a group of subscriptions and acquire a handle to the call

    The block of memory pointed to by \a subs should be an array of
    subscriptions.  The number of elements in that array should be \a
    n_subs.  A message as specified by the remaining parameters will
    be dispatched to all of the subscription points in the array, and
    a handle to the call will be returned in \a call.

    The returned \a call will reference all of the dispatches that
    were made.
*/
KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex(
    khm_handle * subs, 
    khm_int32 n_subs, 
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * vparam, 
    kmq_call * call);

/*! \brief Send a synchronous message to a group of subscriptions

    The block of memory pointed to by \a subs should be an array of
    subscriptions.  The number of elements in that array should be \a
    n_subs.  A message as specified by the remaining parameters will
    be dispatched to all of the subscription points in the array.  The
    function will not return until all of the calls have succeeded.

    \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors
    \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors
*/
KHMEXP khm_int32 KHMAPI kmq_send_subs_msg(
    khm_handle *subs, 
    khm_int32 n_subs,
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * vparam);

/*! \brief Dispatch a message for the current thread.

    This function opens the message list for the current thread and
    dispatches the first message instance that is found.  Note that if
    multiple callbacks subscribe to the same message type in the same
    thread, then when a message of that type is received, multiple
    message instances are added to the message queue corresponding to
    each subscription.

    If no message instances are waiting in the queue, kmq_dispatch()
    waits for the \a timeout period for a message.

    \param[in] timeout The timeout period in milliseconds.  Specify INFINITE for
        kmq_dispatch() to wait indefinitely.

    \retval KHM_ERROR_SUCCESS A message instance was dispatched
    \retval KHM_ERROR_TIMEOUT The timeout period elapsed
    \retval KHM_ERROR_EXIT The message found on the queue was <KMSG_SYSTEM,KMSG_SYSTEM_EXIT>
*/
KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout);

/*! \brief Send a message

    The specified message will be posted to all the subscribers of the
    message type.  Then the function will wait for all the subscribers
    to finish processing the message before returning.
    
    \param[in] type The type of the message
    \param[in] subtype The subtype
    \param[in] uparam The khm_ui_4 parameter for the message
    \param[in] blob The parameter blob for the message

    \note The internal timeout for this function is INFINITE.  If you
        it is desirable to use a different timeout, use
        kmq_post_message_ex() and kmq_wait() functions.

    \retval KHM_ERROR_SUCCESS The call succeeded and no subscribers returned errors
    \retval KHM_ERROR_PARTIAL The call succeeded but at least one subscriber returned an error
*/
KHMEXP khm_int32 KHMAPI kmq_send_message(
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * blob);

/*! \brief Post a message

    The specified message will be posted to all the subscribers of the
    message type.  The function returns immediately.
    
    If you want to be able to wait for all the subscribers to finish
    processing the message, you should use kmq_post_message_ex()
    instead.

    \param[in] type The type of the message
    \param[in] subtype The subtype
    \param[in] uparam The khm_ui_4 parameter for the message
    \param[in] blob The parameter blob for the message
*/
KHMEXP khm_int32 KHMAPI kmq_post_message(
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * blob);

/*! \brief Post a message and acquire a handle to the call.

    The specified message is posted to all the subscribers.  In
    addition, a handle is obtained for the call which can be used in
    subsequent call to kmq_free_call() or kmq_wait().

    Call kmq_free_call() to free the handle.

    \param[in] type The type of the message
    \param[in] subtype The subtype
    \param[in] uparam The khm_ui_4 parameter for the message
    \param[in] blob The parameter blob for the message
    \param[out] call Receives the call handle.  Set to NULL if the call handle is not required.

    \see kmq_free_call()
*/
KHMEXP khm_int32 KHMAPI kmq_post_message_ex(
    khm_int32 type, 
    khm_int32 subtype, 
    khm_ui_4 uparam, 
    void * blob, 
    kmq_call * call);

/*! \brief Free a handle to a call obtained through kmq_post_message_ex()

    All call handles obtained through kmq_post_message_ex() must be
    freed via a call to kmq_free_call().
*/
KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call);

/*! \brief Sends a <KMSG_SYSTEM,KMSG_SYSTEM_EXIT> message to the specified thread.

    The message itself will not be received by any callback function,
    however, any kmq_dispatch() function that is currently active of
    becomes active will exit with a KHM_ERROR_EXIT code.
    kmq_send_thread_quit_message() will wait for this to happen before
    returning.

    This function should not be called by the thread identified by the
    \a thread parameter.
    */
KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message(
    kmq_thread_id thread, 
    khm_ui_4 uparam);

/*! \brief Post a <KMSG_SYSTEM,KMSG_SYSTEM_EXIT> message to the specified thread.

    The message itself will not be received by any callback function,
    however, any kmq_dispatch() function that is currently active of
    becomes active will exit with a KHM_ERROR_EXIT code.
    kmq_post_thread_quit_message() will return immediately.
    */
KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message(
    kmq_thread_id thread, 
    khm_ui_4 uparam, 
    kmq_call * call);

KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp);

/*! \brief Check if a specific call has completed

    \return TRUE if the call has completed. FALSE otherwise.
*/
KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call);

/*! \brief Wait for a call to complete.

    Waits for the specified call to complete.  If the call dispatched
    to multiple recipients, the function waits for all dispatches to
    complete.

    If the call has already completed, then the function returns
    immediately.

    If more than one thread is waiting for a single message to
    complete, then only one of them will be released when the message
    compeltes.  Each subsequent thread will be released as each
    released thread calls kmq_free_call().

    \param[in] call A handle to a call.
    \param[in] timeout Specifies, in milliseconds, the amount of time
        to wait for the call to complete. Specify INFINITE to wait
        indefinitely.

    \retval KHM_ERROR_SUCCESS The call completed
    \retval KHM_ERROR_TIMEOUT The timeout period expired
    \retval KHM_ERROR_INVALID_PARAM One of the parameters were invalid.
*/
KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout);

/*! \brief Abort a call

    Abort a pending call.  The call handle should have been obtained
    using a prior call to kmq_post_message_ex().

    Note that this function may not abort the call immediately.  It
    merely marks the message as being in an aborted state.  It is upto
    the individual handlers of the message to check if the message has
    been aborted and act accordingly.

    The handlers are expected to call kmq_is_call_aborted()
    periodicially during the processing of specially lengthy
    operations during the course of handling a message. That function
    will return \a TRUE if the last dispatched message is now in an
    aborted state.  In which case, the handler is expected to abort
    handling the message and return control to the dispatcher.
 */
KHMEXP khm_int32 KHMAPI kmq_abort_call(kmq_call call);

/*! \brief Check if the last dispatched message was aborted

    The sender of a message may abort it using a call to
    kmq_abort_call().  This function checks if the last dispatched
    message was aborted.

    A handler of a message is expected to call this function
    periodically if handling the message is going to take a specially
    long time (e.g. more than 5 or 10 seconds).  If the message is
    found to be aborted, the handler is expected to abort handling the
    message, perform any necessary cleanup and return control to the
    dispatcher.

    Doing this allows operations like new credentials acquisition to
    be cleanly aborted by the user if she so wishes.  Otherwise,
    Network Identity Manager has to wait for the message to complete
    processing since it has no means of cleanly terminating an
    executing plug-in thread.
*/
KHMEXP khm_boolean KHMAPI kmq_is_call_aborted(void);

/*! \brief Sets the completion handler for a specified message type.

    \note Only one completion handler can exist for one message type.
        Calling this function overwrites the previous completion
        handler.
*/
KHMEXP khm_int32 KHMAPI kmq_set_completion_handler(
    khm_int32 type, 
    kmq_msg_completion_handler hander);

/*@}*/
#endif