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