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