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