libDtSvc: Resolve 89 compiler warnings.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / ActionDb.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 /* $TOG: ActionDb.c /main/8 1998/07/30 12:09:13 mgreess $ */
24 /*************************************<+>*************************************
25  *****************************************************************************
26  **
27  **   File:         ActionDb.c
28  **
29  **   Project:      DT
30  **
31  **   Description:  Source file for the action database loading functions.
32  **               
33  **
34  **
35  ** (c) Copyright 1993, 1994 Hewlett-Packard Company
36  ** (c) Copyright 1993, 1994 International Business Machines Corp.
37  ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
38  ** (c) Copyright 1993, 1994 Novell, Inc.
39  ****************************************************************************
40  ************************************<+>*************************************/
41
42 /*LINTLIBRARY*/
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <string.h>
46 #include <X11/Intrinsic.h>
47
48 #include <Xm/Xm.h>
49 #include <Xm/XmP.h>
50
51 #include <Dt/DtP.h>
52 #include <Dt/Message.h>
53 #include <Dt/DbReader.h>
54 #include <Dt/Connect.h>
55 #include <Dt/DtNlUtils.h>
56 #include <Dt/UserMsg.h>
57 #include <Dt/CommandM.h>
58
59 #include <Dt/ActionUtilP.h>
60 #include <Dt/ActionP.h>
61 #include <Dt/ActionDbP.h>
62
63 #include <Dt/Utility.h>
64 #include <Dt/DtsDb.h>
65 #include <Dt/Dts.h>
66
67 #include "myassertP.h"
68 #include "DtSvcLock.h"
69
70 /********    Global Function Declarations    ********/
71
72 extern Boolean _DtEmptyString( 
73                         String str) ;
74
75 /********    End Private Function Declarations    ********/
76
77
78 /********    Static Function Declarations    ********/
79
80 static void InitializeLocalizedStrings ( void ) ;
81
82 /********    End Static Function Declarations    ********/
83
84 /*
85  * Pointers to the localized strings.
86  */
87
88 static char *noFields;
89 static char *unrecogField;
90 static char *unrecogType;
91 static char *noMapTo;
92 static char *noExecString;
93 static char *unrecogMsgType;
94 static char *dupFields;
95 static char *invldField;
96 static char *missingField;
97 static char *missingName;
98 static char *unrecogMsgType2;
99
100
101 /*****************************************************************************
102  *****************************************************************************
103  *
104  *      Public API Functions
105  *
106  *****************************************************************************
107  *****************************************************************************/
108
109 /* none here */
110
111 /******************************************************************************
112  ******************************************************************************
113  *
114  *      Private API Functions
115  *
116  ******************************************************************************
117  ******************************************************************************/
118
119 /******************************************************************************
120  *      
121  *      String Utilities
122  *
123  ******************************************************************************/
124
125 /*
126  * See if two strings are exactly the same.
127  */
128
129 Boolean 
130 _DtStringsAreEqual(
131         String string1,
132         String string2 )
133 {
134    if ((strcmp(string1, string2) == 0) && (strlen(string1) == strlen(string2)))
135       return(True);
136
137    return(False);
138 }
139
140
141 /*
142  * Return TRUE if the string pointer is NULL, or if the string is empty.
143  * Empty is also defined to be nothing but spaces.
144  */
145
146 Boolean 
147 _DtEmptyString(
148         String str )
149 {
150    if ((str == NULL)||(strlen(str) == 0)||(strlen(str) == DtStrspn(str, " ")))
151       return(True);
152
153    return(False);
154 }
155
156 typedef struct {
157         char *name;
158         unsigned long bit;
159 } _DtActNameAndBit; 
160
161
162 #ifdef _DT_ALLOW_DT_MSGS
163 /*
164  * The "DT_ARGn_VALUE" and "TT_ARGn_VALUE" field names are represented by
165  * macros (_DtACTION_DTN_VALUE, _DtACTION_TTN_VALUE) which define identical
166  * strings "_VALUE". (The field names minus the "[DT]_ARGn" prefix.)
167  *
168  * To allow an unambiguous table lookup by field name we add the
169  * _DtPFX prefix macro to the "DT_ARGn" field name. 
170  */
171 #define _DtPFX  "DT_"
172 #endif  /* _DT_ALLOW_DT_MSGS */
173
174 /*
175  * List all the action record fields we care about
176  * along with the bitmask that represents the field.
177  */
178 static _DtActNameAndBit _DtActNamesAndBits[] = {
179         _DtACTION_LABEL,                _ActDb_LABEL_SET,
180         _DtACTION_TYPE,                 _ActDb_TYPE_SET,
181         _DtACTION_ARG_CLASS,            _ActDb_ARG_CLASS_SET,
182         _DtACTION_ARG_MODE,             _ActDb_ARG_MODE_SET,
183         _DtACTION_ARG_TYPE,             _ActDb_ARG_TYPE_SET,
184         _DtACTION_ARG_COUNT,            _ActDb_ARG_COUNT_SET,
185         _DtACTION_DESCRIPTION,          _ActDb_DESCRIPTION_SET,
186         _DtACTION_ICON,                 _ActDb_ICON_SET,
187 /*******************************************************************
188 Meaningless for actions -- ignore these for now
189         _DtACTION_INSTANCE_ICON,        _ActDb_INSTANCE_ICON_SET,
190 *******************************************************************/
191         _DtACTION_MAP_ACTION,           _ActDb_MAP_ACTION_SET,
192         _DtACTION_EXEC_STRING,          _ActDb_EXEC_STRING_SET,
193         _DtACTION_EXEC_HOST,            _ActDb_EXEC_HOST_SET,
194         _DtACTION_CWD,                  _ActDb_CWD_SET,
195         _DtACTION_WINDOW_TYPE,          _ActDb_WINDOW_TYPE_SET,
196         _DtACTION_TERM_OPTS,            _ActDb_TERM_OPTS_SET,
197         _DtACTION_TT_CLASS,             _ActDb_TT_CLASS_SET,
198         _DtACTION_TT_SCOPE,             _ActDb_TT_SCOPE_SET,
199         _DtACTION_TT_OPERATION,         _ActDb_TT_OPERATION_SET,
200         _DtACTION_TT_FILE,              _ActDb_TT_FILE_SET,
201         _DtACTION_TTN_MODE,             _ActDb_TT_ARGN_MODE_SET,
202         _DtACTION_TTN_VTYPE,            _ActDb_TT_ARGN_VTYP_SET,
203         _DtACTION_TTN_REP_TYPE,         _ActDb_TT_ARGN_RTYP_SET,
204         _DtACTION_TTN_VALUE,            _ActDb_TT_ARGN_VAL_SET,
205
206 #ifdef _DT_ALLOW_DT_MSGS
207         _DtACTION_DT_REQUEST_NAME,      _ActDb_DT_REQ_NAME_SET,
208         _DtACTION_DT_SVC,               _ActDb_DT_SVC_SET,
209         _DtACTION_DT_NOTIFY_NAME,       _ActDb_DT_NTFY_NAME_SET,
210         _DtACTION_DT_NGROUP,            _ActDb_DT_NGROUP_SET,
211         _DtPFX _DtACTION_DTN_VALUE,     _ActDb_DT_ARGN_VAL_SET,
212 #endif  /* _DT_ALLOW_DT_MSGS */
213         NULL,                           0
214 };
215
216 #define NUM_FIELD_NAMES         sizeof(_DtActNamesAndBits)/sizeof(_DtActNameAndBit) - 1
217
218 /******************************************************************************
219  *
220  * _DtActFieldBitLookup
221  *      Lookup the mask value associated with the given field name in the array
222  *      of names and field bits.  If the field name is not recognized return the
223  *      default value associated with the NULL field name  (i.e. 0 ).
224  *
225  ******************************************************************************/
226  
227 static
228 unsigned long
229 _DtActFieldBitLookup(char *name)
230 {
231         register int j;
232         char *np = name;
233 #ifdef _DT_ALLOW_DT_MSGS
234         char dtnamebuf[sizeof(_DtPFX) + sizeof(_DtACTION_DTN_VALUE)] = _DtPFX;
235 #endif  /* _DT_ALLOW_DT_MSGS */
236
237         if ( !np )
238                 return 0;
239         /*
240          * Check for [DT]T_ARGn_ fields
241          * The following code assumes that a unique suffix identifying each
242          * field results from stripping off the leading "[DT]_ARGn" string.
243          * This assumption is not valid for DT_ARGn_VALUE and TT_ARGn_VALUE.
244          * so we resort to further skulduggery.
245          */
246         if ( !strncmp("TT_ARG",np,sizeof("TT_ARG")-1) )
247         {
248                 np = np + sizeof("TT_ARG"); /* first char beyond prefix */
249                 while( *np && (mblen(np,MB_CUR_MAX) == 1) && DtIsdigit(np) )  
250                     np=DtNextChar(np);  /* skip past digits */
251         } 
252 #ifdef  _DT_ALLOW_DT_MSGS
253         else if ( !strncmp("DT_ARG",np,sizeof("DT_ARG")-1) )
254         {
255                 np = np + sizeof("DT_ARG"); /* first char beyond prefix */
256                 while( *np && (mblen(np,MB_CUR_MAX) == 1) && DtIsdigit(np) ) 
257                        np=DtNextChar(np);  /* skip past digits */
258
259                 /*
260                  * Add the prefix to disambiguate the field name for
261                  * the table lookup.
262                  */
263                 np=strcat(dtnamebuf,np);
264                 
265
266         }
267 #endif  /* _DT_ALLOW_DT_MSGS */
268
269         if ( !np )
270                 return 0;
271
272         for ( j = 0; j < NUM_FIELD_NAMES; j++ )
273                 if ( !strcmp(_DtActNamesAndBits[j].name,np) )
274                         break;  /* found matching field name */
275
276         return _DtActNamesAndBits[j].bit;
277 }
278
279 /******************************************************************************
280  *
281  * _DtActFieldNameLookup
282  *      Lookup the name string associated with the given mask bit in the array
283  *      of names and field bits.  If the mask bit is not recognized return the
284  *      default value associated with the NULL field name  (i.e. 0 ).
285  *
286  ******************************************************************************/
287  
288 static char *
289 _DtActFieldNameLookup(long bitmask)
290 {
291         register int j;
292
293         if ( !bitmask )
294                 return NULL;
295
296         for ( j = 0; j < NUM_FIELD_NAMES; j++ )
297                 if ( _DtActNamesAndBits[j].bit == bitmask )
298                         break;  /* found matching field name */
299
300         return _DtActNamesAndBits[j].name;
301 }
302
303
304 /******************************************************************************
305  *
306  * _DtActDupFieldNameCheck
307  *      return True if "name" duplicates an existing fieldName.
308  *
309  ******************************************************************************/
310 static Boolean
311 _DtActDupFieldNameCheck(DtDtsDbField **fields,int numFields,XrmQuark name)
312 {
313         register int i;
314
315         for ( i = 0; i < numFields; i++ ) 
316         {
317                 if (fields[i]->fieldName == name)
318                         return True;    
319         }
320
321         return False;
322 }
323
324
325 /******************************************************************************
326  *
327  * _DtActValidateFieldValue 
328  *      Given a bitmask and action database field value  apply some heuristics
329  *      to determine the validity of the value.  Return a newly allocated 
330  *      "sanitized" value for valid fields,  NULL otherwise.
331  *
332  ******************************************************************************/
333 static char *
334 _DtActValidateFieldValue( long bit, char *value, char *actName, char *filename)
335 {
336         char *val;
337         char *start;
338         char *p = NULL;
339         char bigBuf[_DtAct_MAX_BUF_SIZE];
340         char *buf = bigBuf;
341
342         if (!(value && *value))
343         {
344                 /*
345                  * Empty field value -- ignore
346                  */
347                 return NULL;
348         }
349
350         /* work on a new copy of the value */
351         val =   strdup( value );
352
353         /*
354          * Strip trailing blanks from all fields except EXEC_STRING and
355          * DESCRIPTION.  The database reader should guarantee that leading
356          * blanks have been stripped from the value field.
357          */
358         if ( !(bit & ( _ActDb_EXEC_STRING_SET | _ActDb_DESCRIPTION_SET )))
359                 _DtRemoveTrailingBlanksInPlace(&val);
360         
361         switch ( bit )
362         {
363         case _ActDb_TYPE_SET:
364                 if (    strcmp(_DtACTION_MAP,val)
365                         && strcmp(_DtACTION_COMMAND,val)
366                         && strcmp(_DtACTION_TT_MSG,val)
367 #ifdef _DT_ALLOW_DT_MSGS
368                         && strcmp(_DtACTION_DT_REQUEST,val)
369                         && strcmp(_DtACTION_DT_NOTIFY,val)  
370 #endif  /* _DT_ALLOW_DT_MSGS */
371                          )
372                 {
373                         /*
374                          * Invalid field value -- issue error msg.
375                          */
376                         buf = malloc(_DtAct_MAX_BUF_SIZE);
377                         (void) sprintf(buf, unrecogMsgType, actName, filename,
378                                         val, _DtACTION_TYPE);
379                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
380                         if ( val ) free(val);
381                         if (buf) free(buf);
382                         return NULL;
383                 }
384                 break;
385         case _ActDb_EXEC_HOST_SET:
386                 /*
387                  * Do NOT add to an existing EXEC_HOST definition.
388                  */
389                 break;
390         case _ActDb_ARG_CLASS_SET:
391
392                 /* Check the list of classes */
393                 p = NULL;
394                 start = val;
395                 while ( (p = DtStrchr(start,_DtACT_LIST_SEPARATOR_CHAR)) )
396                 {
397                         /*
398                          * temporarily truncate string for testing
399                          */
400                         *p = '\0';
401                         if (    strcmp(_DtACT_ANY,start)          &&
402                                 strcmp(_DtACTION_FILE,start)    && 
403                                 strcmp(_DtACTION_BUFFER,start)   )
404                         {
405                                 /*
406                                  * Invalid field value -- issue error msg.
407                                  */
408                                 buf = malloc(_DtAct_MAX_BUF_SIZE);
409                                 (void) sprintf(buf, unrecogMsgType, actName, filename,
410                                                 start, _DtACTION_ARG_CLASS);
411                                 _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
412                                 if ( val ) free(val);
413                                 if (buf) free(buf);
414                                 return NULL;
415                         }
416                         *p = _DtACT_LIST_SEPARATOR_CHAR;
417                         start = p+1;
418                 } 
419                 if (    strcmp(_DtACT_ANY,start)          &&
420                         strcmp(_DtACTION_FILE,start)    && 
421                         strcmp(_DtACTION_BUFFER,start)   )
422                 {
423                         /*
424                          * Invalid field value -- issue error msg.
425                          */
426                         buf = malloc(_DtAct_MAX_BUF_SIZE);
427                         (void) sprintf(buf, unrecogMsgType, actName, filename,
428                                         start, _DtACTION_ARG_CLASS);
429                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
430                         if ( val ) free(val);
431                         if (buf) free(buf);
432                         return NULL;
433                 }
434                 break;
435         case _ActDb_ARG_MODE_SET:
436                 /* Check for the valid values of ARG_MODE */
437                 if (    strcmp(val,_DtACT_ANY)
438                      && strcmp(val, _DtACT_ARG_MODE_WRITE)
439                      && strcmp(val, _DtACT_ARG_MODE_NOWRITE) )
440                 {
441                         /* Invalid Value for ARG_MODE */
442                         buf = malloc(_DtAct_MAX_BUF_SIZE);
443                         (void) sprintf(buf, unrecogMsgType, actName, filename,
444                                         val, _DtACTION_ARG_MODE);
445                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
446                         if ( val ) free(val);
447                         buf = malloc(_DtAct_MAX_BUF_SIZE);
448                         return NULL;
449                 }
450                 break;  /* valid value */
451         case _ActDb_ARG_TYPE_SET:
452                 /* We cannot yet check arg types the database is not complete */
453                 break;
454         case _ActDb_ARG_COUNT_SET:
455                 if ( !strcmp(val,_DtACT_ANY) )
456                         break;
457                 for (p=val; *p; p=DtNextChar(p)) 
458                 {
459                         if ( p == val && ((*p == _DtACT_LT_CHAR) 
460                              || (*p == _DtACT_GT_CHAR))) 
461                         {
462                                 /* skip past "> or <" modifiers */
463                                 p=DtNextChar(p);
464                         }
465                         if ( !(mblen(p,MB_CUR_MAX) == 1 && DtIsdigit(p)) )
466                         {
467                                 /*
468                                  * Report Error -- invalid field
469                                  */
470                                 buf = malloc(_DtAct_MAX_BUF_SIZE);
471                                 (void) sprintf(buf, unrecogMsgType, actName,
472                                                 filename, val,
473                                                 _DtACTION_ARG_COUNT);
474                                 _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
475                                 if ( val ) free(val);
476                                 if (buf) free(buf);
477                                 return NULL;
478                         }
479                 }
480                 break;
481         case _ActDb_WINDOW_TYPE_SET:
482                 if (    strcmp(_DtACTION_TERMINAL,val)          && 
483                         strcmp(_DtACTION_PERM_TERMINAL,val)     &&
484                         strcmp(_DtACTION_NO_STDIO,val)   )
485                 {
486                         /*
487                          * Invalid field value -- issue error msg.
488                          */
489                         buf = malloc(_DtAct_MAX_BUF_SIZE);
490                         (void) sprintf(buf, unrecogMsgType, actName, filename,
491                                         val, _DtACTION_WINDOW_TYPE);
492                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
493                         if (val) free(val);
494                         if (buf) free(buf);
495                         return NULL;
496                 }
497                 break;
498         case _ActDb_CWD_SET:
499                 /*
500                  * This field must be in [host:]/path format
501                  *
502                  * WE REQUIRE A FULL PATH NAME TO BE SPECIFIED FOR THE
503                  * DIRECTORY OTHERWISE WE CANNOT DISTINGUISH BETWEEN A
504                  * RELATIVE FILE ENDING IN ':' AND A HOSTNAME FOLLOWED
505                  * BY A ':'.
506                  */
507                 if ( *val == '/' 
508                      && !( (mblen(val,MB_CUR_MAX) == 1) 
509                             && DtIsspace(DtNextChar(val))) )
510                         break;  /* Accept as good with no hostname */
511
512                 for ( p = val; *p ; p=DtNextChar(p) ) 
513                 {
514
515                         /*
516                          * Accept as a valid hostname as long as 
517                          * there is a string of non-white
518                          * and non-slash characters before the first
519                          * colon and the first colon is immediately
520                          * followed by a slash.
521                          */
522                         if ( (*p == ':' )  
523                              && ( *(DtNextChar(p)) == '/' ) && ( p != val) )
524                                 break;  /* Accept this as good with hostname */
525
526
527                         if ( (*p == '/') 
528                               || ( (mblen(p,MB_CUR_MAX) == 1) && DtIsspace(p)))
529                         {
530                                 /* looks like an error */
531                                 buf = malloc(_DtAct_MAX_BUF_SIZE);
532                                 (void) sprintf(buf, unrecogMsgType, actName,
533                                                 filename, val, _DtACTION_CWD);
534                                 _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
535                                 if ( val ) free(val);
536                                 if (buf) free(buf);
537                                 /*********************
538                                   reject the entire record containing this field
539                                 *********************/
540                                 return (char *) -1;
541                         }
542                 }
543                 if (*p == '\0')
544                 {
545                         /* looks like an error */
546                         buf = malloc(_DtAct_MAX_BUF_SIZE);
547                         (void) sprintf(buf, unrecogMsgType, actName,
548                                         filename, val, _DtACTION_CWD);
549                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
550                         if (val) free(val);
551                         if (buf) free(buf);
552                         /*********************
553                           reject the entire record containing this field
554                         *********************/
555                         return (char *) -1;
556                 }
557                 break;
558         case _ActDb_TT_CLASS_SET:
559                 if (    strcmp(_DtACTION_TT_NOTICE,val) && 
560                         strcmp(_DtACTION_TT_REQUEST,val)   )
561                 {
562                         /*
563                          * Invalid field value -- issue error msg.
564                          */
565                         buf = malloc(_DtAct_MAX_BUF_SIZE);
566                         (void) sprintf(buf, unrecogMsgType, actName, filename,
567                                         val, _DtACTION_TT_CLASS);
568                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
569                         if ( val ) free(val);
570                         if (buf) free(buf);
571                         return NULL;
572                 }
573                 break;
574         case _ActDb_TT_SCOPE_SET:
575                 if (    strcmp(_DtACTION_TT_SESSION,val)        && 
576                         strcmp(_DtACTION_TT_FILE,val)           &&
577                         strcmp(_DtACTION_TT_BOTH,val)           &&
578                         strcmp(_DtACTION_TT_FILE_IN_SESSION,val)  )
579                 {
580                         /*
581                          * Invalid field value -- issue error msg.
582                          */
583                         buf = malloc(_DtAct_MAX_BUF_SIZE);
584                         (void) sprintf(buf, unrecogMsgType, actName, filename,
585                                         val, _DtACTION_TT_SCOPE);
586                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
587                         if ( val ) free(val);
588                         if (buf) free(buf);
589                         return NULL;
590                 }
591                 break;
592         case _ActDb_TT_FILE_SET:
593                 /*
594                  * Must be a real file (host:/syntax?) 
595                  * -- convert to network file syntax?
596                  * or %ARG_n% keyword. 
597                  * NOTE: only one file may be specified
598                  */ 
599                 break;
600         case _ActDb_TT_ARGN_MODE_SET:
601                 /*
602                  * MODE is required for tooltalk actions
603                  * it must be one of TT_IN, TT_OUT or TT_INOUT
604                  */
605                 if (    strcmp(_DtACTION_TT_MODE_IN,val ) &&
606                         strcmp(_DtACTION_TT_MODE_OUT,val) &&
607                         strcmp(_DtACTION_TT_MODE_INOUT,val) )
608                 {
609                         /*
610                          * Invalid field value -- issue error msg.
611                          */
612                         buf = malloc(_DtAct_MAX_BUF_SIZE);
613                         (void) sprintf(buf, unrecogMsgType2, actName, filename,
614                                         val, _DtACTION_TTN_ARG,
615                                         "n", _DtACTION_TTN_MODE);
616                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
617                         if ( val ) free(val);
618                         if (buf) free(buf);
619                         return NULL;
620                 }
621                 break;
622         case _ActDb_TT_ARGN_VTYP_SET:
623                 /*
624                  * VTYPE -- semantic type name (i.e. title) applied to tooltalk
625                  * message value (TT_ARGn_VALUE).  The value of this field is
626                  * either an arbitrary string, or an action argument reference
627                  * (i.e. %Arg_n%).
628                  */
629                 break;
630         case _ActDb_TT_ARGN_RTYP_SET:
631                 /*
632                  * REP_TYPE -- representation type of the corresponding tooltalk value.
633                  * Valid values are: UNDEFINED, INTEGER, BUFFER, and STRING.
634                  */
635                 if (    strcmp(_DtACTION_TT_RTYP_UND,val ) &&
636                         strcmp(_DtACTION_TT_RTYP_INT,val) &&
637                         strcmp(_DtACTION_TT_RTYP_BUF,val) &&
638                         strcmp(_DtACTION_TT_RTYP_STR,val) )
639                 {
640                         /*
641                          * Invalid field value -- issue error msg.
642                          */
643                         buf = malloc(_DtAct_MAX_BUF_SIZE);
644                         (void) sprintf(buf, unrecogMsgType2, actName, filename,
645                                         val, _DtACTION_TTN_ARG,
646                                         "n", _DtACTION_TTN_REP_TYPE);
647                         _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
648                         if ( val ) free(val);
649                         if (buf) free(buf);
650                         return NULL;
651                 }
652                 break;
653         case _ActDb_TT_ARGN_VAL_SET:
654                 /*
655                  * The value for the Nth tooltalk argument.  This field may be
656                  * an arbitrary string.
657                  */
658                 break;
659 #ifdef  _DT_ALLOW_DT_MSGS
660         case _ActDb_DT_REQ_NAME_SET:
661                 break;
662         case _ActDb_DT_NTFY_NAME_SET:
663                 break;
664 #endif  /* _DT_ALLOW_DT_MSGS */
665         default:
666                 break;
667         }
668
669         return val;
670 }
671
672 static char *
673 _DtActCheckRecord( 
674         DtDtsDbRecord *actp, 
675         char    *actionType,
676         unsigned long mask, 
677         char *fileName  )
678 {
679         int     i;
680         char    *s;
681         char argnFieldName[
682                 sizeof(_DtACTION_TTN_ARG) +      /* ARGn prefix */
683                 3 +                             /* space for 3 decimal digits */
684                 sizeof(_DtACTION_TTN_REP_TYPE)]; /* space for longest suffix */
685         char *buf;
686
687         myassert(actionType);   /* actionType should never be NULL */
688
689         /*
690          * Check action type information for accuracy/completeness.
691          */
692         if ( !strcmp(actionType,_DtACTION_COMMAND) )
693         {
694                 /*
695                  * Check that all recognized fields are suitable for
696                  * COMMAND type actions.
697                  */
698                 if ( mask & ( 
699                         _ActDb_TT_BITS 
700 #ifdef _DT_ALLOW_DT_MSGS
701                         |  _ActDb_DT_REQUEST_BITS 
702                         |  _ActDb_DT_NOTIFY_BITS
703 #endif  /* _DT_ALLOW_DT_MSGS */
704                         | _ActDb_MAP_BITS ))
705                 {
706                         /*
707                          * Fields unsuitable for COMMAND type actions were 
708                          * found. -- reject this record.
709                          */
710                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
711                         (void) sprintf (buf, invldField, 
712                                 XrmQuarkToString(actp->recordName),
713                                 fileName, _DtACTION_COMMAND );
714                         return buf;
715                 }
716
717                 /*
718                  * Check that all required fields are present or that
719                  * the appropriate default has been set.
720                  */
721                 if ( !(mask & _ActDb_EXEC_STRING_SET) )
722                 {
723                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
724                         (void) sprintf (buf, noExecString, 
725                                 XrmQuarkToString(actp->recordName),
726                                 fileName, _DtACTION_EXEC_STRING);
727                         return buf;
728                 }
729         }
730         else if ( !strcmp(actionType,_DtACTION_MAP) )
731         {
732                 /*
733                  * Check that all recognized fields are suitable for
734                  * MAP type actions.
735                  */
736                 if ( mask & ( 
737                          _ActDb_TT_BITS 
738 #ifdef _DT_ALLOW_DT_MSGS
739                         |  _ActDb_DT_REQUEST_BITS 
740                         | _ActDb_DT_NOTIFY_BITS
741 #endif  /* _DT_ALLOW_DT_MSGS */
742                         | _ActDb_CMD_BITS ))
743                 {
744                         /*
745                          * Fields unsuitable for MAP type actions were 
746                          * found. -- reject this record.
747                          */
748                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
749                         (void) sprintf (buf, invldField, 
750                                 XrmQuarkToString(actp->recordName),
751                                 fileName, _DtACTION_MAP );
752                         return buf;
753                 }
754                 /*
755                  * Check for required fields
756                  */
757                 if ( !(mask & _ActDb_MAP_ACTION_SET) )
758                 {
759                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
760                         (void) sprintf (buf, missingField, 
761                                 XrmQuarkToString(actp->recordName),
762                                 fileName, _DtACTION_MAP_ACTION, _DtACTION_MAP);
763                         return buf;
764                 }
765
766         }
767         else if ( !strcmp(actionType,_DtACTION_TT_MSG) )
768         {
769                 /*
770                  * Check that all recognized fields are suitable for
771                  * TT_MSG type actions.
772                  */
773                 if ( mask & (
774                           _ActDb_CMD_BITS 
775 #ifdef _DT_ALLOW_DT_MSGS
776                         | _ActDb_DT_NOTIFY_BITS
777                         | _ActDb_DT_REQUEST_BITS 
778 #endif  /* _DT_ALLOW_DT_MSGS */
779                         | _ActDb_MAP_BITS ))
780                 {
781                         /*
782                          * Fields unsuitable for TT_MSG type actions were 
783                          * found. -- reject this record.
784                          */
785                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
786                         (void) sprintf (buf, invldField, 
787                                 XrmQuarkToString(actp->recordName),
788                                 fileName, _DtACTION_TT_MSG );
789                         return buf;
790                 }
791
792                 /*
793                  * Insure that all the required fields are present.
794                  */
795                 if ( !(mask & _ActDb_TT_CLASS_SET) )
796                 {
797                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
798                         (void) sprintf (buf, missingField, 
799                                 XrmQuarkToString(actp->recordName),
800                                 fileName, _DtACTION_TT_CLASS, _DtACTION_TT_MSG);
801                         return buf;
802                 }
803                 if ( !(mask & _ActDb_TT_SCOPE_SET) )
804                 {
805                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
806                         (void) sprintf (buf, missingField, 
807                                 XrmQuarkToString(actp->recordName),
808                                 fileName, _DtACTION_TT_SCOPE, _DtACTION_TT_MSG);
809                         return buf;
810                 }
811                 if ( !(mask & _ActDb_TT_OPERATION_SET) )
812                 {
813                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
814                         (void) sprintf (buf, missingField, 
815                                 XrmQuarkToString(actp->recordName),
816                                 fileName, _DtACTION_TT_OPERATION,
817                                          _DtACTION_TT_MSG);
818                         return buf;
819                 }
820
821                 /*
822                  * Check if tooltalk arg info is supplied by this action
823                  */
824                 if ( (mask & _ActDb_TT_ARGN_BITS) )
825                 {
826                         /*
827                          * Check for consistency of the fields
828                          * describing tooltalk arguments.
829                          */
830                         if ( !( mask & _ActDb_TT_ARGN_MODE_SET) )
831                         {
832                                 char argModeString[ 1
833                                         + sizeof(_DtACTION_TTN_ARG)
834                                         + sizeof(_DtACTION_TTN_MODE)];
835                                 /*
836                                  * Missing required arg mode
837                                  */
838                                 sprintf(argModeString,"%s%s%s",
839                                         _DtACTION_TTN_ARG,
840                                         "n",
841                                         _DtACTION_TTN_MODE);
842                                 buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
843                                 (void) sprintf (buf, missingField, 
844                                         XrmQuarkToString(actp->recordName),
845                                         fileName, 
846                                         argModeString,
847                                         _DtACTION_TT_MSG);
848                                 return buf;
849                         }
850
851                         /* 
852                          * For each tt arg mode specifier see that the other
853                          * required info has been supplied.
854                          * -- If a mode specifier is missing for a TT argument;
855                          *    that argument and all subsequent TT args will
856                          *    be ignored.
857                          *   MOVE THIS UP TO DATABASE LOAD TIME
858                          */
859                         for ( i = 0; True; i++ )
860                         {
861                                 sprintf(argnFieldName,"%s%d%s",
862                                          _DtACTION_TTN_ARG, i, _DtACTION_TTN_MODE);
863                                 if ( !(s = _DtDtsDbGetFieldByName(actp,
864                                                 argnFieldName)) )
865                                         break;  /* no argn mode  specified */
866                                 /*
867                                  * See that the other required tt argn 
868                                  * fields exist for n == i.
869                                  */
870                         
871                                 if ( strcmp(s, _DtACTION_TT_MODE_OUT ) )
872                                 {
873                                         char *modeStr = s;
874                                         /*
875                                          * VTYPE is required for mode 
876                                          * TT_IN/TT_INOUT 
877                                         */
878                                         sprintf(argnFieldName,"%s%d%s",
879                                                  _DtACTION_TTN_ARG, i,
880                                                  _DtACTION_TTN_VTYPE);
881                                         if (!(s= _DtDtsDbGetFieldByName(actp,
882                                                  argnFieldName)))
883                                         {
884                                                 /*
885                                                  * Missing required field 
886                                                  */
887                                                 buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
888                                                 (void) sprintf (buf, 
889                                                         missingField,
890                                                         XrmQuarkToString(actp->recordName),
891                                                         fileName,
892                                                         argnFieldName,
893                                                         modeStr);
894                                                 return buf;
895                                         }
896                                 }
897                                 /* RWV -- more checks to add */
898                         }
899
900                 }
901
902         }
903 #ifdef _DT_ALLOW_DT_MSGS
904         else if  ( !strcmp(actionType,_DtACTION_DT_REQUEST))
905         {
906                 /*
907                  * Check that all recognized fields are suitable for
908                  * DT_REQUEST type actions.
909                  */
910                 if ( mask & ( _ActDb_CMD_BITS 
911                         | _ActDb_DT_NOTIFY_BITS
912                         | _ActDb_TT_BITS 
913                         | _ActDb_MAP_BITS ))
914                 {
915                         /*
916                          * Fields unsuitable for DT_REQUEST type actions were 
917                          * found. -- reject this record.
918                          */
919                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
920                         (void) sprintf (buf, invldField, 
921                                 XrmQuarkToString(actp->recordName),
922                                 fileName, _DtACTION_DT_REQUEST );
923                         return buf;
924                 }
925
926         }
927         else if  ( !strcmp(actionType,_DtACTION_DT_NOTIFY))
928         {
929                 /*
930                  * Check that all recognized fields are suitable for
931                  * Dt_NOTIFY type actions.
932                  */
933                 if ( mask & ( _ActDb_DT_REQUEST_BITS 
934                         | _ActDb_CMD_BITS
935                         | _ActDb_TT_BITS 
936                         | _ActDb_MAP_BITS ))
937                 {
938                         /*
939                          * Fields unsuitable for DT_NOTIFY type actions were 
940                          * found. -- reject this record.
941                          */
942                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
943                         (void) sprintf (buf, invldField, 
944                                 XrmQuarkToString(actp->recordName),
945                                 fileName, _DtACTION_DT_NOTIFY );
946                         return buf;
947                 }
948
949         }
950 #endif  /* _DT_ALLOW_DT_MSGS */
951         else
952         {
953
954                 /*
955                  * Unrecognized action type
956                  * Throw out the whole record
957                  */
958                 buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
959                 (void) sprintf (buf, unrecogType, _DtACTION_TYPE,
960                          actionType, fileName );
961                 return buf;
962         }
963
964         /*
965          * The record checks out OK
966          */
967         return NULL;
968 }
969
970 /******************************************************************************
971  *
972  * _DtActionConverter - given a list of the fields for an action
973  *   definition, put the definition into an internal array.
974  *
975  * Returns 'True' if the definition was rejected for any reason, otherwise,
976  * 'False' is returned.
977  *
978  * Note:     Space that is allocated for database structures uses vanilla
979  *       malloc/strdup/realloc/free functions because the database 
980  *       component (Dts) attempts to be independent of X and Xt.  
981  *           Space for local usage is allocated using XtMalloc/XtNewString/
982  *       /XtRealloc/XtFree family of functions which are somewhat more robust
983  *       than the vanilla allocators.
984  *
985  * (Replaces _DtParseActionDbEntry)
986  *****************************************************************************/
987
988 Boolean
989 _DtActionConverter(DtDtsDbField * fields,
990                DtDbPathId pathId,
991                char *hostPrefix,
992                Boolean rejectionStatus)
993 {
994         static  int     firstTime = True;
995         DtDtsDbDatabase *act_db;
996         DtDtsDbRecord   *act_rec;
997         DtDtsDbField    *fld;
998         register int    i;
999         unsigned int    mask = 0;
1000         char            bigBuf[_DtAct_MAX_BUF_SIZE];
1001         char            *buf = bigBuf;
1002         char            *fileName = _DtDbPathIdToString(pathId);
1003         char            *actionType;
1004
1005         _DtSvcProcessLock();       
1006         if (firstTime)
1007         {
1008                 firstTime = False;
1009                 InitializeLocalizedStrings ();
1010         }
1011
1012         /*
1013          * The action database should have been initialized in
1014          * DtDbLoad().
1015          */
1016         act_db = _DtDtsDbGet(_DtACTION_NAME);
1017         myassert(act_db);
1018
1019         /* Action records require that an action name be specified */
1020         if (fields[0].fieldValue == NULL)
1021         {
1022                 
1023                 buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
1024                 sprintf (buf, missingName, _DtACTION_NAME, fileName);
1025                 _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
1026                 XtFree(fileName);
1027                 if (buf) XtFree(buf);
1028                 _DtSvcProcessUnlock();
1029                 return(True);
1030         }
1031         else if (  fields[1].fieldName == 0)
1032         {
1033                 /* The record contains no fields */
1034                 buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
1035                 (void) sprintf (buf, noFields, fields[0].fieldValue, fileName);
1036                 _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
1037                 XtFree(fileName);
1038                 if (buf) XtFree(buf);
1039                 _DtSvcProcessUnlock();
1040                 return(True);
1041         }
1042
1043
1044         /*
1045          * The first field contains the record name.
1046          */
1047         act_rec = _DtDtsDbAddRecord(act_db);
1048         act_rec->recordName = XrmStringToQuark(fields[0].fieldValue);
1049
1050         /*
1051          * Get all the field data  -- we may get an arbitrary number
1052          * of TT_ARGn_MODE, TT_ARGn_VTYPE, or  DT_ARGn_VALUE fields.
1053          * We may also want to support user-defined fields at some
1054          * time in the future -- for now reject unrecognized fileds.
1055          */
1056         for ( i=1; fields[i].fieldName; i++)
1057         {
1058                 unsigned long ThisBit = 0;
1059                 char *fieldVal = NULL;
1060
1061                 /* find the corresponding field entry and bitmask */
1062
1063                 if ((ThisBit = _DtActFieldBitLookup(XrmQuarkToString(fields[i].fieldName))) != 0)
1064                 {
1065                         switch ((int)(fieldVal=_DtActValidateFieldValue(ThisBit,
1066                                 fields[i].fieldValue, fields[0].fieldValue,
1067                                 fileName)))
1068                         {
1069                         case 0:
1070                                 /* 
1071                                  *  invalid minor field 
1072                                  *  -- reject field only
1073                                  */
1074                                 continue;
1075                                 break;
1076                         case -1:
1077                                 /*
1078                                  *  Invalid critical field 
1079                                  *  --reject entire record
1080                                  */
1081                                 _DtDtsDbDeleteRecord(act_rec,act_db);
1082                                 XtFree(fileName);
1083                                 _DtSvcProcessUnlock();
1084                                 return True;
1085                                 break;
1086                         default:
1087                                 /*
1088                                  * validated fieldVal returned
1089                                  */
1090                                 break;
1091                         }
1092                                         
1093                         if ( ThisBit == _ActDb_TYPE_SET )
1094                                 actionType =  fieldVal;
1095                 }
1096                 else    /* Unrecognized Field */
1097                 {
1098
1099                         /*
1100                          * Unrecognized Field:
1101                          *    issue a warning and ignore it for now.
1102                          * --- Later we may decide to
1103                          * store arbitrary fields for users. 
1104                          * As a control we may require that a user field
1105                          * name begin with some well-known string
1106                          * -- say "USER_".
1107                          */
1108                         buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
1109                         (void) sprintf (buf, unrecogField, 
1110                                         fields[0].fieldValue, 
1111                                         fileName, 
1112                                         XrmQuarkToString(fields[i].fieldName),
1113                                         fields[i].fieldValue);
1114
1115
1116
1117                         /*************************************************
1118                          * Unrecognized Field -- lets NOT reject the 
1119                          * entire record (for now) and just ignore the
1120                          * unrecognized field.  -- this allows old
1121                          * syntax to exist in an action record without
1122                          * causing outright rejection of the record.
1123                          * We may decide to reject such records again
1124                          * once things settle down, hence the UNREACHABLE
1125                          * code which follows the continue statement.
1126                          *************************************************/
1127                         _DtSimpleError(DtProgName,DtWarning, NULL, "%s", buf);
1128                         if (buf) XtFree(buf);
1129                         continue;
1130                 }
1131
1132                 if ( mask & ThisBit )
1133                 {
1134                         /*
1135                          * An exhaustive name check is required for the "*_ARGn_"
1136                          * fields -- a simple bitmask check is sufficient for
1137                          * other field names.
1138                          */
1139                         if ( ((ThisBit & _ActDb_ARGN_BITS) 
1140                                 && _DtActDupFieldNameCheck( act_rec->fieldList,
1141                                         act_rec->fieldCount,
1142                                         fields[i].fieldName)) 
1143                                 || !(ThisBit & _ActDb_ARGN_BITS) )      
1144                         {
1145                                 /*
1146                                  * Attempt to redefine a field
1147                                  * reject this record.
1148                                  */
1149                                 buf = XtMalloc(_DtAct_MAX_BUF_SIZE);
1150                                 (void) sprintf (buf,dupFields, fields[0].fieldValue, 
1151                                                  fileName, 
1152                                                  XrmQuarkToString(fields[i].fieldName));
1153                                 _DtSimpleError(DtProgName,DtError, NULL, "%s", buf);
1154                                 _DtDtsDbDeleteRecord(act_rec,act_db);
1155                                 XtFree(fileName);
1156                                 if (buf) XtFree(buf);
1157                                 free(fieldVal);
1158                                 _DtSvcProcessUnlock();
1159                                 return True;
1160                         }
1161                 }
1162
1163
1164                 mask |= ThisBit;
1165                 fld = _DtDtsDbAddField(act_rec);
1166                 fld->fieldName = fields[i].fieldName;
1167                 fld->fieldValue = fieldVal;
1168
1169         }
1170
1171         /*
1172          * Fill in default action type if necessary
1173          */
1174         if ( !(mask & _ActDb_TYPE_SET) )
1175         {
1176                 /*
1177                  * No type specified for this action
1178                  *  -- revert to default type (i.e. COMMAND).
1179                  */
1180                 mask |= _ActDb_TYPE_SET;
1181                 actionType = _DtACT_TYPE_DFLT;
1182         }
1183
1184
1185         /*
1186          * Now check the record for consistency
1187          */
1188
1189         if ( (buf = _DtActCheckRecord(act_rec,actionType,mask,fileName))
1190                  != NULL )
1191         {
1192                 /*
1193                  * This is an invalid record
1194                  */
1195                 _DtSimpleError(DtProgName,DtError,NULL,"%s",buf);
1196                 _DtDtsDbDeleteRecord(act_rec,act_db);
1197                 XtFree(buf);
1198                 XtFree(fileName);
1199
1200                 _DtSvcProcessUnlock();
1201                 return True;
1202         }
1203
1204         act_rec->seq =  ++(act_db->ActionSequenceNumber);
1205         act_rec->pathId = pathId;
1206
1207         XtFree(fileName);       
1208         _DtSvcProcessUnlock();
1209         return False;
1210 }
1211
1212
1213 void 
1214 _DtFreeActionDB( void )
1215 {
1216         DtDtsDbDatabase *act_db = _DtDtsDbGet(_DtACTION_NAME);
1217
1218         if ( act_db)
1219         {
1220                 _DtDtsDbDeleteDb(act_db);
1221         }
1222
1223 }
1224
1225 /********************
1226  *
1227  * InitializeLocalizedStrings - initializes the localized strings.
1228  *
1229  * MODIFIED:    The following variables are all initialized.
1230  *
1231  *   char       *noFields;
1232  *   char       *unrecogField;
1233  *   char       *unrecogType;
1234  *   char       *noMapTo;
1235  *   char       *noExecString;
1236  *   char       *unrecogMsgType;
1237  *   char       *dupFields;
1238  *   char       *invldField;
1239  *   char       *missingField;
1240  *   char       *missingName;
1241  *   char       *unrecogMsgType2;
1242  *
1243  ********************/
1244
1245 static void
1246 InitializeLocalizedStrings ( void )
1247 {
1248    noFields = XtNewString (((char *) Dt11GETMESSAGE (6, 1, "The action definition \"%s\" in the file:\n  \"%s\"\n  does not have any fields.\n")));
1249
1250    unrecogField = XtNewString (((char *) Dt11GETMESSAGE (6, 2, "The action definition \"%s\" in the file\n  \"%s\"\n  contains the following unrecognized field name and value:\n  \"%s\":\"%s\"\n")));
1251
1252    unrecogType = XtNewString (((char *) Dt11GETMESSAGE (6, 4, "The \"%s\" field in the action definition \"%s\"\n  in the file \"%s\"\n  has an unrecognized action type.\n")));
1253
1254    noMapTo = XtNewString (((char *) Dt11GETMESSAGE (6, 5, "The action definition \"%s\" in the file\n  \"%s\"\n  is not mapped properly.  The \"%s\" field\n  should be: TYPE MAP action_mapped_to.\n")));
1255
1256    noExecString = XtNewString (((char *) Dt11GETMESSAGE (6, 8, "The action definition \"%s\" in the file\n  \"%s\"\n  is a \"COMMAND\" action type but lacks the\n  required field \"%s\".\n")));
1257
1258    unrecogMsgType = XtNewString (((char *) Dt11GETMESSAGE (6, 11, "The action definition \"%s\" in the file\n  \"%s\"\n  has the illegal value \"%s\" in the \"%s\" field.\n")));
1259
1260    dupFields = XtNewString (((char *) Dt11GETMESSAGE (6, 12, "The action definition \"%s\" in the file\n  \"%s\"\n  contains duplicate fields named:\n \"%s\".\n")));
1261
1262    invldField = XtNewString (((char *) Dt11GETMESSAGE (6, 13, "The action definition \"%s\" in the file\n  \"%s\"\n  contains invalid fields for \"%s\" type actions.\n")));
1263
1264    missingField = XtNewString (((char *) Dt11GETMESSAGE (6, 14, "The action definition \"%s\" in the file\n  \"%s\"\n  is missing the required field, \"%s\"\n for \"%s\" type actions.\n")));
1265
1266    missingName = XtNewString (((char *) Dt11GETMESSAGE (4, 1, "A \"%s\" definition in the file:\n  \"%s\"\n  is missing a name.  Add the name\n  to the defintion.\n")));
1267
1268    unrecogMsgType2 = XtNewString (((char *) Dt11GETMESSAGE (6, 16, "The action definition \"%s\" in the file\n  \"%s\"\n  has the illegal value \"%s\" in the \"%s%s%s\" field.\n")));
1269 }