Automated conversational script with a modem (QNX Neutrino)
chat [options] script
The chat program defines a conversational exchange between the computer and the modem. Its primary purpose is to establish the connection between the Point-to-Point Protocol Daemon (pppd) and the remote's pppd process.
You should consider the modem functions (modem_open(), modem_read(), modem_script(), and modem_write(), described in the Library Reference) or the Photon Dialer as an alternative to chat.
The chat script defines the communications.
A script consists of one or more "expect -- send" pairs of strings, separated by spaces, with an optional "subexpect -- subsend" string pair, separated by a dash as in the following example:
ogin:-BREAK-ogin: ppp ssword: hello2u2
This line indicates that the chat program should expect the string ogin:. If it fails to receive a login prompt within the time interval allotted, it's to send a break sequence to the remote and then expect the string ogin:. If the first ogin: is received, the break sequence isn't generated.
Once it receives the login prompt, chat sends the string ppp and then expects the prompt ssword:. When it receives the prompt for the password, it sends the password hello2u2.
|This could be a security issue as only plain-text passwords may be passed.|
A carriage return is normally sent following the reply string. It isn't expected in the "expect" string unless it's specifically requested by using the \r character sequence.
The expect sequence should contain only what is needed to identify the string. Since it's normally stored on a disk file, it shouldn't contain variable information. It's generally not acceptable to look for time strings, network identification strings, or other variable pieces of data as an expect string.
To help correct for characters that may be corrupted during the initial sequence, look for the string ogin: rather than login:. The leading l character might be received in error and you may never find the string even though it was sent by the system. For this reason, scripts look for ogin: rather than login: and ssword: rather than password:.
A very simple script might look like this:
ogin: ppp ssword: hello2u2
In other words, expect ...ogin:, send ppp, expect ...ssword:, send hello2u2.
In actual practice, simple scripts are rare. At the very least, you should include sub-expect sequences in case the original string isn't received. For example, consider the following script:
ogin:--ogin: ppp ssword: hello2u2
This is a better script than the simple one used earlier. It looks for the same login: prompt, however, if one isn't received, a single return sequence is sent and then it looks for login: again. Should line noise obscure the first login prompt, sending the empty line usually generates a login prompt again.
Many modems report the status of the call as a string. These strings may be CONNECTED, NO CARRIER or BUSY. It's often desirable to terminate the script should the modem fail to connect to the remote. The difficulty is that a script doesn't know exactly which modem string it may receive. On one attempt, it may receive BUSY, while the next time it may receive NO CARRIER.
These "abort" strings may be specified in the script using the ABORT sequence. It's written in the script as in the following example:
ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT
This sequence expects nothing and then sends the string ATZ. The expected response to this is the string OK. When it receives OK, chat sends the string ATDT5551212 to dial the telephone. The expected string is CONNECT. If the string CONNECT is received, the remainder of the script is executed. However, should the modem find a busy telephone, it sends the string BUSY. This causes the string to match the abort character sequence. The script then fails because it found a match to the abort string. If it received the string NO CARRIER, it aborts for the same reason. Either string may be received. Either string terminates the chat script.
A "report" string is similar to the ABORT string. The difference is that the strings, and all characters to the next control character such as a carriage return, are written to the report file.
The report strings may be used to isolate the transmission rate of the modem's connect string and return the value to the chat user. The analysis of the report string logic occurs in conjunction with the other string processing such as looking for the expect string. The use of the same string for a report and abort sequence is probably not very useful, however, it is possible.
The report strings don't change the completion code of the program.
These report strings may be specified in the script using the REPORT sequence. It's written in the script as in the following example:
REPORT CONNECT ABORT BUSY '' ATDT5551212 CONNECT '' ogin: account
This sequence expects nothing and then sends the string ATDT5551212 to dial the telephone. The expected string is CONNECT. If the string CONNECT is received, the remainder of the script is executed. In addition the program writes to the expect-file the string CONNECT plus any characters that follow it, such as the connection rate.
The initial timeout value is 45 seconds; you can change it by using the -t option.
To change the timeout value for the next expect string, specify the TIMEOUT string. For exmple:
ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 ssword: hello2u2
This changes the timeout to 10 seconds when it expects the login: prompt. The timeout is then changed to 5 seconds when it looks for the password: prompt.
The timeout, once changed, remains in effect until it's changed again.
The special reply string of EOT indicates that the chat program should send an EOT character to the remote. This is normally the end-of-file character sequence. A return character isn't sent following the EOT. The EOT sequence may be embedded into the send string using the sequence ^D.
The special reply string of BREAK causes a break condition to be sent. The break is a special signal on the transmitter. The normal processing on the receiver is to change the transmission rate. It may be used to cycle through the available transmission rates on the remote until you're able to receive a valid login: prompt. The break sequence may be embedded into the send string using the \K sequence.
The expect and reply strings may contain escape sequences. All of the sequences are legal in the reply string. Many are legal in the expect. The Expect? column in the table below indicates whether or not the sequence is valid in an expect string.
|''||Yes||Expects or sends a null string. If you send a null string, it still sends the return character. This sequence may either be a pair of apostrophe or quote characters.|
|\b||Yes||Represents a backspace character.|
|\c||No||Suppresses the newline at the end of the reply string. This is the only method to send a string without a trailing return character. It must be at the end of the send string. For example, the sequence hello\c sends the characters h, e, l, l, o.|
|\d||No||Delay for one second. The program uses sleep(1), which delays for a maximum of one second.|
|\K||No||Insert a BREAK.|
|\n||Yes||Send a newline or linefeed character.|
|\N||No||Send a null character. The same sequence may be represented by \0.|
|\p||No||Pause for a fraction of a second. The delay is 1/10th of a second.|
|\q||No||Suppress writing the string to the SYSLOG file. The string ?????? is written to the log in its place.|
|\r||Yes||Send or expect a carriage return.|
|\s||Yes||Represents a space character in the string. This may be used when it isn't desirable to quote the strings that contains spaces. The sequence 'HI TIM' and HI\sTIM are the same.|
|\t||Yes||Send or expect a tab character.|
|\\||Yes||Send or expect a backslash character.|
|\ddd||Yes||Collapse the octal digits ddd into a single ASCII character and send that character. (Some characters aren't valid in expect sequences.)|
|^C||Yes||Substitute the sequence with the control character represented by C. For example, the character DC1 (17) is shown as ^Q. (Some characters aren't valid in expect sequences.)|
Using the termination code, it's possible to determine which event terminated the script. It's possible to decide if the string BUSY was received from the modem as opposed to NO DIALTONE. While the first event may be retried, the second probably has little chance of succeeding during a retry.
modem_open(), modem_read(), modem_script(), modem_write() in the Library Reference