Don't declare 'Chunk' as both public and private, that's just daft.
[oweals/cde.git] / cde / lib / csa / api.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 /* $XConsortium: api.c /main/1 1996/04/21 19:21:31 drk $ */
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 /*
32  * Implements the calendar manager API functions.
33  */
34
35 #include <EUSCompat.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <pwd.h>
40 #ifdef SunOS
41 #include <stropts.h>
42 #endif
43 #include "csa.h"
44 #include "agent_p.h"
45 #include "entry.h"
46 #include "rpccalls.h"
47 #include "connection.h"
48 #include "debug.h"
49 #include "attr.h"
50 #include "xtclient.h"
51 #include "misc.h"
52 #include "free.h"
53 #include "iso8601.h"
54 #include "match.h"
55
56 /******************************************************************************
57  * forward declaration of static functions used within the file
58  ******************************************************************************/
59 static CSA_return_code _handle_register_callback_ext(CSA_extension *ext);
60 static CSA_return_code _handle_logon_ext(CSA_extension *ext,
61                                         CSA_extension **pext);
62 static CSA_return_code _handle_query_config_ext(CSA_extension *ext);
63 static void _handle_com_support_ext(CSA_extension *ext);
64
65 /******************************************************************************
66  * Calendar Manager API
67  ******************************************************************************/
68
69 /*
70  * List calendars supported by a server
71  */
72 extern CSA_return_code
73 csa_list_calendars(
74         CSA_service_reference   calendar_service,
75         CSA_uint32      *number_names,
76         CSA_calendar_user       **calendar_names,
77         CSA_extension   *list_calendars_extensions)
78 {
79         DP(("api.c: csa_list_calendars\n"));
80
81         if (calendar_service == NULL || number_names == NULL ||
82             calendar_names == NULL)
83                 return (CSA_E_INVALID_PARAMETER);
84
85         /* no function extension is supported */
86         if (list_calendars_extensions != NULL)
87                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
88
89         return (_DtCm_rpc_list_calendars(calendar_service, number_names,
90                 calendar_names));
91 }
92
93 /*
94  * Logon to a calendar.
95  * Returns a calendar session handle.
96  *
97  * arguments not used by this implementation:
98  * calendar_servce, password, character_set, caller_csa_version,
99  * logon_extensions
100  * 
101  * arguments ignored for now
102  * character_set, caller_csa_version
103  *
104  * user - only the calendar_address field is used, other fields are ignored
105  *      - format is calendar_name@host
106  */
107 extern CSA_return_code
108 csa_logon(
109         CSA_service_reference   calendar_service,
110         CSA_calendar_user       *user,
111         CSA_string              password,
112         CSA_string              character_set,
113         CSA_string              caller_csa_version,
114         CSA_session_handle      *session,
115         CSA_extension           *logon_extensions)
116 {
117         CSA_return_code stat;
118         Calendar        *cal;
119         CSA_extension   *pext = NULL;
120
121         DP(("api.c: csa_logon\n"));
122
123         /* check validity of arguments */
124         if (user == NULL || user->calendar_address == NULL || session == NULL
125            || strchr(user->calendar_address, '@') == NULL)
126                 return (CSA_E_INVALID_PARAMETER);
127
128         /* create calendar object */
129         if ((cal = _DtCm_new_Calendar(user->calendar_address)) == NULL) {
130                 return (CSA_E_INSUFFICIENT_MEMORY);
131         }
132
133         if (logon_extensions != NULL) {
134                 if ((stat = _handle_logon_ext(logon_extensions, &pext))
135                     != CSA_SUCCESS)
136                         return (stat);
137         }
138
139         /* open calendar */
140         if ((stat = _DtCm_rpc_open_calendar(cal)) == CSA_SUCCESS) {
141
142                 if (pext) pext->item_data = cal->access;
143
144                 *session = (CSA_session_handle)cal;
145
146         } else {
147                 _DtCm_free_Calendar(cal);
148         }
149
150         return (stat);
151 }
152
153 /*
154  * Create a calendar.
155  *
156  * arguments not used by this implementation:
157  * session - always ignored
158  * add_calendar_extensions
159  * 
160  * user - only the calendar_address field is used, other fields are ignored
161  *      - format is calendar_name@host
162  */
163 extern CSA_return_code
164 csa_add_calendar(
165         CSA_session_handle      session,
166         CSA_calendar_user       *user,
167         CSA_uint32              number_attributes,
168         CSA_attribute           *calendar_attributes,
169         CSA_extension           *add_calendar_extensions)
170 {
171         CSA_return_code stat;
172         Calendar        *cal;
173         char            *host;
174
175         DP(("api.c: csa_add_calendar\n"));
176
177         /* check validity of arguments */
178         if (user == NULL || user->calendar_address == NULL ||
179             (host = strchr(user->calendar_address, '@')) == NULL)
180                 return (CSA_E_INVALID_PARAMETER);
181
182         /* check add_calendar_extensions and return appropriate return code */
183         /* no function extension is supported */
184         if (add_calendar_extensions != NULL)
185                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
186
187         /* create calendar object */
188         if ((cal = _DtCm_new_Calendar(user->calendar_address)) == NULL) {
189                 return (CSA_E_INSUFFICIENT_MEMORY);
190         }
191
192         host++;
193         if ((stat = _DtCm_get_server_rpc_version(host, &cal->rpc_version))
194             != CSA_SUCCESS)
195                 return (stat);
196
197         /* check validity of attributes */
198         if (number_attributes > 0 &&
199             (stat = _DtCm_check_cal_csa_attributes(cal->rpc_version - 1,
200             number_attributes, calendar_attributes, user->calendar_address,
201             B_TRUE, B_TRUE, B_FALSE)) != CSA_SUCCESS) {
202                 return (stat);
203         }
204
205         /* create calendar */
206         stat = _DtCm_rpc_create_calendar(cal, number_attributes,
207                 calendar_attributes);
208
209         _DtCm_free_Calendar(cal);
210
211         return (stat);
212 }
213
214 /*
215  * Logoff a calendar.
216  * The calendar handle becomes invalid
217  *
218  * argument not used by this implementation:
219  * logoff_extensions
220  */
221 extern CSA_return_code
222 csa_logoff(
223         CSA_session_handle session,
224         CSA_extension *logoff_extensions)
225 {
226         Calendar        *cal;
227
228         DP(("api.c: csa_logoff\n"));
229
230         /* get calendar object */
231         if ((cal = _DtCm_get_Calendar(session)) == NULL)
232                 return (CSA_E_INVALID_SESSION_HANDLE);
233
234         /* check logoff_extensions and return appropriate return code */
235         /* no function extension is supported */
236         if (logoff_extensions != NULL)
237                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
238
239         /* unregister with server */
240         if (cal->all_reasons)
241                 (void) _DtCm_rpc_unregister_client(cal, cal->all_reasons);
242
243         /* clean up */
244         _DtCm_free_Calendar(cal);
245
246         return (CSA_SUCCESS);
247 }
248
249 /*
250  * delete calendar
251  */
252 extern CSA_return_code
253 csa_delete_calendar(
254         CSA_session_handle      session,
255         CSA_extension   *delete_calendar_extensions)
256 {
257         Calendar        *cal;
258
259         DP(("api.c: csa_delete_calendar\n"));
260
261         /* get calendar object */
262         if ((cal = _DtCm_get_Calendar(session)) == NULL)
263                 return (CSA_E_INVALID_SESSION_HANDLE);
264
265         /* check extensions and return appropriate return code */
266         /* no function extension is supported */
267         if (delete_calendar_extensions != NULL)
268                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
269
270         if (cal->rpc_version < 5)
271                 return (CSA_E_NOT_SUPPORTED);
272
273         return (_DtCm_rpc_delete_calendar(cal));
274 }
275
276 extern CSA_return_code
277 csa_list_calendar_attributes(
278         CSA_session_handle      session,
279         CSA_uint32      *number_names,
280         CSA_attribute_reference **calendar_attributes_names,
281         CSA_extension   *list_calendar_attributes_extensions)
282 {
283         Calendar        *cal;
284
285         DP(("api.c: csa_list_calendar_attributes\n"));
286
287         if (number_names == NULL || calendar_attributes_names == NULL)
288                 return (CSA_E_INVALID_PARAMETER);
289
290         /* no function extension is supported */
291         if (list_calendar_attributes_extensions != NULL)
292                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
293
294         /* get calendar object */
295         if ((cal = _DtCm_get_Calendar(session)) == NULL)
296                 return (CSA_E_INVALID_SESSION_HANDLE);
297
298         if (cal->rpc_version < _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION) {
299                 return (_DtCm_list_old_cal_attr_names(cal, number_names,
300                         calendar_attributes_names));
301         } else
302                 return (_DtCm_rpc_list_calendar_attributes(cal, number_names,
303                         calendar_attributes_names));
304 }
305
306 extern CSA_return_code
307 csa_save(
308         CSA_session_handle      session,
309         CSA_string      archive_name,
310         CSA_uint32      number_attributes,
311         CSA_attribute   *attributes,
312         CSA_enum        *operators,
313         CSA_boolean     delete_entry,
314         CSA_extension   *save_extensions)
315 {
316         DP(("api.c: csa_save\n"));
317
318         return (CSA_E_NOT_SUPPORTED);
319 }
320
321 extern CSA_return_code
322 csa_restore(
323         CSA_session_handle      session,
324         CSA_string      archive_name,
325         CSA_uint32      number_attributes,
326         CSA_attribute   *attributes,
327         CSA_enum        *operators,
328         CSA_extension   *restore_extensions)
329 {
330         DP(("api.c: csa_restore\n"));
331
332         return (CSA_E_NOT_SUPPORTED);
333 }
334
335 /*
336  * If list_operators is NULL, the operator is default to be CSA_MATCH_EQUAL_TO
337  * for all attributes.
338  * *** might want to check operator for conflicts that won't result in no match
339  */
340 extern CSA_return_code
341 csa_list_entries(
342         CSA_session_handle      session,
343         CSA_uint32      number_attributes,
344         CSA_attribute   *entry_attributes,
345         CSA_enum        *list_operators,
346         CSA_uint32      *number_entries,
347         CSA_entry_handle        **entries,
348         CSA_extension   *list_entries_extensions)
349 {
350         CSA_return_code         stat;
351         Calendar                *cal;
352         _DtCm_libentry          *elist;
353         int                     i;
354
355         DP(("api.c: csa_list_entries\n"));
356
357         if (entries == NULL || number_entries == NULL)
358                 return (CSA_E_INVALID_PARAMETER);
359         else {
360                 *entries = NULL;
361                 *number_entries = 0;
362         }
363
364         /* check list_entries_extensions
365          * and return appropriate return code
366          * no function extension is supported
367          */
368         if (list_entries_extensions != NULL)
369                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
370
371         /* get calendar object */
372         if ((cal = _DtCm_get_Calendar(session)) == NULL)
373                 return (CSA_E_INVALID_SESSION_HANDLE);
374
375         if (list_operators && (stat = _DtCm_check_operator(number_attributes,
376             entry_attributes, NULL, list_operators)) != CSA_SUCCESS) {
377
378                 return (stat);
379         }
380
381         /* check data type */
382         if ((stat = _DtCm_check_entry_attributes(cal->file_version,
383             number_attributes, entry_attributes, 0, B_FALSE)) != CSA_SUCCESS) {
384                 /*
385                  * if attribute not supported by old backends
386                  * are specified, just fail the match,
387                  * i.e. return NULL and CSA_SUCCESS
388                  */
389                 if (stat == CSA_E_UNSUPPORTED_ATTRIBUTE)
390                         stat = CSA_SUCCESS;
391
392                 return (stat);
393         }
394
395         /* lookup entries */
396         if ((stat = _DtCm_rpc_lookup_entries(cal, number_attributes,
397             entry_attributes, list_operators, &elist)) == CSA_SUCCESS) {
398
399                 if (elist) {
400                         *number_entries = _DtCm_add_to_entry_list(cal, (caddr_t)elist);
401                         stat = _DtCm_libentry_to_entryh(elist, number_entries,
402                                 entries);
403                 }
404         }
405
406         return (stat);
407 }
408
409 extern CSA_return_code
410 csa_list_entry_attributes(
411         CSA_session_handle      session,
412         CSA_entry_handle        entryh,
413         CSA_uint32      *number_names,
414         CSA_attribute_reference **entry_attribute_names,
415         CSA_extension   *list_entry_attributes_extensions)
416 {
417         CSA_return_code stat;
418         _DtCm_libentry  *entry;
419
420         DP(("api.c: csa_list_entry_attributes\n"));
421
422         if (number_names == NULL || entry_attribute_names == NULL)
423                 return (CSA_E_INVALID_PARAMETER);
424
425         /* check list_entry_attributes_extensions
426          * and return appropriate return code
427          * no function extension is supported
428          */
429         if (list_entry_attributes_extensions != NULL)
430                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
431
432         /* get appointment */
433         if ((entry = _DtCm_get_libentry(entryh)) == NULL)
434                 return (CSA_E_INVALID_ENTRY_HANDLE);
435
436         if ((stat = _DtCm_get_entry_detail(entry)) != CSA_SUCCESS)
437                 return (stat);
438
439         return (_DtCm_get_entry_attr_names(entry, number_names,
440                 entry_attribute_names));
441 }
442
443
444 extern CSA_return_code
445 csa_read_entry_attributes(
446         CSA_session_handle      session,
447         CSA_entry_handle        entryh,
448         CSA_uint32      number_names,
449         CSA_attribute_reference *attribute_names,
450         CSA_uint32      *number_attributes,
451         CSA_attribute   **entry_attributes,
452         CSA_extension   *read_entry_attributes_extensions)
453 {
454         CSA_return_code stat;
455         _DtCm_libentry  *entry;
456         int             i;
457
458         DP(("api.c: csa_read_entry_attributes\n"));
459
460         if (number_attributes == 0 || entry_attributes == NULL)
461                 return (CSA_E_INVALID_PARAMETER);
462
463         /* check read_entry_attributes_extensions
464          * and return appropriate return code
465          * no function extension is supported
466          */
467         if (read_entry_attributes_extensions != NULL)
468                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
469
470         /* get entry object */
471         if ((entry = _DtCm_get_libentry(entryh)) == NULL)
472                 return (CSA_E_INVALID_ENTRY_HANDLE);
473
474         if ((stat = _DtCm_get_entry_detail(entry)) != CSA_SUCCESS)
475                 return (stat);
476
477         if (number_names > 0) {
478                 return (_DtCm_get_entry_attrs_by_name(entry, number_names,
479                         attribute_names, number_attributes, entry_attributes));
480         } else {
481                 return (_DtCm_get_all_entry_attrs(entry, number_attributes,
482                         entry_attributes));
483         }
484 }
485
486 extern CSA_return_code
487 csa_free(CSA_buffer memory)
488 {
489         DP(("api.c: csa_free\n"));
490
491         return (_DtCm_free(memory));
492 }
493
494 extern CSA_return_code
495 csa_look_up(
496         CSA_session_handle      session,
497         CSA_calendar_user       *users,
498         CSA_flags       look_up_flags,
499         CSA_uint32      *number_users,
500         CSA_calendar_user       **user_list,
501         CSA_extension   *look_up_extensions)
502 {
503         DP(("api.c: csa_look_up\n"));
504
505         return (CSA_E_NOT_SUPPORTED);
506 }
507
508 extern CSA_return_code
509 csa_query_configuration(
510         CSA_session_handle      session,
511         CSA_enum        item,
512         CSA_buffer      *reference,
513         CSA_extension   *query_configuration_extensions)
514 {
515         CSA_return_code stat = CSA_SUCCESS;
516         Calendar        *cal;
517         DP(("api.c: csa_query_configuration\n"));
518
519         /* get calendar object */
520         if ((cal = _DtCm_get_Calendar(session)) == NULL)
521                 return (CSA_E_INVALID_SESSION_HANDLE);
522
523         if (item < CSA_CONFIG_CHARACTER_SET || item > CSA_CONFIG_VER_SPEC)
524                 return (CSA_E_INVALID_ENUM);
525
526         if (reference == NULL)
527                 return (CSA_E_INVALID_PARAMETER);
528
529         if (query_configuration_extensions) {
530                 if ((stat = _handle_query_config_ext(
531                     query_configuration_extensions)) != CSA_SUCCESS)
532                         return (stat);
533         }
534
535         switch (item) {
536         case CSA_CONFIG_DEFAULT_SERVICE:
537         case CSA_CONFIG_DEFAULT_USER:
538                 *reference = NULL;
539                 break;
540
541         case CSA_CONFIG_REQ_PASSWORD:
542                 *reference = (CSA_buffer)CSA_REQUIRED_NO;
543                 break;
544
545         case CSA_CONFIG_REQ_SERVICE:
546         case CSA_CONFIG_REQ_USER:
547                 *reference = (CSA_buffer)CSA_REQUIRED_YES;
548                 break;
549
550         case CSA_CONFIG_UI_AVAIL:
551                 *reference = (CSA_buffer)CSA_FALSE;
552                 break;
553
554         case CSA_CONFIG_VER_SPEC:
555                 *reference = (CSA_buffer)strdup(_DtCM_SPEC_VERSION_SUPPORTED);
556                 break;
557
558         case CSA_CONFIG_CHARACTER_SET:
559         case CSA_CONFIG_LINE_TERM:
560         case CSA_CONFIG_VER_IMPLEM:
561                 stat = CSA_E_UNSUPPORTED_ENUM;
562         }
563         
564         return (stat);
565 }
566
567 extern CSA_return_code
568 csa_read_calendar_attributes(
569         CSA_session_handle      session,
570         CSA_uint32      number_names,
571         CSA_attribute_reference *attribute_names,
572         CSA_uint32      *number_attributes,
573         CSA_attribute   **calendar_attributes,
574         CSA_extension   *read_calendar_attributes_extensions)
575 {
576         CSA_return_code stat;
577         Calendar        *cal;
578         int             i;
579
580         DP(("api.c: csa_read_calendar_attributes\n"));
581
582         if (number_attributes == 0 || calendar_attributes == NULL)
583                 return (CSA_E_INVALID_PARAMETER);
584
585         /* check read_calendar_attributes_extensions
586          * and return appropriate return code
587          * no function extension is supported
588          */
589         if (read_calendar_attributes_extensions != NULL)
590                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
591
592         /* get calendar object */
593         if ((cal = _DtCm_get_Calendar(session)) == NULL)
594                 return (CSA_E_INVALID_SESSION_HANDLE);
595
596         _DtCm_reset_cal_attrs(cal);
597         if (number_names > 0) {
598                 return (_DtCm_get_cal_attrs_by_name(cal, number_names,
599                         attribute_names, number_attributes,
600                         calendar_attributes));
601         } else {
602                 return (_DtCm_get_all_cal_attrs(cal, number_attributes,
603                         calendar_attributes));
604         }
605 }
606
607 extern CSA_return_code
608 csa_register_callback(
609         CSA_session_handle      session,
610         CSA_flags               reason,
611         CSA_callback            callback,
612         CSA_buffer              client_data,
613         CSA_extension           *register_callback_extensions)
614 {
615         CSA_return_code         stat = CSA_SUCCESS;
616         _DtCmCallbackEntry      *cb_entry;
617         Calendar                *cal;
618         boolean_t               async = B_FALSE;
619
620         /* get calendar object */
621         if ((cal = _DtCm_get_Calendar(session)) == NULL)
622                 return (CSA_E_INVALID_SESSION_HANDLE);
623
624         /* make sure some valid flags are set
625          * and only entry added, deleted or updated is specified for
626          * servers support up to version 4 rpc protocol
627          */
628         if (reason == 0 || reason >= (CSA_CB_ENTRY_UPDATED << 1) ||
629             (cal->rpc_version < _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION &&
630              (reason & ~(CSA_CB_ENTRY_ADDED|CSA_CB_ENTRY_DELETED|
631              CSA_CB_ENTRY_UPDATED))))
632                 return (CSA_E_INVALID_FLAG);
633
634         /* must specify a callback function otherwise
635          * there is no point to make this call
636          */
637         if (callback == NULL)
638                 return (CSA_E_INVALID_PARAMETER);
639
640         /* need to initialize agent before doing XtAppAddInput */
641         _DtCm_init_agent();
642
643         if (register_callback_extensions != NULL) {
644                 if ((stat = _handle_register_callback_ext(
645                     register_callback_extensions)) != CSA_SUCCESS)
646                         return (stat);
647                 else
648                         async = B_TRUE;
649         }
650
651         /*
652          * register interest only if we have a new flag
653          * NOTE: It's OK to register more than once, even if it's
654          * the same calendar, same reason.  The customer is always right.
655          */
656         if (((cal->all_reasons | reason) ^ cal->all_reasons) &&
657             (stat = _DtCm_rpc_register_client(cal, reason)) != CSA_SUCCESS)
658                 return stat;
659
660         if ((cb_entry = (_DtCmCallbackEntry*)malloc(sizeof(_DtCmCallbackEntry)))
661             == NULL)
662                 return (CSA_E_INSUFFICIENT_MEMORY);
663
664         /* update info in calendar structure */
665         cal->all_reasons |= reason;
666
667         /* don't just do cal->async_process = async, since cal->async_process
668          * might have been set to B_TRUE before.
669          */
670         if (async == B_TRUE)
671                 cal->async_process = B_TRUE;
672         if (cal->async_process == B_TRUE)
673                 cal->do_reasons = cal->all_reasons;
674
675         /* fill in the callback record */
676         cb_entry->reason = reason;
677         cb_entry->handler = callback;
678         cb_entry->client_data = client_data;
679         
680         /* insert it at head of list */
681         cb_entry->next = cal->cb_list;
682         cb_entry->prev = (_DtCmCallbackEntry*) NULL;
683         if (cal->cb_list != (_DtCmCallbackEntry*) NULL)
684                 cal->cb_list->prev = cb_entry;
685         cal->cb_list = cb_entry;
686
687         return CSA_SUCCESS;
688 }
689
690 /*
691  * csa_unregister_callback
692  *
693  * removes a previsouly registered callback from the callback list
694  * of the specified calendar.
695  */
696 extern CSA_return_code
697 csa_unregister_callback(
698         CSA_session_handle      session,
699         CSA_flags               reason,
700         CSA_callback            handler,
701         CSA_buffer              client_data,
702         CSA_extension           *unregister_callback_extensions)
703 {
704         Calendar        *cal;
705         boolean_t       match_one = B_FALSE;
706         boolean_t       match_all = B_FALSE;
707         boolean_t       matched;
708         CSA_flags       all = 0, unreg;
709         _DtCmCallbackEntry *cb, *ncb;
710
711         /* get calendar object */
712         if ((cal = _DtCm_get_Calendar(session)) == NULL)
713                 return (CSA_E_INVALID_SESSION_HANDLE);
714
715         if (reason == 0 || reason >= (CSA_CB_ENTRY_UPDATED << 1))
716                 return (CSA_E_INVALID_FLAG);
717
718         /* check unregister_callback_extensions
719          * and return appropriate return code
720          * no function extension is supported
721          */
722         if (unregister_callback_extensions != NULL)
723                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
724
725         if (handler == NULL && client_data == NULL)
726                 match_all = B_TRUE;
727         else if (handler == NULL)       /* but client data is not NULL */
728                 return (CSA_E_INVALID_PARAMETER);
729
730         /*
731          * Removal policy: If both handler and client data are NULL,
732          * match all callbacks for the specified reason.
733          * Otherwise, all of reason, handler and client data must
734          * match.
735          */
736         cb = cal->cb_list;
737         while (cb) {
738                 matched = B_TRUE;
739                 ncb = cb->next;
740
741                 if (!(reason & cb->reason) ||
742                     (match_all == B_FALSE && (handler != cb->handler ||
743                     client_data != cb->client_data))) {
744                         all = all | cb->reason;
745                         cb = cb->next;
746                         continue;
747                 }
748
749                 match_one = B_TRUE;
750
751                 if (cb->reason = (cb->reason | reason) ^ reason) {
752                         all = all | cb->reason;
753                 } else {
754                         /* remove entry */
755                         if (cb->prev != NULL)
756                                 cb->prev->next = cb->next;
757                         if (cb->next != NULL)
758                                 cb->next->prev = cb->prev;
759                         if (cb == cal->cb_list)
760                                 cal->cb_list = cb->next;
761                         free(cb);
762                 }
763
764                 cb = ncb;
765         }
766
767         unreg = all ^ cal->all_reasons;
768         cal->all_reasons = all;
769
770         if (unreg)
771                 (void) _DtCm_rpc_unregister_client(cal, unreg);
772
773         if (match_one == B_TRUE)
774                 return (CSA_SUCCESS);
775         else
776                 return (CSA_E_CALLBACK_NOT_REGISTERED);
777 }
778
779 CSA_return_code
780 csa_call_callbacks(
781         CSA_session_handle      session,
782         CSA_flags               reason,
783         CSA_extension           *call_callbacks_extensions)
784 {
785         Calendar        *cal;
786
787         DP(("api.c: csa_call_callbacks\n"));
788
789         /* get calendar object */
790         if ((cal = _DtCm_get_Calendar(session)) == NULL)
791                 return (CSA_E_INVALID_SESSION_HANDLE);
792
793         /* no function extension is supported */
794         if (call_callbacks_extensions != NULL)
795                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
796
797         /* set up information in calendar structure */
798         if (cal->async_process == B_FALSE)
799                 cal->do_reasons = reason;
800
801         /* trigger callback mechanism */
802         _DtCm_process_updates();
803
804         if (cal->async_process == B_FALSE)
805                 cal->do_reasons = 0;
806
807         return (CSA_SUCCESS);
808 }
809
810 extern CSA_return_code
811 csa_update_calendar_attributes(
812         CSA_session_handle      session,
813         CSA_uint32      num_attrs,
814         CSA_attribute   *attrs,
815         CSA_extension   *update_calendar_attributes_extensions)
816 {
817         CSA_return_code stat = CSA_SUCCESS;
818         Calendar        *cal;
819         int             i;
820
821         DP(("api.c: csa_update_calendar_attributes\n"));
822
823         /* get calendar object */
824         if ((cal = _DtCm_get_Calendar(session)) == NULL)
825                 return (CSA_E_INVALID_SESSION_HANDLE);
826
827         if (num_attrs == 0 || attrs == NULL)
828                 return (CSA_E_INVALID_PARAMETER);
829
830         /*
831          * check update_calendar_attributes_extensions
832          * return appropriate return code
833          * no function extension is supported
834          */
835         if (update_calendar_attributes_extensions != NULL)
836                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
837
838         /* check authority */
839         if ((cal->file_version >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
840             !(cal->access & (CSA_OWNER_RIGHTS | CSA_INSERT_CALENDAR_ATTRIBUTES |
841             CSA_CHANGE_CALENDAR_ATTRIBUTES))) ||
842             (cal->file_version < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
843             !(cal->access & CSA_OWNER_RIGHTS)))
844                 return (CSA_E_NO_AUTHORITY);
845
846         /* check data type */
847         if ((stat = _DtCm_check_cal_csa_attributes(cal->file_version,
848             num_attrs, attrs, cal->name, B_TRUE, B_FALSE, B_TRUE))
849             != CSA_SUCCESS) {
850                 return (stat);
851         }
852
853         /* set attributes */
854         stat = _DtCm_rpc_set_cal_attrs(cal, num_attrs, attrs);
855
856         return (stat);
857 }
858
859 extern CSA_return_code
860 csa_add_entry(
861         CSA_session_handle      session,
862         CSA_uint32      num_attrs,
863         CSA_attribute   *attrs,
864         CSA_entry_handle        *entry_r,
865         CSA_extension   *add_entry_extensions)
866 {
867         CSA_return_code stat;
868         Calendar        *cal;
869         _DtCm_libentry  *entry;
870
871         DP(("api.c: csa_add_entry\n"));
872
873         if (num_attrs == 0 || attrs == NULL)
874                 return (CSA_E_INVALID_PARAMETER);
875
876         /* get calendar object */
877         if ((cal = _DtCm_get_Calendar(session)) == NULL)
878                 return (CSA_E_INVALID_SESSION_HANDLE);
879
880         /* check data type, readonly attributes, etc */
881         if ((stat = _DtCm_check_entry_attributes(cal->file_version,
882             num_attrs, attrs, CSA_CB_ENTRY_ADDED, B_TRUE)) != CSA_SUCCESS) {
883                 return (stat);
884         }
885
886         /* no function extension is supported */
887         if (add_entry_extensions != NULL)
888                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
889
890         /* insert in calendar */
891         if ((stat = _DtCm_rpc_insert_entry(cal, num_attrs, attrs, &entry))
892             == CSA_SUCCESS) {
893
894                 if (entry_r != NULL) {
895                         if ((entry = _DtCm_convert_entry_wheader(entry))==NULL)
896                                 stat = CSA_E_INSUFFICIENT_MEMORY;
897                         else {
898                                 _DtCm_add_to_entry_list(cal, (caddr_t)entry);
899                                 *entry_r = (CSA_entry_handle)entry;
900                         }
901                 } else
902                         _DtCm_free_libentries(entry);
903         }
904
905         return (stat);
906 }
907
908 /*
909  * The session argument is ignored in this implementation.
910  */
911 extern CSA_return_code
912 csa_delete_entry(
913         CSA_session_handle      session,
914         CSA_entry_handle        entryh,
915         CSA_enum        delete_scope,
916         CSA_extension   *delete_entry_extensions)
917 {
918         CSA_return_code stat;
919         _DtCm_libentry  *entry;
920         int             i;
921
922         DP(("api.c: csa_delete_entry\n"));
923
924         /* get entry object */
925         if ((entry = _DtCm_get_libentry(entryh)) == NULL)
926                 return (CSA_E_INVALID_ENTRY_HANDLE);
927
928         if (delete_scope < CSA_SCOPE_ALL || delete_scope > CSA_SCOPE_FORWARD)
929                 return (CSA_E_INVALID_ENUM);
930
931         /* check delete_entry_extensions and return appropriate return code */
932         /* no function extension is supported */
933         if (delete_entry_extensions != NULL)
934                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
935
936         /* delete entry from calendar */
937         stat = _DtCm_rpc_delete_entry(entry->cal, entry, delete_scope);
938
939         return (stat);
940 }
941
942 extern CSA_return_code
943 csa_free_time_search(
944         CSA_session_handle      session,
945         CSA_date_time_range     date_time_range,
946         CSA_time_duration       time_duration,
947         CSA_uint32              number_users,
948         CSA_calendar_user       *users,
949         CSA_free_time   **free_time,
950         CSA_extension   *free_time_search_extensions)
951 {
952         DP(("api.c: csa_free_time_search\n"));
953
954         return (CSA_E_NOT_SUPPORTED);
955 }
956
957 extern CSA_return_code
958 csa_list_entry_sequence(
959         CSA_session_handle      session,
960         CSA_entry_handle        entryh,
961         CSA_date_time_range     time_range,
962         CSA_uint32              *number_entries,
963         CSA_entry_handle        **entries,
964         CSA_extension   *list_entry_sequence_extensions)
965 {
966         CSA_return_code stat;
967         _DtCm_libentry  *entry, *elist;
968         cms_attribute   *rtype;
969         cms_attribute   *rtimes;
970         /* needed temporaryly */
971         time_t start = 0, end = 0;
972         char *ptr;
973
974         DP(("api.c: csa_list_entry_sequence\n"));
975
976         /* get entry object */
977         if ((entry = _DtCm_get_libentry(entryh)) == NULL)
978                 return (CSA_E_INVALID_ENTRY_HANDLE);
979
980         if (number_entries == NULL || entries == NULL)
981                 return (CSA_E_INVALID_PARAMETER);
982         else {
983                 *number_entries = 0;
984                 *entries = NULL;
985         }
986
987         /* check whether this entry repeats */
988         /* fail it if it's not a repeating event */
989         if (entry->cal->file_version < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
990                 rtype = &entry->e->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I];
991                 if (rtype->value == NULL ||
992                     rtype->value->item.sint32_value == CSA_X_DT_REPEAT_ONETIME)
993                 {
994                         return (CSA_E_INVALID_PARAMETER);
995                 }
996         } else {
997                 rtype = &entry->e->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I];
998                 if (rtype->value == NULL ||
999                     rtype->value->item.string_value == NULL ||
1000                     *(rtype->value->item.string_value) == NULL) {
1001                         return (CSA_E_INVALID_PARAMETER);
1002                 }
1003         }
1004
1005
1006         /* if this entry repeats indefinitely and time range is not
1007          * specified, fail it
1008          */
1009         if (time_range) {
1010                 if (_csa_iso8601_to_range(time_range, &start, &end) != 0)
1011                         return (CSA_E_INVALID_DATE_TIME);
1012         }
1013
1014         if (entry->cal->file_version < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION)
1015                 rtimes = &entry->e->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I];
1016         else
1017                 rtimes = &entry->e->attrs[CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I];
1018
1019         if (start == 0 && end == 0 &&
1020             (rtimes->value && rtimes->value->item.uint32_value
1021             == CSA_X_DT_DT_REPEAT_FOREVER))
1022                 return (CSA_E_INVALID_PARAMETER);
1023
1024         /* no function extension is supported */
1025         if (list_entry_sequence_extensions != NULL)
1026                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
1027
1028         /* lookup sequence */
1029         if ((stat = _DtCm_rpc_enumerate_sequence(entry->cal, entry, start, end,
1030             &elist)) == CSA_SUCCESS) {
1031
1032                 if (elist) {
1033                         *number_entries = _DtCm_add_to_entry_list(entry->cal,
1034                                         (caddr_t)elist);
1035                         stat = _DtCm_libentry_to_entryh(elist, number_entries,
1036                                         entries);
1037                 }
1038         }
1039
1040         return (stat);
1041 }
1042
1043 /*
1044  * Due to the implementation of existing backends (versions 2-4)
1045  * which will unmanage any reminders that happens before the
1046  * the given tick, the user specified tick is ignore and
1047  * we will pass in the current time.
1048  */
1049 extern CSA_return_code
1050 csa_read_next_reminder(
1051         CSA_session_handle      session,
1052         CSA_uint32      number_names,
1053         CSA_attribute_reference *reminder_names,
1054         CSA_date_time   given_time,
1055         CSA_uint32      *number_reminders,
1056         CSA_reminder_reference  **reminders,
1057         CSA_extension   *read_next_reminder_extensions)
1058 {
1059         CSA_return_code stat;
1060         Calendar        *cal;
1061         _DtCm_libentry  *eptr, *prev = NULL, *head = NULL;
1062         CSA_reminder_reference * rlist;
1063         int     i;
1064         time_t  timeval;
1065
1066         DP(("api.c: csa_read_next_reminder\n"));
1067
1068         /* get calendar object */
1069         if ((cal = _DtCm_get_Calendar(session)) == NULL)
1070                 return (CSA_E_INVALID_SESSION_HANDLE);
1071
1072         if (number_reminders == 0 || reminders == NULL)
1073                 return (CSA_E_INVALID_PARAMETER);
1074
1075         if (given_time == NULL || _csa_iso8601_to_tick(given_time, &timeval))
1076                 return (CSA_E_INVALID_DATE_TIME);
1077
1078         /*
1079          * check read_next_reminder_extensions and
1080          * return appropriate return code
1081          * no function extension is supported
1082          */
1083         if (read_next_reminder_extensions != NULL)
1084                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
1085
1086         /* lookup reminders */
1087         if ((stat = _DtCm_rpc_lookup_reminder(cal, timeval,
1088             number_names, reminder_names, number_reminders, reminders))
1089             == CSA_SUCCESS) {
1090
1091                 /*
1092                  * link up all associated entries
1093                  * and add to calendar structure
1094                  */
1095                 for (i = 0; i < *number_reminders; i++) {
1096                         eptr = (_DtCm_libentry *)((*reminders)[i]).entry;
1097
1098                         /* link entry back to cal */
1099                         eptr->cal = cal;
1100
1101                         /* link up entries in the same order as
1102                          * the associated reminders
1103                          */
1104                         if (head == NULL)
1105                                 head = eptr;
1106                         else {
1107                                 prev->next = eptr;
1108                                 eptr->prev = prev;
1109                         }
1110                         prev = eptr;
1111
1112                 }
1113
1114                 (void)_DtCm_add_to_entry_list(cal, (caddr_t)head);
1115         }
1116
1117         return (stat);
1118 }
1119
1120 /*
1121  * These arguments are ignored in this implementation:
1122  *      session, update_propagation
1123  */
1124 extern CSA_return_code
1125 csa_update_entry_attributes(
1126         CSA_session_handle      session,
1127         CSA_entry_handle        entry,
1128         CSA_enum                scope,
1129         CSA_boolean             update_propagation,
1130         CSA_uint32              num_attrs,
1131         CSA_attribute           *attrs,
1132         CSA_entry_handle        *new_entry,
1133         CSA_extension           *update_entry_attributes_extensions)
1134 {
1135         CSA_return_code stat;
1136         _DtCm_libentry  *oentry, *tptr, *nentry;
1137
1138         DP(("api.c: csa_update_entry_attributes\n"));
1139
1140         /* get entry object */
1141         if ((oentry = _DtCm_get_libentry(entry)) == NULL)
1142                 return (CSA_E_INVALID_ENTRY_HANDLE);
1143
1144         if (scope < CSA_SCOPE_ALL || scope > CSA_SCOPE_FORWARD)
1145                 return (CSA_E_INVALID_ENUM);
1146
1147         if (num_attrs == 0 || attrs == NULL)
1148                 return (CSA_E_INVALID_PARAMETER);
1149
1150         /*
1151          * check update_entry_attributes_extensions and
1152          * return appropriate return code
1153          * no function extension is supported
1154          */
1155         if (update_entry_attributes_extensions != NULL)
1156                 return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
1157
1158         /* check data type, readonly attributes, etc */
1159         if ((stat = _DtCm_check_entry_attributes(oentry->cal->file_version,
1160             num_attrs, attrs, CSA_CB_ENTRY_UPDATED, B_TRUE)) != CSA_SUCCESS) {
1161                 return (stat);
1162         }
1163
1164         /* change entry in calendar */
1165         if ((stat = _DtCm_rpc_update_entry(oentry->cal, oentry, num_attrs,
1166             attrs, scope, &nentry)) == CSA_SUCCESS) {
1167                 if (new_entry) {
1168                         if ((nentry = _DtCm_convert_entry_wheader(nentry))
1169                             == NULL)
1170                                 stat = CSA_E_INSUFFICIENT_MEMORY;
1171                         else {
1172                                 _DtCm_add_to_entry_list(oentry->cal,
1173                                         (caddr_t)nentry);
1174                                 *new_entry = (CSA_entry_handle)nentry;
1175                         }
1176                 } else
1177                         _DtCm_free_libentries(nentry);
1178         }
1179
1180         return (stat);
1181 }
1182
1183 /* ADD EVENT */
1184 extern CSA_return_code
1185 csa_add_event(
1186         CSA_service_reference   calendar_service,
1187         CSA_string              calendar_address,
1188         CSA_string              logon_user,
1189         CSA_string              logon_password,
1190         CSA_string              attendee,
1191         CSA_enum                attendee_priority,
1192         CSA_enum                attendee_status,
1193         CSA_boolean             attendee_rsvp_requested,
1194         CSA_date_time           start_date,
1195         CSA_date_time           end_date,
1196         CSA_string              organizer,
1197         CSA_string              sponsor,
1198         CSA_string              summary,
1199         CSA_string              description,
1200         CSA_string              recurrence_rule,
1201         CSA_string              exception_rule,
1202         CSA_string              subtype,
1203         CSA_enum                classification,
1204         CSA_string              delimiters,
1205         CSA_string              add_event_extensions)
1206 {
1207         DP(("api.c: csa_add_event\n"));
1208
1209         return (CSA_E_NOT_SUPPORTED);
1210 }
1211
1212 /* ADD TODO */
1213 CSA_return_code
1214 csa_add_todo(
1215         CSA_service_reference   calendar_service,
1216         CSA_string              calendar_address,
1217         CSA_string              logon_user,
1218         CSA_string              logon_password,
1219         CSA_enum                attendee_priority,
1220         CSA_enum                attendee_status,
1221         CSA_boolean             attendee_rsvp_requested,
1222         CSA_date_time           start_date,
1223         CSA_date_time           due_date,
1224         CSA_uint32              priority,
1225         CSA_string              summary,
1226         CSA_string              description,
1227         CSA_enum                classification,
1228         CSA_string              delimiters,
1229         CSA_string              add_todo_extensions)
1230 {
1231         DP(("api.c: csa_add_todo\n"));
1232
1233         return (CSA_E_NOT_SUPPORTED);
1234 }
1235
1236 /* ADD MEMO */
1237 CSA_return_code
1238 csa_add_memo(
1239         CSA_service_reference   calendar_service,
1240         CSA_string              calendar_address,
1241         CSA_string              logon_user,
1242         CSA_string              logon_password,
1243         CSA_date_time           start_date,
1244         CSA_string              summary,
1245         CSA_string              delimiters,
1246         CSA_string              add_memo_extensions)
1247 {
1248         DP(("api.c: csa_add_memo\n"));
1249
1250         return (CSA_E_NOT_SUPPORTED);
1251 }
1252
1253 /******************************************************************************
1254  * static functions used within in the file
1255  ******************************************************************************/
1256
1257 static CSA_return_code
1258 _handle_register_callback_ext(CSA_extension *ext)
1259 {
1260         int             i;
1261
1262         for (i = 0; ; i++) {
1263                 if (ext[i].item_code == CSA_X_XT_APP_CONTEXT_EXT) {
1264                         _DtCm_register_xtcallback(
1265                                 (XtAppContext)ext[i].item_data);
1266                 } else
1267                         return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
1268
1269                 if (ext[i].extension_flags & CSA_EXT_LAST_ELEMENT)
1270                         break;
1271         }
1272
1273         return (CSA_SUCCESS);
1274 }
1275
1276 static CSA_return_code
1277 _handle_logon_ext(CSA_extension *ext, CSA_extension **pext)
1278 {
1279         int             i;
1280         int             get_access_index = -1;
1281         int             com_support_index = -1;
1282
1283         for (i = 0; ; i++) {
1284                 if (ext[i].item_code == CSA_X_DT_GET_USER_ACCESS_EXT)
1285                         get_access_index = i;
1286                 else if (ext[i].item_code == CSA_X_COM_SUPPORT_EXT)
1287                         com_support_index = i;
1288                 else
1289                         return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
1290
1291                 if (ext[i].extension_flags & CSA_EXT_LAST_ELEMENT)
1292                         break;
1293         }
1294
1295         if (get_access_index >= 0)
1296                 *pext = &ext[get_access_index];
1297
1298         if (com_support_index >= 0)
1299                 _handle_com_support_ext(&ext[com_support_index]);
1300
1301         return (CSA_SUCCESS);
1302 }
1303
1304 static CSA_return_code
1305 _handle_query_config_ext(CSA_extension *ext)
1306 {
1307         int             i;
1308         int             com_support_index = -1;
1309
1310         for (i = 0; ; i++) {
1311                 if (ext[i].item_code == CSA_X_COM_SUPPORT_EXT) {
1312                         com_support_index = i;
1313                 } else
1314                         return (CSA_E_UNSUPPORTED_FUNCTION_EXT);
1315
1316                 if (ext[i].extension_flags & CSA_EXT_LAST_ELEMENT)
1317                         break;
1318         }
1319
1320         if (com_support_index >= 0)
1321                 _handle_com_support_ext(&ext[com_support_index]);
1322
1323         return (CSA_SUCCESS);
1324 }
1325
1326 static void
1327 _handle_com_support_ext(CSA_extension *ext)
1328 {
1329         int                     i;
1330         CSA_X_COM_support       *xcom;
1331
1332         for (i = 0, xcom = ext->item_reference; i < ext->item_data; i++) {
1333                 switch (xcom[i].item_code) {
1334                 case CSA_X_COM_SUPPORT_EXT:
1335                 case CSA_X_XT_APP_CONTEXT_EXT:
1336                 case CSA_XS_DT:
1337                 case CSA_X_DT_GET_USER_ACCESS_EXT:
1338                         xcom[i].flags = CSA_X_COM_SUPPORTED;
1339                         break;
1340
1341                 case CSA_XS_COM:
1342                 case CSA_X_UI_ID_EXT:
1343                 default:
1344                         xcom[i].flags = CSA_X_COM_NOT_SUPPORTED;
1345                         break;
1346                 }
1347         }
1348 }
1349