/* Generic Folder Builder                                                    */
/* Version 1.4                                                               */
/*                                                                           */
/* Builds folder and program objects on the OS/2 desktop based upon Novell   */
/* group membership.  All previous objects created by this program are       */
/* replaced by new ones or deleted if not in user's groups.                  */ 
/*                                                                           */
/* Novell group membership is determined by calling WHOAMI.EXE, which is     */
/* assumed to be located in the PATH.  Map Z: to \PUBLIC\OS2, then add Z:    */
/* to your PATH in CONFIG.SYS.                                               */
/*                                                                           */
/* This program requires one parameter and has an optional second parameter. */
/*  Required: server name                                                    */
/*  Optional: verbose flag (only checks for existence of third parameter)    */
/* Verbose mode displays status of all object creations and deletions.       */
/* Format:                                                                   */
/*  GENFLDR server [verbose]                                                 */
/* Examples:                                                                 */
/*  Regular:                                                                 */
/*   GENFLDR pcatd                                                           */
/*  Verbose:                                                                 */
/*   GENFLDR pcatd x                                                         */
/*                                                                           */
/* Folder and program objects are defined in a data file named OBJECTS.DAT.  */
/* Each line in the data file represents one object and uses the format:     */
/*    GROUP~LOCATION~CLASSNAME~TITLE~OBJECTID~SETUP~INITCMD                  */
/* where these values, except for INITCMD, are defined in the CRTOBJ.TXT     */
/* document.  INITCMD is the name of a batch file or program to run when the */
/* object is created.  This command is run asynchronously from this file.    */
/*                                                                           */
/* Below are some sample records.                                            */
/*                                                                           */
/*  Create a folder named "LAN Folder" for members of group EVERYONE         */
/*    EVERYONE~<WP_DESKTOP>~WPFolder~LAN Folder~<LAN_FOLDER>                 */
/*                                                                           */
/*  Create a program object for SYSCON to run in a window for members of     */
/*  group EVERYONE in the previously created "LAN Folder".                   */
/*    EVERYONE~<LAN_FOLDER>~WPProgram~Syscon~<LAN_SYSCON>~EXENAME=Z:SYSCON.EXE;PROGTYPE=WINDOWABLEVIO;  */
/*                                                                           */
/*  Create a program object for a DOS application that requires a customized */
/*  batch to be created for the user.  The DOS batch file is SPECIAL.BAT and */
/*  is generated by GENSPEC.CMD.                                             */
/*    EVERYONE~<LAN_FOLDER>~WPProgram~Special~<LAN_SPECIAL>~EXENAME=D:\SPECIAL.BAT;PROGTYPE=WINDOWEDVDM;~GENSPEC.CMD */
/*                                                                           */
/*  Create a program object for a DOS application that requires multiple     */
/*  DOS_DEVICE or DOS_VERSION statements.  The WPS replaces commas with      */
/*  newlines, so use commas to separate the multiple entries.  To include a  */
/*  comma as part of the value in DOS_VERSION, prefix it with a caret (^).   */
/*    EVERYONE~<LAN_FOLDER>~WPProgram~3D-Data~<LAN_3DDATA>~EXENAME=D:\3D\3DDATA.EXE;PROGTYPE=WINDOWEDVDM;~SET DOS_DEVICE=C:\OS2\MDOS\LPTDD.SYS,C:\OS2\MDOS\ANSI.SYS,D:\3D\DATAGLOV.SYS;SET DOS_VERSION=BOGUS.EXE^,5^,00^,255;  */
/*                                                                           */
/*  To include comments, just begin the line with a tilde (~).               */
/*    ~Create LAN Folder                                                     */
/*                                                                           */
/*  If a program or folder will no longer be included in the login process,  */
/*  leave it in the data file, but give it a non-existent group name.  This  */
/*  will still delete it, but won't create a new object for it.              */
/*    REMOVED~<LAN_FOLDER>~WPProgram~WP 5.0~<LAN_WP50>                       */
/*                                                                           */
/* General Notes:                                                            */
/*                                                                           */
/*  If a folder is destroyed, then all of its contents are also destroyed.   */
/*                                                                           */
/*  The current version of the NetWare Requester contains a "feature" that   */
/*  makes setting the NETWARE_RESOURCES tricky to use.  The setting is a     */
/*  fixed length field, unlike all the other DOS Session settings.  The      */
/*  field has a size of 7 characters, which is equal to the length of its    */
/*  largest value, PRIVATE.  To change the setting to GLOBAL or NONE, append */
/*  1 or 3 spaces.                                                           */
/*     Example: SET NETWARE_RESOURCES=NONE   ;                               */
/*                                                                           */
/*  Apparently there is an upper limit on the setup string length imposed by */
/*  REXX and/or OS/2.  Setup strings must be less than 234 characters to     */
/*  create the objects correctly.  The first setup string that is too long   */
/*  will cause subsequent creates to fail also.                              */
/*  NOTE: This is listed as fixed in the Service Pack.                       */
/*                                                                           */
/* Version History                                                           */
/*  1.0   Initial version .                                                  */
/*  1.1   Eliminated need for temporary file and used WHOAMI to determine    */
/*        group membership.                                                  */
/*  1.1a  Changed brute force method of deleting all objects to just         */
/*        deleting objects that are not created.                             */
/*  1.2   Added data file option for an initialization command to be run     */
/*        when the object is created.                                        */
/*  1.3   Added translation of the | (vertical bar) character to hex 0A in   */
/*        setup string to allow multiple values for settings like DEVICE or  */
/*        VERSION.                                                           */
/*  1.4   Finally got an answer on why the Service Pack handles commas       */
/*        differently than previous releases.  Commas are translated to      */
/*        newlines, so to use a comma in setting DOS_VERSION, prefix it with */
/*        the caret escape character (e.g. ^,).  No code change, just        */
/*        updated documentation.                                             */
/*                                                                           */
/* Lee S. Fields                                                             */

/*trace('I')*/

/* verify at least one parameter, server name, was passed */
parse upper arg server verbose
if (server = '') then
  ErrorMessage('Server name is required.')

/* check for verbose parameter */
if verbose = '' then verbose = 0 
else verbose = 1

/* read user's group membership */
call readgroups server

/* Load REXXUTIL */
call rxfuncadd sysloadfuncs, rexxutil, sysloadfuncs
call sysloadfuncs
 
/* load the object data from the specified file, OBJECTS.DAT */
call LoadObj 'objects.dat'

say 'Managing LAN objects...'

/* create all objects */
do j = 1 to objectcount
  if MemberOf(groups.j) then do
    call BldObj classnames.j, titles.j, locations.j, 'OBJECTID='objectids.j';'setups.j
    if initcmds.j \= '' then '@start' initcmds.j
    else nop
    end
  else
    call DelObj objectids.j
end

Exit



/*****************************************************************************/
/* Subroutines:                                                              */
/*****************************************************************************/
 
/*****************************************************************************/
/* BldObj - Build object                                                     */
/*                                                                           */
/* Parameters: classname, title, location, and setup                         */
/* Uses:       verbose                                                       */
/* Modifies:                                                                 */
/* Returns:                                                                  */
/*****************************************************************************/
BldObj: procedure expose verbose
if verbose then call charout ,'Building: 'arg(2)

/* Build object using REPLACE as duplicateflag */
result = SysCreateObject(arg(1), arg(2), arg(3), arg(4), 'R')

if verbose then do 
  If result=1 Then call charout ,'...   Object created!'
  Else             call charout ,'...   Not created! Return code='result
 
  Say '';
end
Return


/*****************************************************************************/
/* DelObj - Destroy object                                                   */
/*                                                                           */
/* Parameters: full path name or object id                                   */
/* Uses:       verbose                                                       */
/* Modifies:                                                                 */
/* Returns:                                                                  */
/*****************************************************************************/
DelObj: procedure expose verbose
if verbose then call charout ,'Destroying: 'arg(1)
 
result = SysDestroyObject(arg(1))

if verbose then do
  If result=1 Then call charout ,'...   Object destroyed!'
  Else             call charout ,'...   Not destroyed! Return code='result
  Say '';
end
Return


/*****************************************************************************/
/* LoadObj - Load object data                                                */
/*                                                                           */
/* Parameters: file name                                                     */
/* Uses:       objectcount, groups, classnames, titles, locations, objectids */
/*             setups initcmds                                               */
/* Modifies:   objectcount, groups, classnames, titles, locations, objectids */
/*             setups initcmds                                               */
/* Returns:                                                                  */
/*****************************************************************************/
LoadObj: procedure expose groups. classnames. titles. locations. objectids. setups. initcmds. objectcount
objectfile = arg(1)
/* verify name passed and file existence */
if objectfile = '' then 
  ErrorMessage('Data file of objects not specified.')
if stream(objectfile,'c','query exists') = '' then 
  ErrorMessage('Unable to open object data file')

objectcount = 0
/* open file */
call linein objectfile 1 0
do while lines(objectfile)
  objectcount = objectcount + 1
  parse value linein(objectfile) with groups.objectcount '~' locations.objectcount '~' classnames.objectcount '~' titles.objectcount '~' objectids.objectcount '~' setups.objectcount '~' initcmds.objectcount
  if groups.objectcount = '' 
    then objectcount = objectcount - 1
    else setups.objectcount = translate(setups.objectcount, '0A'X, '|')
end
call lineout objectfile /* close file */
return


/*****************************************************************************/
/* ReadGroups - Reads list of user's groups                                  */
/*                                                                           */
/* Parameters: server                                                        */
/* Uses:       usergroups                                                    */
/* Modifies:   usergroups                                                    */
/* Returns:                                                                  */
/* Note:       Requires access to GROUPS.EXE                                 */
/*****************************************************************************/
ReadGroups: procedure expose usergroups.
/* clear queue */
'@rxqueue /clear'

/* run GROUPS to get group list in queue */
'@whoami' arg(1) '/G |RXQUEUE'

counter = 1
do i = 1 to lines("QUEUE:")
  parse value linein("QUEUE:") with usergroups.counter stuff .
  if stuff = '' then do
    usergroups.0 = counter
    counter = counter + 1
  end
end

if counter = 1 then
  ErrorMessage('Unable to determine group membership.')

return


/*****************************************************************************/
/* MemberOf - Tests if user is member of a group                             */
/*                                                                           */
/* Parameters: test group                                                    */
/* Uses:       usergroups                                                    */
/* Modifies:                                                                 */
/* Returns:    1 if member, 0 if not                                         */
/*****************************************************************************/
MemberOf: procedure expose usergroups.
do i = 1 to usergroups.0
  if usergroups.i = arg(1) then return 1
end
return 0


/*****************************************************************************/
/* ErrorMessage - Display error message and exit                             */
/*                                                                           */
/* Parameters: error message                                                 */
/* Uses:                                                                     */
/* Modifies:                                                                 */
/* Returns:    DOES NOT RETURN                                               */
/*****************************************************************************/
ErrorMessage: procedure
say arg(1)
say 'No objects loaded, contact your LAN Administrator.'
exit
