{\rtf0\ansi{\fonttbl\f0\fnil Times-Roman;\f1\fswiss Helvetica;\f2\fmodern Courier;} {\colortbl\red0\green0\blue0;} \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\f0\b\i0\qc\fs24\li2160 \ \ The C- programming Language\ \ by Ray Davison\ ray_davison@sfu.ca\ \ May 1992\ Revised October 1992\ \f1\b0 \ \f0\li0 Computing Services\ Simon Fraser University\ Burnaby, B.C. Canada V5A 1S6\ \f1 \ \ \b\ul\ql \ \ Introduction\ \b0\plain \ \f0 The C- programming language was developed as a vehicle for writing scripts for establishing serial line connections. In particular it was developed for Eudora, a Macintosh e-mail package.\ \ As the name implies, C- is based on a subset of C. The main differences are C-'s smaller set of control structures and operators, and the different handling of types, although there are many other minor differences.\ \ C- is an interpreted language and so some things (like local variables) may not be handled in quite the way you would expect in a compiled language. Because C- is imbedded in other programs (e.g. Eudora), frills such as error detection have been kept to a minimum to keep the implementation small. Because login scripts are usually small (the example in Appendix B to the contrary) it should not be too great a task to write scripts that are syntactically correct. Getting them to handle the information that is spewed at them is another thing entirely.\ \f1 \ \b\ul \ 1. The C- Programming Language\ \b0\plain \ \f0 A C- program consists of a series of statements that are executed one after another. Each statement consists of various syntactic items that may be separated by liberal amounts of white space (spaces, tabs and carriage returns) and comments.\ \ Comments in C- are any sequence of characters starting with \f2\fs20 /* \f0\fs24 and ending with \f2\fs20 */ \f0\fs24 .\ \ \b\fs20 Note: \b0\fs24 In order to maintain compatibility with a precursor to C-, comments can also consist of any string of characters starting with \f2\fs20 # \f0\fs24 and continuing to the end of the line.\ \f1 \ \f0 Case is not significant in input to the C- interpreter, and except in string constants will be ignored.\ \ Statements in C- are either compound statements (statement blocks, whiles and ifs) or simple statements (variable definition, function call or assignment statements). Appendix C provides a BNF syntax for C-. The following sections describe in more detail the various statement types and other elements of the language. \f1 \ \b\ul \ 2. Types, Operators and Expressions\ \b0\plain \ \b 2.1 Variables\ \b0 \ \f0 Variable names in C- are a sequence of characters, which may be letters, digits or the underscore. The first character must be a letter. Upper or lower case letters may be used, but are considered equivalent. Thus the variable name MYPASSWORD is the same as the variable name MyPaSsWoRd.\ \ Variable names may be any length, restricted only by available memory.\ \ If a variable is defined using the \f2\fs20 variable \f0\fs24 statement then it becomes a local variable. Any variable that is used but not defined is global. A global or local variable will be inherited by statements within subsequent statement blocks. There is a difference between global variables and local variables at the top level. While both are inherited by all parts of the script, global variables live from one invocation of the script to the next (and even from one script to another as from a Navigate In script to a Navigate Out script. See Appendix D) while local variables are disposed of when a block is finished or the script ends. \f1 \ \b \ 2.2 Data Types\ \b0 \ \f0 Variables and constants in C- are one of two types, numeric or character. Variable types are not fixed, but can change if assigned a value of a different type.\ \ \f1\b\li360 2.2.1 Numeric Types\ \b0\li0 \ \f0\li360 A numeric type is an integer value. C- does not support floating point numbers. Numeric constants are an optional plus or minus sign followed by one or more decimal digits.\ \ \b\fs20 Note: \b0\fs24 Implementation restriction. Numbers are restricted to four byte integers.\ \f1\b \ 2.2.2 Character Types\ \b0 \ \f0 Character constants are represented by strings of characters enclosed in double quotes. The backslash is used as an "escape" character to help represent certain other characters as outlined in the table below:\ \ \f2\fs20 \\\\ \f0\fs24 represents a single \\\ \f2\fs20 \\" \f0\fs24 represents a "\ \f2\fs20 "" \f0\fs24 also represents a single "\ \f2\fs20 \\n \f0\fs24 is a new line character\ \f2\fs20 \\r \f0\fs24 is a carriage return character\ \f2\fs20 \\t \f0\fs24 is a tab character\ \f2\fs20 \\b \f0\fs24 is a backspace character\ \f2\fs20 \\ddd \f0\fs24 is an arbitrary character where ddd is one to three octal digits.\ \ \b\fs20 Note: \b0\fs24 Implementation restriction. Character strings may be any length, but internal Macintosh functions make 255 characters an upper limit for string lengths.\ \ \ \f1\b\li0 2.3 Operators\ \b0 \ \f0 C- expressions consist of constants, variables and function calls combined with a small set of operators. The operators include the four basic arithmetic operators, four relational operators and two logical operators. C- expressions follow the precedence rules for the operators as outlines in the following table:\ \ 1 (highest) multiplying operators *,/\ 2 adding operators +,-\ 3 relational operators <, >, ==, !=\ 4 logical operators &,|\ \ \f1\b\li360 2.3.1 Arithmetic operators\ \f0\b0 \ C- supports the four basic arithmetic operators addition (+), subtraction (-), multiplication (*) and division (/). All of these operators take two numeric operands and will convert character string operands to numeric values if needed.\ \ \f1\b 2.3.2 Relational Operators\ \b0\li0 \ \f0\li360 C- supports four relational operators: less than (<), greater than (>), equal to (==) and not equal to (!=). The result of these operators is a numeric 0 if the relation is false and a numeric 1 if the relation is true. If both operands are numeric then the comparisons are done as would be expected for such operands. If only one of the operands is a character string, then the other is converted to a character string before the comparison is done.\ \ Character strings are treated normally by the less than and greater than operators, with the result being a lexicographic comparison. The equal to and not equal to operators, however, are done as a "contains" comparison. So the expression:\ \ \f2\fs20 "abcd" == "bc"\ \ \f0\fs24 will yield a value of 1 (true) because "abcd" contains "bc".\ \ \b\fs20 Note: \b0\fs24 To maintain compatibility with a precursor to C- a single = is treated the same as the equality operator == in circumstances where a comparison is expected.\ \ \ \ \f1\b 2.3.3 Logical Operators\ \b0\li0 \ \f0\li360 C- supports two logical operators: and (&) and or (|). Both of these operators take two numeric operands and will convert character string operands to numeric values if needed. The operands are interpreted as false if 0 and true otherwise. The result is either a 0 for false or a 1 for true.\ \ The logical expressions are not evaluated as McCarthy-and and McCarthy-or. In other words, both operands are evaluated even if the outcome can be determined from the value of the first.\ \ \f1\b\li0 2.4 Expressions\ \b0 \ \f0 Expressions in C- consist of constants, functions and variables combined with the preceding operators, and optionally combined with parenthesis to force order of evaluation. \f1 \ \b\ul \ 3. Simple Statements\ \b0\plain \ \f0 Simple statements in C- are described below. Each statement is followed by a semicolon.\ \ \b\fs20 Note: \b0\fs24 In order to maintain compatibility with a precursor to C-, the semicolon is optional and its absence should not cause any ambiguity problems. \f1 \ \b \ 3.1 Variable definition\ \b0 \ \f0 The variable definition statement consists of the keyword \f2\fs20 variable \f0\fs24 followed by one or more variable names separated by commas. The variables defined in this statement become local variables at the level they are defined. If a local variable with that name at the same level already exists the statement does nothing.\ \ For example:\ \ \f2\fs20 variable MyPassword, MyId; \f0\fs24 \ \ \b\fs20 Note: \b0\fs24 The \f2\fs20 variable \f0\fs24 command is an executable command. In a sequence of statements as shown below, if \f2\fs20 foo \f0\fs24 is a global variable, or a local variable inherited from an enclosing block, then the first reference to the variable \f2\fs20 foo \f0\fs24 is \i not \i0 the same as the last reference:\ \f2\fs20 foo = 1;\ variable foo;\ foo = 2;\ \f0\fs24 But then you wouldn't write code like this, would you. \f1 \ \b \ 3.2 Assignment statement\ \b0 \ \f0 An assignment statement is simply a variable name followed by an equal sign followed by an arbitrary expression. The variable will acquire the type of the expression (either numeric or character string). If the variable does not exist, a global variable will be created.\ \ For example:\ \ \f2\fs20 foo = substring(bar, length(bar)-3, 1); \f1\fs24 \ \ \b 3.3 Function calls\ \b0 \ \f0 Function calls can be used as stand alone statements, as well as parts of expressions. If a function that normally returns a value is used as a simple statement, its value is simply ignored. For example:\ \ \f2\fs20 get(2); /* get the next line and ignore it */ \f1\fs24 \ \b\ul \ 4. Compound Statements\ \b0\plain \ \f0 The compound statements in C- allow the controlled execution of statements (if), repeated execution of statements (while) or grouping of statements (block). \f1 \ \ \b 4.1 Statement Block\ \b0 \ \f0 A statement block in C- is a sequence of statements (simple or compound) contained in left and right braces. Statement blocks can be useful to limit the scope of local variables and to combine statements to be executed within the if and while statements. \f1 \ \ \b 4.2 While statement\ \b0 \ \f0 The \f2\fs20 while \f0\fs24 statement consists of the key word \f2\fs20 while \f0\fs24 followed by an expression and a C- statement (simple or compound). If the expression evaluates to true (non zero) then the statement is executed and the expression is re-evaluated. The sequence of expression evaluation and statement execution will continue as long as the expression evaluates to true.\ \ For example:\ \ \f2\fs20 while get(1) != "DATAPAC"\ \{\ while length(get(1)) ;\ send(".\\r");\ \} \f1\fs24 \ \ \b 4.3 If statement\ \b0 \ \f0 The \f2\fs20 if \f0\fs24 statement consists of the key word \f2\fs20 if \f0\fs24 followed by an expression and a C- statement (simple or compound). If the expression evaluates to true (non zero) then the statement is executed and any optional \f2\fs20 elseif \f0\fs24 or \f2\fs20 else \f0\fs24 parts are skipped. If the expression evaluates to false (zero) then the optional \f2\fs20 elseif \f0\fs24 or \f2\fs20 else \f0\fs24 part will be executed.\ \ The \f2\fs20 if \f0\fs24 statement can optionally be followed by one or more \f2\fs20 elseif \f0\fs24 parts. Each of these consists of the key word \f2\fs20 elseif \f0\fs24 (which may have white space between the word else and the word if) followed by an expression and a statement (simple or compound). If the preceding \f2\fs20 if \f0\fs24 expression and all preceding \f2\fs20 elseif \f0\fs24 expressions have evaluated to false then the expression is evaluated and if true then the statement is executed. In this case all following \f2\fs20 elseif \f0\fs24 and \f2\fs20 else \f0\fs24 parts are skipped.\ \ The \f2\fs20 if \f0\fs24 statement can optionally be followed (after all \f2\fs20 elseif \f0\fs24 parts) by an \f2\fs20 else \f0\fs24 part. This part consists of the keyword \f2\fs20 else \f0\fs24 followed by a statement. If the preceding \f2\fs20 if \f0\fs24 expression and all subsequent \f2\fs20 elseif \f0\fs24 expressions evaluated to false then the statement is executed, otherwise it is skipped.\ \ For example:\ \ \f2\fs20 if substring(Phone_Number,i,1)<"0" |\ substring(Phone_Number,i,1)>"9"\ Phone_Number = Concat(Substring(Phone_Number,0,i),\ Substring(Phone_Number,i+1));\ else\ i=i+1; \f1\fs24 \ \b\ul \ 5. Built-in Functions\ \b0\plain \ \f0 Most of the work that your program will do while making a connection will be done using various built-in functions. All of these functions will convert their arguments to the type they expect.\ \ \f1\b 5.1 Sending data out along the connection\ \ \f0\b0 When your program needs to send data over the serial line, there are two functions to do this. Both functions take one or more character arguments and send the concatenation of them. Note that no carriage return or line feed will be added by these routines. If you want to terminate the string with a carriage return, you must do so yourself.\ \ \b\fs20 Note: \b0\fs24 In the Eudora implementation of C-, strings should be a maximum of 255 characters long. In the case of \f2\fs20 Send \f0\fs24 and \f2\fs20 QuietSend \f0\fs24 this applies to the result of concatenating all of their arguments.\ \ \b\fs20\li360 Function \f2\b0 Send(arg1, ...)\ \f0\b\fi-1560\li1920 Description \b0\fs24 The \f2\fs20 send \f0\fs24 function takes one or more strings as arguments. The concatenation of the strings is sent down the serial line and is also echoed in the progress window.\ \b\fs20\fi0\li360 Example \f2\b0 send(popaccount(), "\\r");\ \ \f0\b Function \f2\b0 QuietSend(arg1, ...)\ \f0\b\fi-1560\li1920 Description \b0\fs24 The \f2\fs20 quietsend \f0\fs24 function takes one or more strings as arguments. Like the \f2\fs20 send \f0\fs24 function, the concatenation of the arguments is sent down the serial line, but is not echoed in the progress window. Instead the string \f2\fs20 <<>> \f0\fs24 is echoed.\ \b\fs20\fi0\li360 Example \f2\b0 quietsend(password(), "\\r");\ \ \f0\b Function \f2\b0 Break(duration)\ \f0\b\fi-1560\li1920 Description \b0\fs24 The \f2\fs20 break \f0\fs24 function takes one numeric argument \f2\fs20 \f0\fs24 which is the number of ticks (60ths of a second) that the break should last.\ \b\fs20\fi0\li360 Example \f2\b0 break(10);\ \f1\fs24 \ \b\li0 5.2 Getting data from the connection\ \ \f0\b0 Getting data back from the serial connection is done with the \f2\fs20 get \f0\fs24 function.\ \ \b\fs20\li360 Function \f2\b0 Get(wait)\ \f0\b\fi-1560\li1920 Description \b0\fs24 The \f2\fs20 get \f0\fs24 function takes one numeric argument which indicates the maximum length of time in seconds to wait for data. If the wait exceeds the amount of time indicated, the function returns a null string. Otherwise it returns a string containing the data received.\ \b\fs20 Example \f2\b0 nextline = get(2);\ \f1\fs24 \ \b\fi0\li0 5.3 Saving and restoring information\ \ \f0\b0 The following functions are used to save and retrieve information that is either private to the script (and so can be retrieved during a later run) or modifies some variable used by Eudora (be careful with this).\ \ \b\fs20\li360 Function \f2\b0 Save(rsrcnum, [item,] value)\ \f0\b\fi-1560\li1920 Description \b0\fs24 The \f2\fs20 save \f0\fs24 function modifies an item in an STR or STR# resource. The resource number is given as the first argument and, for an STR# resource, the string position is given as the second argument. The final argument is a string value that is placed in the resource.\ \b\fs20 Example \f2\b0 save(7400, 13, "telnet -r %p %d\\r");\ \ \f0\b Function \f2\b0 Restore(rsrcnum[, item])\ \f0\b Description \b0\fs24 The \f2\fs20 restore \f0\fs24 function retrieves a value from an STR or STR# resource. The resource number is given as the first argument and, for an STR# resource, the index into that resource is given as the second argument. The value returned by the function is the value of the string resource.\ \ \fi0 If the resource doesn't exist, then the value returned will be a null string in the case of an STR# resource. For an STR resource the value returned will be a nonexistant variable, which can ge tested for with the exists() function. See Appendix G for more on string resources.\ \b\fs20 Example \f2\b0 CTBtool = Restore(1001);\ \f0\fs24\fi0\li0 \ \ \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\f1\b\fc0 5.4 \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600 Functions on strings \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520 \ \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600 \ \f0\b0 Because C- was designed to control the sending of information over a serial connection, it is no surprise that there are a few functions for dealing with character strings.\ \ \b\fs20\fi-1560\li1920 Function \f2\b0 length(string)\ \f0\b Description \b0\fs24 The \f2\fs20 length \f0\fs24 function takes a string as an argument and returns a number indicating the number of characters in the string.\ \b\fs20 Example \f2\b0 if length(Phone_Nbr)==0 progress("Turn on your Blue Box");\ \ \f0\b Function \f2\b0 substring(string,start,length)\ \f0\b Description \b0\fs24 The \f2\fs20 substring \f0\fs24 function takes a string as its first argument and returns a part of that string starting at the point indicated by the second argument (zero indicating the first character) and for a length indicated by the third. If the length argument is missing or larger than the rest of the string then the rest of the string is returned. If the length argument is zero or negative, or the start argument is past the end of the string then a null string is returned.\ \b\fs20 Example \f2\b0 line = substring(line, 0, length(line)-1);\ \ \f0\b Function \f2\b0 concat(arg1,...)\ \f0\b Description \b0\fs24 The \f2\fs20 concat \f0\fs24 function takes one or more strings as arguments and returns a string that is the concatenation of all its arguments.\ \b\fs20 Example \f2\b0 line = concat(line, "\\r");\ \f1\fs24 \ \b\fi0\li0 5.5 A dialog with the user\ \ \f0\b0 There are times when it is necessary to inform the user of certain things, or to get information from the user. \ \ \b\fs20\fi-1560\li1920 Function \f2\b0 dialog(dialogid, arg1,...)\ \f0\b Description \b0\fs24 The \f2\fs20 dialog \f0\fs24 function puts a dialog box on the screen and waits for the user to click on one of the dialog's buttons. The first argument is either a number corresponding to a DLOG resource or a character string corresponding to a DLOG resource name. Up to four more parameters may be given, and the text of these parameters will replace the special strings '^0' through '^3' in all statText items in the dialog. You must use ResEdit to create the DLOG resource and its corresponding DITL resource.\ \ \fi0 The function returns a number indicating the button the user clicked on to dismiss the dialog. If item number one in the dialog is a button, then the \f2\fs20 dialog \f0\fs24 function will outline that button before displaying the dialog.\ \fi-1560 \ \fi0 The value in any user-editable fields are returned in variables named \f2\fs20 DialogStr \i n \f0\i0\fs24 where \f2\i\fs20 n \f0\i0\fs24 is the item number of the text field. The variables are assigned values as though there was an assignment statement at that point, so if there is an appropriately named local variable defined at that point, it will be assigned the value, otherwise a global variable will be used (and created if necessary).\ \ \fi0 The user-editable fields are also initialized if an appropriatly named DialogStr \i n \f0\i0\fs24 variable exists. The lowest numbered of these fields is selected and the cursor is placed in that field.\ \b\fs20\fi-1560 Example \f2\b0 dialog("OK", "Datapac is not available at this time.");\ \ \f0\b Function \f2\b0 pwdialog(dialogid, arg1,...)\ \f0\b Description \b0\fs24 All information about the \f2\fs20 dialog \f0\fs24 function applies to the \f2\fs20 pwdialog \f0\fs24 function as well. The difference is that the \f2\fs20 pwdialog \f0\fs24 function uses a filter to blank out text entered in one of the user-editable fields of the dialog. As the name implies, this can be used to prompt for passwords. This filter is also used by Eudora for its own password prompt, so certain fields in the dialog should only be used for certain purposes.\ \ \f2\fs20 \f0\fs24 item 1 - an OK button (return or enter are like clicking here)\ item 2 - a CANCEL button (command-. is like clicking here)\ item 4 - a text field to be blanked\ item 5 - a field to be flashed on and off if the caps lock is down\ \ \fi0 Any other items that are text fields will not be blanked. Note that if item 3 is a text field then the cursor will be placed in that field first, rather than in item 4. This is useful when prompting for both an id and password in one dialog, as the user would expect to enter the id first.\ \b\fs20\fi-1560 Example \f2\b0 pwdialog("OurPassWord", OurAccount);\ \ \f0\b Function \f2\b0 progress(arg1, ...)\ \f0\b Description \b0\fs24 The \f2\fs20 progress \f0\fs24 function is used to place a character string in the progress window (the small rectangular window used by Eudora to display information on the progress of the connection). The \f2\fs20 progress \f0\fs24 function takes one or more character strings as arguments and concatenates them before displaying them in the progress window.\ \ \b\fs20\fi0 Note: \b0\fs24 In the Eudora implementation of C-, strings should be a maximum of 255 characters long. In the case of \f2\fs20 Progress \f0\fs24 function this applies to the result of concatenating all of its arguments.\ \b\fs20\fi-1560 Example \f2\b0 Progress("Turn on your Blue Box.");\ \f1\fs24 \ \b\fi0\li0 5.6 Information about the environment\ \ \f0\b0 It is often useful to get various pieces of information about the environment that the user has set up. Some of the information available from the following functions can also be retrieved using the \f2\fs20 restore \f0\fs24 function, but these routines are often more convenient.\ \ \b\fs20\fi-1560\li1920 Function \f2\b0 password()\ \f0\b Description \b0\fs24 The \f2\fs20 password \f0\fs24 function takes no arguments and returns a string containing the users password. If the password was not saved by Eudora and has not yet been prompted for, Eudora will be asked to prompt for it at this time.\ \b\fs20 Example \f2\b0 quietsend(password(), "\\r");\ \ \f0\b Function \f2\b0 forgetpassword()\ \f0\b Description \b0\fs24 The \f2\fs20 forgetpassword \f0\fs24 function will make Eudora throw away the password it has. This will cause Eudora to re-prompt for the password the next time it needs it, including the next use of the script \f2\fs20 password \f0\fs24 function.\ \b\fs20 Example \f2\b0 forgetpassword();\ \ \f0\b Function \f2\b0 popaccount()\ \f0\b Description \b0\fs24 The \f2\fs20 popaccount \f0\fs24 function takes no arguments and returns a string containing the users POP account.\ \b\fs20 Example \f2\b0 send(POPaccount(), "\\r");\ \ \f0\b Function \f2\b0 popserver()\ \f0\b Description \b0\fs24 The \f2\fs20 popserver \f0\fs24 function takes no arguments and returns a string containing the POP server name.\ \b\fs20 Example \f2\b0 ourserver = POPserver();\ \ \f0\b Function \f2\b0 smtpserver()\ \f0\b Description \b0\fs24 The \f2\fs20 smtpserver \f0\fs24 function takes no arguments and returns a string containing the SMTP server name.\ \b\fs20 Example \f2\b0 oursmtp = SMTPserver();\ \ \f0\b Function \f2\b0 mousedown()\ \f0\b Description \b0\fs24 The \f2\fs20 mousedown \f0\fs24 function returns 0 if the mouse button is up and 1 if it is down.\ \b\fs20 Example \f2\b0 if mousedown() trace(1);\ \ \f0\b Function \f2\b0 getconfig(item)\ \f0\b Description \b0\fs24 The \f2\fs20 getconfig \f0\fs24 function takes one argument which is a string indicating which Communications Tool Box tool variable to return. The value returned is a string containing the value of that variable if it exists, or a null string if it doesn't. Appendix A contains the variables available for the Apple Modem Tool and the Serial Tool.\ \b\fs20 Example \b0\fs24 Phone_Number = GetConfig("PhoneNumber");\ \f1 \ \b\fi0\li0 5.7 Miscellaneous Functions\ \ \f0\b0 A few miscellaneous functions.\ \ \b\fs20\fi-1560\li1920 Function \f2\b0 quit()\ \f0\b Description \b0\fs24 The \f2\fs20 quit \f0\fs24 function causes the script to abort. It does not return and the connection will be abandoned by Eudora.\ \b\fs20 Example \f2\b0 quit();\ \ \f0\b Function \f2\b0 trace(level)\ \f0\b Description \b0\fs24 The \f2\fs20 trace \f0\fs24 function is a debugging tool that may be useful while composing a script. The function takes one numeric argument which indicates the detail of tracing needed. The value can range from 0 (the least information) to 2 (the most). Appendix E contains a description of the information produced by the \f2\fs20 trace \f0\fs24 function.\ \ \fi0 The trace information will be dumped unceremoniously in a file called "Trace" which will be created if necessary, and will be given the type TEXT.\ \b\fs20\fi-1560 Example \f2\b0 if mousedown() trace(1);\ \ \f0\b Function \f2\b0 echo(state)\ \f0\b Description \b0\fs24 The \f2\fs20 echo \f0\fs24 function takes one numeric argument which controls the echoing of data by the \f2\fs20 get \f0\fs24 function. Normally echo is true and information retrieved by the \f2\fs20 get \f0\fs24 function is echoed in the progress window. If \f2\fs20 echo \f0\fs24 is called with a zero argument then the information from \f2\fs20 get \f0\fs24 will no longer be echoed in the progress window. Echoing can be turned on again by using a non-zero argument.\ \b\fs20 Example \f2\b0 echo(0);\ \ \f0\b Function \f2\b0 trapecho(state)\ \f0\b Description \b0\fs24 The trapecho function takes one numeric argument which controls the handling of echoing of characters when doing a send. Normally trapecho is false and the next get statement will return the echoed characters. If you use trapecho(1) then the echoed characters will be ignored. The state of trapecho is used after the script is finished as well, so if characters will be echoed by the system connected to, it is important to set trapecho on.\ \b\fs20 Example \f2\b0 trapecho(1);\ \ \f0\b Function \f2\b0 exists(variable)\ \f0\b Description \b0\fs24 It is sometimes useful to assign a variable the first time a script is run, and use that value during subsequent runs without resetting it. For example, if your script needs to prompt the user for some information, such as a second password, you may not want to bother the user each time the script is used to make a connection. The \f2\fs20 exists \f0\fs24 function can be used for this purpose. It takes as an argument a variable name and returns zero if the variable has not yet been assigned a value, otherwise it returns one.\ \b\fs20 Example \b0\fs24 if 0==exists(ourpassword) \{ /* prompt for password here */ \} \f1 \ \b\ul\fi0\li0 \ 6. Helpful Hints\ \b0\plain \ \f0 The \f2\fs20 mousedown \f0\fs24 function can be used to turn on trace information while debugging. For example:\ \ \f2\fs20 if mousedown() trace(1); \f0\fs24 \ \ It is probably unwise to leave this in the script when you are finished because if the user has set auto check for mail on than while Eudora is checking for mail, the user might well have the mouse button down and generate an unwanted Trace file.\ \ \ The telnet command that Eudora uses to connect to the POP, SMTP or PH server is kept in STR# resource 7400 at position 13. As outlined in the Eudora documentation, a "%p" in the string is replaced with the server name and a "%d" is replaced with the port number. You can use the \f2\fs20 save \f0\fs24 function to modify this string. For example\ \ \f2\fs20 save(7400, 13, "telnet %p %d\\r");\ \f0\fs24 \ \ The line end character(s) used by Eudora when writing lines to the servers is kept in STR# resource 6000 at position 17. You can use the save function to modify this string. For example:\ \ \f2\fs20 save(6000, 17, "\\r");\ \f0\fs24 \ \ At various points in your script you may want to read and ignore information being sent down the line by the computer or terminal server you are connected to. An easy way to do this is to use an empty while loop that waits for the line to be quiet for some fixed length of time. For example, if we want to wait until no data comes down the line for two seconds, we can use the following command:\ \ \f2\fs20 while length(get(2)) ;\ \f0\fs24 \ \ While C- will complain about the use of uninitialized variables at run time in most \pard\tx1152\tx2304\tx3456\tx4608\tx5760\tx6912\tx8064\tx9216\tx10368\tx11520\fc0 circumstances \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600 , assignment is not one of them. You can use this to reset a variable to an uninitialized state by assigning it an uninitialized variable. For example, if you use the \f2\fs20 exists() \f0\fs24 function to prompt for a password the first time through a script, you could allow the user to force a prompt for a password by holding down the mouse button on subsequent connections by putting the following line at the beginning of the script:\ \ \f2\fs20 if mousedown() userpw = dummyvalue;\ if exists(userpw) == 0 \{\ .\ .\ .\ \} \f0\fs24 \ \f1\b\ul \ Appendix A CTB variables\ \b0\plain \ \f0 The GetConfig function is used to return the value of various Communication Tool Box variables. The following list shows what variables are available from the Apple Modem Tool and the Serial Tool. The variable name must be given as shown (i.e. upper/lower case is significant). If the variable name does not exist for that tool, a zero length string is returned.\ \ The following table is for the Apple Modem Tool.\ \ \pard\tx1720\tx8640\tx9600\b\fs20 Variable \f1\b0\fs24 \f0\b\fs20 Description Example\ \b0 Baud Baud rate of modem. "2400"\ DataBits Number of data bits to use. "5"\ Dial Dialing method. "Tone"\ Handshake Type of handshaking on connection. "None"\ HoldConnection When true, tool does not drop DTR while closing connection. "True"\ ModemType Type of modem to which computer is connected. "Apple Data Modem 2400"\ Parity Type of parity on connection. "None"\ PhoneNumber Phone number to dial. "291-5947"\ Port Current port for sending and receiving data. "Modem Port"\ RemindDisconnect When true and HoldConnection is true, tool reminds user it is holding DTR high. "True"\ Retry Specifies whether tool should retry number when remote modem does not pickup. "True"\ RetryInterval Number of seconds between retries. "1"\ RetryTimes Number of times to retry. "3"\ StopBits Number of stop bits on connection. "1"\ TypeOfCall Specifies whether originating or answering a call. "Originate"\ WaitRings Number of rings to wait before answering incoming call. "2" \f1\fs24 \ \f0 \ \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600 The following table is for the Serial Tool.\ \ \pard\tx1700\tx8640\tx9600\b\fs20 Variable Description Example\ \b0 Baud Baud rate of modem. "2400"\ Data BitsNumber of data bits. "8"\ Handshake Specifies type of handshaking on connection. "None"\ HoldConnection When true, tool does not drop DTR while closing connection. "True"\ Parity Type of parity on connection. "None"\ Port Current port for sending and receiving data. "Modem Port"\ RemindDisconnect When true and HoldConnection is true, tool reminds user it is holding DTR high. "True"\ StopBits Number of stop bits on connection. "1" \f1\fs24 \ \b\ul \ \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600 Appendix B Example Script\ \f2\b0\plain\fs20 \ \f0\fs24 The following script is used by Eudora to connect over a serial line to Simon Fraser University. It detects (by looking at the phone number) if the user is calling in over Datapac (Canada's public packet switched network) or not. If not then the user is either calling in over a phone line or is using a directly connected serial line. In either case the connection is through a Gandalf PACX and then an Annex terminal server. The terminal server requires the user's Unix id and password.\ \ \f2\fs20 /* \ This is a script used by Eudora to login via dialup to the PACX\ and then into the annex terminal server or via Datapac.\ */\ variable nextline; /* used to store the next input line */\ variable Phone_Number; /* the CTB phone number being called */\ while length(get(2)); /* loop until the line is quiet */\ \ Phone_Number = GetConfig("PhoneNumber");\ \ /*\ Try to tell from the phone number if this is a call to Datapac.\ */\ \ variable i; i=0;\ /* strip all the non-numbers out of the phone number */\ while (i "9" )\ Phone_Number = Concat(Substring(Phone_Number,0,i),\ Substring(Phone_Number,i+1));\ else \ i=i+1;\ \}\ /* if it isn't a 291 number, then it must be Datapac */\ if (length(Phone_Number) > 6 &\ substring(Phone_Number,length(Phone_Number)-7,3) != "291") \{\ send(".\\r"); /* Datapac needs a dot to wake it up */\ while (get(1) != "DATAPAC") \{\ while length(get(1));\ send(".\\r");\ \}\ send("83501100\\r"); /* send our datapac address */\ nextline = get(1);\ while (nextline != "call connected") \{\ if (nextline == "destination not responding") \{\ Dialog("OK", "Datapac is not available at this time.");\ quit();\ \}\ nextline = get(1);\ \}\ while length(get(2)); /* read the rest of the stuff */\ /* Set the telnet command for the VAX */\ Save(7400, 13, "telnet %p /PORT=%d\\r"); \ TrapEcho(1); /* Let Eudora know we can't shut echo off */\ \}\ \ /* \ Else it isn't Datapac, so connect through the PACX to the annex.\ */\ else \{\ \ /*\ Wake up the PACX and tell it we want the annex terminal server\ */\ \ send("\\r"); /* send a carriage return to wake up the PACX */\ get(1); /* ignore echo of carriage return */\ nextline = get(1);\ echo(0); /* turn off echo so our "progress" message sticks around */\ while (nextline != "INVALID RESPONSE" & nextline != "ENTER CLASS" & \ nextline != "Checking authorization") \{\ while length(get(1));\ send("\\r"); /* send a carriage return again */\ if (length(Phone_Number)==0) progress("Turn on your Blue Box");\ get(1); /* ignore the echo again */\ nextline = get(1);\ \}\ echo(1); /* turn echo back on now that we are connected */\ \ /* If we are connected to the PACX, give it what it wants. */\ \ if (nextline == "INVALID RESPONSE" | nextline == "ENTER CLASS") \{\ send("16\\r"); /* port 16 for the annex */\ get(0); /* get echo of annex request */\ \ /* \ If all ports to the annex are busy, we can wait.\ */\ \ if (get(0) == "ENTER CLASS BUSY") /* oops, no lines available */ \{\ if (dialog("ports busy",get(0)) != 1) /* ask the user to wait */ \{\ while length(get(2));\ send("n\\r\\r\\r\\r"); /* send "n" for no and enough returns\ to make PACX hang up */\ quit(); /* let Eudora know things didn't work */\ \}\ while length(get(2));\ send("y\\r");\ while (get(0) != "You are subscriber") ; /* wait until a line\ is free */\ \}\ while length(get(2));\ \ /*\ Now try to wake up the annex\ */\ send("\\r");\ while (get(1) != "Annex") \{ /* loop until we hear from the annex */\ send ("\\r"); \ \}\ \ \}\ \ /*\ Now login to the annex \ */\ \ while length(get(1));\ \ variable TryingPassword;\ TryingPassword = 1;\ /* Give the Id/Password a couple of tries in case noise eats them */\ \ while (TryingPassword) \{\ send(popaccount(), "\\r");\ get(1); /* get the echo */\ quietsend(password(), "\\r");\ variable WaitingForDecision;\ WaitingForDecision = 1;\ while WaitingForDecision \{\ nextline = get(0);\ if (nextline == "Permission granted") \{\ /* Everything is OK, so break out of these loops. */\ TryingPassword = 0;\ WaitingForDecision = 0;\ \}\ else if (nextline == "Permission denied") \{\ /* Something is wrong with the ID/password so give up */\ Dialog("OK", "Your password is incorrect. Try again.");\ /* We will only forget the users password if it wasn't saved.\ otherwise the user will have to forget it manually. */\ if (restore(1000,24) != "y") ForgetPassword();\ Quit();\ \}\ else if (nextline == "Incorrect") \{\ /* Bad ID/password, but maybe we got hit with line noise */\ WaitingForDecision = 0;\ \}\ \}\ \}\ \ send("stty -echo\\r"); /* Eudora doesn't like things echoed */\ while length(get(1)); /* Eat up any other data the annex may send */\ \ /*\ Finally, make sure Eudora sends the right things\ */\ Save(7400, 13, "telnet -r %p %d\\r"); /* the telnet cmd for the annex */\ \}\ Save(6000, 17, "\\r"); /* the line end char */\ \f1\b\ul\fs24 \ Appendix C BNF Syntax\ \f0\b0\plain \ The grammar that follows is a slightly simplified version of the grammar used by the C- interpreter. The actual grammar contains rules required by the interpreter to perform semantic actions at the appropriate points.\ \ \f2\fs20 ::= \ \ ::= \ | \ \ ::= \ | \b ; \b0 \ \ ::= \ | \ | \ \ ::= \ | \ | \ \ ::= \b \{ \b0 \b \} \b0 \ \ ::= \b if \b0 \ \ ::= \ \ ::= \b else \b0 \ | \b elseif \b0 \ | \i empty\ \i0 \ ::= \b while \b0 \ \ ::= \b variable \b0 \ \ ::= \ | \b , \b0 \ \ ::= \i identifier \i0 \b ( \b0 \b ) \b0 \ \ ::= \ | \b , \b0 \ | \i empty \i0 \ \ ::= \i identifier \i0 \b = \b0 \ \ ::= \ | \b & \b0 \ | \ \ ::= \ | \b < \b0 \ | \b > \b0 \ | \b != \b0 \ | \b == \b0 \ \ ::= \ | \b + \b0 \ | \b - \b0 \ \ ::= \ | \b * \b0 \ | \b / \b0 \ \ ::= \b ( \b0 \b ) \b0 \ | \ \ ::= \i integer \i0 \ | \i string \i0 \ | \ | \i identifier \i0 \ \f1\b\ul\fs24 \ Appendix D Eudora Implementation\ \b0\plain \ \f0 Before trying to understand how C- scripts work with Eudora, it is a good idea to read Appendix D of the Eudora Reference Guide and understand how Eudora Navigation works. If the navigation feature in Eudora will work for you, you may not have to write a script at all.\ \ If you do need a script then you will need to write from one to three scripts. Like the Eudora Navigations Strings, the scripts consists of a Navigate In scripts for getting connected, a Navigate Mid script for getting ready for another server connection, and a Navigate Out script for closing the connection.\ \ The scripts are kept in separate TEXT resources numbered consecutively. If the Navigate In script is 128, for example, the Navigate Mid script must be 129 and the Navigate Out script must be 130. Both the Navigate Mid and the Navigate Out script may be missing if not needed.\ \ The Navigate In script must have a name, and the name must be in three parts. The first, possibly null, part is ignored. The second part must be "Script" with the capital S. The final part is the name presented by the user to allow them to select the script. The Navigate Mid and Navigate Out scripts should not have names.\ \ Each collection of Navigate In, Navigate Mid and Navigate Out scripts along with associated dialogs can be kept in separate files or Reseditted into Eudora. If they are in separate files, then they must be included as Eudora Plug-in resource files.\ \ Each script will be presented to the user in a pop up menu in the Communications dialog. Users can then select the appropriate script much as they select the CTB Tool to use.\ \ If the user chooses no script, then the process as outlined in Appendix D of the Eudora Reference Guide is followed to find an STR# resource to use for its standard navigation procedure.\ \f1 \ \b\ul \ Appendix E Reading C- traces\ \b0\plain \ \f0 The \f2\fs20 trace \f0\fs24 function in C- is a debugging tool that may be of use when trying to figure out exactly what the machine at the other end is sending and what it expects in return. One thing is sure about the \f2\fs20 trace \f0\fs24 function, it will produce a lot of data. Each level of trace, from 0 to 2 produces more output. The following describes each level and what the output will look like.\ \ \b Level 0 \b0 \ \ At level 0, the information written out by the various built in functions or other parts of the language to show what they are doing. For example, the get function might write out a line such as:\ \ \f1 \f2\fs20 Text returned -> "sfu> "\ \ \f0\fs24 As another example, a text operator might product out like the following (note that the carriage return at the end of the first string causes a new line in the Trace file):\ \f1 \ \f2\fs20 Test: Left side = "DATAPAC: 8340 0301 \ ".\ Test: Right side = "DATAPAC".\ \ \f0\fs24 As a final example, a while or if statement whose expression was false (i.e. had the value 0) would write out the following line:\ \f1 \ \f2\fs20 Execution suspended.....\ \f0\fs24 \ \ \b Level 1\ \b0 \ At level 1, all the information of level 0 is also produced. In addition, the parser will produce a line of output each time a "semantic routine" is called. The semantic routines are where the work is done by the language and some of these produce the output at level 0. In addition to the name of the semantic routine called, the output line contains a short sample of the script program with a vertical bar indicating where the parser is. This may give you a bit more help following the execution of your script. An example of some (slightly cleaned up) output at level 1 follows. You can see that the while test was true so the parse point is set back to the beginning of the while in the last line of the example.\ \ \f2\fs18 @Pop_Clean ... Datapac address */\\n|while length(...\ @Push_Parm ... Datapac address */\\nwhile| length(...\ @Push_Parm ...while length(|get(2)); /* read a...\ @Push_Parm ...while length(get(|2)); /* read a...\ @Push_Integer ...while length(get(2|)); /* read a...\ @Pop_Parm ...while length(get(2|)); /* read a...\ @Get_Function ...while length(get(2)|); /* read a...\ Text returned -> "Simon Fraser University, Computing Services\ "\ @Pop_Parm ...while length(get(2)|); /* read a...\ @Length_Function ...while length(get(2))|; /* read a...\ @Pop_Parm ...while length(get(2))|; /* read a...\ @Do_Test ...while length(get(2))|; /* read a...\ @Test_While ...while length(get(2));| /* read a...\ @Pop_Clean ... Datapac address */\\n|while length(...\ \f0\fs24 \ \ \b Level 2\ \ \b0 This level of trace is probably only useful to the developers of Eudora and those wishing to use up lots of disk space for the trace file. In addition to all the information produced by the level 1 trace, level 2 provides a detailed trace of the parse of the script. Thus as each character in the script is analyzed, one or more lines of trace may be generated.\ \f1\b\ul \ Appendix F C- Error Messages\ \b0\plain \ \f0 C- will catch a number of syntax and run-time errors. The Eudora version of C- will put up a dialog box with the error message and some information on where the error occurred. When you press the OK button, the script will be terminated.\ \ For most errors, the dialog box will contain two numbers. The first will be the offset into the script text that the current syntactic item started. The second number is the current position in the text. These two numbers should give you some idea where to look for the problem. For example, if the error is "Missing right parenthesis", then the second number is where in the script the parser expected the right parenthesis, and the first number will point to the left parenthesis that was being matched.\ \ The memory error message contains different information. It too gives two numbers. The first is the error number from the system (for example -108 is the error message meaning "Not enough room in heap zone".) while the second number is the line number in the source file for the C- semantic routine (useful only if you suspect a bug in the C- interpreter).\ \f1\b\ul \ Appendix G Eudora String Resources\ \b0\plain \ \f0 There are a number of string resources in Eudora that may be referenced from within scripts. Some of these may be safely changed from a script as well. See the SAVE and RESTORE functions for information on how to access string resources.\ \ The preferences set by the user with the Configuration and Switches dialogs are kept in STR# 1000. In particular are the following:\ 61 The Dialup Username from the Configuration screen.\ 62 A place to store a second password.\ 63-69 Strings for use within scripts.\ 70 The name of the script.\ \ Other strings that may be of use:\ STR 1001 contains the name of the CTB Tool being used.\ STR# 7400, 13 contains the format of the telnet command used by Eudora to connect. May be set by a script.\ STR# 6000, 17 contains the end of line character sent to the host by Eudora. May be set by a script.\ \ See the Eudora Q&A stack for information on other string resources.\ }