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