Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / lib / api / c / api_spec.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $XConsortium: api_spec.C /main/3 1995/10/23 09:54:31 rswiston $                                                   
28 /* @(#)api_spec.C       1.15 @(#)
29  *
30  * api_spec.cc
31  *
32  * Copyright (c) 1990 by Sun Microsystems, Inc.
33  */
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include "mp/mp_c.h"
38 #include "api/c/tt_c.h"
39 #include "api/c/api_api.h"
40 #include "api/c/api_mp.h"
41 #include "api/c/api_handle.h"
42 #include "api/c/api_spec_map_ref.h"
43 #include "api/c/api_error.h"
44 #include "db/tt_db_property.h"
45 #include "db/tt_db_access.h"
46 #include "util/tt_audit.h"
47 #include "util/tt_path.h"
48
49 static Tt_status objid_to_spec(const char *objid, _Tt_objid_spec_ptr &specP);
50
51 /************************************************************************
52 * Node Functions (FSpec A.7)                                            *
53 ************************************************************************/
54
55 Tt_status 
56 tt_spec_bprop(const char *objid, const char *propname, int i,
57               unsigned char **value, int *length)
58 {
59         _Tt_audit audit;
60         Tt_status status = audit.entry("ori", TT_SPEC_BPROP, objid,
61                                             propname, i);
62
63         if (status != TT_OK) {
64                 audit.exit(status);
65                 return status;
66         }
67
68         status = _tt_spec_bprop(objid, propname, i, value, length);
69         audit.exit(status);
70
71         return status;
72 }
73
74
75 Tt_status 
76 tt_spec_bprop_add(const char *objid, const char *propname,
77                   const unsigned char *value, int length)
78 {
79         _Tt_audit audit;
80         Tt_status status = audit.entry("ornI", TT_SPEC_BPROP_ADD, objid,
81                                             propname, value, length);
82  
83         if (status != TT_OK) { 
84                 audit.exit(status);
85                 return status; 
86         } 
87  
88         status = _tt_spec_bprop_add(objid, propname, value, length);
89         audit.exit(status); 
90  
91         return status;
92 }
93
94
95 Tt_status 
96 tt_spec_bprop_set(const char *objid, const char *propname,
97                   const unsigned char *value, int length)
98 {
99         _Tt_audit audit;
100         Tt_status status = audit.entry("ornI", TT_SPEC_BPROP_SET, objid,
101                                             propname, value, length);
102  
103         if (status != TT_OK) { 
104                 audit.exit(status);
105                 return status; 
106         } 
107  
108         status = _tt_spec_bprop_set(objid, propname, value, length);
109         audit.exit(status); 
110  
111         return status;
112 }
113
114
115 char           *
116 tt_spec_create(const char *filepath)
117 {
118         _Tt_audit audit;
119         Tt_status status = audit.entry("C", TT_SPEC_CREATE, filepath);
120         char *result;
121
122         if (status != TT_OK) {
123                 audit.exit((char *)error_pointer(status));
124                 return (char *)error_pointer(status);
125         }
126
127         result = _tt_spec_create(filepath);
128         audit.exit(result);
129
130         return result;
131 }
132
133
134 Tt_status 
135 tt_spec_destroy(const char *objid)
136 {
137         _Tt_audit audit;
138         Tt_status status = audit.entry("o", TT_SPEC_DESTROY, objid);
139  
140         if (status != TT_OK) { 
141                 audit.exit(status);
142                 return status; 
143         } 
144  
145         status = _tt_spec_destroy(objid);
146         audit.exit(status); 
147  
148         return status;
149 }
150
151
152 char           *
153 tt_spec_file(const char *objid)
154 {
155         _Tt_audit audit;
156         Tt_status status = audit.entry("o", TT_SPEC_FILE, objid);
157         char *result;
158
159         if (status != TT_OK) {
160                 audit.exit((char *)error_pointer(status));
161                 return (char *)error_pointer(status);
162         }
163
164         result = _tt_spec_file(objid);
165         audit.exit(result);
166
167         return result;
168 }
169
170
171 char           *
172 tt_spec_move(const char *objid, const char *newfilepath)
173 {
174         _Tt_audit audit;
175         Tt_status status = audit.entry("oC", TT_SPEC_MOVE, objid,
176                                             newfilepath);
177         char *result;
178
179         if (status != TT_OK) {
180                 audit.exit((char *)error_pointer(status));
181                 return (char *)error_pointer(status);
182         }
183
184         result = _tt_spec_move(objid, newfilepath);
185         audit.exit(result);
186
187         return result;
188 }
189
190
191 Tt_status
192 tt_spec_type_set(const char * objid, const char * otid)
193 {
194         _Tt_audit audit;
195         Tt_status status = audit.entry("oo", TT_SPEC_TYPE_SET, objid, otid);
196
197         if (status != TT_OK) {
198                 audit.exit(status);
199                 return status;
200         }
201
202         status = _tt_spec_type_set(objid, otid);
203         audit.exit(status);
204
205         return status;
206 }
207
208
209 char *
210 tt_spec_type(const char * objid)
211 {
212         _Tt_audit audit;
213         Tt_status status = audit.entry("o", TT_SPEC_PROP, objid);
214         char *result;
215
216         if (status != TT_OK) {
217                 audit.exit((char *)error_pointer(status));
218                 return (char *)error_pointer(status);
219         }
220
221         result = _tt_spec_type(objid);
222         audit.exit(result);
223
224         return result;
225 }
226
227
228 char           *
229 tt_spec_prop(const char *objid, const char *propname, int i)
230 {
231         _Tt_audit audit;
232         Tt_status status = audit.entry("ori", TT_SPEC_PROP, objid,
233                                             propname, i);
234         char *result;
235
236         if (status != TT_OK) {
237                 audit.exit((char *)error_pointer(status));
238                 return (char *)error_pointer(status);
239         }
240
241         result = _tt_spec_prop(objid, propname, i);
242         audit.exit(result);
243
244         return result;
245 }
246
247
248 Tt_status 
249 tt_spec_prop_add(const char *objid, const char *propname, const char *value)
250 {
251         _Tt_audit audit;
252         Tt_status status = audit.entry("ornI", TT_SPEC_PROP_ADD, objid,
253                                             propname, value,
254                                             (char *) 0 == value ? 0 : strlen(value));
255
256         if (status != TT_OK) {
257                 audit.exit(status);
258                 return status;
259         }
260
261         status = _tt_spec_prop_add(objid, propname, value);
262         audit.exit(status);
263
264         return status;
265 }
266
267
268 int 
269 tt_spec_prop_count(const char *objid, const char *propname)
270 {
271         _Tt_audit audit;
272         Tt_status status = audit.entry("or", TT_SPEC_PROP_COUNT, objid,
273                                             propname);
274         int result;
275
276         if (status != TT_OK) {
277                 audit.exit(error_int(status));
278                 return error_int(status);
279         }
280
281         result = _tt_spec_prop_count(objid, propname);
282         audit.exit(result);
283
284         return result;
285 }
286
287
288 Tt_status 
289 tt_spec_prop_set(const char *objid, const char *propname, const char *value)
290 {
291         _Tt_audit audit;
292         Tt_status status = audit.entry("ornI", TT_SPEC_PROP_SET, objid,
293                                             propname, value,
294                                             (char *) 0 == value ? 0 : strlen(value));
295
296         if (status != TT_OK) {
297                 audit.exit(status);
298                 return status;
299         }
300  
301         status = _tt_spec_prop_set(objid, propname, value);
302         audit.exit(status);
303  
304         return status;
305 }
306
307
308 char           *
309 tt_spec_propname(const char *objid, int n)
310 {
311         _Tt_audit audit;
312         Tt_status status = audit.entry("oi", TT_SPEC_PROPNAME, objid, n);
313         char *result;
314
315         if (status != TT_OK) {
316                 audit.exit((char *)error_pointer(status));
317                 return (char *)error_pointer(status);
318         }
319
320         result = _tt_spec_propname(objid, n);
321         audit.exit(result);
322
323         return result;
324 }
325
326
327 int 
328 tt_spec_propnames_count(const char *objid)
329 {
330         _Tt_audit audit;
331         Tt_status status = audit.entry("o", TT_SPEC_PROPNAMES_COUNT,
332                                             objid);
333         int result;
334
335         if (status != TT_OK) {
336                 audit.exit(error_int(status));
337                 return error_int(status);
338         }
339
340         result = _tt_spec_propnames_count(objid);
341         audit.exit(result);
342
343         return result;
344 }
345
346
347 Tt_status 
348 tt_spec_write(const char *objid)
349 {
350         _Tt_audit audit;
351         Tt_status status = audit.entry("o", TT_SPEC_WRITE, objid);
352
353         if (status != TT_OK) {
354         audit.exit(status);
355                 return status;
356         }
357
358         status = _tt_spec_write(objid);
359         audit.exit(status);
360
361         return status;
362 }
363
364
365 int 
366 tt_objid_equal(const char *objid1, const char *objid2)
367 {
368         _Tt_audit audit;
369         Tt_status status = audit.entry("oo", TT_OBJID_EQUAL, objid1,
370                                             objid2);
371         int result;
372
373         if (status != TT_OK) {
374                 audit.exit(error_int(status));
375                 return error_int(status);
376         }
377
378         result = _tt_objid_equal(objid1, objid2);
379         audit.exit(result);
380
381         return result;
382 }
383
384
385 char           *
386 tt_objid_objkey(const char *objid)
387 {
388         _Tt_audit audit;
389         Tt_status status = audit.entry("o", TT_OBJID_OBJKEY, objid);
390         char *result;
391
392         if (status != TT_OK) {
393                 audit.exit((char *)error_pointer(status));
394                 return (char *)error_pointer(status);
395         }
396
397         result = _tt_objid_objkey(objid);
398         audit.exit(result);
399
400         return result;
401 }
402 // _tt_spec_bprop() - retrive the `i'-th value, starting at 0, of
403 //                    the property `propname' specified.
404 Tt_status
405 _tt_spec_bprop(const char * objid, const char * propname, int i,
406                unsigned char ** value, int * length)
407 {
408         Tt_status result;
409         _Tt_string temp;
410         _Tt_objid_spec_ptr specP;
411
412         // find spec for objid
413         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
414                 return result;
415         }
416
417         _Tt_db_property_ptr propP;
418
419         // Initialize return value
420         *value = (unsigned char *)NULL;
421
422         // get list of values for specified property
423         propP = specP->getProperty(propname);
424         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
425                 case TT_ERR_NOMP:
426                 case TT_ERR_OBJID:
427                 case TT_ERR_DBAVAIL:
428                 case TT_ERR_DBEXIST:
429                 case TT_ERR_NUM:
430                 case TT_ERR_PROPNAME:
431                         break;
432                 case TT_OK:
433                 case TT_WRN_STALE_OBJID:
434                         if ((i < 0) || (i > propP->values->count())) {
435                                 return TT_ERR_NUM;
436                         }
437                         if (propP->values->count() == i) {
438                                 return result;
439                         }
440
441                         temp = (*(propP->values))[i];
442
443                         *length = temp.len();
444                         *value = (unsigned char *) _tt_strdup((char *) temp,
445                                                                 *length);
446                         return result;
447                 default:
448                         return TT_ERR_INTERNAL;
449         }
450         return result;
451 }       // end -_tt_spec_bprop()-
452
453
454 Tt_status
455 _tt_spec_bprop_add(const char * objid, const char * propname,
456                    unsigned const char * value, int length)
457 {
458         Tt_status result;
459         _Tt_objid_spec_ptr specP;
460         _Tt_string temp(value, length);
461
462
463         // find spec for objid
464         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
465                 return result;
466         }
467
468         _Tt_db_property_ptr newPropP = new _Tt_db_property;
469
470
471         // load new property
472         newPropP->name = propname;
473         newPropP->values->append(temp);
474
475         // add it to db
476         specP->addProperty(newPropP);
477         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
478                 case TT_OK:
479                 case TT_WRN_STALE_OBJID:
480                         specP->setOnDiskFlag(FALSE);
481                 case TT_ERR_DBAVAIL:
482                 case TT_ERR_DBEXIST:
483                 case TT_ERR_NOMP:
484                 case TT_ERR_OBJID:
485                 case TT_ERR_PROPLEN:
486                 case TT_ERR_PROPNAME:
487                         break;
488                 default:
489                         return TT_ERR_INTERNAL;
490         }
491         return result;
492 }       // end -_tt_spec_bprop_add()-
493
494
495 Tt_status
496 _tt_spec_bprop_set(const char * objid, const char * propname,
497                    unsigned const char * value, int length)
498 {
499         Tt_status result;
500         _Tt_objid_spec_ptr specP;
501         _Tt_string temp(value, length);
502
503         // find spec for objid
504         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
505                 return result;
506         }
507
508         _Tt_db_property_ptr newPropP = new _Tt_db_property;
509  
510  
511         // load new property
512         newPropP->name = propname;
513         newPropP->values->append(temp);
514
515         specP->setProperty(newPropP);
516         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) { 
517                 case TT_OK:
518                 case TT_WRN_STALE_OBJID:
519                         specP->setOnDiskFlag(FALSE);
520                 case TT_ERR_DBAVAIL: 
521                 case TT_ERR_DBEXIST: 
522                 case TT_ERR_NOMP:
523                 case TT_ERR_OBJID:
524                 case TT_ERR_PROPLEN:
525                 case TT_ERR_PROPNAME:
526                         break;
527                 default:
528                         return TT_ERR_INTERNAL;
529         }
530         return result;
531 }       // end -_tt_spec_bprop_set()-
532
533
534 // _tt_spec_create()- create a new spec, and associated tt_db_object,
535 //                    in memory.
536 //
537 char *
538 _tt_spec_create(const char * filepath)
539 {
540         Tt_status               result; 
541         _Tt_string              objid;
542         _Tt_db_access_ptr       accessP;
543         _Tt_objid_spec_ptr      newSpecP = new _Tt_objid_spec; // create a new spec
544
545         // create new tt_db_object in memory, checking for db error
546         objid = newSpecP->create(filepath);
547         switch (result = _tt_get_api_error(newSpecP->getDBResults(), _TT_API_SPEC)) { 
548                 case TT_OK:
549                 case TT_WRN_STALE_OBJID:
550                         break;
551
552                 case TT_ERR_DBAVAIL: 
553                 case TT_ERR_DBEXIST: 
554                 case TT_ERR_NOMP:
555                 case TT_ERR_OTYPE:
556                 case TT_ERR_PATH:
557                         return (char *)error_pointer(result);
558                 default:
559                         return (char *)error_pointer(TT_ERR_INTERNAL);
560         }
561
562         // Make the object so that everyone can read and write it
563         accessP = new _Tt_db_access;
564         accessP->mode = (mode_t)-1;
565         newSpecP->setAccess(accessP);
566         switch (result = _tt_get_api_error(newSpecP->getDBResults(), _TT_API_SPEC)) {
567                 case TT_OK:
568                 case TT_WRN_STALE_OBJID:
569                         break;
570                 case TT_ERR_DBAVAIL: 
571                 case TT_ERR_DBEXIST:  
572                 case TT_ERR_NOMP:
573                 case TT_ERR_OTYPE: 
574                 case TT_ERR_PATH:
575                         return (char *)error_pointer(result);
576                 default: 
577                         return (char *)error_pointer(TT_ERR_INTERNAL);
578         } 
579
580         _Tt_api_spec_map_ref specMap;
581
582
583         // add new spec to map.
584         specMap.addSpec(newSpecP);
585
586         return _tt_strdup(objid);
587 }       // end -_tt_spec_create()-
588
589
590 // _tt_spec_destroy()- destroy a spec, and associated tt_db_object.
591 //
592 Tt_status
593 _tt_spec_destroy(const char * objid)
594 {
595
596         Tt_status result; 
597         _Tt_objid_spec_ptr specP;
598         _Tt_api_spec_map_ref specMap;
599
600         // find spec for objid
601         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
602                 return result;
603         }
604
605         specP->remove();                // remove associated tt_db_object
606         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
607                 case TT_OK:
608                 case TT_WRN_STALE_OBJID:
609                         break;
610                 case TT_ERR_ACCESS:
611                 case TT_ERR_DBAVAIL: 
612                 case TT_ERR_DBEXIST:  
613                 case TT_ERR_NOMP:
614                 case TT_ERR_OBJID:
615                         return result;
616                 default: 
617                         return TT_ERR_INTERNAL;
618         }
619         specMap.deleteSpec(objid);// delete spec from table
620         return TT_OK;
621 }       // end -_tt_spec_destroy()-
622
623
624 // _tt_spec_file()- retrieves the name of the file containing the
625 //                  object described by the spec.
626 //
627 char *
628 _tt_spec_file(const char * objid)
629 {
630         Tt_status result; 
631         _Tt_string filepath;
632         _Tt_objid_spec_ptr specP;
633         _Tt_api_spec_map_ref specMap;
634
635         // find spec for objid
636         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
637                 return (char *)error_pointer(result);
638         }
639
640         filepath = specP->getFile();
641         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
642                 case TT_OK:
643                 case TT_WRN_STALE_OBJID:
644                         break;
645                 case TT_ERR_DBAVAIL: 
646                 case TT_ERR_DBEXIST:  
647                 case TT_ERR_NOMP:
648                 case TT_ERR_OBJID:
649                         return (char *)error_pointer(result);
650                 default: 
651                         return (char *)error_pointer(TT_ERR_INTERNAL);
652         }
653         return _tt_strdup(_tt_network_path_to_local_path(filepath));
654 }       // end -_tt_spec_file()-
655
656
657 // _tt_spec_move()- tell tooltalk service ythat the object has moved
658 //                  to a different file
659 //
660 char *
661 _tt_spec_move(const char * objid, const char * newfilepath)
662 {
663         Tt_status result; 
664         _Tt_string newObjid;
665         _Tt_objid_spec_ptr specP;
666
667         // find spec for objid
668         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
669                 return (char *)error_pointer(result);
670         }
671
672         newObjid = specP->move(newfilepath);
673         if ((result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) != TT_OK) {
674                 return (char *)error_pointer(result);
675         }
676         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
677                 case TT_OK:
678                 case TT_WRN_STALE_OBJID:
679                 case TT_WRN_SAME_OBJID:
680                         break;
681
682                 case TT_ERR_DBAVAIL:
683                 case TT_ERR_DBEXIST:
684                 case TT_ERR_NOMP:
685                 case TT_ERR_OBJID:
686                 case TT_ERR_PATH:
687                         return (char *)error_pointer(result);
688                 default:
689                         return (char *)error_pointer(TT_ERR_INTERNAL);
690         }
691         return _tt_strdup(newObjid);
692 }       // end -_tt_spec_move()-
693
694
695 Tt_status
696 _tt_spec_type_set(const char * objid, const char * otid)
697 {
698         Tt_status result;
699         _Tt_objid_spec_ptr specP;
700
701
702         if (TT_WRN_LAST < (result = _tt_valid_otype(otid))) {
703                 return result;
704         }
705
706         // find spec for objid
707         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
708                 return result;
709         }
710
711         // set otid on object
712         switch (result = _tt_get_api_error(specP->setType(otid), _TT_API_SPEC)) {
713                 case TT_OK:
714                 case TT_WRN_STALE_OBJID:
715                 case TT_ERR_DBAVAIL:
716                 case TT_ERR_DBEXIST:
717                 case TT_ERR_NOMP:
718                 case TT_ERR_OBJID:
719                 case TT_ERR_READONLY:
720                         break;
721                 default:
722                         return TT_ERR_INTERNAL;
723         }
724         return result;
725 }       // end -_tt_spec_type_set()-
726
727
728 char *
729 _tt_spec_type(const char * objid)
730 {
731         Tt_status result;
732         _Tt_string objType;
733         _Tt_objid_spec_ptr specP;
734
735         // find spec for objid
736         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
737                 return (char *)error_pointer(result);
738         }
739
740         objType = specP->getType();
741         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
742                 case TT_OK:
743                 case TT_WRN_STALE_OBJID:
744                         break;
745                 case TT_ERR_DBAVAIL:
746                 case TT_ERR_DBEXIST:
747                 case TT_ERR_NOMP:
748                 case TT_ERR_OBJID:
749                         return (char *)error_pointer(result);
750                 default:
751                         return (char *)error_pointer(TT_ERR_INTERNAL);
752         }
753         return _tt_strdup(objType);
754 }       // end -_tt_spec_type()-
755
756
757 char *
758 _tt_spec_prop(const char * objid, const char * propname, int i)
759 {
760         int len;
761         Tt_status err;
762         unsigned char *value;
763
764         err = _tt_spec_bprop(objid, propname, i, &value, &len);
765         switch (err) {
766                 case TT_OK:
767                 case TT_WRN_STALE_OBJID:
768                         break;
769                 default:
770                         return (char *)error_pointer(err);
771         }
772         return _tt_strdup((const char *)value);
773 }       // end -_tt_spec_prop()-
774
775
776 Tt_status
777 _tt_spec_prop_add(const char * objid, const char * propname, const char * value)
778 {
779         return _tt_spec_bprop_add(objid, propname, (unsigned char *)value,
780                                   (char *) 0 == value ? 0 : strlen(value));
781 }       // end -_tt_spec_prop_add()-
782
783
784 int
785 _tt_spec_prop_count(const char * objid, const char * propname)
786 {
787         Tt_status result;
788         _Tt_objid_spec_ptr specP;
789         
790         // find spec for objid
791         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
792                 return tt_error_int(result);
793         }
794
795         _Tt_db_property_list_ptr propListP;
796
797
798         propListP = specP->getProperties();
799         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
800                 case TT_OK:
801                 case TT_WRN_STALE_OBJID:
802                         break;
803                 case TT_ERR_DBAVAIL:
804                 case TT_ERR_DBEXIST:
805                 case TT_ERR_NOMP:
806                 case TT_ERR_OBJID:
807                 case TT_ERR_PROPNAME:
808                 case TT_ERR_PROPLEN:
809                         return tt_error_int(result);
810                 default:
811                         return tt_error_int(TT_ERR_INTERNAL);
812         }
813
814         _Tt_db_property_list_cursor properties_cursor(propListP);
815         while (properties_cursor.next()) {
816                 if ((*properties_cursor)->name == propname) {
817                         if (!(*properties_cursor)->values.is_null()) {
818                                 return (*properties_cursor)->values->count();
819                         }
820                         else {
821                                 return 0;
822                         }
823                 }
824         }
825
826         return 0;
827 }       // end _tt_spec_prop_count()-
828
829
830 Tt_status
831 _tt_spec_prop_set(const char * objid, const char * propname, const char * value)
832 {
833         return _tt_spec_bprop_set(objid, propname, (unsigned char *)value,
834                                   (char *)0==value?0:strlen(value));
835 }       // end -_tt_spec_prop_set()-
836
837
838 char *
839 _tt_spec_propname(const char *objid, int n)
840 {
841         Tt_status result;
842         _Tt_string propname;
843         _Tt_objid_spec_ptr specP;
844
845         // find spec for objid
846         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
847                 return (char *)error_pointer(result);
848         }
849
850         _Tt_db_property_ptr propP;
851         _Tt_db_property_list_ptr propListP;
852  
853
854         // get property list
855         propListP = specP->getProperties();
856         if ((result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) != TT_OK) {
857                 return (char *)error_pointer(result);
858         }
859
860         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
861                 case TT_OK:
862                 case TT_WRN_STALE_OBJID:
863                         break;
864                 case TT_ERR_DBAVAIL:
865                 case TT_ERR_DBEXIST:
866                 case TT_ERR_NOMP:
867                 case TT_ERR_OBJID:
868                 case TT_ERR_NUM:
869                         return (char *)error_pointer(result);
870                 default: 
871                         return (char *)error_pointer(TT_ERR_INTERNAL);
872         }
873
874         // range check index number
875         if ((n < 0) || (n > propListP->count()-1)) {
876                 return (char *)error_pointer(TT_ERR_NUM);
877         }
878
879         // get individual property
880         propP = (*propListP)[n];
881
882         // return propname of individual property
883         return (_tt_strdup((char *) propP->name));
884
885 }       // end -_tt_spec_propname()-
886
887
888 int
889 _tt_spec_propnames_count(const char * objid)
890 {
891         Tt_status result;
892         _Tt_objid_spec_ptr specP;
893         _Tt_db_property_list_ptr propListP;
894
895         // find spec for objid
896         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
897                 return tt_error_int(result);
898         }
899
900         propListP = specP->getProperties();
901         switch (result = _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC)) {
902                 case TT_OK:
903                 case TT_WRN_STALE_OBJID:
904                         break;
905                 case TT_ERR_DBAVAIL:
906                 case TT_ERR_DBEXIST:
907                 case TT_ERR_NOMP:
908                 case TT_ERR_OBJID:
909                 case TT_ERR_NUM:
910                         return tt_error_int(result);
911                 default:
912                         return tt_error_int(TT_ERR_INTERNAL);
913         }
914         return propListP->count();
915 }       // end -_tt_spec_propnames_count()-
916
917
918 Tt_status
919 _tt_spec_write(const char * objid)
920 {
921         Tt_status result;
922         _Tt_db_results db_results = TT_DB_OK;
923         _Tt_objid_spec_ptr specP;
924         _Tt_api_spec_map_ref specMap;
925
926         // find spec for objid
927         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
928                 return result;
929         }
930
931         // Check the properties for special access privilege properties
932         // and generate the approptiate setAccess call
933         _Tt_db_property_list_ptr properties = specP->getProperties();
934         _Tt_db_property_list_cursor properties_cursor(properties);
935
936         bool_t access_prop_found = FALSE;
937         uid_t user = (uid_t)-1;
938         gid_t group = (gid_t)-1;
939         mode_t mode = (mode_t)-1;       
940         _Tt_string temp_string;
941         while (properties_cursor.next()) {
942
943                 if (properties_cursor->name == TT_OBJECT_OWNER_PROPERTY) {
944                         access_prop_found = TRUE;
945
946                         if (!properties_cursor->is_empty() &&
947                             !(*properties_cursor->values)[0].is_null()) {
948                                 temp_string = (*properties_cursor->values)[0];
949                                 user = (uid_t)atoi((char *)temp_string);
950                         }
951                 }
952                 else if (properties_cursor->name == TT_OBJECT_OWNER_PROPERTY) {
953                         access_prop_found = TRUE;
954
955                         if (!properties_cursor->is_empty() &&
956                             !(*properties_cursor->values)[0].is_null()) {
957                                 temp_string = (*properties_cursor->values)[0];
958                                 group = (gid_t)atoi((char *)temp_string);
959                         }
960                 }
961                 else if (properties_cursor->name == TT_OBJECT_MODE_PROPERTY) {
962                         access_prop_found = TRUE;
963
964                         if (!properties_cursor->is_empty() &&
965                             !(*properties_cursor->values)[0].is_null()) {
966                                 temp_string = (*properties_cursor->values)[0];
967                                 mode = (mode_t)atoi((char *)temp_string);
968                         }
969                 }
970         }
971
972         if (access_prop_found) {
973                 _Tt_db_access_ptr access = new _Tt_db_access;
974                 access->user = user;
975                 access->group = group;
976                 access->mode = mode;
977                 db_results = specP->setAccess(access);
978         }
979
980         if (db_results == TT_DB_OK) {
981                 // write associated tt_db_object to disk
982                 db_results = specP->write();
983         }
984
985         switch (result = _tt_get_api_error(db_results, _TT_API_SPEC)) { 
986                 case TT_OK: 
987                 case TT_WRN_STALE_OBJID:
988                         specP->setOnDiskFlag(TRUE);
989                         break;
990                 case TT_ERR_DBAVAIL:
991                 case TT_ERR_DBEXIST:
992                 case TT_ERR_NOMP:
993                 case TT_ERR_OBJID:
994                 case TT_ERR_OTYPE:
995                 case TT_ERR_NUM:
996                         return result;
997                 default:
998                         return TT_ERR_INTERNAL;
999         }
1000
1001         return TT_OK;
1002 }       // end -tt_spec_write()-
1003
1004
1005 int
1006 _tt_objid_equal(const char *objid1, const char *objid2)
1007 {
1008         Tt_status        err;
1009         _Tt_objid_spec_ptr spec1, spec2;
1010
1011         if ((err = objid_to_spec(objid1, spec1)) > TT_WRN_LAST) {
1012                 return tt_error_int(err);
1013         }
1014         if ((err = objid_to_spec(objid2, spec2)) > TT_WRN_LAST) {
1015                 return tt_error_int(err);
1016         }
1017
1018         return spec1->getObjectKey() == spec2->getObjectKey();
1019 }       // end -tty_objid_equal()-
1020
1021
1022 char *
1023 _tt_objid_objkey(const char *objid)
1024 {
1025         Tt_status       result;
1026         _Tt_objid_spec_ptr specP;
1027
1028
1029         if ((result = objid_to_spec(objid, specP)) > TT_WRN_LAST) {
1030                 return (char *)error_pointer(TT_ERR_OBJID);
1031         }
1032         return  _tt_strdup(specP->getObjectKey());
1033 }       // end -tt_objid_key()-
1034
1035
1036 /*
1037  * Following service functions take care of changing from externally
1038  * visible objid to internal node structure pointers and back.
1039  * This isn't really the right place for it, since the external
1040  * form is not specific to the C api, but it's not clear where
1041  * the code should really be; it doesn't really belong to 
1042  * _Tt_node either.
1043  */
1044
1045 Tt_status
1046 objid_to_spec(const char * objid, _Tt_objid_spec_ptr &specP)
1047 {
1048         _Tt_api_spec_map_ref specMap;
1049
1050
1051         // find spec for objid
1052         specP = specMap.getSpec(objid);
1053         if (specP.is_null()) {
1054                 return TT_ERR_OBJID;
1055         }
1056         
1057         return _tt_get_api_error(specP->getDBResults(), _TT_API_SPEC);
1058 }       // end -objid_to_spec()-