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