Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / slib / mp_typedb.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 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $TOG: mp_typedb.C /main/5 1998/03/20 14:29:07 mgreess $                                                   
28 /*
29  * @(#)mp_typedb.C      1.54 93/07/29 SMI
30  *
31  * mp_typedb.cc - _Tt_typedb represents the database of ToolTalk types
32  *
33  * Copyright (c) 1990,1992 by Sun Microsystems, Inc.
34  */
35
36 //
37 // Contains methods for reading and writing type databases which can be
38 // stored either as Classing Engine databases or a native xdr format
39 // databases. 
40 //
41 #include <stdlib.h>
42 #if defined(linux)
43 # include <g++/minmax.h>
44 #else
45 # include <macros.h>
46 #endif
47 #include <fcntl.h>
48 #include "tt_options.h"
49 #include "mp/mp_arg.h"
50 #include "mp/mp.h"
51 #include "mp_otype.h"
52 #include "mp_ptype.h"
53 #include "mp_typedb.h"
54 #include "api/c/api_api.h"
55 #include "tttk/tttk.h"
56 #include <sys/stat.h>
57 #include <errno.h>
58 #include <sys/wait.h>
59 #include "mp_ce_attrs.h"
60 #ifdef OPT_CLASSING_ENGINE
61 /*
62  * See the comments in ./ce.h for why local includes are used instead of
63  * the real ce.h.
64  */
65 #       include "ce.h"
66 #       include "ce_err.h"
67 #endif
68 #include <stdlib.h>
69 #include <unistd.h>
70 #include "util/tt_enumname.h"
71 #include "util/tt_port.h"
72 #include "util/tt_gettext.h"
73 #include "util/tt_global_env.h"
74 #include "util/tt_xdr_version.h"
75
76 #if defined(ultrix)
77 extern "C" void xdrstdio_create(XDR *, FILE *, enum xdr_op);
78 #endif
79
80
81 enum _Tt_typedb_flags {
82         _TT_TYPEDB_USER,
83         _TT_TYPEDB_SYSTEM,
84         _TT_TYPEDB_NETWORK,
85         _TT_TYPEDB_XDR_MODE,
86         _TT_TYPEDB_LOCKED
87 };
88
89 #ifdef OPT_CLASSING_ENGINE
90 #       ifdef OPT_DLOPEN_CE
91 #               include <util/tt_ldpath.h>
92 #               include <dlfcn.h>
93
94         typedef void *(*_Tt_cefn_ptr)(...);
95         // Function-table for all Classing Engine functions used. Note
96         // that it is important that the function slots be named the
97         // same as the corresponding Classing Engine function. This is
98         // so the CALLCE macro works properly.
99         //
100         struct {
101                 _Tt_cefn_ptr    ce_abort_write;
102                 _Tt_cefn_ptr    ce_add_attribute;
103                 _Tt_cefn_ptr    ce_add_entry;
104                 _Tt_cefn_ptr    ce_add_namespace;
105                 _Tt_cefn_ptr    ce_alloc_entry;
106                 _Tt_cefn_ptr    ce_alloc_ns_entry;
107                 _Tt_cefn_ptr    ce_begin;
108                 _Tt_cefn_ptr    ce_commit_write;
109                 _Tt_cefn_ptr    ce_get_attribute;
110                 _Tt_cefn_ptr    ce_get_attribute_id;
111                 _Tt_cefn_ptr    ce_get_attribute_name;
112                 _Tt_cefn_ptr    ce_get_attribute_type;
113                 _Tt_cefn_ptr    ce_get_entry_db_info;
114                 _Tt_cefn_ptr    ce_get_namespace_id;
115                 _Tt_cefn_ptr    ce_map_through_attrs;
116                 _Tt_cefn_ptr    ce_map_through_entries;
117                 _Tt_cefn_ptr    ce_remove_entry;
118                 _Tt_cefn_ptr    ce_start_write;
119         } _tt_celib;
120         //
121         // define CALLCE such that it indirects through a function
122         // slot in _tt_celib which will be filled in by dlsyming
123         // entry points from a dynamically loaded libce.so
124         //
125 #       define CALLCE(fn) (*_tt_celib . fn)
126 #       else
127         // assume libce.so is linked in so CALLCE just becomes a
128         // function call.
129 #       define CALLCE(fn) fn
130 #       endif                           // OPT_DLOPEN_CE
131 /*
132  * Handle to the Type namespace
133  */
134 static CE_NAMESPACE     _ce_type_ns = (CE_NAMESPACE)0;
135 /* 
136  * Set of CE attributes used to avoid having to do string comparisons for
137  * string fields in the CE databases. Each CE namespace assigns unique
138  * numeric ids to all attribute names in order to provide a cheap way for
139  * clients to compare against attribute names.
140  */
141 static CE_ATTRIBUTE     _tt_attrs[_TT_CE_ATTR_LAST];
142 static CE_NAMESPACE     _ce_write_ns = (CE_NAMESPACE)0;
143 #endif                          // OPT_CLASSING_ENGINE
144
145
146 #ifdef OPT_CLASSING_ENGINE
147 _Tt_typedb::
148 _Tt_typedb(char *ce_dir)
149 {
150         _ce_dir = ce_dir;
151 #else
152 _Tt_typedb::
153 _Tt_typedb(char * /* ce_dir */)
154 {
155 #endif
156         _flags = 0;
157         ptable = new _Tt_ptype_table(_tt_ptype_ptid);
158         otable = new _Tt_otype_table(_tt_otype_otid);
159         ceDB2Use = TypedbAll;
160 }
161
162
163 _Tt_typedb::
164 ~_Tt_typedb()
165 {
166 }
167
168
169 //
170 // XDR's a _Tt_typedb object. 
171 bool_t _Tt_typedb::
172 xdr(XDR *xdrs)
173 {
174         if (!ptable.xdr(xdrs)) {
175                 return  0;
176         }
177
178         if (!otable.xdr(xdrs)) {
179                 return  0;
180         }
181
182         if  (xdrs->x_op == XDR_DECODE) {
183
184                 // We have to be sure that a null ptable or otable are
185                 // NEVER passed into the _Tt_object_table::xdr. XXX.
186
187                 if (ptable.is_null()) {
188                         ptable = new _Tt_ptype_table(_tt_ptype_ptid);
189                 }
190                 if (otable.is_null()) {
191                         otable = new _Tt_otype_table(_tt_otype_otid);
192                 }
193         }
194
195         return 1;
196 }
197
198
199
200 // 
201 // This function returns the full pathnames to the user database, system
202 // database, and network databases in udb, sdb, and ndb respectively.
203 // This three-level model of databases is intended to be similar to the
204 // Classing Engine model. The intent is that types in the user database
205 // shadow types in the system and network databases and that the types in
206 // the system database shadow the types in the network database. In order
207 // to provide some user-configurability, we provide an
208 // environment variable TTPATH that is a three-path list separated by ":"
209 // pointing to the user,system, and network databases. This function
210 // looks at that variable and returns the paths.
211 // 
212 //  If TTPATH isn't set this function should returns
213 //  $HOME/.tt/types.xdr for the user database, /etc/tt/types.xdr for the
214 //  system database, and $OPENWINHOME/etc/tt/types.xdr for the network
215 //  database.
216 // 
217 int
218 _tt_map_xdr_dbpaths(_Tt_string &udb, _Tt_string &sdb, _Tt_string &ndb)
219 {
220         _Tt_string_list_ptr path = _Tt_typedb::tt_path();
221         if (path.is_null()) return 1;
222         _Tt_string_list_cursor pathC( path );
223         if (! pathC.next()) {
224                 return 1;
225         }
226         udb = *pathC;
227         if (! pathC.next()) {
228                 return 1;
229         }
230         sdb = *pathC;
231         if (! pathC.next()) {
232                 return 1;
233         }
234         ndb = path->bot();
235         return 1;
236 }
237
238 _Tt_string_list *
239 _Tt_typedb::tt_path()
240 {
241         _Tt_string_list *pathlist = new _Tt_string_list;
242         if (pathlist == 0) return 0;
243         _Tt_string path = getenv("TTPATH");
244         if (path.len() <= 0) {
245                 _Tt_string home = getenv("HOME");
246                 pathlist->append(home.cat("/.tt/types.xdr"));
247                 pathlist->append(_Tt_string("/etc/tt/types.xdr"));
248                 pathlist->append(
249                         _Tt_string("/usr/dt/appconfig/tttypes/types.xdr"));
250                 home = getenv("OPENWINHOME");
251                 if (home.len() == 0) {
252                         home = "/usr/openwin";
253                 }
254                 pathlist->append(home.cat(_Tt_string("/etc/tt/types.xdr")));
255         } else {
256                 // parse the user:system:network from path variable
257                 int n = 0;
258                 _Tt_string pathname;
259                 while (n >= 0) {
260                         n = path.index(':');
261                         if (n > 0) {
262                                 pathname = path.left(n);
263                                 if (pathname.len() == 0) break;
264                                 path = path.right(path.len() - n - 1);
265                         } else {
266                                 pathname = path;
267                                 path = 0;
268                         }
269                         if (_tt_isdir(pathname)) {
270                                 pathname = pathname.cat("/types.xdr");
271                         }
272                         pathlist->append( pathname );
273                 }
274         }
275         return pathlist;
276 }
277
278
279 Tt_status _Tt_typedb::
280 init_xdr(const _Tt_string &compiled_file)
281 {
282         //
283         // A temporary is needed because
284         // a types file is an XDRed _Tt_typedb_ptr, (XXX)
285         // instead of an XDRed _Tt_typedb, and
286         // _Tt_typedb_ptr::xdr() creates a new _Tt_typedb.
287         // This was a bad choice, but we are stuck with it.
288         //
289         _Tt_typedb_ptr  tmpdb;
290         Tt_status       status;
291         //
292         // Need to remember what kind of _Tt_typedb we are,
293         // in case we are asked to remove or merge types.
294         //
295         _flags |= (1<<_TT_TYPEDB_XDR_MODE);
296         
297         status = merge_from(compiled_file, tmpdb);
298         if (status != TT_OK) {
299                 return(status);
300         }
301         //
302         // Now snare a reference to the tables of the temp db.
303         // The temp db goes away, but we keep its tables.
304         //
305         if (!tmpdb.is_null()) {
306                 ptable = tmpdb->ptable;
307                 otable = tmpdb->otable;
308         }
309         return TT_OK;
310 }
311
312 Tt_status _Tt_typedb::
313 init_xdr(FILE *f)
314 {
315         _Tt_typedb_ptr  tmpdb;
316         Tt_status       status;
317         int             version;
318
319         _flags |= (1<<_TT_TYPEDB_XDR_MODE);
320
321         status = merge_from(f, tmpdb, version);
322         if (status != TT_OK) {
323                 return(status);
324         }
325
326         if (!tmpdb.is_null()) {
327                 ptable = tmpdb->ptable;
328                 otable = tmpdb->otable;
329         }
330         return TT_OK;
331 }
332
333 // 
334 // Initializes this object from the given xdr database.
335 // Returns:
336 //      TT_ERR_PATH             Bad $TTPATH
337 //      TT_ERR_NO_MATCH         version mismatch
338 //      TT_ERR_DBCONSIST        XDR failure, corrupt database
339 // 
340 Tt_status _Tt_typedb::
341 init_xdr(_Tt_typedbLevel xdb)
342 {
343         _Tt_typedb_ptr          tmpdb;
344         Tt_status               status;
345         
346         if (! _tt_map_xdr_dbpaths(user_db, system_db, network_db)) {
347                 _tt_syslog(stderr, LOG_ERR, "$TTPATH: %s", strerror(EINVAL));
348                 return(TT_ERR_PATH);
349         }
350
351         _flags |= (1<<_TT_TYPEDB_XDR_MODE);
352         
353         // type files are read in in reverse order of TTPATH
354         // variable so that entries in databases to the left
355         // of others in TTPATH shadow those to the right.
356         
357         _Tt_string_list_ptr path;
358         switch (xdb) {
359             case TypedbAll:
360             default:
361                 path = tt_path();
362                 if (path.is_null()) {
363                         status = TT_ERR_NOMEM;
364                 } else {
365                         _Tt_string_list_cursor pathC( path );
366                         status = TT_OK;
367                         while (pathC.prev() && (status == TT_OK)) {
368                                 status = merge_from(*pathC, tmpdb);
369                         }
370                         if (status == TT_OK) {
371                                 _flags |= (1<<_TT_TYPEDB_NETWORK);
372                                 _flags |= (1<<_TT_TYPEDB_SYSTEM);
373                                 _flags |= (1<<_TT_TYPEDB_USER);
374                         }
375                 }
376                 break;
377             case TypedbNetwork:
378                 if (network_db.len()) {
379                         status = merge_from(network_db, tmpdb);
380                         if (status == TT_OK) {
381                                 _flags |= (1<<_TT_TYPEDB_NETWORK);
382                         }
383                 } else {
384                         _tt_syslog(stderr, LOG_ERR, "!network_db.len()");
385                         status = TT_ERR_INTERNAL;
386                 }
387                 break;
388             case TypedbSystem:
389                 if (system_db.len()) {
390                         status = merge_from(system_db, tmpdb);
391                         if (status == TT_OK) {
392                                 _flags |= (1<<_TT_TYPEDB_SYSTEM);
393                         }
394                 } else {
395                         _tt_syslog(stderr, LOG_ERR, "!system_db.len()");
396                         status = TT_ERR_INTERNAL;
397                 }
398                 break;
399             case TypedbUser:
400                 if (user_db.len()) {
401                         status = merge_from(user_db, tmpdb);
402                         if (status == TT_OK) {
403                                 _flags |= (1<<_TT_TYPEDB_USER);
404                         }
405                 } else if (xdb != TypedbAll) {
406                         _tt_syslog(stderr, LOG_ERR, "!user_db.len()");
407                         status = TT_ERR_INTERNAL;
408                 }
409                 break;
410         }
411         if (status != TT_OK) {
412                 return status;
413         }
414         if (!tmpdb.is_null()) {
415                 ptable = tmpdb->ptable;
416                 otable = tmpdb->otable;
417         }
418         return(TT_OK);
419 }
420
421
422 // 
423 // Merges (or reads) types from dbpath into a (new) _Tt_typedb in tdb
424 // 
425 Tt_status _Tt_typedb::
426 merge_from(const _Tt_string &dbpath, _Tt_typedb_ptr &tdb)
427 {
428         FILE                    *f;
429         Tt_status               result;
430         int                     version;
431
432         // The automatic converter (ttce2xdr) will just touch the
433         // user\'s .tt/types.xdr if there were no ToolTalk types in the
434         // classing engine db.  This means that a zero-length file
435         // is perfectly OK, it just contains no types.
436
437         struct stat     stat_buf;
438         if (stat( (char *)dbpath, &stat_buf ) == 0) {
439                 if (stat_buf.st_size == 0) {
440                         return TT_OK;
441                 }
442         }
443
444         if (f = fopen((char *)dbpath, "r")) {
445                 fcntl(fileno(f), F_SETFD, 1);   /* close on exec */
446                 result = merge_from(f, tdb, version);
447                 fclose(f);
448         } else {
449                 // It is OK for the database not to exist, ToolTalk runs
450                 // even if there are no types.
451                 result = TT_OK;
452         }
453         
454         if (result == TT_ERR_NO_MATCH) {
455                 // This file is newer than we are, so we cannot
456                 // decode it.
457                 _tt_syslog(stderr, LOG_ERR,
458                            catgets(_ttcatd, 2, 9,
459                                    "%s is a version %d types "
460                                    "database, and this version "
461                                    "can only read versions %d and earlier"),
462                            (char *)dbpath, version,
463                            TT_PUSH_ROTATE_XDR_VERSION);
464         } else if (result == TT_ERR_DBCONSIST) {
465                 _tt_syslog(stderr, LOG_ERR,
466                            catgets(_ttcatd, 2, 10,
467                                    "could not decode types from types "
468                                    "database: %s. It may be damaged."),
469                            (char *)dbpath);
470         }
471
472         return TT_OK;
473 }
474
475
476 // 
477 // Merges (or reads) types from f into a (new) _Tt_typedb in tdb
478 // 
479 Tt_status _Tt_typedb::
480 merge_from(FILE *f, _Tt_typedb_ptr &tdb, int &version)
481 {
482         XDR                     xdrs;
483
484         xdrstdio_create(&xdrs, f, XDR_DECODE);
485         return merge_from(&xdrs, tdb, version);
486 }
487
488 // 
489 // Merges (or reads) types from xdrs into a (new) _Tt_typedb in tdb
490 // 
491 // Picks the version off the xdr xstream and then invokes the
492 // xdr method on the given _Tt_typedb object to merge in the types.
493 // Used both by merge_from above to read in files and to handle
494 // the types sent over from clients via tt_session_types_load().
495 // 
496 Tt_status _Tt_typedb::
497 merge_from(XDR *xdrs, _Tt_typedb_ptr &tdb, int &version)
498 {
499         
500         if (! xdr_int(xdrs, &version)) {
501                 return TT_ERR_DBCONSIST;
502         }
503         if (version > TT_PUSH_ROTATE_XDR_VERSION) {
504                 // This file is newer than we are, so we cannot
505                 // decode it.
506                 return TT_ERR_NO_MATCH;
507         }
508         
509         _Tt_xdr_version xvers(version);
510         
511         if (! tdb.xdr(xdrs)) {
512                 return TT_ERR_DBCONSIST;
513         }
514         return TT_OK;
515 }
516
517 #ifdef OPT_CLASSING_ENGINE
518
519 // 
520 // Function that prints out the given Classing Engine error code to
521 // stderr.
522 // 
523 static void
524 print_ce_error(int ce_err)
525 {
526         _tt_syslog(stderr, LOG_ERR, "Classing Engine: %d (%s)",
527                    ce_err, _tt_enumname( (_Tt_ce_status)ce_err ));
528 }
529 #endif                          // OPT_CLASSING_ENGINE
530
531
532 // 
533 // Aborts a write transaction to a databse. If this is a write to an xdr
534 // database then the lock file is removed. Otherwise it is a Classing
535 // Engine database and the appropiate abort function is invoked.
536 // 
537 int _Tt_typedb::
538 abort_write()
539 {
540 #ifdef OPT_CLASSING_ENGINE
541         if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
542 #endif
543
544                 (void)unlink((char *)_lock_file);
545                 return(1);
546
547 #ifdef OPT_CLASSING_ENGINE
548         } else {
549                 int        ce_err;
550
551                 ce_err = (int)CALLCE(ce_abort_write)(0);
552
553                 return(ce_err != 0);
554         }
555 #endif                          // !OPT_CLASSING_ENGINE
556 }
557
558
559 // 
560 // Removes an otype with id otid from the database either in xdr format
561 // or in Classing Engine format. If the database is in xdr format then
562 // this method just removes the otype from the in-memory otype table
563 // since it is assumed that a subsequent _Tt_typedb::end_write will cause
564 // the in-memory otype table to supersede the one on disk. If the
565 // database is a Classing Engine database then we remove it using the
566 // appropiate Classing Engine routines.
567 // 
568 int _Tt_typedb::
569 remove_otype(_Tt_string otid)
570 {
571         _Tt_otype_ptr   ot;
572         if (! otable->lookup(otid,ot)) {
573                 return(1);
574         }
575
576 #ifdef OPT_CLASSING_ENGINE
577         char            *db_name, *db_path;
578
579         if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
580                 int                             ce_err;
581                 _Tt_signature_list_cursor       sigs;
582
583                 // remove the otype entry from the ce database
584                 // XXX: shouldn't this be done only if this entry was
585                 // in the database we have open for write?? (see how
586                 // this is done below in removing signatures)
587                 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
588                                                       (CE_ENTRY)ot->ce_entry);
589
590                 // remove all the observer signatures (which are
591                 // separate entries) from the ce databse.
592                 sigs.reset(ot->_osigs);
593                 while (ce_err == 0 && sigs.next()) {
594                         // get the db info for this ce entry.
595                         ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
596                                                               (CE_ENTRY)sigs->ce_entry,
597                                                               &db_name, &db_path);
598                         if (ce_err==0 && _ce_dir==db_name) {
599                                 // if this entry was in the ce
600                                 // database we have open for write
601                                 // then remove it.
602                                 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
603                                                                  (CE_ENTRY)sigs->ce_entry);
604                         }
605                 }
606
607                 // remove all the handler signatures (which are
608                 // separate entries) from the ce databse.
609                 sigs.reset(ot->_hsigs);
610                 while (ce_err == 0 && sigs.next()) {
611                         // get the db info for this ce entry.
612                         ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
613                                                               (CE_ENTRY)sigs->ce_entry,
614                                                               &db_name, &db_path);
615                         if (ce_err==0 && _ce_dir==db_name) {
616                                 // if this entry was in the ce
617                                 // database we have open for write
618                                 // then remove it.
619                                 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
620                                                                  (CE_ENTRY)sigs->ce_entry);
621                         }
622                 }
623                 if (ce_err != 0) {
624                         print_ce_error(ce_err);
625                         return(0);
626                 }
627         }
628 #endif                          // OPT_CLASSING_ENGINE
629
630         otable->remove(otid);
631         return(1);
632 }
633
634
635
636 // 
637 // Removes an ptype with id ptid from the database either in xdr format
638 // or in Classing Engine format. If the database is in xdr format then
639 // this method just removes the ptype from the in-memory ptype table
640 // since it is assumed that a subsequent _Tt_typedb::end_write will cause
641 // the in-memory ptype table to supersede the one on disk. If the
642 // database is a Classing Engine database then we remove it using the
643 // appropiate Classing Engine routines.
644 // 
645 int _Tt_typedb::
646 remove_ptype(_Tt_string ptid)
647 {
648         _Tt_ptype_ptr   pt;
649         if (! ptable->lookup(ptid,pt)) {
650                 return(1);
651         }
652
653 #ifdef OPT_CLASSING_ENGINE
654         char            *db_name, *db_path;
655
656         if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
657                 int                             ce_err;
658                 _Tt_signature_list_cursor       sigs;
659
660                 // remove the ptype entry from the database
661                 // XXX: shouldn't this be done only if this entry was
662                 // in the database we have open for write?? (see how
663                 // this is done below in removing signatures)
664                 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
665                                                  (CE_ENTRY)pt->ce_entry);
666
667                 // remove the ptype's observer signatures from the
668                 // database. 
669                 sigs.reset(pt->_osigs);
670                 while (ce_err==0 && sigs.next()) {
671                         // get the db info for this ce entry.
672                         ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
673                                                               (CE_ENTRY)sigs->ce_entry,
674                                                               &db_name, &db_path);
675                         if (ce_err==0 && _ce_dir==db_name) {
676                                 // if this entry was in the ce
677                                 // database we have open for write
678                                 // then remove it.
679                                 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
680                                                                  (CE_ENTRY)sigs->ce_entry);
681                         }
682                 }
683
684                 // remove the ptype's handler signatures from the database.
685                 sigs.reset(pt->_hsigs);
686                 while (ce_err==0 && sigs.next()) {
687                         // get the db info for this ce entry.
688                         ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
689                                                               (CE_ENTRY)sigs->ce_entry,
690                                                               &db_name, &db_path);
691                         if (ce_err==0 && _ce_dir==db_name) {
692                                 // if this entry was in the ce
693                                 // database we have open for write
694                                 // then remove it.
695                                 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
696                                                                  (CE_ENTRY)sigs->ce_entry);
697                         }
698                 }
699                 if (ce_err != 0) {
700                         print_ce_error(ce_err);
701                         return(0);
702                 }
703         }
704 #endif                          // OPT_CLASSING_ENGINE
705
706         ptable->remove(ptid);
707         return(1);
708 }
709
710
711 // 
712 // Inserts a new ptype into the ptype table for this type database. If
713 // this database is stored in xdr format then this method just inserts
714 // the object into the in-memory table since it assumes a subsequent
715 // invocation of _Tt_typedb::end_write will write out the new table to
716 // disk. In Classing Engine format we create a Classing Engine entry and
717 // then use the appropiate ce functions to insert it into the database.
718 // 
719 int _Tt_typedb::
720 insert(_Tt_ptype_ptr &pt)
721 {
722
723         ptable->insert(pt);
724
725
726 #ifndef OPT_CLASSING_ENGINE
727         return(1);
728 #else   
729         if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
730                 return(1);
731         }
732
733         int                             ce_err;
734         _Tt_signature_list_cursor       sigs;
735
736         pt->ce_entry = make_ce_entry(pt);
737         ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns, pt->ce_entry);
738
739         // insert all observer signatures as separate classing engine
740         // entries. 
741         sigs.reset(pt->_osigs);
742         while (ce_err==0 && sigs.next()) {
743                 if (sigs->otid().len()) {
744                         continue;
745                 }
746                 sigs->ce_entry = (void *)make_ce_entry(*sigs);
747                 if (sigs->ce_entry == (void *)0) {
748                         return(0);
749                 }
750                 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
751                                               (CE_ENTRY)sigs->ce_entry);
752         }
753
754         // insert all handler signatures as separate classing engine
755         // entries. 
756         sigs.reset(pt->_hsigs);
757         while (ce_err==0 && sigs.next()) {
758                 if (sigs->otid().len()) {
759                         continue;
760                 }
761                 sigs->ce_entry = (void *)make_ce_entry(*sigs);
762                 if (sigs->ce_entry == (void *)0) {
763                         return(0);
764                 }
765                 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
766                                               (CE_ENTRY)sigs->ce_entry);
767         }
768         if (ce_err != 0) {
769                 print_ce_error(ce_err);
770                 return(0);
771         }
772
773         return(1);
774 #endif                          // !OPT_CLASSING_ENGINE
775
776 }
777
778
779 // 
780 // Inserts a new otype into the ptype table for this type database. If
781 // this database is stored in xdr format then this method just inserts
782 // the object into the in-memory table since it assumes a subsequent
783 // invocation of _Tt_typedb::end_write will write out the new table to
784 // disk. In Classing Engine format we create a Classing Engine entry and
785 // then use the appropiate ce functions to insert it into the database.
786 // 
787 int _Tt_typedb::
788 insert(_Tt_otype_ptr &ot)
789 {
790
791         otable->insert(ot);
792
793 #ifndef OPT_CLASSING_ENGINE
794         return(1);
795 #else   
796         if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
797                 return(1);
798         }
799
800         int                             ce_err;
801         _Tt_signature_list_cursor       sigs;
802
803         ot->ce_entry =  make_ce_entry(ot);
804         if (ot->ce_entry == (void *)0) {
805                 return(0);
806         }
807         ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns, ot->ce_entry);
808
809         // insert all the otype's observer signatures as separate
810         // entries. 
811         sigs.reset(ot->_osigs);
812         while (ce_err==0 && sigs.next()) {
813                 sigs->ce_entry = (void *)make_ce_entry(*sigs);
814                 if (sigs->ce_entry == (void *)0) {
815                         return(0);
816                 }
817                 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
818                                               (CE_ENTRY)sigs->ce_entry);
819         }
820
821         // insert all the otype's handler signatures as separate
822         // entries. 
823         sigs.reset(ot->_hsigs);
824         while (ce_err==0 && sigs.next()) {
825                 sigs->ce_entry = (void *)make_ce_entry(*sigs);
826                 if (sigs->ce_entry == (void *)0) {
827                         return(0);
828                 }
829                 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
830                                               (CE_ENTRY)sigs->ce_entry);
831         }
832         if (ce_err != 0) {
833                 print_ce_error(ce_err);
834                 return(0);
835         }
836
837         return(1);
838 #endif                          // !OPT_CLASSING_ENGINE
839 }
840
841
842 // 
843 // Prepares the database to be written out to disk. In Classing Engine
844 // mode this means we have to add the ToolTalk namespace to the database
845 // if it doesn't exist and invoke the appropiate Classing Engine function
846 // to start the write transaction. In xdr mode, we have to acquire the
847 // lock file to write out the database.
848 // 
849 int _Tt_typedb::
850 #ifdef OPT_CLASSING_ENGINE
851 begin_write(_Tt_typedbLevel db)
852 #else
853 begin_write(_Tt_typedbLevel /* db */)
854 #endif
855 {
856 #ifdef OPT_CLASSING_ENGINE
857         if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
858                 CE_ENTRY        cn;
859                 int             ce_err;
860                 int             i;
861                 _Tt_string      val;
862                 int             namespace_created = 0;
863
864                 ce_err = (int)CALLCE(ce_start_write)(level_name(db));
865                 if (ce_err != 0) {
866                         print_ce_error(ce_err);
867                         return(0);
868                 }
869                 ce_err = (int)CALLCE(ce_add_namespace)(TT_NS_NAME, &_ce_write_ns);
870                 switch (ce_err) {
871                       case 0:
872                         // namespace not already there add it
873                         ce_err = (int)CALLCE(ce_alloc_ns_entry)(_ce_write_ns, &cn);
874                         if (ce_err != 0) {
875                                 print_ce_error(ce_err);
876                                 return(0);
877                         }
878                         val = "$CEPATH/tns_mgr.so";
879                         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
880                                                           "NS_MANAGER",
881                                                           "string",
882                                                           val, val.len());
883                         for (i=0; ce_err == 0 && i < _TT_CE_ATTR_LAST; i++) {
884                                 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns,
885                                                                 &cn);
886                                 if (ce_err != 0) {
887                                         break;
888                                 }
889                                 val = "$CEPATH/tns_mgr.so";
890                                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns,
891                                                                   &cn,
892                                                                   _tt_ce_attr_string((_Tt_ce_attr)i), "string", "attr", strlen("attr"));
893                         }
894                         if (ce_err != 0) {
895                                 print_ce_error(ce_err);
896                                 return(0);
897                         }
898                         namespace_created = 1;
899                         // fall into next case
900                       case CE_ERR_NAMESPACE_EXISTS:
901                         if (!namespace_created) {
902                                 _ce_write_ns = _ce_type_ns;
903                         }
904                         _ce_dir = level_name(db);
905                         return(1);
906                       default:
907                         print_ce_error(ce_err);
908                         break;
909                 }
910
911                 return(0);
912         }
913 #endif                          // OPT_CLASSING_ENGINE
914
915         int             n;
916         int             fd;
917         _Tt_string      path;
918         _Tt_string      dir_path;
919
920         // acquire a write lock
921         if (_flags&(1<<_TT_TYPEDB_USER)) {
922                 path = user_db;
923         } else if (_flags&(1<<_TT_TYPEDB_SYSTEM)) {
924                 path = system_db;
925         } else if (_flags&(1<<_TT_TYPEDB_NETWORK)) {
926                 path = network_db;
927         }
928
929         n = path.rindex('/');
930         if (n == -1) {
931                 dir_path = ".";
932         } else {
933                 dir_path = path.left(n);
934                 
935         }
936         _lock_file = dir_path.cat("/.tt_lock");
937         n = 0;
938
939         // mkdir in case the "tt" or ".tt" subdirectory doesn't exist.
940
941         (void)mkdir((char *)dir_path, 0777); // ignore errors, probably EEXIST
942
943         while ((fd = open((char *)_lock_file,
944                           O_WRONLY|O_CREAT|O_EXCL, 0777) == -1)
945                 && errno == EEXIST)
946         {
947                 _tt_syslog(stderr, LOG_ERR, "%s: %m",
948                            (char *)_lock_file, strerror(EEXIST));
949                 if (n++ == 5) {
950                         _flags &= ~(1<<_TT_TYPEDB_LOCKED);
951                         return(0);
952                 }
953                 sleep(2);
954         }
955         if (fd > -1 ) {
956                 close(fd);      // Cleanup
957         }
958         _flags |= (1<<_TT_TYPEDB_LOCKED);
959         return(1);
960 }
961
962
963 // 
964 // Commits the write transaction to the database. In Classing Engine mode
965 // we just call the ce_commit_write function. In xdr mode we write out
966 // the database to a temporary file and then rename the file to be the
967 // appropiate path.
968 // 
969 int _Tt_typedb::
970 end_write()
971 {
972 #ifdef OPT_CLASSING_ENGINE
973         if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
974                 int     ce_err = (int)CALLCE(ce_commit_write)(0);
975
976                 if (ce_err != 0) {
977                         print_ce_error(ce_err);
978                         return(0);
979                 }
980
981                 return(1);
982         }
983 #endif                          // OPT_CLASSING_ENGINE
984
985         _Tt_string              dbpath;
986         _Tt_string              dbpath_tmp;
987         int                     success;
988
989         if (!(_flags&(1<<_TT_TYPEDB_LOCKED))) {
990                 return(0);
991         }
992         if (_flags&(1<<_TT_TYPEDB_USER)) {
993                 dbpath = user_db;
994         } else if (_flags&(1<<_TT_TYPEDB_SYSTEM)) {
995                 dbpath = system_db;
996         } else if (_flags&(1<<_TT_TYPEDB_NETWORK)) {
997                 dbpath = network_db;
998         }
999         dbpath_tmp = dbpath.cat("_tmp");
1000         success = write(dbpath_tmp) == TT_OK;
1001         if (! success) {
1002                 (void)unlink((char *)dbpath_tmp);
1003                 (void)unlink((char *)_lock_file);
1004                 return(0);
1005         }
1006
1007         success = (0 == rename((char *)dbpath_tmp, (char *)dbpath));
1008         if (success) {
1009                 send_saved( dbpath );
1010                 _tt_syslog(stdout, LOG_INFO,
1011                            catgets(_ttcatd, 2, 11, "Overwrote %s"),
1012                            (char *)dbpath);
1013         } else {
1014                 _tt_syslog(stderr, LOG_ERR,
1015                            "rename( \"%s\", \"%s\" ): %m",
1016                            (char *)dbpath_tmp, (char *)dbpath);
1017         }
1018         (void)unlink((char *)_lock_file);
1019         (void)unlink((char *)dbpath_tmp);
1020         return(success);
1021 }
1022
1023 Tt_status _Tt_typedb::
1024 write(const _Tt_string &outfile)
1025 {
1026         if (outfile.len() == 0) {
1027                 return TT_DESKTOP_ENOENT;
1028         }
1029         FILE *f = fopen((char *)outfile,"w");
1030         if (f == 0) {
1031                 _tt_syslog(stderr, LOG_ERR, "%s: %m", (char *)outfile);
1032                 return _tt_errno_status( errno );
1033         }
1034         fcntl(fileno(f), F_SETFD, 1);   /* Close on exec */
1035         Tt_status status = write( f );
1036         fclose(f);
1037         return status;
1038 }
1039
1040 Tt_status _Tt_typedb::
1041 write(FILE *outfile)
1042 {
1043         int     xdr_version;
1044         XDR     xdrs;
1045         _Tt_typedb_ptr          tdb_ptr = this;
1046
1047         // For maximum compatibility, only write out types files
1048         // using the new XDR routines if the signatures have
1049         // contexts.
1050         xdr_version = xdr_version_required();
1051         _Tt_xdr_version xvers(xdr_version);
1052  
1053         xdrstdio_create(&xdrs, outfile, XDR_ENCODE);
1054         if (! xdr_int(&xdrs, &xdr_version) || ! tdb_ptr.xdr(&xdrs)) {
1055                 _tt_syslog(stderr, LOG_ERR, "! _Tt_typedb_ptr::xdr()" );
1056                 return TT_ERR_XDR;
1057         }
1058         return TT_OK;
1059 }
1060
1061 //
1062 // Do a tt_open() (if needed) and a ttdt_file_notice(), syslog()ing any error.
1063 //
1064 Tt_status _Tt_typedb::
1065 send_saved(const _Tt_string &savedfile)
1066 {
1067         const char      *default_opt = "Saved";
1068
1069         char *procid = tt_default_procid();
1070         Tt_status status = tt_ptr_error( procid );
1071         switch (status) {
1072             case TT_OK:
1073                 tt_free( procid );
1074                 break;
1075             case TT_ERR_NOMP:
1076             case TT_ERR_PROCID:
1077                 procid = tt_open();
1078                 status = tt_ptr_error( procid );
1079                 if (status == TT_OK) {
1080                         tt_free( procid );
1081                 }
1082         }
1083         if (status != TT_OK) {
1084                 //
1085                 // No default session from which to send the notice,
1086                 // so silently omit it.  In principle libtt can send
1087                 // a file-scoped notice without having a default session,
1088                 // but the API does not permit this.
1089                 //
1090                 return status;
1091         }
1092         //
1093         // The HP linker thinks that ttdt_file_notice() ultimately
1094         // depends on some Xt symbols.  The HP linker is wrong.
1095         // The AIX linker knows better.  On SunOS, of course, we
1096         // use dlopen().
1097         //
1098         Tt_message msg = tt_message_create();
1099         tt_message_class_set( msg, TT_NOTICE );
1100         tt_message_scope_set( msg, TT_FILE );
1101         tt_message_address_set( msg, TT_PROCEDURE );
1102         tt_message_op_set( msg, default_opt );
1103         status = tt_message_file_set( msg, savedfile );
1104         if (status != TT_OK) {
1105                 _tt_syslog(stderr, LOG_ERR,
1106                    "tt_message_file_set(): %s", tt_status_message(status));
1107         }
1108         tt_message_arg_add( msg, TT_IN, "File", 0 );
1109         status = tt_message_send( msg );
1110         if (status != TT_OK) {
1111                 _tt_syslog(stderr, LOG_ERR,
1112                            "tt_message_send(): %s", tt_status_message(status));
1113         }
1114         return status;
1115 }
1116
1117 #ifdef OPT_CLASSING_ENGINE
1118
1119 //
1120 // Creates a Classing Engine entry from a pointer to a _Tt_ptype
1121 // object. A CE entry is essentially an attribute/value list. The
1122 // names of the attributes are derived from the function
1123 // _tt_ce_attr_string which returns a string from an enum describing
1124 // the attribute that is to be written out.
1125 //
1126 void * _Tt_typedb::
1127 make_ce_entry(_Tt_ptype_ptr &pt)
1128 {
1129         CE_ENTRY                        cn;
1130         int                             ce_err;
1131         const char                      *val;
1132         int                             len;
1133         _Tt_ptype_prop_list_cursor      props;
1134
1135         ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1136         if (ce_err != 0) {
1137                 print_ce_error(ce_err);
1138                 return(void *)0;
1139         }
1140         val = (char *)pt->ptid();
1141         len = pt->ptid().len();
1142         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1143                                   _tt_ce_attr_string(_TYPE_NAME),
1144                                   _tt_ce_attr_string(_TT_TOOLTALK_PTYPE),
1145                                   val, len);
1146         if (ce_err != 0) {
1147                 print_ce_error(ce_err);
1148                 return(void *)0;
1149         }
1150         val = _tt_ce_attr_string(_TT_TOOLTALK_PTYPE);
1151         len = strlen(val);
1152         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1153                                           _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1154                                           "string", val,len);
1155         if (ce_err != 0) {
1156                 print_ce_error(ce_err);
1157                 return(void *)0;
1158         }
1159         props.reset(pt->_props);
1160         while (props.next()) {
1161                 val = (char *)props->value();
1162                 len = props->value().len();
1163                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1164                                                   (char *)props->name(),
1165                                                   "string", val, len);
1166                 if (ce_err != 0) {
1167                         print_ce_error(ce_err);
1168                         return(void *)0;
1169                 }
1170         }
1171
1172         return((void *)cn);
1173 }
1174
1175 //
1176 // Creates a Classing Engine entry from a pointer to a _Tt_otype
1177 // object. A CE entry is essentially an attribute/value list. The
1178 // names of the attributes are derived from the function
1179 // _tt_ce_attr_string which returns a string from an enum describing
1180 // the attribute that is to be written out.
1181 //
1182 void * _Tt_typedb::
1183 make_ce_entry(_Tt_otype_ptr &ot)
1184 {
1185         CE_ENTRY                        cn;
1186         int                             ce_err;
1187         _Tt_string_list_cursor          anc;
1188         const char                     *val;
1189         int                             len;
1190
1191         ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1192         if (ce_err != 0) {
1193                 print_ce_error(ce_err);
1194                 return((void *)0);
1195         }
1196         val = (char *)ot->_otid;
1197         len = ot->_otid.len();
1198         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1199                                           _tt_ce_attr_string(_TYPE_NAME),
1200                                           _tt_ce_attr_string(_TT_TOOLTALK_OTYPE),
1201                                           val, len);
1202         if (ce_err != 0) {
1203                 print_ce_error(ce_err);
1204                 return((void *)0);
1205         }       
1206         val = _tt_ce_attr_string(_TT_TOOLTALK_OTYPE);
1207         len = strlen(val);
1208         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1209                                           _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1210                                           "string", val, len);
1211         if (ce_err != 0) {
1212                 print_ce_error(ce_err);
1213                 return((void *)0);
1214         }
1215         if (! ot->_ancestors.is_null()) {
1216                 anc.reset(ot->_ancestors);
1217                 while (anc.next()) {
1218                         val = (char *)*anc;
1219                         len = strlen(val);
1220                         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1221                                                           _tt_ce_attr_string(_TT_PARENT),
1222                                                           "string",val, len);
1223
1224                         if (ce_err != 0) {
1225                                 print_ce_error(ce_err);
1226                                 return(void *)0;
1227                         }
1228                 }
1229         }
1230
1231         return((void *)cn);
1232 }
1233
1234
1235 //
1236 // Creates a Classing Engine entry from a pointer to a _Tt_signature
1237 // object. A CE entry is essentially an attribute/value list. The
1238 // names of the attributes are derived from the function
1239 // _tt_ce_attr_string which returns a string from an enum describing
1240 // the attribute that is to be written out.
1241 //
1242 void * _Tt_typedb::
1243 make_ce_entry(_Tt_signature_ptr &st)
1244 {
1245         CE_ENTRY                cn;
1246         int                     ce_err;
1247         _Tt_arg_list_cursor     argc;
1248         _Tt_string              val;
1249         const char             *name;
1250         Tt_mode                 amode;
1251
1252         ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1253         if (ce_err != 0) {
1254                 print_ce_error(ce_err);
1255                 return(void *)0;
1256         }
1257         if (st->_mangled_args.len() == 0) {
1258                 // in order to uniquely name this signature we have to
1259                 // play the same tricks that C++ does and write out
1260                 // the ptype or otype, the operation name of the
1261                 // signature and then an encoding of the signature
1262                 // argument types to distinguish it in the case of
1263                 // overloading. 
1264
1265                 st->_mangled_args = "_";
1266                 argc.reset(st->_args);
1267                 while (argc.next()) {
1268                         amode = argc->mode();
1269                         st->_mangled_args = st->_mangled_args.cat(_tt_enumname(amode)).cat(argc->type()).cat("_");
1270                 }
1271         }
1272
1273         val = ((st->_otid.len()) ? st->_otid : st->_ptid);
1274         val = val.cat("::").cat(st->_op).cat(st->_mangled_args);
1275         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1276                                           _tt_ce_attr_string(_TYPE_NAME),
1277                                           _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1278                                           (char *)val, val.len());
1279         if (ce_err != 0) {
1280                 print_ce_error(ce_err);
1281                 return(void *)0;
1282         }
1283         val = _tt_ce_attr_string(_TT_TOOLTALK_SIGNATURE);
1284         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1285                                           _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1286                                           "string", (char *)val, val.len());
1287         if (ce_err != 0) {
1288                 print_ce_error(ce_err);
1289                 return(void *)0;
1290         }
1291
1292         val = st->_op;
1293         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1294                                           _tt_ce_attr_string(_TT_OP),
1295                                           "string", (char *)val, val.len());
1296         if (ce_err != 0) {
1297                 print_ce_error(ce_err);
1298                 return(void *)0;
1299         }
1300
1301         val = _tt_enumname(st->_pattern_category);
1302         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1303                                           _tt_ce_attr_string(_TT_CATEGORY),
1304                                           "string", (char *)val, val.len());
1305         if (ce_err != 0) {
1306                 print_ce_error(ce_err);
1307                 return(void *)0;
1308         }
1309
1310         argc.reset(st->_args);
1311         int argn=0;
1312         _Tt_string      argc_type;
1313         char *attrname =
1314           (char *)malloc(strlen(_tt_ce_attr_string(_TT_ARG)) + 5);
1315         char *attrnamenum = attrname+strlen(_tt_ce_attr_string(_TT_ARG));
1316         strcpy(attrname,_tt_ce_attr_string(_TT_ARG));
1317
1318         while (argc.next()) {
1319                 sprintf((char *)attrnamenum, "%d", argn);
1320                 val = _tt_enumname(argc->mode());
1321                 argc_type = argc->type();
1322                 val = val.cat(" ").cat(argc_type).cat(" ").cat(argc->name());
1323                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1324                                                        attrname,
1325                                                        "string",
1326                                                        (char *)val, val.len());
1327                 if (ce_err != 0) {
1328                         print_ce_error(ce_err);
1329                         return(void *)0;
1330                 }
1331                 argn++;
1332         }
1333         free(attrname);
1334
1335         name = ((st->_otid.len()) ? _tt_ce_attr_string(_TT_MSET_SCOPE) :
1336                 _tt_ce_attr_string(_TT_SCOPE));
1337         val = _tt_enumname(st->_scope);
1338         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn, name, "string",
1339                                           (char *)val, val.len());
1340         if (ce_err != 0) {
1341                 print_ce_error(ce_err);
1342                 return(void *)0;
1343         }
1344
1345         val = _tt_enumname(st->_message_class);
1346         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1347                                           _tt_ce_attr_string(_TT_CLASS),
1348                                           "string", (char *)val, val.len());
1349         if (ce_err != 0) {
1350                 print_ce_error(ce_err);
1351                 return(void *)0;
1352         }
1353         _Tt_string attr_typename = "string";
1354         switch (st->_reliability) {
1355             case TT_START+TT_QUEUE:
1356 #ifdef NOT_BACKWARD_COMPATIBLE
1357                 val = _tt_ce_attr_string( _TT_START );
1358                 val = val.cat( "+" ).cat( _tt_ce_attr_string( _TT_QUEUE ));
1359                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1360                                                   _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1361                                                   (char *)attr_typename,
1362                                                   (char *)val, val.len());
1363                 if (ce_err != 0) {
1364                         print_ce_error(ce_err);
1365                         return(void *)0;
1366                 }
1367                 break;
1368 #else
1369                 //
1370                 // Version 1.0 can only handle finding start, queue,
1371                 // or discard in the disposition attribute (bug
1372                 // 1082628).  So we will hide a clue that we are
1373                 // something else in the typename of this attribute.
1374                 // This works because in 1.0 _tt_convert_signature_attrs()
1375                 // assumes the typename is "string", and never checks it.
1376                 //
1377                 attr_typename =
1378                         attr_typename.cat( ":" )
1379                         .cat( _tt_ce_attr_string( _TT_START ))
1380                         .cat( "+" )
1381                         .cat( _tt_ce_attr_string( _TT_QUEUE ));
1382                 //
1383                 // Now pretend it was START, so that we put start reliability
1384                 // where 1.0 versions will find it.  We assume here
1385                 // that starting is more important than queueing.
1386                 //
1387                 val = "TT_START";
1388                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1389                                                   _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1390                                                   (char *)attr_typename,
1391                                                   (char *)val, val.len());
1392                 if (ce_err != 0) {
1393                         print_ce_error(ce_err);
1394                         return(void *)0;
1395                 }
1396                 break;
1397 #endif /* NOT_BACKWARD_COMPATIBLE */
1398             case TT_START:
1399                 val = "TT_START";
1400                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1401                                                   _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1402                                                   (char *)attr_typename,
1403                                                   (char *)val, val.len());
1404                 if (ce_err != 0) {
1405                         print_ce_error(ce_err);
1406                         return(void *)0;
1407                 }
1408                 break;
1409             case TT_QUEUE:
1410                 val = "TT_QUEUE";
1411                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1412                                                   _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1413                                                   (char *)attr_typename,
1414                                                   (char *)val, val.len());
1415                 if (ce_err != 0) {
1416                         print_ce_error(ce_err);
1417                         return(void *)0;
1418                 }
1419                 break;
1420             case TT_DISCARD:
1421             default:
1422                 val = "TT_DISCARD";
1423                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1424                                                   _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1425                                                   (char *)attr_typename,
1426                                                   (char *)val, val.len());
1427                 if (ce_err != 0) {
1428                         print_ce_error(ce_err);
1429                         return(void *)0;
1430                 }
1431                 break;
1432         }
1433         char opnumstring[40];
1434         sprintf(opnumstring,"%d", st->_opnum);
1435         val = opnumstring;
1436         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1437                                           _tt_ce_attr_string(_TT_MSET_OPNUM),
1438                                           "string", (char *)val, val.len());
1439         if (ce_err != 0) {
1440                 print_ce_error(ce_err);
1441                 return(void *)0;
1442         }
1443
1444         val = st->_ptid;
1445         ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1446                                   _tt_ce_attr_string(_TT_MSET_HANDLER_PTYPE),
1447                                   "string", (char *)val, val.len());
1448         if (ce_err != 0) {
1449                 print_ce_error(ce_err);
1450                 return(void *)0;
1451         }
1452
1453         if (st->_otid.len()) {
1454                 val = st->_otid;
1455                 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1456                                           _tt_ce_attr_string(_TT_MSET_OTYPE),
1457                                           "string", (char *)val, val.len());
1458                 if (ce_err != 0) {
1459                         print_ce_error(ce_err);
1460                         return(void *)0;
1461                 }               
1462         }
1463
1464         return((void *)cn);
1465 }
1466
1467
1468 // 
1469 // This function is passed in as a callback to ce_map_through_attrs by
1470 // _tt_ce_entry_to_ptype. It's function is to process a ptype
1471 // attribute. This involves determining which attribute it is and then
1472 // modifying the _Tt_ptype object (which is passed in as arg by the
1473 // ce_map_through_atts call). 
1474 // 
1475 static void *
1476 _tt_convert_ptype_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1477 {
1478         char                            *name;
1479         _Tt_string                      name_s;
1480         _Tt_string                      value_s;
1481         _Tt_ptype                       *p = (_Tt_ptype *)arg;
1482         
1483         if (attr ==  _tt_attrs[_TYPE_NAME] ||
1484             attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1485                 return(0);
1486         }
1487         name = (char *)CALLCE(ce_get_attribute_name)(attr);
1488         name_s = name;
1489         if (p->getprop(name_s, value_s)) {
1490                 return(0);
1491         }
1492         // add property to ptype.
1493         value_s = value;
1494         p->appendprop(name_s, value_s);
1495         
1496         return(0);
1497 }
1498
1499
1500 //
1501 // This function is passed in as a callback to ce_map_through_attrs by
1502 // _tt_ce_entry_to_otype. Its function is to process the given
1503 // attribute and modify the _Tt_otype object appropiately. This object
1504 // is passed in as arg by ce_map_through_attrs. If this callback
1505 // returns anything other than (void *)0, then it causes
1506 // ce_map_through_attrs to return immediately without processing the
1507 // rest of the current entry's attributes. This signals an error to
1508 // _tt_ce_entry_to_otype.  The attribute is mapped to the appropiate
1509 // tooltalk attribute by way of the _tt_attrs table (this avoid having
1510 // to do repeated strcmps on the attribute's name).
1511 //
1512 static void *
1513 _tt_convert_otype_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1514 {
1515         _Tt_string_list_ptr     ancs;
1516         _Tt_string_list_cursor  anc_c;
1517         _Tt_otype               *o = (_Tt_otype *)arg;
1518         
1519         if (attr ==  _tt_attrs[_TYPE_NAME] ||
1520             attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1521                 return(0);
1522         }
1523         if (attr == _tt_attrs[_TT_PARENT]) {
1524                 ancs = o->parents();
1525                 if (ancs.is_null()) {
1526                         ancs = new _Tt_string_list();
1527                         o->set_ancestors(ancs);
1528                 }
1529                 anc_c.reset(ancs);
1530                 while (anc_c.next()) {
1531                         if (*anc_c == value) {
1532                                 return(0);
1533                         }
1534                 }
1535                 ancs->push(_Tt_string(value));
1536         }
1537         
1538         return(0);
1539 }
1540
1541
1542 //
1543 // This function is passed in as a callback to ce_map_through_attrs by
1544 // _tt_ce_entry_to_signature. It's function is to process the
1545 // attribute and modify the _Tt_signature object (passed in as arg by
1546 // ce_map_through_attrs). If this function returns anything other than
1547 // (void *)0 then ce_map_through_attrs will return immediately with
1548 // this value and _tt_ce_entry_to_signature will return an error. 
1549 // The attribute is mapped to the appropiate tooltalk attribute by way
1550 // of the _tt_attrs table (this avoid having to do repeated strcmps on
1551 // the attribute's name). 
1552 //
1553 static void *
1554 _tt_convert_signature_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1555 {
1556         char                    *name;
1557         _Tt_signature           *s = (_Tt_signature *)arg;
1558         _Tt_arg_list_ptr        args;
1559         _Tt_arg_ptr             narg;
1560         _Tt_string              valstring;
1561         _Tt_string              mstring;
1562         _Tt_string              tstring;
1563         _Tt_string              nstring;
1564         CE_ATTRIBUTE            val_id;
1565         
1566         if (attr ==  _tt_attrs[_TYPE_NAME] ||
1567             attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1568                 return 0;
1569         } else if (attr ==  _tt_attrs[_TT_OP]) {
1570
1571                 s->set_op(value);
1572
1573         } else if (attr == _tt_attrs[_TT_CLASS]) {
1574
1575                 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1576                 if (val_id == _tt_attrs[_TT_REQUEST]) {
1577                         s->set_message_class(TT_REQUEST);
1578                 } else if (val_id == _tt_attrs[_TT_NOTICE]) {
1579                         s->set_message_class(TT_NOTICE);
1580                 } else {
1581                         // XXX: assume TT_CLASS_UNDEFINED
1582                         s->set_message_class(TT_CLASS_UNDEFINED);
1583                 }
1584
1585         } else if ((attr ==  _tt_attrs[_TT_SCOPE])
1586                    || (attr == _tt_attrs[_TT_MSET_SCOPE])) {
1587
1588                 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1589                 if (val_id ==  _tt_attrs[_TT_SESSION]) {
1590                         s->set_scope(TT_SESSION);
1591                 } else if (val_id == _tt_attrs[_TT_FILE]) {
1592                         s->set_scope(TT_FILE);
1593                 } else if (val_id == _tt_attrs[_TT_BOTH]) {
1594                         s->set_scope(TT_BOTH);
1595                 } else if (val_id == _tt_attrs[_TT_FILE_IN_SESSION]) {
1596                         s->set_scope(TT_FILE_IN_SESSION);
1597                 } else {
1598                         return(arg);
1599                 }
1600
1601         } else if ((attr == _tt_attrs[_TT_DISPOSITION]) ||
1602                    (attr == _tt_attrs[_TT_MSET_DISPOSITION])) {
1603
1604                 _Tt_string typename = (char *)CALLCE(ce_get_attribute_type)(
1605                                                         _ce_type_ns,
1606                                                         s->ce_entry, attr );
1607                 if (typename == "string") {
1608                         val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1609                         if (val_id == _tt_attrs[_TT_DISCARD]) {
1610                                 s->set_reliability(TT_DISCARD);
1611                         } else if (val_id == _tt_attrs[_TT_QUEUE]) {
1612                                 s->set_reliability(TT_QUEUE);
1613                         } else if (val_id == _tt_attrs[_TT_START]) {
1614                                 s->set_reliability(TT_START);
1615                         } else {
1616                                 Tt_disposition disp= TT_DISCARD;
1617                                 _Tt_string valstring = value;
1618                                 _Tt_string left, right;
1619
1620                                 while (valstring.len() > 0) {
1621                                         right = valstring.split('+', left);
1622                                         if (left.len() <= 0) {
1623                                                 // XXX change split's behavior
1624                                                 left = right;
1625                                                 right = 0;
1626                                         }
1627                                         if (left ==
1628                                             _tt_ce_attr_string(_TT_START)) {
1629                                                 disp = (Tt_disposition)
1630                                                        (disp | TT_START);
1631                                         } else if (left ==
1632                                                    _tt_ce_attr_string(_TT_QUEUE)) {
1633                                                 disp = (Tt_disposition)
1634                                                        (disp | TT_QUEUE);
1635                                         }
1636                                         valstring = right;
1637                                 }
1638                                 s->set_reliability( disp );
1639                         }
1640                 } else {
1641                         _Tt_string hack = "string:";
1642                         hack = hack.cat( _tt_ce_attr_string( _TT_START ))
1643                                 .cat( "+" )
1644                                 .cat( _tt_ce_attr_string( _TT_QUEUE ));
1645                         if (typename == hack) {
1646                                 s->set_reliability (TT_START);
1647                                 s->set_reliability (TT_QUEUE);
1648                         } else {
1649                                 return(arg);
1650                         }
1651                 }
1652
1653         } else if (attr == _tt_attrs[_TT_MSET_HANDLER_PTYPE]) {
1654
1655                 s->set_ptid(value);
1656
1657         } else if (attr == _tt_attrs[_TT_MSET_OTYPE]) {
1658
1659                 s->set_otid(value);
1660
1661         } else if (attr == _tt_attrs[_TT_MSET_OPNUM]) {
1662
1663                 s->set_opnum(atoi(value));
1664
1665         } else if (attr == _tt_attrs[_TT_CATEGORY]) {
1666
1667                 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1668                 if (val_id == _tt_attrs[_TT_OBSERVE]) {
1669                         s->set_pattern_category(TT_OBSERVE);
1670                 } else if (val_id == _tt_attrs[_TT_HANDLE]) {
1671                         s->set_pattern_category(TT_HANDLE);
1672                 } else {
1673                         return(arg);
1674                 }
1675
1676         } else {
1677                 
1678                 // none of the above, check for TT_ARG%d which is
1679                 // an argument specifier.
1680
1681                 name = (char *)CALLCE(ce_get_attribute_name)(attr);
1682                 if (! strncmp(name,
1683                               _tt_ce_attr_string(_TT_ARG),
1684                               strlen(_tt_ce_attr_string(_TT_ARG)))) {
1685                         narg = new _Tt_arg();
1686                         valstring = value;
1687                         valstring = valstring.split(' ',mstring);
1688                         nstring = valstring.split(' ',tstring);
1689                         val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns,
1690                                                              (char *)mstring);
1691                         if (val_id ==  _tt_attrs[_TT_OUT]) {
1692                                 narg->set_mode(TT_OUT);
1693                         } else if (val_id ==  _tt_attrs[_TT_IN]) {
1694                                 narg->set_mode(TT_IN);
1695                         } else if (val_id == _tt_attrs[_TT_INOUT]) {
1696                                 narg->set_mode(TT_INOUT);
1697                         } else {
1698                                 return(arg);
1699                         }
1700                         narg->set_type(tstring);
1701                         narg->set_name(nstring);
1702                         s->append_arg(narg);
1703                 } else {
1704                         _tt_syslog(stderr, LOG_ERR,
1705                                    catgets(_ttcatd, 2, 12,
1706                                            "Ignoring unknown attribute <%s> "
1707                                            "of ToolTalk signature..."), name );
1708                 }
1709         }
1710         
1711         return(0);
1712 }
1713
1714 // 
1715 // Called by _tt_collect_types_in_cedb to produce a _Tt_ptype object from
1716 // the given Classing Engine entry. Uses the _tt_convert_ptype_attrs
1717 // function as a callback to ce_map_through_attrs to do the real work.
1718 // 
1719 static int
1720 _tt_ce_entry_to_ptype(_Tt_ptype *p, CE_ENTRY ne)
1721 {
1722         p->ce_entry = (void *)ne;
1723         return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1724                                                _tt_convert_ptype_attrs, p));
1725 }
1726
1727
1728 // 
1729 // Called by _tt_collect_types_in_cedb to produce a _Tt_otype object from
1730 // the given Classing Engine entry. Uses the _tt_convert_otype_attrs
1731 // function as a callback to ce_map_through_attrs to do the real work.
1732 // 
1733 static int 
1734 _tt_ce_entry_to_otype(_Tt_otype *o, CE_ENTRY ne)
1735 {
1736         o->ce_entry = (void *)ne;
1737         return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1738                                                _tt_convert_otype_attrs, o));
1739 }
1740
1741
1742 // 
1743 // Called by _tt_collect_types_in_cedb to produce a _Tt_signature object from
1744 // the given Classing Engine entry. Uses the _tt_convert_signature_attrs
1745 // function as a callback to ce_map_through_attrs to do the real work.
1746 // 
1747 static int
1748 _tt_ce_entry_to_signature(_Tt_signature *s, CE_ENTRY ne)
1749 {
1750         s->ce_entry = (void *)ne;
1751         return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1752                                                _tt_convert_signature_attrs,
1753                                                s));
1754 }
1755
1756
1757 //
1758 // This function is a callback passed in to ce_map_though_entries. It
1759 // is applied to each entry in the ToolTalk namespace in a Classing
1760 // Engine database. Each entry specifies either a ptype, otype or
1761 // signature. For each class of entry the appropiate _tt_ce_entry_to_*
1762 // function is invoked. 
1763 //
1764 void *
1765 _tt_collect_types_in_cedb(CE_NAMESPACE ns, CE_ENTRY ne, void *t)
1766 {
1767         _Tt_otype_ptr           o;
1768         _Tt_ptype_ptr           p;
1769         _Tt_signature_ptr       s;
1770         _Tt_typedb              *tdb = (_Tt_typedb *)t;
1771         char                    *type;
1772         CE_ATTRIBUTE            type_id;
1773         char                    *ptid;
1774         char                    *otid;
1775         int                     insert_required = 0;
1776         
1777         // XXX: should use ce_get_attribute_type when it's implemented
1778         //
1779         // type = CALLCE(ce_get_attribute_type)(ne, _TT_TYPE_NAME);
1780
1781         if (tdb->ceDB2Use != TypedbAll) {
1782                 //
1783                 // We have been restricted to a single CE database.
1784                 // Ignore this entry if it is not from the right database.
1785                 // XXX CE should have had a better way to do this, such
1786                 // as a parameter to ce_begin().
1787                 //
1788                 char *db_name, *db_path;
1789                 int ceStatus = (int)CALLCE(ce_get_entry_db_info)(
1790                                                 ns, ne, &db_name, &db_path );
1791                 if (ceStatus != 0) {
1792                         return 0;
1793                 }
1794                 if (_Tt_typedb::level( db_name ) != tdb->ceDB2Use) {
1795                         return 0;
1796                 }
1797         }
1798
1799         type = (char *)CALLCE(ce_get_attribute)(ns, ne, _tt_attrs[_TT_TOOLTALK_TYPE]);
1800         if (type == (char *)0) {
1801                 return(0);
1802         }
1803         type_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, type);
1804         if (type_id == _tt_attrs[_TT_TOOLTALK_PTYPE]) {
1805
1806                 // ptype entry
1807
1808                 ptid = (char *)CALLCE(ce_get_attribute)(ns, ne,
1809                                                         _tt_attrs[_TYPE_NAME]);
1810                 if (tdb->ptable.is_null()) {
1811                         tdb->ptable = new _Tt_ptype_table(_tt_ptype_ptid);
1812                 }
1813                 if (! tdb->ptable->lookup(ptid,p)) {
1814                         p = new _Tt_ptype();
1815                         p->set_ptid(ptid);
1816                         insert_required = 1;
1817                 }
1818                 if (!_tt_ce_entry_to_ptype(p.c_pointer(), ne)) {
1819                         return(t);
1820                 }
1821                 if (insert_required) {
1822                         tdb->ptable->insert(p);
1823                 }
1824                 
1825                 return(0);
1826         } else if (type_id == _tt_attrs[_TT_TOOLTALK_OTYPE]) {
1827
1828                 // otype entry
1829
1830                 otid = (char *)CALLCE(ce_get_attribute)(ns, ne,
1831                                                         _tt_attrs[_TYPE_NAME]);
1832                 if (tdb->otable.is_null()) {
1833                         tdb->otable = new _Tt_otype_table(_tt_otype_otid);
1834                 }
1835                 if (! tdb->otable->lookup(otid,o)) {
1836                         o = new _Tt_otype(otid);
1837                         insert_required = 1;
1838                 }
1839                 if (!_tt_ce_entry_to_otype(o.c_pointer(), ne)) {
1840                         return(t);
1841                 }
1842                 if (insert_required) {
1843                         tdb->otable->insert(o);
1844                 }
1845         } else if (type_id == _tt_attrs[_TT_TOOLTALK_SIGNATURE]) {
1846
1847                 // signature entry
1848
1849                 _Tt_signature_list_ptr  sp;
1850                 
1851                 s = new _Tt_signature();
1852                 if (! _tt_ce_entry_to_signature(s.c_pointer(), ne)) {
1853                         // failed to decode signature
1854                         return(t);
1855                 }
1856                 // first insert the signature into the relevant
1857                 // ptype.
1858                 if (! tdb->ptable->lookup(s->ptid(),p)) {
1859                         p = new _Tt_ptype();
1860                         p->set_ptid(s->ptid());
1861                         tdb->ptable->insert(p);
1862                 }
1863                 switch (s->category()) {
1864                     case TT_OBSERVE:
1865                         p->append_osig(s);
1866                         break;
1867                     case TT_HANDLE:
1868                     case TT_HANDLE_PUSH:
1869                     case TT_HANDLE_ROTATE:
1870                         p->append_hsig(s, s->category());
1871                         break;
1872                 }
1873                 if (s->otid().len() > 0) {
1874                         // otype signature
1875                         if (tdb->otable.is_null()) {
1876                                 tdb->otable = new _Tt_otype_table(_tt_otype_otid);
1877                         }
1878                         if (! tdb->otable->lookup(s->otid(),o)) {
1879                                 o = new _Tt_otype(s->otid());
1880                                 tdb->otable->insert(o);
1881                         }
1882                         switch (s->category()) {
1883                             case TT_OBSERVE:
1884                                 o->append_osig(s);
1885                                 break;
1886                             case TT_HANDLE:
1887                             case TT_HANDLE_PUSH:
1888                             case TT_HANDLE_ROTATE:
1889                                 o->append_hsig(s, s->category());
1890                                 break;
1891                             default: // inherited
1892                                 o->append_inhs(s);
1893                                 break;
1894                         }
1895                 }
1896         }
1897         
1898         return(0);
1899 }
1900 #endif                          // OPT_CLASSING_ENGINE
1901
1902
1903  
1904 Tt_status _Tt_typedb::
1905 init_ce(
1906 #if defined(OPT_CLASSING_ENGINE)        
1907         _Tt_typedbLevel db
1908 #else
1909         _Tt_typedbLevel
1910 #endif  
1911 )
1912 {
1913
1914 #ifndef OPT_CLASSING_ENGINE
1915         _tt_syslog(stderr, LOG_ERR, "_Tt_typedb::init_ce()!");
1916         return(TT_ERR_INTERNAL);
1917 #else
1918         int             i;
1919         CE_ATTRIBUTE    c;
1920         int             ce_err;
1921
1922 #ifdef OPT_DLOPEN_CE
1923         int             load_celib_environment();
1924
1925         if (! load_celib_environment()) {
1926                 _tt_syslog(stderr, LOG_ERR,
1927                            "dlopen( \"libce.so\", 1 ): %s", dlerror());
1928                 return(TT_ERR_INTERNAL);
1929         }
1930 #endif                          // OPT_DLOPEN_CE
1931
1932         ceDB2Use = db;
1933         if ((ce_err = (int)CALLCE(ce_begin)(0)) != 0) {
1934                 print_ce_error(ce_err);
1935                 return(TT_ERR_INTERNAL);
1936         }
1937         _ce_type_ns = CALLCE(ce_get_namespace_id)(TT_NS_NAME);
1938         if (_ce_type_ns == (CE_NAMESPACE)0) {
1939                 return(TT_ERR_DBEXIST);
1940         }
1941         // Initialize the ce attributes relevant to ToolTalk types
1942         for (i = 0; i < _TT_CE_ATTR_LAST; i++) {
1943                 c = CALLCE(ce_get_attribute_id)(_ce_type_ns,
1944                                         _tt_ce_attr_string((_Tt_ce_attr)i));
1945                 // if c==0 then we can continue reading the database
1946                 // since it just means we've encountered an attribute
1947                 // not present in any of the namespace entries.
1948                 _tt_attrs[i] = c;
1949         }
1950         if (0 != CALLCE(ce_map_through_entries)(_ce_type_ns,
1951                                                 _tt_collect_types_in_cedb,
1952                                                 (void *)this)) {
1953                 return(TT_ERR_INTERNAL);
1954         }
1955         return(TT_OK);
1956 #endif                          // !OPT_CLASSING_ENGINE
1957 }
1958
1959
1960 Tt_status _Tt_typedb::
1961 ce2xdr()
1962 {
1963         struct stat     xdrStat, ceStat;
1964         int             status;
1965         int             xdrExists = 0;
1966         _Tt_string      home;
1967         _Tt_string      xdrdb;
1968         _Tt_string      cedb;
1969
1970         home = getenv( "HOME" );
1971         xdrdb = home.cat( "/.tt/types.xdr" );
1972         status = stat( (char *)xdrdb, &xdrStat );
1973         if (status == 0) {
1974                 xdrExists = 1;
1975         } else if (errno != ENOENT) {
1976                 _tt_syslog( 0, LOG_ERR, "$HOME/.tt/types.xdr: %m" );
1977                 return TT_ERR_FILE;
1978         }
1979         cedb = home.cat( "/.cetables/cetables" );
1980         status = stat( (char *)cedb, &ceStat );
1981         if (status != 0) {
1982                 if (errno == ENOENT) {
1983                         // No cetables to convert
1984                         return TT_OK;
1985                 } else {
1986                         _tt_syslog( 0, LOG_ERR,
1987                                     "$HOME/.cetables/cetables: %m" );
1988                         return TT_ERR_FILE;
1989                 }
1990         }
1991         if (xdrExists) {
1992                 if (ceStat.st_mtime <= xdrStat.st_mtime) {
1993                         // XDR database is newer
1994                         return TT_OK;
1995                 }
1996         }
1997         status = system( "ttce2xdr -d user &" );
1998         if (WIFEXITED(status)) {
1999                 if (WEXITSTATUS(status) == 0) {
2000                         return TT_OK;
2001                 } else {
2002                         _tt_syslog(stderr, LOG_ERR,
2003                                    catgets(_ttcatd, 2, 13,
2004                                            "ttce2xdr failed (status=%d); types"
2005                                            " in Classing Engine \"user\" "
2006                                            "database not converted..."),
2007                                    WEXITSTATUS(status) );
2008                         return TT_ERR_PTYPE_START;
2009                 }
2010         } else {
2011                 _tt_syslog(stderr, LOG_ERR, "system(\"ttce2xdr -d user\"): %d",
2012                            status );
2013                 return TT_ERR_PTYPE_START;
2014         }
2015 }
2016
2017 _Tt_typedbLevel _Tt_typedb::
2018 level( const _Tt_string &dbname )
2019 {
2020         if (dbname == "user") {
2021                 return TypedbUser;
2022         } else if (dbname == "system") {
2023                 return TypedbSystem;
2024         } else if (dbname == "network") {
2025                 return TypedbNetwork;
2026         } else {
2027                 return TypedbNone;
2028         }
2029 }
2030
2031 const char * _Tt_typedb::
2032 level_name( _Tt_typedbLevel db )
2033 {
2034         switch (db) {
2035             case TypedbUser:
2036                 return "user";
2037             case TypedbSystem:
2038                 return "system";
2039             case TypedbNetwork:
2040                 return "network";
2041             default:
2042                 return 0;
2043         }
2044 }
2045
2046
2047 int _Tt_typedb::
2048 xdr_version_required() const
2049 {
2050         int version = TT_TYPESDB_DEFAULT_XDR_VERSION;
2051         _Tt_ptype_table_cursor  ptypes(ptable);
2052         while (ptypes.next()) {
2053                 version = max(version, ptypes->xdr_version_required());
2054         }
2055         _Tt_otype_table_cursor  otypes(otable);
2056         while (otypes.next()) {
2057                 version = max(version, otypes->xdr_version_required());
2058         }
2059         return version;
2060 }
2061
2062
2063 static void
2064 write_out_tt_attrs(const _Tt_ostream &os)
2065 {
2066         int             i;
2067
2068         FILE *fs = os.theFILE();
2069         for (i=0; i < _TT_CE_ATTR_LAST; i++) {
2070                 fprintf(fs,"\t\t(%s,string,<attr>)\n",
2071                         _tt_ce_attr_string((_Tt_ce_attr)i));
2072         }
2073         fprintf(fs,"\t)");
2074 }
2075
2076
2077 void _Tt_typedb::
2078 pretty_print(const _Tt_ostream &os) const
2079 {
2080         _Tt_ptype_table_cursor  ptypes(ptable);
2081         while (ptypes.next()) {
2082                 ptypes->pretty_print(os);
2083                 os << "\n";
2084         }
2085         _Tt_otype_table_cursor  otypes(otable);
2086         while (otypes.next()) {
2087                 otypes->pretty_print(os);
2088                 os << "\n";
2089         }
2090 }
2091
2092
2093
2094 void _Tt_typedb::
2095 print(const _Tt_ostream &os) const
2096 {
2097         if (write_ce_header(os)) {
2098                 os << "\nNS_ENTRIES= (\n\t(\t";
2099                 write_out_tt_attrs(os);
2100                 ptable->print(_tt_ptype_print, os);
2101                 otable->print(_tt_otype_print, os);
2102                 os << "\n)\n}";
2103         }
2104 }
2105
2106
2107 int _Tt_typedb::
2108 write_ce_header(const _Tt_ostream &os) const
2109 {
2110         os << "{\nNS_NAME=" << TT_NS_NAME
2111            << "\nNS_ATTR=(\n\t\t(NS_MANAGER,string,"
2112               "<$CEPATH/tns_mgr.so>)\n\t)";
2113         return(1);
2114 }
2115
2116
2117
2118 #if defined(OPT_DLOPEN_CE) && defined(OPT_CLASSING_ENGINE)
2119
2120 /************************************************************************** 
2121  * This section contains functions for dynamically loading in the
2122  * necessary ce functions. This avoids the need for applications to link
2123  * in libce. Note that all of this section is ifdefd with OPT_DLOPEN_CE so
2124  * only functions relevant to dynamic loading of ce should be included.
2125  **************************************************************************/
2126
2127
2128
2129 static int
2130 load_celib_environment()
2131 {
2132         int             load_celib_fns_from_handle(void *);
2133         void            *dlhandle;
2134         _Tt_string      path;
2135
2136         // first try opening the current executable to see if the
2137         // functions have already been defined
2138         dlhandle = dlopen((char *)0, 1);
2139         if (load_celib_fns_from_handle(dlhandle)) {
2140                 return(1);
2141         }
2142
2143 #if defined(OPT_BUG_SUNOS_4)    
2144         // Not strictly a bug, but SunOS 4.x doesn't do what we want.
2145         if (! tt_ldpath("libce.so", path)) {
2146                 return(0);
2147         }
2148 #else
2149         // SVR4 version of dlopen does the path searching for us
2150         // (yay!). 
2151         path = "libce.so";
2152 #endif                          // !SVR4
2153
2154 #if defined(OPT_BUG_SUNOS_4)
2155         // SunOS 4 knows nothing of RTLD options
2156         dlhandle = dlopen((char *)path, 1);
2157 #else
2158         // XXX: In theory, RTLD_LAZY (the default) is the preferred way of
2159         // using dlopen. However, there were some bugs in early 5.0 versions
2160         // that made dlopen slow down considerably if RTLD_LAZY is used.
2161         // For now, we'll use RTLD_NOW which seems to get rid of the
2162         // behavior but perhaps not the cause.
2163         // Next time we do performance tuning we should retry with
2164         // RTLD_LAZY.
2165         dlhandle = dlopen((char *)path, RTLD_NOW);
2166 #endif
2167         if (dlhandle == (void *)0) {
2168                 return(0);
2169         }
2170         
2171         return(load_celib_fns_from_handle(dlhandle));
2172 }
2173
2174
2175 /* 
2176  * XXX: This is sort of ugly. dlopen doesn't make the symbol available
2177  * for normal dynamic linking. This means that if the library that is
2178  * dlopened itself uses some of the symbols that are made available by
2179  * the use of dlsym then the library needs to be linked in with the
2180  * executable. We circumvent this by defining those symbols directly
2181  * here. This is unfortunately sensitive to the implementation of libce
2182  * changing. Ie. if it is changed to use more symbols than
2183  * ce_get_attribute_id and ce_get_attribute then libce will have to be
2184  * linked in regardless of whether it is dlopened or not.
2185  * 
2186  * All of a sudden we're getting infinite loops here, under ce_begin().
2187  * So I'm commenting these two puppies out.  Brian 8/05/92
2188  *
2189 CE_ATTRIBUTE
2190 ce_get_attribute_id(CE_NAMESPACE ns, char *a)
2191 {
2192         return((CE_ATTRIBUTE)CALLCE(ce_get_attribute_id)(ns,a));
2193 }
2194
2195 char *
2196 ce_get_attribute(CE_NAMESPACE ns, CE_ENTRY e, CE_ATTRIBUTE a)
2197 {
2198         return((char *)CALLCE(ce_get_attribute)(ns,e,a));
2199 }
2200  */
2201
2202
2203 static int
2204 load_celib_fns_from_handle(void *dlhandle)
2205 {
2206 #if defined(__STDC__)
2207 #define DLINK_FN(fn)\
2208         _tt_celib . fn = (_Tt_cefn_ptr)dlsym(dlhandle, #fn);            \
2209         if (_tt_celib . fn == (_Tt_cefn_ptr)0) {                        \
2210                 return(0);                                              \
2211         }
2212 #else
2213 #define DLINK_FN(fn)\
2214         _tt_celib . fn = (_Tt_cefn_ptr)dlsym(dlhandle, "fn");           \
2215         if (_tt_celib . fn == (_Tt_cefn_ptr)0) {                        \
2216                 return(0);                                              \
2217         }
2218 #endif /* __STDC__ */
2219
2220         DLINK_FN(ce_abort_write)
2221         DLINK_FN(ce_add_attribute)
2222         DLINK_FN(ce_add_entry)
2223         DLINK_FN(ce_add_namespace)
2224         DLINK_FN(ce_alloc_entry)
2225         DLINK_FN(ce_alloc_ns_entry)
2226         DLINK_FN(ce_get_attribute_id)
2227         DLINK_FN(ce_begin)
2228         DLINK_FN(ce_commit_write)
2229         DLINK_FN(ce_get_attribute)
2230         DLINK_FN(ce_get_attribute_name)
2231         DLINK_FN(ce_get_attribute_type)
2232         DLINK_FN(ce_get_entry_db_info)
2233         DLINK_FN(ce_get_namespace_id)
2234         DLINK_FN(ce_map_through_attrs)
2235         DLINK_FN(ce_map_through_entries)
2236         DLINK_FN(ce_remove_entry)
2237         DLINK_FN(ce_start_write)
2238
2239         return(1);
2240 }
2241
2242 #endif                          // OPT_DLOPEN_CE && OPT_CLASSING_ENGINE