Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / libDtCmP / dtfns.c
1 /*******************************************************************************
2 **
3 **  dtfns.c
4 **
5 **  $XConsortium: dtfns.c /main/3 1995/11/03 10:37:35 rswiston $
6 **
7 **  RESTRICTED CONFIDENTIAL INFORMATION:
8 **
9 **  The information in this document is subject to special
10 **  restrictions in a confidential disclosure agreement between
11 **  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
12 **  document outside HP, IBM, Sun, USL, SCO, or Univel without
13 **  Sun's specific written approval.  This document and all copies
14 **  and derivative works thereof must be returned or destroyed at
15 **  Sun's request.
16 **
17 **  Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
18 **
19 *******************************************************************************/
20
21 /*                                                                      *
22  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
23  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
24  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
25  * (c) Copyright 1993, 1994 Novell, Inc.                                *
26  */
27
28
29 #ifndef lint
30 static  char sccsid[] = "@(#)dtfns.c 1.3 94/11/07 Copyr 1993 Sun Microsystems, Inc.";
31 #endif
32
33 /*
34  * Copyright 1993 Sun Microsystems, Inc.  All rights reserved
35  */
36
37 #ifdef FNS
38
39 #include <EUSCompat.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <netdb.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <stdio.h>
46 #include <fcntl.h>
47 #include <string.h>
48 #include <rpc/rpc.h>
49 #include <rpcsvc/nis.h>
50 #include <rpcsvc/nislib.h>
51 #include <rpcsvc/ypclnt.h>
52 #include <dlfcn.h>
53 #include <malloc.h>
54 #include <string.h>
55 #include <ctype.h>
56 #include <fns/fns.h>
57
58 #include "debug.h"
59
60 #include "util.h"
61 #include "dtfns.h"
62
63 extern char *strdup(const char *);
64
65 /*
66  * Names found in the initial context.  Used by isa_helix_name()
67  *
68  * XXX We have a bug here.  If a string happens to start with
69  * thisuser, myorg, etc we'll recognize it as an FNS name even
70  * though it may not be one.
71  */
72 static char *initial_context_names[] = {
73         "user:",
74         "thisuser",
75         "org:",
76         "site:",
77         "myorg",
78         "hostorg",
79         "host:",
80         NULL,
81 };
82 static void             *libfns_handle = NULL;
83 static int              initialized = 0;
84 static NS_Context_t     *initial_ctx = NULL;
85
86 /*
87  * These are dynamically bound entry points into libfns.  We dlopen()
88  * libfns so that cm can still run even if libfns does not exist
89  */
90 static NS_Context_t        *(*NS_Context_get_initial_p)(NS_ContextStatus_t *);
91 static NS_ContextStatus_t *(*NS_ContextStatus_new_p)(void);
92 static void             (*NS_ContextStatus_delete_p)(NS_ContextStatus_t *);
93 static NS_Reference_t      *(*NS_Context_lookup_p)(const NS_Context_t *,
94                                                   const NS_CompositeName_t *,
95                                                         NS_ContextStatus_t *);
96 static int                 (*NS_Context_bind_p)(const NS_Context_t *,
97                                                 const NS_CompositeName_t *,
98                                                 const NS_Reference_t *,
99                                                 unsigned,
100                                                 NS_ContextStatus_t *);
101
102 static NS_Reference_t   *(*NS_Reference_new_p)(const NS_String_t *);
103 static void             (*NS_Reference_delete_p)(const NS_Reference_t *);
104 static NS_String_t      *(*NS_Reference_type_p)(const NS_Reference_t *);
105 static int              (*NS_Reference_count_p)(const NS_Reference_t *);
106 static NS_ReferenceAddress_t *(*NS_Reference_first_p)(const NS_Reference_t *,
107                                                         void **);
108 static NS_ReferenceAddress_t    *(*NS_Reference_next_p)(const NS_Reference_t *,
109                                                         void **);
110 static int                      (*NS_Reference_append_addr_p)(NS_Reference_t *,
111                                                  const NS_ReferenceAddress_t *);
112 static int                      (*NS_Reference_prepend_addr_p)(NS_Reference_t *,
113                                                  const NS_ReferenceAddress_t *);
114 static int                      (*NS_Reference_insert_addr_p)(NS_Reference_t *,
115                                                  void **,
116                                                  const NS_ReferenceAddress_t *);
117 static int                      (*NS_Reference_delete_addr_p)(NS_Reference_t *,
118                                                               void **);
119 static void                     (*NS_ReferenceAddress_delete_p)(
120                                                 NS_ReferenceAddress_t *);
121
122 static NS_ReferenceAddress_t *(*NS_ReferenceAddress_new_p)(const NS_String_t *,
123                                                              unsigned,
124                                                              const void *);
125 static void *   (*NS_ReferenceAddress_data_p)(const NS_ReferenceAddress_t *);
126 static unsigned (*NS_ReferenceAddress_length_p)(const NS_ReferenceAddress_t *);
127 static NS_String_t *(*NS_ReferenceAddress_type_p)(const NS_ReferenceAddress_t*);
128
129
130 static const char *        (*NS_String_cstring_p)(const NS_String_t *);
131 static NS_String_t *       (*NS_String_from_cstring_p)(const char *);
132 static NS_CompositeName_t * (*NS_CompositeName_from_cstring_p)(const char *);
133
134
135 static int get_helix_service_name(const char *name, const char *service,
136                                   const char *service_type, char **buf);
137 /*
138  * Initialization.
139  *
140  * Load libfns (with dlopen) and bind in the entry points we use (with dlsym).
141  *
142  * We dynamically load the FNS library so that we don't have an explicit
143  * dependency  on it.  This lets us run on systems which do not have FNS
144  * installed
145  *
146  * Returns
147  *              0       FNS not available
148  *              1       Success
149  */
150 int
151 dtfns_init(void)
152
153 {
154         char    *libfns = FNS_LIBRARY;
155         int     error;  
156
157         if (libfns_handle != NULL) {
158                 return 1;
159         }
160
161         initialized = TRUE;
162
163         libfns_handle = dlopen(libfns, RTLD_LAZY);
164         if (libfns_handle == NULL) {
165 #ifdef CM_DEBUG
166                 char    *s = dlerror();
167                 if (s == NULL) {
168                         DP(("Could not dlopen %s\n", libfns));
169                 } else {
170                         DP(("Could not dlopen %s: %s\n", libfns, s));
171                 }
172 #endif
173                 return 0;
174         }
175
176         NS_Context_get_initial_p = (NS_Context_t *(*)(NS_ContextStatus_t *))
177                         dlsym(libfns_handle, "NS_Context_get_initial");
178
179         NS_ContextStatus_new_p = (NS_ContextStatus_t *(*)(void))
180                         dlsym(libfns_handle, "NS_ContextStatus_new");
181         NS_ContextStatus_delete_p = (void(*)(NS_ContextStatus_t *))
182                         dlsym(libfns_handle, "NS_ContextStatus_delete");
183
184         NS_Context_lookup_p = (NS_Reference_t *(*)(const NS_Context_t *,
185                                                   const NS_CompositeName_t *,
186                                                   NS_ContextStatus_t *))
187                         dlsym(libfns_handle, "NS_Context_lookup");
188
189         NS_Context_bind_p = (int(*)(const NS_Context_t *,
190                                                 const NS_CompositeName_t *,
191                                                 const NS_Reference_t *,
192                                                 unsigned,
193                                                 NS_ContextStatus_t *))
194                         dlsym(libfns_handle, "NS_Context_bind");
195
196         NS_Reference_new_p = (NS_Reference_t *(*)(const NS_String_t *))
197                         dlsym(libfns_handle, "NS_Reference_new");
198         NS_Reference_delete_p = (void(*)(const NS_Reference_t *))
199                         dlsym(libfns_handle, "NS_Reference_delete");;
200
201         NS_Reference_type_p = (NS_String_t *(*)(const NS_Reference_t *))
202                         dlsym(libfns_handle, "NS_Reference_type");
203
204         NS_Reference_count_p = (int(*)(const NS_Reference_t *))
205                         dlsym(libfns_handle, "NS_Reference_count");
206
207         NS_Reference_first_p = (NS_ReferenceAddress_t *(*)
208                                         (const NS_Reference_t *, void **))
209                         dlsym(libfns_handle, "NS_Reference_first");
210
211         NS_Reference_next_p = (NS_ReferenceAddress_t *(*)
212                                         (const NS_Reference_t *, void **))
213                         dlsym(libfns_handle, "NS_Reference_next");
214
215         NS_Reference_append_addr_p = (int(*)(NS_Reference_t *,
216                                              const NS_ReferenceAddress_t *))
217                         dlsym(libfns_handle, "NS_Reference_append_addr");
218
219         NS_Reference_prepend_addr_p = (int(*)(NS_Reference_t *,
220                                                 const NS_ReferenceAddress_t *))
221                         dlsym(libfns_handle, "NS_Reference_prepend_addr");
222
223         NS_Reference_insert_addr_p = (int(*)(NS_Reference_t *,
224                                           void **,
225                                           const NS_ReferenceAddress_t *))
226                         dlsym(libfns_handle, "NS_Reference_insert_addr");
227
228         NS_Reference_delete_addr_p = (int(*)(NS_Reference_t *, void **))
229                         dlsym(libfns_handle, "NS_Reference_delete_addr");
230
231         NS_ReferenceAddress_delete_p = (void(*)(NS_ReferenceAddress_t *))
232                         dlsym(libfns_handle, "NS_ReferenceAddress_delete");
233
234
235         NS_ReferenceAddress_new_p = (NS_ReferenceAddress_t *(*)
236                         (const NS_String_t *, unsigned, const void *))
237                         dlsym(libfns_handle, "NS_ReferenceAddress_new");
238
239         NS_ReferenceAddress_data_p = (void *(*)(const NS_ReferenceAddress_t *))
240                         dlsym(libfns_handle, "NS_ReferenceAddress_data");
241
242         NS_ReferenceAddress_length_p = (unsigned(*)
243                                         (const NS_ReferenceAddress_t *))
244                         dlsym(libfns_handle, "NS_ReferenceAddress_length");
245
246         NS_ReferenceAddress_type_p = (NS_String_t *(*)
247                                         (const NS_ReferenceAddress_t *))
248                         dlsym(libfns_handle, "NS_ReferenceAddress_type");
249
250         NS_String_cstring_p = (const char *(*)(const NS_String_t *))
251                         dlsym(libfns_handle, "NS_String_cstring");
252
253         NS_String_from_cstring_p = (NS_String_t * (*)(const char *))
254                         dlsym(libfns_handle, "NS_String_from_cstring");
255
256         NS_CompositeName_from_cstring_p =(NS_CompositeName_t *(*)(const char *))
257                         dlsym(libfns_handle, "NS_CompositeName_from_cstring");
258
259         return 1;
260 }
261
262 /*
263  * Check if FNS is available for use.
264  *
265  * You must call dfsinit() before calling this routine.
266  *
267  * First call to this routine may be costly as we get the initial context.
268  * Subsequent calls are very cheap.
269  *
270  * Returns
271  *              1       Yes, FNS is available.  
272  *              0       No, FNS is not available.
273  *              -1      You haven't called dtfns_init().
274  */
275 int
276 dtfns_available(void)
277
278 {
279         static int available;
280         static int called;
281
282         if (called) {
283                 return available;
284         }
285
286         if (libfns_handle != NULL) {
287
288                 /*
289                  * libfns has been dlopened.  Now see if an FNS namespace
290                  * is reachable by getting the initial context.
291                  */
292                 if (dtfns_get_initial_ctx() == NULL) {
293                         available = 0;
294                 } else {
295                         available = 1;
296                 }
297         } else if (initialized) {
298                 /* dlopen must have failed. FNS is not installed */
299                 available = 0;
300         } else {
301                 available = -1;
302         }
303         called = 1;
304
305         return available;
306 }
307
308 /*
309  * Get the initial context.  This routine caches the initial context.
310  * The first call to this routine may be costly, be subsequent calls
311  * are very cheap.
312  */
313 NS_Context_t *
314 dtfns_get_initial_ctx(void)
315
316 {
317         DP(("dtfns_get_initial_ctx: Getting initial context\n"));
318
319         if (initial_ctx == NULL) {
320                 NS_ContextStatus_t *    status;
321
322                 status = (*NS_ContextStatus_new_p)();
323                 initial_ctx = (*NS_Context_get_initial_p)(status);
324                 (*NS_ContextStatus_delete_p)(status);
325         }
326
327         return initial_ctx;
328 }
329
330 /*
331  * Generate a full Helix name for a service. 
332  *
333  *      'name' may be a relative Helix name.  I.e.:
334  *              smith
335  *              smith:service
336  *              smith:service:calendar
337  *      In this case dtfns_service_name() will use the type, service and org
338  *      parameters (if needed) to construct the full Helix name.
339  *
340  *      'name' may also be an absolute Helix name.  I.e.:
341  *              user:smith
342  *              org:ssi.eng:user:smith
343  *              user:smith:service
344  *      In this case dtfns_service_name() will use the type and service
345  *      parameters (if needed) to construct the full Helix name.  The org
346  *      parameter should be NULL (since the organization is already
347  *      determined by the absolute Helix name).
348  *
349  *      'type' specifies the type of object 'name' refers to (ie "user").
350  *
351  *      'service' specifies what service is desired (ie "calendar").
352  *
353  *      'service_type' specifies the reference type of the service
354  *      (ie SUNW_fns_calendar);
355  *
356  *      'org' is the organization name.  This must be NULL if 'name' is
357  *      an absolute Helix name.  'org' may be NULL in all other cases if the
358  *      default organization is to be used.
359  *
360  *      'buf' is a buffer provided by the caller in which the expanded name
361  *      is placed.
362  *
363  *      'size' is the size of 'buf'
364  *      
365  *
366  * The string returned in buf may be used in calls to dtfns_lookup_str() and
367  * dtfns_lookup_ref().
368  *
369  *      Returns
370  *              -1      Name not found / Error
371  *              0       FNS not available
372  *              1       Success
373  */
374 int
375 dtfns_service_name(
376         const char *name,       /* Name to lookup */
377         const char *type,       /* Type of object name is (ie "user") */
378         const char *service,    /* Service name (ie "calendar") */
379         const char *service_type, /* Service reference type     */
380                                   /* (ie "SUNW_fns_calendar");  */
381         const char *org,        /* Org name (ie "ssi").  NULL for default org */
382         char       *buf,        /* Buffer to place name in */
383         const int  size)        /* Size of value_buf */
384
385 {
386         char    *tmp_buf;
387         char    *type_str;
388
389         if (libfns_handle == NULL) {
390                 return 0;
391         }
392
393         if (name == NULL) {
394                 return -1;
395         }
396
397         if (org != NULL && *org != '\0') {
398                 /* Sanity check for size */
399                 if (strlen(org) + strlen(name) > (size_t)size - 50) {
400                         return -1;
401                 }
402
403                 /*Construct Helix name from name and organization */
404                 sprintf(buf,"%s:%s:%s:%s:%s:%s", DTFNS_ORG_NAME,
405                         org, type, name, DTFNS_SERVICE_NAME, service);
406         } else if (dtfns_isa_helix_name(name)) {
407                 /* Helix name. Expand it to point to calendar service */
408                 if (get_helix_service_name(name, service, service_type,
409                                                         &tmp_buf) < 0) {
410                         return -1;
411                 }
412                 buf[size - 1] = '\0';
413                 strncpy(buf, tmp_buf, size - 1);
414                 free(tmp_buf);
415
416         } else {
417                 /* Construct Helix name from name */
418                 sprintf(buf,"%s:%s:%s:%s", type,
419                         name, DTFNS_SERVICE_NAME, service);
420         }
421
422         return 1;
423 }
424
425 /*
426  * Return TRUE if 'name' is an absolute Helix name
427  */
428 int
429 dtfns_isa_helix_name(const char *name)
430
431 {
432         int     n, len;
433         char    **p;
434
435         for (p = initial_context_names; *p != NULL; p++) {
436                 len = strlen(*p);
437                 if (strncmp(name, *p, len) == 0) {
438                         return TRUE;
439                 }
440         }
441
442         return FALSE;
443 }
444
445 /*
446  * Get the org name for "myorg" (ie ssi.eng)
447  */
448 void
449 dtfns_myorg_name(char *buf, int len)
450
451 {
452         char            *__nis_local_root();
453         static char     *myorg_name;
454         char            *principal_name;
455         char            *host_domain;
456         char            *root_domain;
457         char            *pd = NULL;
458         char            *myorg_p, *root_p;
459
460         if (myorg_name == NULL) {
461                 principal_name  = nis_local_principal();
462                 host_domain     = nis_local_directory();
463                 root_domain     = __nis_local_root();
464
465                 if (principal_name) {
466                         /* Get the domain this principal is in */
467                         pd = nis_domain_of(principal_name);
468                         if (pd && *pd == '.') {
469                                 pd = NULL;
470                         }
471                 }
472
473                 /* If no domain for the principal, use the one for the host */
474                 myorg_name = strdup(pd ? pd : (host_domain ? host_domain : ""));
475
476                 /*
477                  * We want to strip the root domain name off of the
478                  * end of the myorg name.  Set pointers to the end
479                  * of each name
480                  */
481                 myorg_p = myorg_name + strlen(myorg_name) - 1;
482                 root_p  = root_domain + strlen(root_domain) - 1;
483
484                 while (tolower(*myorg_p) == tolower(*root_p)) {
485                         if (root_p == root_domain) {
486                                 /* Matched all of root domain name. Truncate */
487                                 if (myorg_p != myorg_name) {
488                                         *--myorg_p = '\0';
489                                 }
490                                 break;
491                         } else if (myorg_p == myorg_name) {
492                                 break;
493                         }
494                         --myorg_p;
495                         --root_p;
496                 }
497         }
498
499         if (myorg_name != NULL) {
500                 buf[len - 1] = '\0';
501                 strncpy(buf, myorg_name, len - 1);
502         }
503
504         return;
505 }
506
507 /*
508  * Return the string value bound to an absolute Helix name
509  *
510  *      Returns
511  *              -1      Error
512  *              0       FNS not available
513  *              1       Success
514  */
515 int
516 dtfns_lookup_str(
517         const char *name,       /* Absolute Helix name */
518                 char *types[],  /* Type of data to get */
519         char    *dbuf,          /* Buffer to place data value in */
520                 int dsize,      /* Size of dbuf */
521         char    *tbuf,          /* Buffer to place address type in */
522                 int tsize)      /* Size of tbuf */
523
524 {
525         NS_Reference_t *        ref;
526         const NS_ReferenceAddress_t *   addr;
527         void                    *iter_pos;
528
529         if (libfns_handle == NULL) {
530                 return 0;
531         }
532
533         /* Get the reference from the name */
534         if ((ref = dtfns_lookup_ref(name)) == NULL) {
535                 return -1;
536         }
537
538         /* Get the address that matches at least one of the specified types */
539         if ((addr = dtfns_addr_from_ref(ref, types, &iter_pos)) == NULL) {
540                 (*NS_Reference_delete_p)(ref);
541                 return -1;
542         }
543
544         (*NS_Reference_delete_p)(ref);
545
546         /* Return data bound to that address */
547         return dtfns_str_from_addr(addr, dbuf, dsize, tbuf, tsize);
548 }
549
550 /*
551  * 
552  *      Bind a string to a name.
553  *
554  *      name            Absolute Helix name to bind string to
555  *
556  *      ref_type        Reference type.  We need this to create
557  *                      the reference if it does not already exist.
558  *      
559  *      types           Array of address types. This routine looks for
560  *                      the address that matches at least one of these
561  *                      types.  The first type is used when the new
562  *                      string is bound.
563  *
564  *      new_str         String to bind to name
565  *
566  *      Returns
567  *              -1      Error
568  *              0       FNS not available
569  *              1       Success
570  */
571 int
572 dtfns_bind_str(
573         const char      *name,  /* Absolute Helix name */
574         const char      *ref_type,      /* Reference type */
575               char      *types[],       /* Address type of data to operate on */
576         const char      *new_str        /* String to bind to name */
577 )
578 {
579         NS_Reference_t          *ref = NULL;
580         const NS_ReferenceAddress_t     *addr = NULL;
581         NS_ReferenceAddress_t           *new_addr = NULL;
582         NS_CompositeName_t      *comp_name;
583         NS_ContextStatus_t      *status = NULL;
584         NS_Context_t            *ctx = NULL;
585         NS_String_t             *nstr;
586         void                    *iter_pos = NULL;
587         char                    buf[256];
588         int                     rcode = -1;
589
590         if (libfns_handle == NULL) {
591                 return 0;
592         }
593
594         /* Get the reference from the name */
595         if ((ref = dtfns_lookup_ref(name)) != NULL) {
596                 /*
597                  * A value is already bound to this name.
598                  * Get the address that matches at least one of
599                  * the specified types
600                  */
601                 addr = dtfns_addr_from_ref(ref, types, &iter_pos);
602                 if (addr != NULL) {
603                         /* Get string bound to that address */
604                         *buf = '\0';
605                         dtfns_str_from_addr(addr, buf, sizeof(buf), NULL, 0);
606
607                         /* Are we changing the string? */
608                         if (strcmp(buf, new_str) == 0) {
609                                 /* Bound value is the same as new value */
610                                 rcode = 1;
611                                 goto EXIT;
612                         } else {
613                                 /* Delete old address string */
614                                 (*NS_Reference_delete_addr_p)(ref, &iter_pos);
615                         }
616                 }
617         } else {
618                 /* Nothing bound to name.  Create an empty reference */
619                 nstr = (*NS_String_from_cstring_p)(ref_type);
620                 ref = (*NS_Reference_new_p)(nstr);
621                 iter_pos = NULL;
622         }
623
624         /* Create new address */
625         if ((new_addr = dtfns_create_str_addr(new_str, types[0])) == NULL) {
626                 goto EXIT;
627         }
628
629         /* Insert new address into reference */
630         if (dtfns_insert_addr(ref, &iter_pos, new_addr) < 1) {
631                 goto EXIT;
632         }
633
634         /* Bind reference into name space */
635         if ((ctx = dtfns_get_initial_ctx()) == NULL) {
636                 goto EXIT;
637         }
638
639         status = (*NS_ContextStatus_new_p)();
640         comp_name = (*NS_CompositeName_from_cstring_p)(name);
641
642         if ((*NS_Context_bind_p)(ctx, comp_name, ref, 0, status) < 1) {
643                 goto EXIT;
644         }
645
646         rcode = 1;
647
648 EXIT:
649         /* Clean up and return */
650         if (new_addr != NULL) (*NS_ReferenceAddress_delete_p)(new_addr);
651         if (ref    != NULL) (*NS_Reference_delete_p)(ref);
652         if (status != NULL) (*NS_ContextStatus_delete_p)(status);
653         return rcode;
654 }
655
656
657 /*
658  * Return the reference bound to an absolute Helix name
659  *
660  *      Returns
661  *              NULL    Error
662  *              NS_Reference_t * for reference
663  */
664 NS_Reference_t *
665 dtfns_lookup_ref(
666         const char     *name)/* Absolute Helix name to lookup */
667
668 {
669         NS_Reference_t *        ref = NULL;
670         NS_ContextStatus_t *    status = NULL;
671         NS_CompositeName_t *    comp_name = NULL;
672         NS_Context_t *          ctx;
673
674         if (libfns_handle == NULL) {
675                 return NULL;
676         }
677
678         status = (*NS_ContextStatus_new_p)();
679         if ((ctx = dtfns_get_initial_ctx()) != NULL) {
680                 /* Lookup the Helix name specified by "name" */
681                 comp_name = (*NS_CompositeName_from_cstring_p)(name);
682                 ref = (*NS_Context_lookup_p)(ctx, comp_name, status);
683         }
684
685         (*NS_ContextStatus_delete_p)(status);
686         return ref;
687 }
688
689 /*
690  * Takes a Helix name and converts it to a full name for a service.
691  * I.e. if service is "calendar":
692  *
693  *              name                             buf
694  *      org:ss-eng:user:dipol   -->     org:ss-eng:user:dipol:service:calendar
695  *      org:ss-eng              -->     org:ss-eng:service:calendar
696  *      org:ss-eng:service:     -->     org:ss-eng:service:calendar
697  *
698  * Returns
699  *              -1      Error.  buf not set
700  *              0       name already points to the service
701  *                      buf is a duplicate of name.
702  *              1       name resolved.  buf is set.  Caller
703  *                      is responsible for freeing memory.
704  */
705 static int
706 get_helix_service_name(
707         const char *name,
708         const char *service,
709         const char *service_type,
710         char **buf)
711
712 {
713         int             n;
714         char            *tmp_name;
715         NS_Reference_t  *ref;
716         NS_String_t     *nstr;
717         const char              *type;
718         char            *p;
719
720         n = strlen(name);
721         tmp_name = strdup(name);
722
723         /* Remove trailing : if there is one */
724         if (tmp_name[n - 1] == ':') {
725                 tmp_name[n - 1] = '\0';
726                 n--;
727         }
728
729         /* Get reference and extract reference type */
730         if ((ref = dtfns_lookup_ref(tmp_name)) == NULL) {
731                 return -1;
732         }
733
734         nstr = (*NS_Reference_type_p)(ref);
735         type = (*NS_String_cstring_p)(nstr);
736
737         (*NS_Reference_delete_p)(ref);
738
739         /* If name is already bound to a calendar service then we are done */
740         if (strcmp(type, service_type) == 0) {
741                 *buf = strdup(name);
742                 return 0;
743         }
744
745         if ((p = strrchr(tmp_name, ':')) != NULL) {
746                 p++;
747         }
748
749         /* 
750          * If name is a service context or the "service" null context
751          * then we want to append ":calendar"
752          */
753         if (strcmp(type, DTFNS_SERVICE_CONTEXT_TYPE) == 0 ||
754             (strcmp(type, DTFNS_NULL_CONTEXT_TYPE) == 0 && p != NULL &&
755             strcmp(p, DTFNS_SERVICE_NAME) == 0)) {
756
757                 *buf = (char *)malloc(n + strlen(service) + 2);
758                 if (*buf == NULL) {
759                         return -1;
760                 }
761                 strcpy(*buf, tmp_name);
762                 strcat(*buf, ":");
763                 strcat(*buf, service);
764                 return 1;
765         } else {
766                 /* Append ":service:calendar" */
767                 *buf = (char *)malloc(n + 
768                                                    strlen(DTFNS_SERVICE_NAME) +
769                                                    strlen(service) + 3);
770                 sprintf(*buf, "%s:%s:%s", tmp_name,
771                                         DTFNS_SERVICE_NAME, service);
772                 return 1;
773         }
774 }
775
776 /*
777  * Get an FNS Address from a Reference.
778  *
779  *      ref             The Reference to get the address from
780  *
781  *      types           NULL terminated array of one or more type strings.
782  *                      This routine returns the first address that matches
783  *                      a type specified in this array.  NULL to just
784  *                      get the first address.
785  *
786  *      iter_pos        Updated to point after retrieved address.
787  *
788  *      Returns
789  *              Pointer to the found address
790  *              NULL if no address is found
791  *
792  */
793 const NS_ReferenceAddress_t *
794 dtfns_addr_from_ref(
795         const NS_Reference_t    *ref,   /* Reference to get addr from */
796               char      *types[],       /* Types of addrs to get */
797         void            **iter_pos      /* Returned pos where addr was found */
798 )
799
800 {
801         const NS_ReferenceAddress_t     *addr;
802         char                    type[128];
803         char                    **p;
804
805         if (libfns_handle == NULL) {
806                 return 0;
807         }
808
809         addr = (*NS_Reference_first_p)(ref, iter_pos);
810         if (types == NULL) {
811                 return addr;
812         }
813
814         while (addr != NULL) {
815                 /* Get the type, and see if it is one we want */
816                 dtfns_str_from_addr(addr, NULL, 0, type, sizeof(type));
817                 for (p = types; *p != NULL && strcmp(*p, type) != 0; *p++)
818                         ;
819
820                 if (*p != NULL) {
821                         /* Found it! */
822                         break;
823                 } else {
824                         /* Get next address */
825                         addr = (*NS_Reference_next_p)(ref, iter_pos);
826                 }
827         }
828
829         return addr;
830 }
831
832 /*
833  * Get the string and type out of an Address
834  *
835  *      Returns
836  *              -1      Error
837  *              0       FNS not available
838  *              1       Success
839  */
840 int
841 dtfns_str_from_addr(
842         const NS_ReferenceAddress_t     *addr,  /* Addr to get string from */
843         char                    *dbuf,          /* Buf to hold string data */
844         int                     dbuf_size,      /* Size of dbuf */
845         char                    *tbuf,          /* Buf to hold string type */
846         int                     tbuf_size       /* size of tbuf */
847 )
848
849 {
850         XDR             xdr;
851         char            *s = NULL;
852         NS_String_t     *nstr;
853         const char      *cs;
854
855         if (libfns_handle == NULL) {
856                 return 0;
857         }
858
859         if (dbuf != NULL) {
860                 /* Convert data from XDR to a string */
861                 xdrmem_create(&xdr,
862                         (caddr_t)(*NS_ReferenceAddress_data_p)(addr),
863                         (*NS_ReferenceAddress_length_p)(addr), XDR_DECODE);
864
865                 if (xdr_string(&xdr, &s, ~0) == FALSE) {
866                         return -1;
867                 }
868
869                 dbuf[dbuf_size - 1] = '\0';
870                 strncpy(dbuf, s, dbuf_size - 1);
871                 free(s);
872         }
873
874         if (tbuf != NULL) {
875                 tbuf[tbuf_size - 1] = '\0';
876                 nstr = (*NS_ReferenceAddress_type_p)(addr);
877                 cs = (*NS_String_cstring_p)(nstr);
878                 strncpy(tbuf, cs, tbuf_size - 1);
879         }
880
881         return 1;
882 }
883
884 /*
885  * Create an Address of type "type" for the string specified by "data"
886  *
887  *      Returns
888  *              A new address contianing the specified data
889  *              NULL on an error
890  */
891 NS_ReferenceAddress_t *
892 dtfns_create_str_addr(
893         const char      *data,
894         const char      *type
895 )
896
897 {
898         XDR     xdr;
899         u_char  buf[1024];
900         NS_String_t     *nstring;
901
902         if (libfns_handle == NULL) {
903                 return NULL;
904         }
905
906         xdrmem_create(&xdr, (caddr_t)buf, sizeof(buf), XDR_ENCODE);
907         if (xdr_string(&xdr, (char**)&data, ~0) == FALSE) {
908                 return NULL;
909         }
910
911         nstring = (*NS_String_from_cstring_p)(type);
912         return (*NS_ReferenceAddress_new_p)(nstring, xdr_getpos(&xdr), buf);
913 }
914
915 /*
916  * Add an address to a reference at the location specified by iter_pos.
917  * The address is inserted before iter_pos.
918  * If *iter_pos is NULL then put the address in the first slot.
919  *
920  *      Returns
921  *              -1      Error
922  *              0       FNS not available
923  *              1       Success
924  */
925 int
926 dtfns_insert_addr(
927         NS_Reference_t          *ref,
928         void                    **iter_pos,
929         const NS_ReferenceAddress_t     *addr
930 )
931
932 {
933         if (libfns_handle == NULL) {
934                 return 0;
935         }
936
937         if (*iter_pos == NULL) {
938                 if ((*NS_Reference_prepend_addr_p)(ref, addr) < 1)
939                         return -1;
940         } else {
941                 if ((*NS_Reference_insert_addr_p)(ref, iter_pos, addr) < 1)
942                         return -1;
943         }
944
945         return 1;
946 }
947
948 /*
949  * Delete the Address at position "iter_pos" from a Reference
950  *
951  *      Returns
952  *              -1      Error
953  *              0       FNS not available
954  *              1       Success
955  */
956 int
957 dtfns_delete_addr(
958         NS_Reference_t          *ref,
959         void                    **iter_pos
960 )
961
962 {
963         if (libfns_handle == NULL) {
964                 return 0;
965         }
966
967         (*NS_Reference_delete_addr_p)(ref, iter_pos);
968
969         return 1;
970 }
971
972 #endif /* FNS */