10.4 Advanced TCPGUI programming topics
The technique described in the previous section, using the LSV_send_command function to send commands over TCP/IP to LISTSERV, will work for most one-line LISTSERV commands, such as ADD, DELETE, SET, SHOW, etc. However, some commands require a different or modified approach:
- Creating or replacing a list header
- Adding or replacing a password
- Bulk operations
- Commands that respond over e-mail
- Application-friendly commands
There may also be some special error handling involved.
10.4.1 Creating or Replacing a List Header
Multi-line commands cannot be sent through the TCPGUI interface. Therefore, the usual approach to send a list header to LISTSERV (the PUT command followed by the multiple lines of the header) cannot be used. Instead, TCPGUI has a special command for sending a list header: X-STL.
The syntax of the X-STL command is:
X-STL listname header-data
where header-data is a single text string that contains every header line (including the leading asterisk), one after the other, formatted in a particular way:
- A count of the number of characters in the header line, to include the asterisk in column 1
- An underscore character (ASCII 0x5F; don't use Unicode or Microsoft "smart characters")
- The header line itself
Finally, the last header line in the string should not have any trailing spaces.
Thus, if the command you would use to put your list through e-mail was:
PUT TEST LIST PW=ABCDE
For Windows, the command you send through the TCPGUI interface would be:
X-STL TEST 6_* test1_*25_* Owner= email@example.com_* Notebook=No18_* Confidential=Yes
For unix, you will have to escape the asterisks, as described in 10.2 Running LCMDX :
X-STL TEST 6_\* test1_\*25_* Owner= firstname.lastname@example.org_\* Notebook=No18_\* Confidential=Yes
(Remember that this is a single-line command -- there should be no line-break characters other than at the very end of the line.) For clarity, ach of the five lines in the header are represented as follows:
Standard header line (emailed)
Number of characters
X-STL formatted header line
(For unix, add the backslash for the asterisks as noted above)
25_* Owner= email@example.com
(The second line is, of course, a blank header line containing a single asterisk, so it is only one character long.)
Note: If double quotes are required (for instance, for the Prime= or Sender= keyword settings), you MUST escape them with a backslash character, thus:
lcmdx listserv.example.com firstname.lastname@example.org XXXXX X-STL XXXXXXXXX 6_* test1_*30_* Owner= email@example.com_* Notebook=No18_* Confidential=Yes49_* Sender= \”test <firstname.lastname@example.org>\”
(remember that the entire command must be on one line, not wrapped as is unavoidable in this document). Additionally, when counting characters for the line counts, the backslash-double quote combination counts as a single character. If the line count is wrong, you will get an “Error in header data stream” message.
10.4.2 Adding or Replacing a Password
You can’t send a “PW ADD” or “PW REP” command through the TCPGUI interface. There is a special command for adding a password:
X-PWADD address password
The LSV_send_command function generally requires a password, which you don’t necessarily have when you’re in the process of adding one. In this case, you can send the command anonymously through TCPGUI by using the anonymous e-mail address “@” as the “originator” in the call to LSV_send_command (but not in the X-PWADD command, obviously).
When LISTSERV receives the X-PWADD command, it sends e-mail to the address provided, requesting confirmation. E-mail confirmation is the only way for LISTSERV to determine that the e-mail address provided is truly the correct address. Therefore, an application should never count on the password being immediately available. A message to the user, letting them know that they can continue after they have successfully confirmed the password registration, may be advisable.
10.4.3 Bulk Operations
As noted above, the TCPGUI interface can only handle single-line commands. Therefore bulk operations, such as the bulk add and delete commands cannot be sent through TCPGUI, and can only be sent through the mail. The only ways to send bulk adds and deletes from an application are:
- Turn them into individual add or delete commands, and send each of these through the TCPGUI interface. If there are many subscribers to add or delete, this can extremely slow, and is therefore not recommended.
- Write a mail file containing the bulk add or delete job and use a local mail application to send it to LISTSERV.
- Open up a connection with the SMTP port on the LISTSERV host and use SMTP commands (documented in RFC821) to send a mail file (documented in RFC822) containing the bulk add or delete job. This is essentially the same thing as the previous bullet, except that in the previous case, you used a third-party application to send the file, whereas in this case you will either type the file manually or use cut and paste into your telnet client to perform the operation.
10.4.4 Commands that Respond Over Email
LISTSERV will accept almost any one-line command through the TCPGUI interface. The answer you receive through the TCPGUI interface, however, may not always be what you expected. Commands whose responses tend to be long will generally be sent through e-mail. LISTSERV will always send the response to the following commands back through e-mail:
- LISTS DETAILED
- LISTS GLOBAL
- LISTS SUMMARY
- GET for anything other than a list header
For these other commands, LISTSERV will send the response back through e-mail unless you use an option to make it come back through the TCPGUI interface:
- GET listname – requires the “(MSG” option
- REVIEW – requires the “MSG” option
10.4.5 Application-Friendly Commands
Some commands that can be sent through the TCPGUI interface and to which LISTSERV will send the response back through the TCPGUI interface nevertheless have responses that are human-friendly but not application-friendly. One such command is the QUERY command, which sends a response that looks like:
Subscription options for Joan Smith, list MYLIST:
MAIL You are sent individual postings as they are received
MIME You prefer to receive messages in MIME format
SUBJECTHDR Full(normal) mail headers with list name in message subject
REPRO You receive a copy of your own postings
NOACK No acknowledgement of successfully processed postings
Subscription date: 12 Mar 2020
The topics you subscribe to are: Mytopic, Other
To assist the application developer, the LISTSERV provides alternate commands for the following:
- A special option for QUERY: DEFSUB
To QUERY subscriber options from an application you should use:
QUERY ***GUI*** listname [FOR address]
The response will look like the following:
***NAME*** firstname lastname
***HDR*** e-mail-address (next subscriber)
N matching entries found.
- The “***HDR***” line denotes the beginning of the subscription settings for a particular subscriber (recall that the QUERY command could yield information for multiple subscriptions) and identifies the e-mail address of the subscription.
- The “***NAME***” line provides the full name stored for that subscriber.
- The “***OPT***” lines each show one option set for the subscription. The first option would always be MAIL or NOMAIL. All the other options are only those options that are NOT the default options in LISTSERV (as opposed to the default options set for the particular list -- these do not apply here).
- The “***SUBDATE***” line contains the subscription date. (If the user subscribed to the list prior to LISTSERV 1.8c, the subscription date is not stored and this line will not appear.)
- The “***TOPICS***” line lists the topics which are selected for this subscription.
- The “***TOPLIST***” line lists all the topics that are available for the list, regardless of whether this particular subscription has them selected, except for “ALL” and “OTHER”.
- These lines are repeated for each matching entry found.
- The last line gives a count of matching entries found.
It should be noted that for scripting purposes, it is possible to use a wildcard rather than a single list name with this command:
QUERY ***GUI*** * [FOR address]
TIP: It should be noted that for reporting or command-line scripting purposes, it is possible to use a wildcard rather than a single list name with this command:
QUERY ***GUI*** * [FOR address]
This makes it possible to write a script that, for instance, can produce a simple list of all lists to which a given subscriber is subscribed. While this is not sufficient for GDPR-type purposes, such a script using the easily-parsed QUERY ***GUI*** command could be more useful to the system administrator than the only other alternative, which is the overly-verbose 'Query * FOR address' command.
While it is also possible to use the wildcard to produce web output via TCPGUI, one should do so with care, as the amount of data returned may be more than you wish to display on a single web page.
10.4.5.2 QUERY DEFSUB
There is also a special QUERY command for obtaining default subscription options:
QUERY ***GUI*** ***DEFSUB*** listname
If this command is sent using an address that is subscribed to the given list, it works exactly the same as the “QUERY ***GUI***” command described above. If it is sent anonymously (see “Adding or replacing a password” above) or from an address which is not subscribed, then the first line in the response is:
And the remainder of the response is the same as the response to “QUERY ***GUI***” for a subscriber with the list’s default subscription settings.
To scan a list for a pattern, you should use
SCAN ***GUI*** listname pattern
The response will look like the following:
Firstname Lastname <email@example.com>
“Full name w/ special characters” <firstname.lastname@example.org> etc.
SCAN: N matches.
10.4.5.4 Changelog access
Please note that this feature is not available under LISTSERV Lite.
Changelogs may be accessed via TCPGUI by using the GET command options MSG and COLumns(...). Both are designed primarily for GUI use, and while they have been documented, there was no attempt at making the syntax intuitive to end users, as they are not expected to use this feature. The design goal was a syntax that is easy to generate and parse.
The MSG option (named for compatibility with the REVIEW option by the same name) simply tells LISTSERV to return the contents of the file as “interactive messages,” which for TCPGUI means that the data will be returned as command output. Thus the option is effective only with text files, as this is not a binary channel.
The COLumns(...) option tells LISTSERV to filter records from the file before sending it. The syntax is as follows:
COLumns(colspec1 colfilter1 [colspec2 colfilter2[...]])
- ‘colspec’ defines the column to which the filter is to be applied. It can be either a-b (positions a to b, inclusive), a- (a through end of line), a.b (positions a to a+b-1) or Wa (blank-delimited word number a).
- ‘colfilter’ is either a-b, a-, -b or a. The latter is equivalent to a-a, whereas the two incomplete forms only check one of the bounds. There must not be any spaces surrounding the hyphen in a-b, and neither a nor b may contain spaces or parentheses.
It is possible to specify as many different columns as desired. Each column must match its respective filter in order for the record to be selected.
It is also possible to specify the same column multiple times (for this purpose, equivalent a-b and a.b specifications are considered the same column). This provides multiple acceptable ranges for the column in question.
It is important to understand how exactly comparisons take place:
- All operands are treated as case-insensitive strings, even if they happen to be valid numbers. Thus, 9.00 is greater than 200.
- Comparisons proceed from left to right and stop at the first differing character. There is no concept of column alignment; in particular, leading blanks are significant (this is not applicable if you defined the column as Wa).
- If the reference is shorter than the column, the comparison ends successfully when the last character in the reference has been compared. For instance, if you search a changelog for W1 200101-200102, effectively only the first 6 characters will be searched.
- If the column is shorter than the reference, it is considered to be padded with blanks. This usually fails the record.
- Another way to describe it would be to say that the reference, which is well-defined, takes precedence over the record column, which could vary widely. If the reference is too short, the remainder of the column is ignored. If the column is too short, it will usually not match.
- Comparisons succeed for their bounds, i.e. 2000-3000 will select both 2000 and 3000.
- Comparisons that are bound to fail will fail as expected. If you look for a string of 4 characters in a column that is defined to be only 3 wide, you will find no match and there will be no error.
If there are no matches, the file is not sent and the message “No matching records” is sent instead as command response. This message is suppressed when the MSG option is used; you simply get an empty response.
To select ADD or DELETE records in 2018 in a changelog, you could use COL(1-4 2018 W2 ADD W2 DELETE).
Note that this feature works with any file, not just changelogs. In particular, it works with archived changelogs.
Example: To show all POST operations for MYLIST-L since 1 June 2017,
GET MYLIST-L CHANGELOG (MSG COLUMNS(W1 20170601- W2 POST)
The COLUMNS() option was enhanced in LISTSERV version 16.5 to make it easier to search changelog files for specific email addresses (primarily for the purpose of GDPR reporting). This was accomplished by adding a comparison sub-option (in addition to all of the existing comparison sub-options documented above) which allows searches using an optional data type followed by a pattern, as follows:
- ‘^’ is an optional negation
- type is a mandatory single character indicating the type of comparison
- pattern is the text to match the requested column to; as usual, a match will select the line for inclusion, and no match will try the next column/pattern pair, if any
- No spaces are allowed in the operand
Type can be:
- ‘=’: column must equal pattern (this is not a substring match)
- ‘W’: pattern must appear in column as a space-delimited word
- ‘*’: wildcard matching of column to pattern
The ‘=’ option is arguably redundant since COLUMNS(16- ==ADD) does the same thing as COLUMNS(16- ADD), but it can come in handy if you want to match to a pattern containing a hyphen, or starting with an equal sign.
In a GDPR context, you might do:
GET listname.CHANGELOG (MSG COL(16- =Wemailaddr)
to pull all records out of the listname.CHANGELOG file that contain the space-delimited email address (represented by emailaddr in the example) anywhere from column 16 of the record to the end of the record. For an email address such as email@example.com, this might include records such as
20170329114508 POST joe@EXAMPLE.COM This is the subject of my email.
10.4.6 Error handling
When the command you send produces an error, the TCPGUI interface sends back the exact error that you would receive through the mail when that error is detected by LISTSERV (for example, if you use the wrong listname, or misspell a command).
However, the TCPGUI interface does have some error messages specific to it, for when the error occurs within TCPGUI rather than LISTSERV. These are:
- ***NOPW*** -- the e-mail address does not have a password registered with LISTSERV
- ***BADPW*** -- the password provided in the TCPGUI command does not match the password registered for the given e-mail address.