Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / csa / agent.c
1 /* $TOG: agent.c /main/2 1998/03/16 14:42:16 mgreess $ */
2 /*
3  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4  *  (c) Copyright 1993, 1994 International Business Machines Corp.
5  *  (c) Copyright 1993, 1994 Novell, Inc.
6  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
7  */
8
9 #include <EUSCompat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <signal.h>
14 #include <rpc/rpc.h>
15 #if defined(linux)
16 # include <sys/poll.h>
17 #else
18 # include <poll.h>
19 #endif
20 #if defined(SunOS) || defined(USL) || defined(__uxp__)
21 #include <netconfig.h>
22 #include <netdir.h>
23 #else
24 #include <sys/signal.h>
25 #include <sys/socket.h>
26 #include <sys/errno.h>
27 #endif /* SunOS || USL || __uxp__ */
28 #include <X11/Intrinsic.h>
29
30 #include "agent.h"
31 #include "cmcb.h"
32 #include "entry.h"
33 #include "debug.h"
34 #include "iso8601.h"
35 #include "free.h"
36 #include "misc.h"
37
38 /*
39  * callback info
40  * - contain update information from backend
41  */
42 typedef struct cb_info {
43         int     vers;
44         char    *cal;
45         char    *user;
46         int     reason;
47         void    *data;
48         struct cb_info *next;
49 } _CallbackInfo;
50
51 static _CallbackInfo *cb_head = NULL, *cb_tail = NULL;
52
53 u_long  _DtCm_transient = 0;
54
55 static u_long   prognum = 0x40000000;
56 static int      mapped = 0;
57
58 /******************************************************************************
59  * forward declaration of static functions used within the file
60  ******************************************************************************/
61 #if defined(SunOS) || defined(USL) || defined(__uxp__)
62 static u_long gettransient (u_long version);
63 #else
64 static u_long gettransient (int proto, u_long vers, int *sockp);
65 #endif
66 static void _DtCm_handle_callback();
67 static CSA_return_code _ConvertCallbackData(cmcb_update_callback_args *args,
68                                         _CallbackInfo **cbi);
69 static CSA_return_code _CopyAttributeNames(uint fnum, char **fnames,
70                                         CSA_uint32 *tnum, char ***tnames);
71 static boolean_t _ProcessV1Callback(_CallbackInfo *ptr);
72 static boolean_t _ProcessV2Callback(_CallbackInfo *ptr);
73 static void _FreeCallbackInfo(_CallbackInfo *ptr);
74
75 /*****************************************************************************
76  * extern functions used in the library
77  *****************************************************************************/
78
79 /*
80  * Register rpc service for server callback
81  */
82 extern void
83 _DtCm_init_agent()
84 {
85         int             s = RPC_ANYSOCK;
86         XtInputId       id;
87
88 #if defined(SunOS) && SunOS < 55 || defined(USL) || defined(__uxp__)
89         extern boolean_t rpc_reg(const u_long, const u_long, const u_long,
90                 const char *(*)(), const xdrproc_t, const xdrproc_t,
91                 const char *);
92 #endif
93
94 #if defined(SunOS) || defined(USL)|| defined(__uxp__)
95         extern void (*sigset(int, void (*)(int)))(int);
96 #else
97         extern void (*sigset())();
98 #endif
99
100         /* locking candidate for MT-safe purpose */
101         if (mapped == 1)
102                 return;
103
104         DP(("libdtcm: _DtCm_init_agent\n"));
105
106 #if defined(SunOS) || defined(USL) || defined(__uxp__)
107         (void)rpcb_unset(_DtCm_transient, AGENTVERS, NULL);
108         if ((_DtCm_transient = gettransient((u_long)1)) == 0) {
109                 _DtCm_print_errmsg("Cannot get transient program number\n");
110                 _DtCm_print_errmsg("Callback cannot be enabled.\n");
111                 return;
112         }
113  
114         /* register v1 callback */
115         if (rpc_reg(_DtCm_transient, AGENTVERS, update_callback,
116             (const char *(*)())_DtCm_update_callback_1, _DtCm_xdr_Table_Res_4,
117             _DtCm_xdr_Update_Status, "udp") == -1) {
118                 _DtCm_print_errmsg("Cannot register v1 callback handler\n");
119                 _DtCm_print_errmsg("Callback cannot be enabled.\n");
120         }
121  
122         /* register v2 callback */
123         if (rpc_reg(_DtCm_transient, AGENTVERS_2, CMCB_UPDATE_CALLBACK,
124             (const char *(*)())cmcb_update_callback_2_svc,
125             xdr_cmcb_update_callback_args, xdr_void, "udp") == -1) {
126                 _DtCm_print_errmsg("Cannot register v2 callback handler\n");
127                 _DtCm_print_errmsg("Callback cannot be enabled.\n");
128         }
129  
130 #else
131         (void)pmap_unset(_DtCm_transient, AGENTVERS);
132         if ((_DtCm_transient = gettransient(IPPROTO_UDP,(u_long)1, &s)) == 0) {
133                 _DtCm_print_errmsg("Cannot get transient program number\n");
134                 _DtCm_print_errmsg("Callback cannot be enabled.\n");
135                 return;
136         }
137  
138         if (registerrpc(_DtCm_transient, AGENTVERS, update_callback,
139             (char *(*)())_DtCm_update_callback_1, _DtCm_xdr_Table_Res_4,
140             _DtCm_xdr_Update_Status) == -1) {
141                 _DtCm_print_errmsg("Cannot register v1 callback handler\n");
142                 _DtCm_print_errmsg("Callback cannot be enabled.\n");
143         }
144
145         if (registerrpc(_DtCm_transient, AGENTVERS_2, CMCB_UPDATE_CALLBACK,
146             (char *(*)())cmcb_update_callback_2_svc,
147             xdr_cmcb_update_callback_args, xdr_void) == -1) {
148                 _DtCm_print_errmsg("Cannot register v2 callback handler\n");
149                 _DtCm_print_errmsg("Callback cannot be enabled.\n");
150         }
151
152 #endif /* SunOS || USL || __uxp__ */
153  
154         /* locking candidate for MT-safe purpose */
155         mapped = 1;
156 }
157  
158 /*
159  * Unregister with the rpc service.
160  */
161 extern void
162 _DtCm_destroy_agent()
163 {
164         if (mapped == 0)
165                 return;
166
167         DP(("libdtcm: _DtCm_destroy_agent\n"));
168
169 #if defined(SunOS) || defined(USL) || defined(__uxp__)
170         (void) rpcb_unset(_DtCm_transient, AGENTVERS, NULL);
171         (void) rpcb_unset(_DtCm_transient, AGENTVERS_2, NULL);
172 #else
173         (void) pmap_unset(_DtCm_transient, AGENTVERS);
174         (void) pmap_unset(_DtCm_transient, AGENTVERS_2);
175 #endif /* SunOS || USL || __uxp__ */
176
177         /* locking candidate for MT-safe purpose */
178         mapped = 0;
179 }
180
181 extern void
182 _DtCm_process_updates()
183 {
184         int     i, j, nfd;
185         fd_set  rpc_bits;
186         fd_mask fmask, *inbits;
187         struct  pollfd pfd[FD_SETSIZE];
188         struct  pollfd *p;
189         int     last;
190         int     do_rpc;
191
192         while (B_TRUE) {
193                 rpc_bits = svc_fdset;
194
195                 /* convert to pollfd structure */
196                 inbits = rpc_bits.fds_bits;
197                 p = pfd;
198                 for (i = 0; i < FD_SETSIZE; i += NFDBITS) {
199                         fmask = *inbits;
200                         for (j = 0; fmask != 0 ; j++, fmask >>= 1) {
201                                 if (fmask & 0x1) {
202                                         p->fd = i + j;
203                                         if (p->fd >= FD_SETSIZE)
204                                                 break;
205                                         p->events = POLLIN;
206                                         p++;
207                                 }
208                         }
209                         inbits++;
210                 }
211
212                 /* poll and return right away */
213                 i = p - pfd;
214
215                 nfd = poll(pfd, i, 0);
216
217                 if (nfd <= 0)
218                         /* done */
219                         return;
220
221                 /* if set, handle rpc calls */
222
223                 /* convert back to fd_set structure */
224                 last = -1;
225                 do_rpc = 0;
226                 FD_ZERO(&rpc_bits);
227                 for (p = pfd; i-- > 0; p++) {
228                         j = p->fd / NFDBITS;
229                         if (j != last) {
230                                 inbits = &rpc_bits.fds_bits[j];
231                                 last = j;
232                         }
233                         if (p->revents & POLLIN) {
234                                 *inbits |= (1 << (p->fd % NFDBITS));
235                                 do_rpc = 1;
236                         }
237                 }
238
239                 if (do_rpc)
240                         svc_getreqset(&rpc_bits);
241         }
242 }
243
244 /*
245  * The server calls this routine when an update event occurs;  
246  * It's job is to notify CM asynchronously that an
247  * update has occurred.  It has to do it this
248  * way (i.e. raise a signal) because the client
249  * can't make an rpc call until this procedure call has
250  * returned to the server.
251  */
252  
253 Update_Status *
254 _DtCm_update_callback_1(Table_Res_4 *t, void *dummy)
255 {
256         static Update_Status status = update_succeeded;
257         _CallbackInfo *cbi;
258
259         DP(("agent.c: _DtCm_update_callback_1()\n"));
260
261         /*
262          * no point to save data for version 4 and before
263          * since the info from old backends does not contain
264          * calendar info
265          * so we just invoke all registered callback with no data
266          */
267         if (cbi = (_CallbackInfo *)calloc(1, sizeof(_CallbackInfo))) {
268                 cbi->vers = AGENTVERS;
269
270                 if (cb_tail == NULL)
271                         cb_head = cbi;
272                 else
273                         cb_tail->next = cbi;
274
275                 cb_tail = cbi;
276         }
277
278         /* handle callback from backend */
279         _DtCm_handle_callback();
280
281         return (&status);
282 }
283
284 /*
285  * Handler for v2 callback protocol
286  */
287 void *
288 cmcb_update_callback_2_svc(cmcb_update_callback_args *args, struct svc_req *d)
289 {
290         _CallbackInfo *cbi;
291
292         DP(("agent.c: cmcb_update_callback_2_svc()\n"));
293
294         if (args == NULL)
295                 return (NULL);
296
297         if (_ConvertCallbackData(args, &cbi) == CSA_SUCCESS) {
298                 cbi->vers = AGENTVERS_2;
299
300                 if (cb_tail == NULL)
301                         cb_head = cbi;
302                 else
303                         cb_tail->next = cbi;
304
305                 cb_tail = cbi;
306
307                 /* handle callback from backend */
308                 _DtCm_handle_callback();
309         }
310
311         return (NULL);
312 }
313
314 /******************************************************************************
315  * static functions used within in the file
316  ******************************************************************************/
317
318 /*
319  * get transient program number for callbacks.
320  */
321 #if defined(SunOS) || defined(USL) || defined(__uxp__)
322 static u_long
323 gettransient (u_long version)
324 {
325         int stat;
326         struct nd_hostserv host = {HOST_SELF, "rpcbind"};
327         struct nd_addrlist *addrp;
328
329         struct netbuf    *addr;
330         struct netconfig *netconf;
331
332         netconf = getnetconfigent("udp");
333         if (!netconf) {
334                 DP(("(gettransient) getnetconfigent(udp) failed\n"));
335                 freenetconfigent(netconf);
336                 return 0;
337         }
338
339         stat = netdir_getbyname(netconf, &host, &addrp);
340         if (stat) {
341                 DP(("(gettransient) netdir_getbyname failed\n"));
342                 netdir_free(addrp, ND_ADDRLIST);
343                 freenetconfigent(netconf);
344                 return 0;
345         }
346
347         if (addrp->n_cnt < 1) {
348                 DP(("(gettransient) netdir_getbyname - zero addresses\n"));
349                 netdir_free(addrp, ND_ADDRLIST);
350                 freenetconfigent(netconf);
351                 return 0;
352         }
353
354         addr = addrp->n_addrs;
355
356         while (!rpcb_set(prognum++, version, netconf, addr))
357             continue;
358         netdir_free(addrp, ND_ADDRLIST);
359         freenetconfigent(netconf);
360
361         prognum--;
362         return prognum;
363 }
364
365 #else /* SunOS || USL || __uxp__ */
366
367 static u_long
368 gettransient (int proto, u_long vers, int *sockp)
369 {
370         int s, len, socktype;
371         struct sockaddr_in addr;
372
373         switch (proto) {
374                 case IPPROTO_UDP:
375                         socktype = SOCK_DGRAM;
376                         break;
377                 case IPPROTO_TCP:
378                         socktype = SOCK_STREAM;
379                         break;
380                 default:
381                         DP(("unknown protocol type\n"));
382                         return 0;
383         }
384
385         if (*sockp == RPC_ANYSOCK) {
386                 if ((s = socket(AF_INET, socktype, 0)) < 0) {
387                         perror("socket");
388                         return 0;
389                 }
390                 *sockp = s;
391         } else
392                 s = *sockp;
393         
394         addr.sin_addr.s_addr = 0;
395         addr.sin_family = AF_INET;
396         addr.sin_port = 0;
397         len = sizeof(addr);
398
399         if (bind(s, (struct sockaddr *)&addr, len) != 0) {
400                 perror("bind");
401                 return 0;
402         }
403
404         if (getsockname(s, (struct sockaddr *)&addr, &len) < 0) {
405                 perror("getsockname");
406                 return 0;
407         }
408
409         while (!pmap_set(prognum++, vers, proto, ntohs(addr.sin_port)))
410                 continue;
411
412         return (prognum-1);
413 }
414
415 #endif /* not SunOS || USL || __uxp__ */
416
417 static void
418 _DtCm_handle_callback()
419 {
420         _CallbackInfo           *ptr, *prev;
421         Calendar                *cal;
422         _DtCmCallbackEntry      *cb;
423         boolean_t               keep = B_FALSE;
424
425         DP(("agent.c: _DtCm_handle_callback()\n"));
426
427         for (ptr = cb_head, prev = NULL; ptr != NULL; ) {
428                 /* we only handle version 1 and version 2 */
429                 if (ptr->vers == AGENTVERS)
430                         keep = _ProcessV1Callback(ptr);
431                 else
432                         keep = _ProcessV2Callback(ptr);
433
434                 if (!keep) {
435                         if (prev == NULL)
436                                 cb_head = ptr->next;
437                         else
438                                 prev->next = ptr->next;
439
440                         _FreeCallbackInfo(ptr);
441
442                 } else {
443                         prev = ptr;
444                 }
445                 ptr = ptr->next;
446         }
447         cb_tail = prev;
448 }
449
450 static CSA_return_code
451 _ConvertCallbackData(cmcb_update_callback_args *args, _CallbackInfo **cbi)
452 {
453         _CallbackInfo                                   *ncbi;
454         CSA_calendar_user                               *user;
455         CSA_logon_callback_data                         *ldata;
456         CSA_calendar_deleted_callback_data              *rdata;
457         CSA_calendar_attr_update_callback_data  *cdata;
458         CSA_add_entry_callback_data                     *adata;
459         CSA_delete_entry_callback_data                  *ddata;
460         CSA_update_entry_callback_data                  *udata;
461         char                                            timebuf[BUFSIZ];
462         
463         if ((ncbi = (_CallbackInfo *)calloc(1, sizeof(_CallbackInfo))) == NULL)
464                 return (CSA_E_INSUFFICIENT_MEMORY);
465
466         if (args->calendar && (ncbi->cal = strdup(args->calendar)) == NULL) {
467                 free(ncbi);
468                 return (CSA_E_INSUFFICIENT_MEMORY);
469         }
470
471         if (args->user && (ncbi->user = strdup(args->user)) == NULL) {
472                 _FreeCallbackInfo(ncbi);
473                 return (CSA_E_INSUFFICIENT_MEMORY);
474         }
475
476         if ((user = (CSA_calendar_user *)calloc(1, sizeof(CSA_calendar_user)))
477             == NULL) {
478                 _FreeCallbackInfo(ncbi);
479                 return (CSA_E_INSUFFICIENT_MEMORY);
480         } else
481                 user->user_name = ncbi->user;
482
483         ncbi->reason = args->data.reason;
484         switch (ncbi->reason) {
485         case CSA_CB_CALENDAR_LOGON:
486                 if ((ldata = (CSA_logon_callback_data *)calloc(1,
487                     sizeof(CSA_logon_callback_data))) == NULL) {
488                         free(user);
489                         _FreeCallbackInfo(ncbi);
490                         return (CSA_E_INSUFFICIENT_MEMORY);
491                 }
492                 ldata->user = user;
493                 ncbi->data = (void *)ldata;
494                 break;
495
496         case CSA_CB_CALENDAR_DELETED:
497                 if ((rdata = (CSA_calendar_deleted_callback_data *)calloc(1,
498                     sizeof(CSA_calendar_deleted_callback_data))) == NULL) {
499                         free(user);
500                         _FreeCallbackInfo(ncbi);
501                         return (CSA_E_INSUFFICIENT_MEMORY);
502                 }
503                 rdata->user = user;
504                 ncbi->data = (void *)rdata;
505                 break;
506
507         case CSA_CB_CALENDAR_ATTRIBUTE_UPDATED:
508                 if ((cdata = (CSA_calendar_attr_update_callback_data *)
509                     calloc(1, sizeof(
510                     CSA_calendar_attr_update_callback_data))) == NULL) {
511                         free(user);
512                         _FreeCallbackInfo(ncbi);
513                         return (CSA_E_INSUFFICIENT_MEMORY);
514                 }
515                 cdata->user = user;
516                 ncbi->data = (void *)cdata;
517
518                 if (_CopyAttributeNames(args->data.data.cdata->num_names,
519                     args->data.data.cdata->names, &cdata->number_attributes,
520                     &cdata->attribute_names)) {
521                         _FreeCallbackInfo(ncbi);
522                         return (CSA_E_INSUFFICIENT_MEMORY);
523                 }
524
525                 break;
526
527         case CSA_CB_ENTRY_ADDED:
528                 if ((adata = (CSA_add_entry_callback_data *)calloc(1,
529                     sizeof(CSA_add_entry_callback_data))) == NULL) {
530                         free(user);
531                         _FreeCallbackInfo(ncbi);
532                         return (CSA_E_INSUFFICIENT_MEMORY);
533                 }
534                 adata->user = user;
535                 ncbi->data = (void *)adata;
536
537                 if (args->data.data.adata->id && (adata->added_entry_id.data =
538                     (unsigned char *)strdup(args->data.data.adata->id))
539                     == NULL) {
540                         _FreeCallbackInfo(ncbi);
541                         return (CSA_E_INSUFFICIENT_MEMORY);
542                 } else
543                         adata->added_entry_id.size =
544                                 strlen((char *)adata->added_entry_id.data);
545
546                 break;
547
548         case CSA_CB_ENTRY_DELETED:
549                 if ((ddata = (CSA_delete_entry_callback_data *)calloc(1,
550                     sizeof(CSA_delete_entry_callback_data))) == NULL) {
551                         free(user);
552                         _FreeCallbackInfo(ncbi);
553                         return (CSA_E_INSUFFICIENT_MEMORY);
554                 }
555                 ddata->user = user;
556                 ncbi->data = (void *)ddata;
557
558                 if (args->data.data.ddata->id && (ddata->deleted_entry_id.data =
559                     (unsigned char *)strdup(args->data.data.ddata->id))
560                     == NULL) {
561                         _FreeCallbackInfo(ncbi);
562                         return (CSA_E_INSUFFICIENT_MEMORY);
563                 } else
564                         ddata->deleted_entry_id.size =
565                                 strlen((char *)ddata->deleted_entry_id.data);
566
567                 _csa_tick_to_iso8601(args->data.data.ddata->time, timebuf);
568                 if ((ddata->date_and_time = strdup(timebuf)) == NULL) {
569                         _FreeCallbackInfo(ncbi);
570                         return (CSA_E_INSUFFICIENT_MEMORY);
571                 }
572
573                 ddata->scope = args->data.data.ddata->scope;
574                 break;
575
576         case CSA_CB_ENTRY_UPDATED:
577                 if ((udata = (CSA_update_entry_callback_data *)calloc(1,
578                     sizeof(CSA_update_entry_callback_data))) == NULL) {
579                         free(user);
580                         _FreeCallbackInfo(ncbi);
581                         return (CSA_E_INSUFFICIENT_MEMORY);
582                 }
583                 udata->user = user;
584                 ncbi->data = (void *)udata;
585
586                 if (args->data.data.udata->newid && (udata->new_entry_id.data =
587                     (unsigned char *)strdup(args->data.data.udata->newid))
588                     == NULL) {
589                         _FreeCallbackInfo(ncbi);
590                         return (CSA_E_INSUFFICIENT_MEMORY);
591                 } else
592                         udata->new_entry_id.size =
593                                 strlen((char *)udata->new_entry_id.data);
594
595                 if (args->data.data.udata->oldid && (udata->old_entry_id.data =
596                     (unsigned char *)strdup(args->data.data.udata->oldid))
597                     == NULL) {
598                         _FreeCallbackInfo(ncbi);
599                         return (CSA_E_INSUFFICIENT_MEMORY);
600                 } else
601                         udata->old_entry_id.size =
602                                 strlen((char *)udata->old_entry_id.data);
603
604                 _csa_tick_to_iso8601(args->data.data.udata->time, timebuf);
605                 if ((udata->date_and_time = strdup(timebuf)) == NULL) {
606                         _FreeCallbackInfo(ncbi);
607                         return (CSA_E_INSUFFICIENT_MEMORY);
608                 }
609
610                 udata->scope = args->data.data.udata->scope;
611                 break;
612         }
613
614         *cbi = ncbi;
615         return (CSA_SUCCESS);
616 }
617
618 static CSA_return_code
619 _CopyAttributeNames(uint fnum, char **fnames, CSA_uint32 *tnum, char ***tnames)
620 {
621         int     i;
622         char    **nnames;
623
624         if (fnum == 0) {
625                 *tnum = 0;
626                 *tnames = NULL;
627                 return (CSA_SUCCESS);
628         }
629
630         if ((nnames = calloc(1, sizeof(char *) * fnum)) == NULL)
631                 return (CSA_E_INSUFFICIENT_MEMORY);
632
633         for (i = 0; i < fnum; i++) {
634                 if ((nnames[i] = strdup(fnames[i])) == NULL)
635                         break;
636         }
637
638         if (i == fnum) {
639                 *tnum = i;
640                 *tnames = nnames;
641                 return (CSA_SUCCESS);
642         } else {
643                  _DtCm_free_character_pointers(i, nnames);
644                 free(nnames);
645                 return (CSA_E_INSUFFICIENT_MEMORY);
646         }
647 }
648
649 /*
650  * pre callback protocol V2, there is no distinction
651  * between different reasons, and no data passed.  So
652  * there's only one possible thing to do, and that's
653  * run all the callbacks.
654  */
655 static boolean_t
656 _ProcessV1Callback(_CallbackInfo *ptr)
657 {
658         Calendar                *cal;
659         _DtCmCallbackEntry      *cb;
660         boolean_t               keep = B_FALSE;
661
662         for (cal = _DtCm_active_cal_list; cal != NULL; cal = cal->next) {
663                 if (cal->rpc_version >= _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION)
664                         continue;
665
666                 if (cal->do_reasons &
667                     (CSA_CB_ENTRY_ADDED | CSA_CB_ENTRY_DELETED |
668                     CSA_CB_ENTRY_UPDATED))
669                 {
670                         /* only do dumb processing if it was a V4 server */
671                         for (cb = cal->cb_list; cb != NULL; cb = cb->next) {
672                                 if (cal->do_reasons & cb->reason) {
673                                         cb->handler((CSA_session_handle)cal,
674                                                 cal->do_reasons & cb->reason,
675                                                 (CSA_buffer) NULL,
676                                                 cb->client_data,
677                                                 (CSA_extension*) NULL);
678                                 }
679                         }
680                 } else if (cal->all_reasons & (CSA_CB_ENTRY_ADDED |
681                     CSA_CB_ENTRY_DELETED | CSA_CB_ENTRY_UPDATED))
682                         keep = B_TRUE;
683         }
684
685         return (keep);
686 }
687
688 static boolean_t
689 _ProcessV2Callback(_CallbackInfo *ptr)
690 {
691         Calendar                *cal;
692         _DtCmCallbackEntry      *cb;
693         boolean_t               keep = B_FALSE;
694
695         for (cal = _DtCm_active_cal_list; cal != NULL; cal = cal->next) {
696                 if (cal->rpc_version < _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION ||
697                     strcmp(ptr->cal, cal->name))
698                         continue;
699
700                 if (cal->do_reasons & ptr->reason) {
701
702                         /* only do dumb processing if it was a V4 server */
703                         for (cb = cal->cb_list; cb != NULL; cb = cb->next) {
704                                 if (ptr->reason & cb->reason) {
705                                         cb->handler((CSA_session_handle)cal,
706                                                 ptr->reason,
707                                                 (CSA_buffer)ptr->data,
708                                                 cb->client_data,
709                                                 (CSA_extension*) NULL);
710                                 }
711                         }
712                 } else if (cal->all_reasons & ptr->reason)
713                         keep = B_TRUE;
714         }
715
716         return (keep);
717 }
718
719 static void
720 _FreeCallbackInfo(_CallbackInfo *ptr)
721 {
722         CSA_logon_callback_data                         *ldata;
723         CSA_calendar_deleted_callback_data              *rdata;
724         CSA_calendar_attr_update_callback_data  *cdata;
725         CSA_add_entry_callback_data                     *adata;
726         CSA_delete_entry_callback_data                  *ddata;
727         CSA_update_entry_callback_data                  *udata;
728
729         if (ptr) {
730                 if (ptr->cal) free(ptr->cal);
731                 if (ptr->user) free(ptr->user);
732
733                 if (ptr->data) switch (ptr->reason) {
734                 case CSA_CB_CALENDAR_LOGON:
735                         ldata = ptr->data;
736                         if (ldata->user) free(ldata->user);
737                         free(ldata);
738                         break;
739                 case CSA_CB_CALENDAR_DELETED:
740                         rdata = ptr->data;
741                         if (rdata->user) free(rdata->user);
742                         free(rdata);
743                         break;
744                 case CSA_CB_CALENDAR_ATTRIBUTE_UPDATED:
745                         cdata = (CSA_calendar_attr_update_callback_data *)
746                                 ptr->data;
747                         if (cdata->user) free(cdata->user);
748                         if (cdata->number_attributes > 0)
749                                 _DtCm_free_character_pointers(
750                                         cdata->number_attributes,
751                                         cdata->attribute_names);
752                         free(cdata);
753                         break;
754                 case CSA_CB_ENTRY_ADDED:
755                         adata = (CSA_add_entry_callback_data *)ptr->data;
756                         if (adata->user) free(adata->user);
757                         if (adata->added_entry_id.data)
758                                 free(adata->added_entry_id.data);
759                         free(adata);
760                         break;
761                 case CSA_CB_ENTRY_DELETED:
762                         ddata = (CSA_delete_entry_callback_data *)ptr->data;
763                         if (ddata->date_and_time) free(ddata->date_and_time);
764                         if (ddata->user) free(ddata->user);
765                         if (ddata->deleted_entry_id.data)
766                                 free(ddata->deleted_entry_id.data);
767                         free(ddata);
768                         break;
769                 case CSA_CB_ENTRY_UPDATED:
770                         udata = (CSA_update_entry_callback_data *)ptr->data;
771                         if (udata->user) free(udata->user);
772                         if (udata->date_and_time) free(udata->date_and_time);
773                         if (udata->old_entry_id.data)
774                                 free(udata->old_entry_id.data);
775                         if (udata->new_entry_id.data)
776                                 free(udata->new_entry_id.data);
777                         free(udata);
778                 }
779
780                 free(ptr);
781         }
782 }
783
784