═══ 1. Introduction ═══ INIServe is a server application that allows a remote client to edit INI file entries on the machine on which INIServe is running. It is distributed as freeware. This documentation is for version 0.4. Disclaimer of Warranty This Product is provided "as-is", without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the Product is with you. Should the Product prove defective, the full cost of repair, servicing, or correction lies with you. The author of INIServe is Peter Moylan, peter@ee.newcastle.edu.au. The latest version of INIServe is normally kept at ftp://eepjm.newcastle.edu.au/software Information about other software on this site may be found at http://eepjm.newcastle.edu.au/os2/software.html. I keep a mailing list of people who receive e-mail notification of new versions of my software. If you want to be put on this list, let me know by e-mail to peter@ee.newcastle.edu.au. The mailing list is not used for any other purposes, and the addresses will not be passed on to anyone else. ═══ 2. What is it for? ═══ One of the most common ways for an OS/2 program to store its configuration data is in an INI file. This means that you can, in many cases, alter the program options by editing the program's INI file. There are, in fact, several INI editors available to let you do just that. Normally you wouldn't work directly with the INI file, because developers generally consider INI data to be internal detail that's not properly documented for the end user. Most typically these data are manipulated either via "setup" options in the program itself, or by a configuration utility supplied by the program's author. It is sufficient that the author of the software knows what's in the INI file. There is one situation where it can be difficult to change a program's configuration options, and that is where the manager is trying to look after the software across a network. A way around the problem is to use a client-server approach to INI editing, and that's where INIServe comes in. INIServe, which runs on the machine where the INI file is located, provides the server end of the connection. All that is needed is a client to run at the other end. When you received the INIServe package, you probably also received a demonstration client that is a remote INI file editor. This is intended only as a demonstration. The long-term aim is that application-specific clients be written, preferably by the authors of the software that owns the INI file. The protocol for the commands accepted by INIServe has been deliberately kept simple, so that it is easy to write client software. Any existing "setup" software that manipulates INI files via operating system API calls should be able to be modified, with relatively little effort, to instead use INIServe commands to read and write INI data. ═══ 3. The contents of an INI file ═══ An INI file is a place where a program can store just about any data that it likes. Typically it is used to store information that the program needs to retain from one invocation to the next: screen location, fonts, user-configurable options, and the like. You wouldn't want to use it to store a huge database - that could be inefficient - but an INI file is the ideal place to store those little bits of information that aren't big enough to deserve a file of their own. Internally, the file is a binary file, and I don't plan to tell you about the precise internal structure. (In fact I've never looked this up, although I believe it's documented somewhere on Hobbes.) The important thing is that OS/2 provides API calls that let a programmer read and write INI file entries. Conceptually, each entry is a triple (application,key,value), where the application and key are character strings that are usually human-readable. You can think of this as a two-level hierarchy. The INI file holds data for a number of different applications; each application can have a number of keys; and associated with each key there is a value, which is the thing the program actually wants to read. Historically, there was probably an intention to have all programs save their INI data in one huge "user INI file", and in that case the "application" part of the triple would have identified the program owning that part of the data. These days we've learnt that concentrating all the important data in a single central registry is bad design - it leaves the system vulnerable to damage by a single misbehaving program - so there's more of a tendency to use a separate INI file for each program. This being the case, it would be logical to rename the "application" to something like "section label", since it doesn't identify an application in many cases; but we continue to call it the "application" in order to be consistent with the existing documentation. The "value" part of the entry can be anything at all, depending on the needs of the programmer who is using the INI file. It can be something as simple as a one-byte binary value; it could also be a character string, with or without a null terminating byte; or it could be a complex record whose internal structure is known only to the programmer. The meaning of INI file data is usually not documented, because programmers tend to see it as internal implementation detail. Before modifying anything in an INI file, make sure that you understand what the modification will do. ═══ 4. A functional overview of the INIServe commands ═══ The INIServe protocol is intentionally very simple. Every command is a single letter, followed (without any spaces) by a parameter if necessary. Some commands have no parameters, so the single letter is the entire command. Some other commands have a single character string as a parameter. The parameter for the W command is a string of bytes, where each byte is expressed as a two-digit hexadecimal number. The most complicated case is the O command, which has two numeric parameters separated by a comma. The command must be terminated by an ASCII carriage return followed by an ASCII line feed. The server sends back a response to each command. There are two kinds of response.  If the command failed or was rejected, the response starts with the '-' character, and this might be followed by a plain-text error message.  If the command was successful, the first character of the response is the '+' character, and then the data follows if this is the sort of command that returns data. Most commands don't return anything except the '+' or '-'; the exceptions are: - The S and T commands produce a numeric reply, and this comes as a hexadecimal number immediately after the '+'. - The V command produces a byte string as the reply, and this is in the form of a long hexadecimal number, immediately after the '+', where each two hexadecimal characters represent one byte. - The L command is a special case, producing a multi-line reply. This is the only case where the reply is more than one line long. Every response line is terminated with a carriage return and line feed. The following pages describe the steps you would go through in a single INIServe session. For more precise details, refer to the alphabetical list of commands later in this manual.  Logging in  Choosing a file to edit  Finding out what applications and keys are present  Checking the size of an entry  Reading a value  Adding or modifying an entry  Deleting an entry  Logging out ═══ 4.1. Logging in ═══ To start a session, the client must connect to the destination machine using the TCP port on which INIServe is listening. The default port number is 8000, but this can be changed by altering an entry in INIServe.INI. The server replies with a confirmation line; that is, a line starting with the '+' character. The client should then give a password with the 'P' command, for example Psecret If the password is correct, the server replies with another confirmation line, and the client is then able to issue other commands. The default password is the empty string, but this can be changed by changing the password in INIServe.INI. ═══ 4.2. Choosing a file to edit ═══ Three commands are useful here. The L command gives a listing of the current directory. The C command is a "change directory" command. Finally, the F command specifies a file name; this should be the name of an INI file, of course. The parameter for the C and F commands can be either an absolute path, or a path relative to the current directory. Initially the "current directory" is a pseudo-directory containing the names of all accessible drives. The information returned by the L command does not indicate whether any given entry is a directory or a non-directory file. An easy way to check this is to issue a C command to change to that entry. If the name is the name of a file rather than of a directory, then the C command will result in a '-' failure indication; and then you can, if desired, issue an F command with the same parameter. If you know the full filename, including drive and directory, for the file to be worked on, then you can of course give it directly in the F command. In this case the L and C commands are unnecessary. ═══ 4.3. Finding out what applications and keys are present ═══ The A command is for specifying an application, and the K command is for specifying a key. After you've given these two commands, you are ready to read the existing value, or write a new value. But what if you don't know what applications and/or keys exist in the INI file? If you specify an empty string as the application - that is, if you use the A command with no parameter - and then use the V command, the value returned is a hexadecimal string that should be interpreted as follows: 1. Each two hexadecimal characters represents one byte, with the obvious encoding, so the hexadecimal string can be turned into a byte string. 2. Considering the byte values as ASCII character codes, the result can further be interpreted as a character string. 3. The character string is in fact a sequence of substrings, where each substring is terminated by a zero byte. (The last substring is terminated with two zero bytes, one to end the substring and the other to mark the end of the sequence.) Each of those substrings will turn out to be the name of one application. In summary, specifying the empty string as the application will give you a result, when you read the value, which is a list of all applications in that INI file. Likewise, you can get a list of all keys, for a given application, by specifying a real application but setting the key to the empty string with the K command. ═══ 4.4. Checking the size of an entry ═══ The S command asks how many bytes there are in a particular INI file entry. Use the A and K commands to set the application and key, and then give the S command (with no parameters). The reply is a + sign followed by a hexadecimal number. Depending on how the client software is designed, there might be some situations where an entry is too big to be read or written in one piece. The O command tells the server that you want to pick up the data in limited-size chunks. It has two parameters, an offset and a limit. The offset says how far from the beginning of an item we should start. (For example, if the offset is 10 when you issue a V command, then the V command skips the first 10 bytes of the current entry.) The second parameter, the limit, specifies a maximum number of bytes that can be returned by the V command. Initially, and also after you give an O command with no parameters, the offset is zero and the limit is the largest possible 32-bit number. In effect, there is initially no offset or limit. The T command is like the S command, except that it takes the offset and limit into account, and tells you the number of bytes that would actually be returned as a response to the V command. ═══ 4.5. Reading a value ═══ To read an INI file entry, you use the A and K commands to specify the application and key, and then you give the V command to get the value. The response to the V command is a + sign followed by a long string of hexadecimal digits. Each pair of hexadecimal digits gives the value of one byte. As noted in the previous subsection, the behaviour of the V command is affected by the offset and limit specified by the most recent O command. In particular, the V command will never return more bytes than specified by the limit, even if there are more bytes than that in the INI file entry. To get the missing part, if any, you have to give a new O command with a larger offset. ═══ 4.6. Adding or modifying an entry ═══ The W command is for writing data. First you give the A and K commands to specify the application and key, then you give the W command. The letter W should be followed by an even number of hexadecimal digits. Each pair of digits gives the value of one byte. If the application/key pair already exists in the INI file, the new value overwrites the existing entry. Otherwise, a new entry is created. If the O command has not been issued, then the length of the new entry is exactly as long as the number of bytes specified in the W command. (Even if the old entry was longer.) However, the offset and limit given by an O command modify the action of the W command. What happens is that the new value overlays the old value. (If there wasn't any old value, and you have a nonzero offset, then you can end up with random rubbish.) The first "offset" bytes of the old value remain unchanged; then you have the new values supplied with the W command; and then, possibly, you have more bytes of the old value. Whether the "tail" is retained depends on the size of the new data relative to the current limit. If the number of bytes supplied with the W command is greater than or equal to the limit, then the server assumes that this is not the final section of the data, i.e. it keeps the old data, if any, that stretch more than (offset+N) bytes from the beginning of the value, where N is the number of bytes supplied with the W command. If, on the other hand, the number of bytes supplied with the W command is smaller than the limit, then the value is truncated at that point. ═══ 4.7. Deleting an entry ═══ The D command tells the server to delete the INI file entry corresponding to the current application and key, as set by the most recent A and K commands. If the K command specified an empty string, then all entries, for all keys associated with the current application, are deleted. If the A command specified an empty string, then the D command is illegal. ═══ 4.8. Logging out ═══ When the client has finished working on the INI file(s), it should send the Q command to terminate the current session. ═══ 5. Alphabetic list of commands ═══ A set application C change directory D delete the current entry F select file to edit K set key L list current directory M make directory O, set offset and limit (for V and W commands) P password Q quit S return size of current item T return truncated size of current item V return value of current item W store new value for current item The parameters, if any, for the commands come immediately after the command letter, with no intervening space. The possible parameter types are as follows. A character string specifying a file name, a password, etc. A number, expressed in hexadecimal. A byte sequence of arbitrary length, where each byte is specified by exactly two hexadecimal digits. The command must be terminated by a carriage return and line feed. ═══ ═══ A is a sequence of characters in human-readable form. It should not include the null character (the character with code 0). It is legal to have an empty string, i.e. a string of zero length. ═══ ═══ A is a single unsigned 32-bit integer expressed in hexadecimal. The value must be in the range 0 to FFFFFFFF. ═══ ═══ This is a byte sequence of arbitrary length, where each byte is specified by exactly two hexadecimal digits. ═══ 5.1. The A command: set Application ═══ Form A Reply + if the command was successful - if the command failed Example AProg1 Discussion To read or write an INI file entry, you must first specify an application and key. The usual way to do this is to send an A command, then a K command, and then the command to read or write the value. The application name specified in this command remains in force until the next A command. ═══ 5.2. The C command: Change directory ═══ Form C Reply + if the command was successful - if the command failed Example C.. Discussion The letter C is followed by a directory name, and this can either be a complete path (e.g. D:\uvw\xyz) or a name relative to the current directory (e.g. xyz or ..). You can use this command - multiple times, if desired - to walk through the directory tree on the target machine until you reach the directory containing the INI file that you want to work on. Before the first C command, the "current directory" is a hypothetical top-level directory containing all the drives on the system. Normally, then, your first C command would be something like "CE:" to select a drive. Hint: after obtaining a file listing with the L command, you usually can't tell whether any given entry is a subdirectory or an ordinary file. One way to tell is to use a C command and see whether there is a failure response. The "current directory" set by this command remains in force until the next C command, if any. If a C command fails, the current directory is unchanged. ═══ 5.3. The D command: Delete the current entry ═══ Form D Reply + if the command was successful - if the command failed Example D Discussion The D command has no parameters. It causes the current INI file entry, as specified by the most recent A and K commands, to be deleted. If the current key is the empty string, then all keys and values for the current entry are deleted. If the current application is the empty string, the command will fail. ═══ 5.4. The F command: select File to edit ═══ Form F Reply + if the command was successful - if the command failed Example Fweasel.INI Discussion This is in effect the "open file" operation that the client must do before reading or writing INI file entries. The file name after the F can either be a complete path string, or a name relative to the directory that was most recently set by the C command. Physically, this does not open the file. It simply sets the name of the file to be worked on. For safety, the server opens and re-closes the file for every operation on the file; this is mildly inefficient, but it ensures that the INI file remains in a well-defined state even if the INIServe session is aborted because of something like a communications failure. The "current file" set by this command remains in force until the next F command, if any. ═══ 5.5. The K command: set Key ═══ Form K Reply + if the command was successful - if the command failed Example KPassword Discussion To read or write an INI file entry, you must first specify an application and key. The usual way to do this is to send an A command, then a K command, and then the command to read or write the value. The key name specified in this command remains in force until the next K command. ═══ 5.6. The L command: List current directory ═══ Form L (Note that this command has no parameters.) Reply This command produces a multi-line reply, where each line is terminated by a carriage return and line feed. The first line contains the single character '+'. Each of the following lines, except for the last, lists one file name. That is, the current directory is listed with one line per entry. Only the names are given, not other details such as date and file size. The final line is empty, i.e. it contains nothing except the terminating carriage return and line feed. This is to mark the end of the reply. Example L If the current directory contained two files called "file1" and "mydata", then the response from the server would be + file1 mydata Discussion Note that, at least in the current version, there is no failure response: the command always succeeds. In the case of an error like selecting a nonexistent directory, the L command simply returns an empty directory listing. ═══ 5.7. The M command: Make directory ═══ Form M Reply + if the command was successful - if the command failed Example Msubdir Discussion The letter M is followed by a directory name, and this can either be a complete path (e.g. D:\uvw\xyz) or a name relative to the current directory (e.g. xyz). You can use this command to create a new directory on the target machine. (If the directory already exists, the command fails and the directory is left unchanged.) ═══ 5.8. The O command: set Offset and limit ═══ Form O, Reply + if the command was successful - if the command failed Example OF8,40 This sets the offset to F8 hexadecimal (248 decimal) and the limit to 40 hexadecimal (64 decimal). Discussion If you deal only with INI file entries that are short, you will never need the O command. It is there to handle the possibility of entries that are too large to fit in a client's data buffer, so that you have to work with substrings of the data. The offset and limit defined by the O command affect future V and W commands that read and write data. The offset says how many bytes are ahead of the chunk of data being dealt with by V and W. The limit is an upper bound on how many bytes will be read by a V command. The initial defaults are an offset of zero, and a limit which is the largest possible 32-bit number. Suppose, for example, that you have to deal with an INI file entry that is 1024 bytes long, but that buffer size restrictions mean that you can't deal with more than 128 bytes at a time. In this case you would set the offset to 0 and the limit to 128, and process the first 128 bytes of the data. Then you would set the offset to 128 (leaving the limit at 128) to process the next 128 bytes. Next, you would set the offset to 256 (still with the limit set at 128), and so on. If an O command is received and only one numeric parameter is supplied, then the other one reverts to its default value: a zero offset, or a very large limit, depending on which parameter is missing. The offset and limit specified in this command remain in force until the next O command. ═══ 5.9. The P command: supply a Password ═══ Form P Reply + if the password was accepted - if the password was rejected Example Psecret Discussion The P command should be the first command sent by the client. Until the client has supplied a valid password, no commands except P and Q will be accepted. When the server is first installed, the initial password is the empty string, so the correct way to log in is with a P followed directly by a carriage return and line feed. You should of course change this as soon as possible. Malicious clients could use INIServe to read or even alter important system settings. The way to stop this is to use a password that nobody knows except you. The password can be up to 32 characters long, and it is case-sensitive. It can contain any character except the null character. ═══ 5.10. The Q command: Quit ═══ Form Q (Note that this command has no parameters.) Reply The reply will always be the single character '+' (followed, of course, by a carriage return and line feed) to indicate successful completion. The server will never reject this command, unless of course it is so badly corrupted by transmission errors that the server does not see the Q. Example Q Discussion This is the "log out" command, and it should be the last command issued by a client. ═══ 5.11. The S command: return Size of current item ═══ Form S (Note that this command has no parameters.) Reply If the size of the current item cannot be determined (usually because the INI file doesn't exist) then the reply is the failure code '-'. Otherwise, the reply is the single character '+' followed by a hexadecimal number. This number is the length, in bytes, of the INI data specified by the current application and key, i.e. specified by the most recent A and K commands. Example S The reply to this would be something like "+2E" (without the quote marks, and terminated by a carriage return and line feed). Note that the answer is always given in hexadecimal. Discussion The size reported by this command is always the full size of the item. The answer is not affected by any previous O command. (If you want an answer that does depend on the O command parameters, use the T command.) If the current application or the current key is the empty string, then strictly speaking there should be no value to return. In fact the V command does return an answer in this case - see the description of special cases for the V command - and the S command reports how many bytes would be returned. ═══ 5.12. The T command: return Truncated size of current item ═══ Form T (Note that this command has no parameters.) Reply If the size of the current item cannot be determined (usually because the INI file doesn't exist) then the reply is the failure code '-'. Otherwise, the reply is the single character '+' followed by a hexadecimal number. This number is the length, in bytes, of the data that would be returned by the V command. Example T The reply to this would be something like "+20" (without the quote marks, and terminated by a carriage return and line feed). Note that the answer is always given in hexadecimal. Discussion This command is almost exactly the same as the S command. The difference is that the S command is not affected by any previous O command, while the answer returned for the T command is modified by the offset and limit set by the most recent O command. The result of the T command tells you how many data bytes will be returned by the next V command (always assuming, of course, that you don't issue a new A or K command before the V). The S command, on the other hand, tells you how many bytes would have been returned if you hadn't used an O command to limit the size of the transfer. ═══ 5.13. The V command: return Value of current item ═══ Form V Reply If the current item cannot be determined (usually because the INI file doesn't exist) then the reply is the failure code '-'. Otherwise, the reply is the single character '+' followed by N bytes of data, where each byte is specified as a two-digit hexadecimal number. The total number of characters in the reply is 2N+3; 2N characters for the N bytes of data, one more for the '+', and two for the carriage return and line feed that terminate the line. For the value of N, see the discussion below. Example V If the current item is a four-byte value, then the reply would be something like +00014F37 Discussion If the O command has not been issued, so that the offset is 0 and the limit is very large, the result is precisely the current item, however many bytes that might be. If the O command has been issued, then the value returned is the value of the current item, truncated as follows.  First, the initial "offset" bytes of the value are removed.  If the string resulting from the first operation still has more than "limit" bytes, then the result is truncated so that only "limit" bytes are returned. Otherwise, all bytes, apart from the initial ones removed in the first step, are returned. Special cases  If the current application name, as set by the A command, is the empty string, then what is returned is a list of all application names in this INI file. The result is still encoded in hexadecimal, with two hexadecimal digits per character, but after decoding this you will have a sequence of null-terminated character strings, where each character string is the name of one application. The end of the list is marked by an extra zero byte.  If the current application name is a valid application name, but the current key name, as set by the K command, is the empty string, then what is returned is a list of all key names for this application. The result is still encoded in hexadecimal, with two hexadecimal digits per character, but after decoding this you will have a sequence of null-terminated character strings, where each character string is the name of one key. The end of the list is marked by an extra zero byte. You can use this information to deduce the set of all application/key pairs in the INI file. ═══ 5.14. The W command: Write new value for current item ═══ Form W Reply + if the command was successful - if the command failed Example W74657374696E6700 This would set the value of the current item to the null-terminated character string "testing". Discussion If the O command has not been issued, so that the current offset is 0 and the current limit is very large, then the byte string specified as the is stored as the value of the INI file entry for the current application and key (as set by the most recent A and K commands). This either creates a new entry or overwrites an existing entry, depending on whether an old value already existed for that application and key. The new entry does not have to have the same size as the old entry. If an offset and limit have been set by the O command, then the new data supplied by the W command are overlaid over the original data. The first "offset" bytes remain as before, then the next N bytes (where N is the number of bytes supplied by the W command) are modified, and subsequent bytes if any remain unchanged. Note that N, the number of bytes supplied by the W command, is not constrained by the current limit. The value of the limit is, however, used in deciding whether to shorten an existing entry. If N is greater than or equal to the limit, then later bytes are left unmodified, as described above. If N is strictly less than the current limit, then we assume that this is the last "chunk" of this value to be stored, and the value is truncated at that point. In this case the modified entry ends up being exactly (offset+N) bytes long. If N and offset are both zero, the value stored is a byte string of zero length. This is legal, and it is not equivalent to deleting the current entry. ═══ 6. Installation ═══ Installation See also De-installation You should have received this package in the form of a zip file. To install it, simply unzip the file into a directory of your choice. (Presumably you've already done this.) The server is now ready to run. The server itself is the program called INIServe.exe. You can run it either by double-clicking on the desktop icon, or by entering the command "iniserve" in a command-line session. If you want the server to be running all the time, then you should probably create a shadow or program object to go into the startup folder. The server can be run detached, if desired. In theory it can also be run from inetd, but I've never tested that option. As supplied, the server uses an empty password and listens on port 8000. To change these parameters, make the obvious changes to the file INIServe.INI. You can use another INI file editor to do this, but it is also legal to use INIServe to modify its own INI file. The file source.zip is optional. If you're not interested in the source code, you can delete it. ═══ 7. De-installation ═══ De-installation INIServe does not tamper with CONFIG.SYS or with other system files. If you decide that you don't want to keep it, simply delete the directory into which you installed it.