imported from 0.3 as provided by UniNa
authorthierry <thierry@41d37cc5-eb28-0410-a9bf-d37491348ade>
Wed, 4 Jul 2007 07:49:43 +0000 (07:49 +0000)
committerthierry <thierry@41d37cc5-eb28-0410-a9bf-d37491348ade>
Wed, 4 Jul 2007 07:49:43 +0000 (07:49 +0000)
14 files changed:
CHANGELOG [new file with mode: 0644]
COMPILING [new file with mode: 0644]
GPRS.txt [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile [new file with mode: 0644]
TODO [new file with mode: 0644]
UMTS.txt [new file with mode: 0644]
gcom.1 [new file with mode: 0644]
gcom.c [new file with mode: 0644]
gcom.h [new file with mode: 0644]
gpl.txt [new file with mode: 0644]
operator [new file with mode: 0644]
sigmon [new file with mode: 0755]
sigmon.1 [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..fc361dd
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,88 @@
+Change log
+==========
+Changes to gcom
+===============
+Tues Jan 03 2006 Paul Hardwick
+    - Updated gcom for GT EDGE support and added many new built-in scripts
+    - Re-wrote the header file to make it easier to maintain
+    - Updated man-pages
+    - Put it under version control since this utility will now be maintained.
+    - http://peck.gotdns.com/svn/gcom
+    
+Mon Jan 24 2005 Martin Gregorie
+   - changed option handler to avoid reporting a NULL option when no
+     arguments were supplied or when an invalid option was given.
+   - changed the help display to fit neatly on a 25 x 80 telnet or
+     ssh screen.
+   - created the man page from dcon and previous gcom documentation.
+   - created the COMPILING, CHANGELOG, MANIFEST and TODO files from
+     pre-existing documentation.
+
+October 2003 Paul Hardwick
+   0 Minor changes to make dcon compile with current gcc without 
+     errors or warnings.
+   1 Added gcom.h which provides "built-in" scripts and a support 
+     routine of specific use to (Option) gsm type modems.
+   2 Modified script loading so that by default every script is 
+     pre-pended with an internal "default" script that opens the 
+     serial port correctly, checks if a PIN is required (prompting 
+     the user if needed) then checks registration status and signal 
+     strength. If you call the other built-in scripts then this 
+     default is not executed.
+   3 Added "-s" option to skip the internal default script. If this 
+     option is used then the user must manually open the serial port 
+     with the right baud rate.
+
+Changes to dcon, all done by Daniel.Chouinard
+---------------
+Wed Jan  1 15:32:04 EST 1997
+   - Made it case independent.
+   - Happy new year!
+   - Indexed labels, major speed improvement.
+
+Mon Dec 30 21:10:46 EST 1996 not distributed
+   - Fixed select() on comfd so that `pppd connect 'dcon script'` works again.
+
+
+Mon Dec 23 16:10:24 EST 1996 not distributed
+ 22 hour session!
+   - Added $right(), $left(), $dirname(), $basename(), $hex(), $hexu(), $oct(),
+     $script(), $tolower(), $toupper(), and verbose() functions.
+   - Added abort, flash, and dump commands.
+   - Fixed #!/usr/local/bin/dcon support.
+   - Fixed re-entrant getstring() bug.
+   - Normalized gettoken() and getstring()
+   - Used getopt() instead of if...else if...else if...
+   - Added 0xffff (hex), 07777 (octal), 0%1111 (binary) notations.
+   - Added [$]a0-z9 variable ranges and managed (Woohee!) to keep it
+     compatible with old syntax.
+   - Only allocate strings as needed.
+   - Much better error reporting and exit code handling.
+   - Pulled a groin muscle while sitting crooked.  Go figure.
+   - Created makescript.
+   - Added automatic xterm call in ppp-ex.scr when in X.
+   - Doc: Contents, syntax, error reporting, added new functions, etc...
+
+Wed Dec 11 18:30:42 EST 1996
+   - Changed my E-mail address in doc.
+   - Added a fix to dogoto() so that the label gets printed in log
+     (less confusing to see if a goto or gosub in test executed or not.)
+   - Had lasagna for supper.
+
+Sometime a while ago before I moved (August 1996, I think)
+   - Ansified code and Makefile, contributed by John Gotts.
+     (You guys out there are such purists!  :)
+
+Sat Jul 20 08:19:13 EDT 1996  V: 0.96
+   - Better error reporting.
+
+Fri Jul 19 22:29:37 EDT 1996
+   - Got a bug report from Glen Thigpen that dcon-0.91 reports "Token too long"
+     errors.  Found that dcon didn't deal with non-terminated last lines
+     properly.  Fixed.
+
+Mon Apr 29 21:38:04 EDT 1996  V: 0.95
+   - Got a bug report from J. Van Koll reporting that the included
+     ppp-ex.scr had two lines that were truncated.  Modified ppp-ex.scr
+
+
diff --git a/COMPILING b/COMPILING
new file mode 100644 (file)
index 0000000..aa10ada
--- /dev/null
+++ b/COMPILING
@@ -0,0 +1,33 @@
+Building gcom
+=============
+Switch to the directory where files from gcom.tgz were unpacked. Run:
+
+       make all
+
+You can run gcom immediately if your datacard is plugged in and the 
+USB devices used by it have the appropriate permissions.
+
+To install gcom, sigmon and their documentation, become root,
+make sure you're in the directory where gcom was compiled and run:
+
+       make install
+
+This will install gcom and sigmon in /usr/local/bin and their manpages 
+in /usr/local/man/man1. If this doesn't match your installation or you 
+want to install the executables and manpages somewhere else, simply 
+edit the EXE and MAN macro definitions on lines 3 and 4 of Makefile.
+
+To remove the executables and manpages, become root, make sure you're 
+in the directory where gcom was compiled and run:
+
+       make uninstall
+
+To tidy to after installing gcom, make sure you're logged in as the
+used who compiled gcom and in the directory where gcom was compiled.
+Then run:
+
+       make clean
+
+The example scripts included in the distribution are left in the
+build directory.
diff --git a/GPRS.txt b/GPRS.txt
new file mode 100644 (file)
index 0000000..8601975
--- /dev/null
+++ b/GPRS.txt
@@ -0,0 +1,10 @@
+#Set GPRS only mode
+set com 115200n81
+set senddelay 0.05
+waitquiet 1 0.2
+send "AT_OPSYS=0^m"
+print "Setting GPRS only mode\n"
+    get 2 "^m" $s
+    get 2 "^m" $s
+print $s
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..6fafd84
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,19 @@
+The following files should have been installed when you unarchived
+the tarball. If your file set does not match this list then you
+have an invalidly tarball and should delete the files and obtain 
+a valid download.
+
+CHANGELOG
+COMPILING
+gcom.1
+gcom.c
+gcom.h
+gpl.txt
+GPRS.txt
+Makefile
+MANIFEST
+operator
+sigmon
+sigmon.1
+TODO
+UMTS.txt
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..2540e7d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,60 @@
+#
+#   Makefile - build and install the gmon package
+#   Copyright (C) 2005  Martin Gregorie
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#    martin@gregorie.org
+#
+#      $Id$
+#
+LIB     = -L/usr/local/lib
+INC     = -I/usr/local/include
+EXE    = /usr/local/bin
+MAN     = /usr/share/man/man1
+CPROG  = gcom
+SCRIPT  = sigmon
+BIN     = $(CPROG) $(SCRIPT)
+MANP   = gcom.1 sigmon.1
+
+CFLAGS  = -c
+LDFLAGS =
+
+all: $(BIN)
+
+install:
+       chmod a-w $(BIN)
+       chmod u+rw $(BIN)
+       chmod a+x $(BIN)
+       cp $(BIN) $(EXE)
+       chmod a-wx $(MANP)
+       chmod u+rw $(MANP)
+       chmod a+r $(MANP)
+       cp $(MANP) $(MAN)
+
+uninstall:
+       cd $(EXE); rm $(BIN)
+       cd $(MAN); rm $(MANP)
+
+clean:
+       rm *.o $(CPROG)
+
+
+gcom: gcom.o
+       cc gcom.o $(LDFLAGS) -o gcom
+
+gcom.o: gcom.c gcom.h
+       cc gcom.c $(CFLAGS) 
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..bbed0c3
--- /dev/null
+++ b/TODO
@@ -0,0 +1,17 @@
+To Do
+=====
+Better error handling for built-in scripts. (non-existent at the moment)
+
+Old - unlikely to be addressed:
+Option: locking (uucp? What's the standard?) (Who cares?)
+
+Better testkey (Change stdin mode to raw, update input, system, exec & exit)
+
+getcomchar() (Get one byte from com so a dumb term could be written in a
+              script.  Should be done only after testkey)
+
+Polling sucks.  Could this be (major) changed to be interrupt-driven?
+(Do people still use non-16550s out there?)
+
+Error reporting doesn't display the line containing the error.
+
diff --git a/UMTS.txt b/UMTS.txt
new file mode 100644 (file)
index 0000000..9f956e1
--- /dev/null
+++ b/UMTS.txt
@@ -0,0 +1,7 @@
+#Set UMTS only mode
+set com 115200n81
+set senddelay 0.05
+waitquiet 1 0.2
+send "AT_OPSYS=1^m"
+print "Setting UMTS only mode\n"
+
diff --git a/gcom.1 b/gcom.1
new file mode 100644 (file)
index 0000000..c54d1c5
--- /dev/null
+++ b/gcom.1
@@ -0,0 +1,1262 @@
+.\" Paul Hardwick 
+.\" paul@peck.org.uk
+.TH gcom 1 "04 January, 2006"
+.LO 1
+.SH NAME
+gcom  \- Option GlobeTrotter GPRS/EDGE/3G/HSDPA  and Vodafone 3G/GPRS datacard control tool
+.SH SYNOPSIS
+.B gcom
+.RB \-d 
+.I "device" 
+.RB -ehstvx
+.I "script"
+.SH OPTIONS
+.in +5
+.B \-d 
+.I device
+.in +10
+set the device to be used to communicate with the data-card.
+Defaults to 
+.I /dev/modem
+.PP
+.in +5
+.B \-e 
+.in +10
+turn on serial communications echo.
+.PP
+.in +5
+.B \-h 
+.in +10
+display summary help and exit.
+.PP
+.in +5
+.B \-s
+.in +10
+don\'t run the internal 
+.I default 
+script before an external script.
+.PP
+.in +5
+.B \-t
+.in +10
+change to an alternate line terminator (default "\n"). 
+.PP
+.in +5
+.B \-v 
+.in +10
+run in verbose mode. This traces scripts as they are executed. 
+It is intended to help in debugging scripts.
+.PP
+.in +5
+.B \-x
+.in +10
+for internal and external scripts, any reference to 115200 baud is converted to 57600.
+This is useful for data cards that don't like 115200 baud such as the GlobeTrotter EDGE.
+.PP
+.in -10
+.SH DESCRIPTION
+.B gcom 
+is a scripting language interpreter useful for establishing
+communications on serial lines and through PCMCIA modems
+as well as GPRS and 3G datacards.  
+.PP
+.B gcom 
+has some features that are rarely found in other utilities of the same type.
+.in 5
+.SS Features
+.nf
+- Pre-defined built-in scripts for 2G/3G datacard control
+- Simple, BASIC-like script language.
+- Command-line and file sourcing of script.
+- Multi-response waitfor.
+- waitquiet permits line stabilization.
+- In-line text capture.
+- Multi-process support: fork, wait, kill, exit.
+- Debugging verbose and log output.
+- logging to file.
+- Flow control: goto, gosub, return, if, else.
+- Low-impact on system resources.
+- Time commands and functions.
+- String manipulations.
+- Environment manipulation: env(), putenv.
+- External utilities system calls: system, exec.
+.PP
+.SS Supported GPRS and 3G datacards
+.B gcom 
+has been tested against GlobeTrotter GPRS,EDGE, Combo EDGE, 3G, 3G EDGE, HSDPA 
+and GlobeTrotter Fusion as well as Vodafone 3G. 
+It can set the PIN and display information about datacards before a PPP 
+connection is started.
+Additionally, because the GlobeTrotter and Vodafone 3G/GPRS datacard have 
+a secondary serial interface, these datacards can be monitored while a PPP 
+connection is in existence and transferring data.  
+.PP
+.B gcom
+is primarily designed to work with the GlobeTrotter range of datacards but 
+should be compatible with any other GPRS or 3G datacard provided its 
+interface is implemented as one or more serial or USB serial devices 
+and it is controlled and queried by an implementation of the Hayes 
+command interface with the same AT command extensions used by the listed
+datacards. 
+.
+.SS Using gcom
+.B gcom 
+has only one function: to run a script. This may be one of a number 
+of "standard" internal scripts or an external script. Both types of script are
+invoked in the same way. The "standard" scripts are built into 
+.B gcom
+and will work for serially connected modems, built-in modems, PCMCIA modems
+as well as the GlobeTrotter GPRS and the Vodafone 3G/GPRS datacards.
+.PP
+.SS Built-in scripts
+
+.in -5
+.I gcom
+.in +5
+This runs the default internal script. Running
+.B gcom
+without any script specified, e.g., 
+.I gcom -d /dev/ttyS1 
+it will check for a PIN and  
+prompt you if it is required. The next thing it does is wait for the
+device to register, it then reports the signal strength.
+If you don\'t specify a port with the 
+.B -d 
+option then 
+.I /dev/modem 
+is assumed.
+If the -s switch is not used then this default script is run before any external script.
+
+.in -5
+.I gcom help 
+.in +5
+Lists these and the other options available.
+.PP 
+.in -5
+.I gcom info 
+.in +5
+Lists the datacard configuration. 
+
+.in -5
+.I gcom sig 
+.in +5
+Prints the signal strength. 
+
+.in -5
+.I gcom reg
+.in +5
+Prints the registration state. 
+
+.in -5
+.I gcom 3G
+.in +5
+Puts a GlobeTrotter 3G/Fusion and Vodafone 3G into 3G network only 
+mode (UMTS/HSDPA). 
+
+.in -5
+.I gcom 2G
+.in +5
+Puts a GlobeTrotter 3G/Fusion and Vodafone 3G into 2G network only 
+mode (GSM/GPRS/EDGE). 
+
+.in -5
+.I gcom 3G2G
+.in +5
+Puts a GlobeTrotter 3G/Fusion and Vodafone 3G into 3G preferred 
+mode (UMTS/HSDPA and GSM/GPRS/EDGE). 
+
+.in -5
+.I gcom GTEDGE
+.in +5
+Use this command to initialise GlobeTrotter EDGE and GlobeTrotter 
+Combo EDGE cards before doing anything else. (It switches on the radio). 
+
+.in -5
+.I gcom USA 
+.in +5
+Switch to 900/1900 MHz band for USA operation. GlobeTrotter GPRS datacards only. 
+
+.in -5
+.I gcom EUROPE 
+.in +5
+Switch to 900/1800 MHz band for European operation. GlobeTrotter GPRS datacards only. 
+
+.PP
+.SS Custom Scripts
+
+As well as built in scripts you can make your own. The following
+script sets a Vodafone 3G datacard or Option Fusion card\'s UMTS mode to GPRS:
+.PP
+.in +5
+#Set GPRS only mode
+.br
+set com 115200n81
+.br
+set senddelay 0.05
+.br
+waitquiet 1 0.2
+.br    
+send "AT_OPSYS=0^m"
+.br
+print "Setting GPRS only mode"
+.PP
+If you saved the above script as GPRS you would call it like this:  
+.PP
+.in +5
+.I gcom GPRS
+.in -5
+.PP
+If you needed to specify the port as well then do this: 
+.PP
+.in +5
+.I gcom -d /dev/ttyS1 GPRS
+.in -5
+.PP    
+You can also pass environment parameters to a
+.B gcom 
+script via 
+.I $env().
+.
+
+.SS Replacing chat
+.B chat 
+is a utility that comes with the ppp package (for Linux, anyway) that,
+with a set of expect-send string couples, does enough to connect most people
+to ISPs and such.  While chat\'s use is very simple, it isn\'t very flexible.
+That\'s where 
+.B gcom 
+takes over.
+.PP
+.B gcom 
+can be used in place of 
+.B chat
+using the same strategy.  
+For example, a pppd
+line reading:
+.PP
+.in +5
+.nf
+pppd connect \\ 
+     \'chat -v "" ATDT5551212 CONNECT "" ogin: ppp \\
+     word: whitewater\' \\
+     /dev/cua1 38400 debug crtscts modem defaultroute
+.fi
+.in -5
+.PP
+Would, using 
+.B gcom, 
+read:
+.PP
+.in +5
+.nf
+pppd connect \'gcom /root/scripts/isp.scr\' /dev/cua1 38400 \\
+     debug crtscts modem defaultroute
+.fi
+.in -5
+.PP
+And the isp.scr script would read:
+.PP
+.nf
+     send "ATDT5551212^m"
+     waitfor 60 "ogin:"
+     send "ppp^m"
+     waitfor 60 "word:"
+     send "whitewater^m"
+.fi
+.PP
+Of course it then becomes trivial to make this script a whole lot more
+functional by adding code for busy detect, re-dialing, etc...
+.
+.SS Verbose output
+
+When the verbose option is turned on, 
+.B gcom 
+reports everthing on
+the standard error channel.
+If turned on from the command line (-v), the output contains 4 sections.
+.PP
+- Command line argument actions
+.in +2
+These are actions taken because they were specified from the command 
+line, such as opening a communication device (-d), etc...
+For these to be output, you must specify -v as the first argument.
+.in -2
+.PP
+- List of arguments
+.in +2
+The number and list of arguments passed. This is useful in case 
+you have a bunch of environment variables or quotes, back-quotes, 
+backslashes on the command line and you\'re not sure what the 
+script really sees.
+.in -2
+.PP
+- Script list
+.in +2
+A list of the script to execute.  This may be a concatenation of 
+the default internal script, unless this is suppressed by the -s
+option, and a script file.  Every line is listed with its 
+line number and character position.
+.in -2
+.PP
+- Execution output
+.in +2
+List of commands as they are executed. The parser prints the 
+line its currently on, starting from the exact point where its 
+at to the end of the line. Multiple command groups on a single 
+line produce multiple output lines. Verbose output may be mixed 
+with script output (print, eprint or lprint.)
+.in -2
+.PP
+Here\'s an example:
+.PP
+.in +2
+.nf
+$ gcom -v -d/dev/cua1 -s blah.scr
+gcom 00:18:46 -> Verbose output enabled
+gcom 00:18:46 -> Script file: blah.scr
+gcom 00:18:46 -> argc:5
+gcom 00:18:46 -> argv[0]=gcom
+gcom 00:18:46 -> argv[1]=-v
+gcom 00:18:46 -> argv[2]=-d/dev/cua1
+gcom 00:18:46 -> argv[3]=-s
+gcom 00:18:46 -> argv[4]=blah.scr
+gcom 00:18:46 ->  ---Script---
+.in +3
+1@0000 set com 38400n81 let a=2
+2@0025 print "9x",a,"=",9*a,"\\n"
+3@0051 sleep 5
+4@0059 exit 0
+.in -3
+gcom 00:18:46 ->  ---End of script---
+gcom 00:18:46 -> @0000 set com 38400n81 let a=2
+gcom 00:18:46 -> @0017 let a=2
+gcom 00:18:46 -> @0025 print "9x",a,"=",9*a,"\\n"
+9x2=18
+gcom 00:18:46 -> @0051 sleep 5
+gcom 00:18:51 -> @0059 exit 0
+.in -2
+.fi
+.
+.SH Programming manual
+.SS Syntax
+The syntax used for 
+.B gcom 
+scripts is rather simple, somewhat BASIC-like.
+A script is a non-tokenized, pure ASCII text file containing lines terminated
+by newline characters (Unix standard.)  Scripts can be created and/or modified
+using any standard text editor (vi, vim, joe, pico, emacs, ed, microEmacs)
+Lines in a 
+.B gcom
+script read like so:
+.nf
+
+ - Empty line
+ - [indent]rem remark
+ - [indent][[:|label] LABEL] [command [arguments]] rem remark
+ - [indent][[:|label] LABEL] [command [arguments]] [command [arguments]]...
+.PP
+Characters used for indentation are the space and tabulation characters.
+The rem command makes the script parser skip the rest of the line.
+The rem command can also be written as "#" or "//".
+.PP
+Labels consist of lowercase and uppercase letters and digits.
+Case is ignored in labels.
+.PP
+Commands and their arguments are separated by spaces and/or tabs.
+Command groups are separated by spaces, tabs, or newlines.
+.PP
+Expressions must not contain spaces or tabs.
+.nf
+This is ok : let n=x+76
+This is not: let n= x + 76
+  Because this space ^ would terminate the let command group.
+.fi
+.
+.SS Error reporting
+
+When 
+.B gcom
+detects a script error, it immediately turns on verbose mode,
+generates a dump (see the dump command), reports the error in three lines
+and stops the execution.  The first line reported is the command group
+being executed, the second one shows where the parser got and the third
+line reports the character position of the program counter, the error and
+the exit code.
+
+Here\'s an example:
+.PP
+.in +5
+.nf
+$ gcom -vs blar2.scr
+.fi
+.in -5
+.PP
+Where the blar2.scr script is:
+.PP
+.nf
+.in +5
+inc n 
+dec d3 
+let a=58/3 
+let $d="fod" 
+let c=1/0 
+let $y4="sdfgsdfgsdfg"
+.in -5
+.fi
+.PP
+The trace and error report looks like this:
+.PP
+.in +5
+.nf
+gcom 11:20:15 -> Verbose output enabled
+gcom 11:20:15 -> Script file: blar2.scr
+gcom 11:20:15 -> argc:3
+gcom 11:20:15 -> argv[0]=gcom
+gcom 11:20:15 -> argv[1]=-vs
+gcom 11:20:15 -> argv[2]=blar2.scr
+gcom 11:20:15 ->  ---Script---
+.in +3
+1@0000 inc n
+2@0007 dec d3
+3@0015 let a=58/3
+4@0027 let $d="fod"
+5@0041 let c=1/0
+6@0052 let $y4="sdfgsdfgsdfg"
+.in -3
+gcom 11:20:15 ->  ---End of script---
+gcom 11:20:15 -> @0000 inc n
+gcom 11:20:15 -> @0007 dec d3
+gcom 11:20:15 -> @0015 let a=58/3
+gcom 11:20:15 -> @0027 let $d="fod"
+gcom 11:20:15 -> @0041 let c=1/0
+gcom 11:20:15 -> -- Error Report --
+gcom 11:20:15 -> ---->         ^
+gcom 11:20:15 -> Error @49, line 5, Division by zero. (6)
+.fi
+.in -5
+.
+.SS Exit codes
+When 
+.B gcom
+terminates, it does so with an "exit code".  That is a number passed
+back to the calling process to signify success or failures.  In every-day
+Unix, 0 (zero) means success and everything else means whatever the author
+of the program wants it to mean.  In a shell script, or directly on the command
+line, you may look at the content of 
+.I $? 
+after having called 
+.B gcom
+to examine its exit code.
+.PP
+Example:
+.PP
+.in +5
+.nf
+#!/bin/sh
+gcom /root/bin/call-isp
+if [ $? != 0 ]; then
+  echo "Oops! Something went wrong."
+fi
+.fi
+.in -5
+.PP
+Internal 
+.B gcom
+error codes are as follows:
+.PP
+.in +5
+.nf
+0 : No problems whatsoever.  Apparently.
+1 : Communication device problems.
+2 : Console (tty) device problems.
+3 : Memory problems.
+4 : File or pipe problems.
+5 : Syntax errors.
+6 : Division by zero.
+7 : Variable mis-management.
+8 : System problems.  (Couldn\'t call /bin/sh or some such)
+.fi
+.in -5
+.
+.SS Commands
+.PP
+.nf
+Command     : :   Alias: label
+Description : Notes an anchor point for goto or gosub to branch to.
+Syntax      : Keyword must not contain any special characters.
+Note        : Must be first statement in a line.
+See Also    : goto, gosub, return.
+Example:
+              :loop
+              gosub bravo
+              print "The time is ",$time(),"\\n"
+              sleep 1
+              goto loop
+              label bravo
+              print "Twonk!\\n"
+              return
+
+Command     : abort
+Description : Causes gcom to call abort() and produce a core dump.
+Syntax      : abort
+See Also    : dump, exit.
+
+
+Command     : cd
+Description : Change directory.
+Syntax      : cd directory
+Notes       : -1 is returned in % if the change could not be made.
+Notes       : directory is a string and thus could be a variable.
+See Also    : $cwd().
+Example:
+              cd "duh"
+              if % != 0 print "Could not cd into duh.\\n"
+
+
+Command     : close
+Description : closes file previously opened with open.
+Syntax      : close file
+See Also    : open.
+
+
+Command     : dec
+Description : Decrements the content of an integer variable by 1.
+Syntax      : dec x
+Notes       : x is from a to z or a0 to z9.
+Notes       : Note that "let x=x-1" also works.
+See Also    : let, inc.
+
+
+Command     : dump
+Description : Lists all non-zero integer variables and modified string
+Description : variables as log entries (standard error channel.)
+Syntax      : dump
+See Also    : abort, exit
+
+
+Command     : else
+Description : Alternatively execute commands if last "if" tested false.
+Syntax      : else commands...
+See Also    : if
+Example:
+              if w<350 print "Wow! Imagine that.\\n"
+              else print "Rush Limbaugh is a big fat bastard.\\n"
+
+
+Command     : eprint
+Description : print a comma-separated list of arguments on stderr.
+Syntax      : eprint var,stringvar,"text",...
+Notes       : Like print but on the standard error file descriptor.  
+Notes       : The error output can be re-directed with "2>file" on 
+Notes       : the command line.
+See Also    : print.
+
+
+Command     : exec
+Description : Replaces current gcom process with another process.
+Syntax      : exec "command -args..."
+See Also    : system, fork.
+Example:
+              #Finished script, call cu.
+              exec "cu -l "+$dev()+" -s "+$baud()
+
+
+Command     : exit
+Description : terminates script execution with exit code.
+Syntax      : exit exit_code
+See Also    : abort, dump.
+Example:
+              :error
+              exit 1
+              :smeggit
+              exit 0
+
+
+Command     : flash
+Description : Toggles DTR on communication device for a specified time.
+Syntax      : flash float_constant
+Notes       : float_constant is precise down to 1/100th sec.
+Notes       : Causes modem to drop carrier or go to command mode, 
+Notes       : depending on modem settings.  Setting the baud rate to 0 
+Notes       : for a time has the same effect.
+See Also    : sleep, set com.
+Example:
+              :disconnect
+              flash 0.5
+              exit 0
+
+
+Command     : fprint
+Description : print a comma-separated list of arguments in a file.
+Syntax      : fprint var,stringvar,"text",...
+Notes       : Like print but appended to a file previously opened 
+Notes       : by open.
+See Also    : print.
+
+
+Command     : fork
+Description : forks gcom process in two.  Both processes continue 
+Description : executing the script.
+Syntax      : fork
+Notes       : % returns 0 for child process, new process ID for 
+Notes       : parent or -1 for error.
+See Also    : wait, kill, pid(), ppid().
+Example:
+              fork
+              if % = -1 goto error
+              if % = 0 goto child
+              :parent
+              ...
+
+Command     : get
+Description : get string from communication device.
+Syntax      : get timeout "terminators" $string
+Notes       : timeout is a float constant, terminators is a 
+Notes       : list of characters that, when received, terminate 
+Notes       : get.  Terminators are ignored when received first.
+See Also    : waitfor.
+Example:
+              waitfor 60 "connect"
+              if % != 0 goto error
+              get 2 " ^m" $s
+              print "Connection parameters: ",$s,"\\n"
+
+
+Command     : gosub
+Description : calls a subroutine.
+Syntax      : gosub label
+Notes       : Currently, gcom only supports 128 levels of gosub 
+Notes       : calls (enough!)
+See Also    : :, goto, return.
+Example:
+              gosub routine
+              sleep 1
+              gosub routine
+              goto end
+              :routine
+              print "Flim-flam!\\n"
+              return
+
+
+Command     : goto
+Description : Sends execution somewhere else in the script.
+Syntax      : goto label
+See Also    : :, gosub, return.
+Example:
+              :win95
+              print "Today I want to go and use Linux, thank you.\\n"
+              goto win95
+
+
+Command     : hset
+Description : Set the hundreds timer.
+Syntax      : hset value
+Notes       : This command resets the hundreds of seconds timer to 
+Notes       : a value for htime to start from.
+See Also    : htime().
+Example:
+              hset 0
+              :loop
+              print "Time in 1/100 of a sec.: ",htime(),"\\n"
+              sleep 0.01
+              goto loop
+
+
+Command     : if
+Description : tests a condition
+Syntax      : if test_condition commands...
+Notes       : Conditionnaly executes commands if test condition is true.
+Notes       : Test operators are = (equal), != (not equal), 
+Notes       : <> (not equal to) < (less than), > (greater than), 
+Notes       : <= (less or equal), >= (greater or equal).  
+Notes       : All operators can be used with integers and strings.  
+Notes       : If test_condition is false, if skips to
+Notes       : the next line.
+See Also    : else.
+Example:
+              if n>30 print "Oh-ho! too many sheep!\\n" goto error
+              if n=17 print "Hurray! we\'ve enough sheep\\n" goto party
+              if n<17 print "Murray, get more sheep.\\n" goto getmore
+              if $z < "Marmaluke" goto ...
+              if 3*a>5+b goto ...
+
+
+Command     : inc
+Description : increments the content of an integer variable by 1.
+Syntax      : inc x
+Notes       : x is a-z or a0-z9.
+See Also    : dec, let.
+
+
+Command     : input
+Description : input string from keyboard into string variable.
+Syntax      : input $x
+Notes       : input terminates entry only with the ENTER key.  
+Notes       : Spaces, tabs and other funny characters are all 
+Notes       : stored in the variable.
+See Also    : set echo.
+Example:
+              print "Enter your full name :"
+              input $n4
+
+
+Command     : kill
+Description : Sends a signal to a process.
+Syntax      : kill signal processID
+Notes       : Both signal and processID are integer values.  Same as 
+Notes       : standard unix kill except that signal aliases are not 
+Notes       : accepted and signal is not optional.
+Notes       : 0 is returned in % if the signal could be sent, -1 
+Notes       : otherwise.
+Notes       : Signal 0 can be used to detect process existance.
+See Also    : wait, pid(), ppid().
+Example:
+              fork
+              let p=%
+              if p = 0 goto child
+              sleep 300
+              kill 15 p
+              sleep 1
+              kill 0 p
+              if % != 0 print "Child terminated\\n" goto ok
+              print "Could not terminate child!\\n"
+              kill 9 p
+              sleep 1
+              kill 0 p
+              if % = 0 print "Could not kill child!\\n" goto error
+              print "Child killed.\\n"
+              :ok
+              ...
+
+
+Command     : let
+Description : Does a variable assignment.
+Syntax      : let x=content
+Notes       : x is [$]a0-z9.
+See Also    : inc, dec.
+Example:
+              let a=5
+              let b=(time()-a)+5
+              let y7=6809
+              let z=0%11010111  #Binary
+              let z=077324      #octal
+              let z=0xf5b8      #hexadecimal
+              let $c="Daniel "
+              let $d=$c+" Chouinard"
+              let $s5="Frimpin\' Jeosaphat!"
+
+
+Command     : lprint
+Description : Print a comma-separated list of arguments to the log.
+Syntax      : fprint var,stringvar,"text",...
+Notes       : Like print but printed like a log entry if verbose is on.
+Notes       : logging is sent to stderr.
+See Also    : print, eprint, fprint.
+
+
+Command     : open
+Description : Opens a file or a communication device.
+Syntax      : open com device, open com (stdin), open file FILE
+See Also    : close.
+Example:
+              open com /dev/cua1
+              set com 38400n81
+              open file "/tmp/log"
+              fprintf "This is a log\\n"
+              close file
+
+
+Command     : print
+Description : print a comma-separated list of arguments.
+Syntax      : print var,stringvar,"text",...
+Notes       : Spaces and newlines are not automatically added.
+See Also    : eprint, fprint, lprint.
+Example:
+              let b=26
+              let $c="text variables"
+              print "Contstant text ",b," ",$c," time: ",$time(),"\\n"
+
+
+Command     : putenv
+Description : Sets an environment variable.
+Syntax      : putenv "var=content"
+Notes       : Environment variables are automatically exported, 
+Notes       : never returned. Children processes inherit the 
+Notes       : environment.
+See Also    : $env().
+Example:
+              putenv "SCRIPTDIR=/usr/lib/gcom/scripts"
+              system "dothat"  # dothat reads env. var. SCRIPTDIR...
+
+
+Command     : rem  Aliases: #, //
+Description : Remark.  Rest of line is ignored.
+Syntax      : Note that a space must follow "rem".
+Example:
+              #This is a remark
+              // So is this
+              rem This ain\'t no disco.
+
+
+Command     : return
+Description : Returns from subroutine.
+Syntax      : return
+See Also    : gosub.
+
+
+Command     : send
+Description : sends a string to the communication line (modem usually).
+Syntax      : send string
+Notes       : Carriage return (ENTER) is not sent automatically 
+Notes       : (use ^m).
+Example:
+              send "atdt555-1212^m"
+              send $g+"^m"
+              send "The time is "+$time()+"^m^j"
+
+
+Command     : set
+Description : sets working parameters.
+Syntax      : set parameter value
+Notes       :
+
+Command                       Description
+----------------------------- -------------------------------------------------
+set echo on|off               Keyboard echo on-screen.
+set comecho on|off            Received characters echoed on-screen.
+set senddelay time_constant   In-between character delay for "send"
+set ignorecase on|off         Case sensitivity for "waitfor". 
+                              Default=on.
+set clocal on|off             clocal on = ignore modem signals
+set umask mode                file mode creation defaults. 
+                              See man umask.
+set verbose on|off            verbose on = debug output enabled.
+set com com_params            communication parameters. 
+                                   ex.: 19200n81, 300e71
+                                             baud |||
+                                           Parity    |
+                                        Data bits     |
+                                        Stop bits      |
+
+Example:
+              set echo off
+              print "Password :"
+              input $p
+              print "\\n"
+              set echo on
+              set comecho on
+              set clocal on
+              set senddelay 0.1
+              set ignorecase on
+              set com 38400n81
+              set umask 022 # Must be octal (leading zero)
+              ...
+
+Note on clocal:
+  If want your script to keep working after the carrier detect 
+  signal has dropped, set clocal on, otherwise, a CD drop causes 
+  the device line to close (hang up).  This could happen if, 
+  let\'s say, your script calls and connects, then disconnects or 
+  drops dtr (flash), then tries to re-connect again.
+
+
+Command     : sleep
+Description : Pauses execution.
+Syntax      : sleep float_constant
+Notes       : Float_constant is precise down to 1/100th sec, unless
+Notes       : more than 100 seconds, in which case the precision 
+Notes       : falls down to 1 sec.
+
+Example:
+              sleep 0.06
+              sleep 3
+              sleep 86400 /* A whole day */
+
+
+Command     : system
+Description : Calls a system (unix) command
+Syntax      : system "command"
+See Also    : exec.
+Example:
+              :dir
+              print "listing of directory ",$cwd(),\\n"
+              system "ls -l |more"
+
+
+Command     : testkey
+Description : Tests keyboard for keystroke, returns 1 in % if present.
+Syntax      : testkey
+Notes       : Can only test for ENTER key.  Future versions of gcom 
+Notes       : will test for more and return keycodes in %.
+See Also    : input.
+Example:
+              let n=1
+              :loop
+              print n," sheep... ZZZzzz...\\n"
+              sleep n
+              inc n
+              testkey
+              if % = 0 goto loop
+
+
+Command     : wait
+Description : Wait for a child process to terminate.
+Syntax      : wait
+Notes       : Process ID of terminated child is returned in %
+See Also    : fork, kill.
+Example:
+              fork
+              let p=%
+              if p=0 goto child
+              if p=-1 goto error
+              print "Waiting for child to finish..."
+              wait
+              print "\\n"
+              if %!=p print "Wait got wrong PID!\\n" goto error
+              print "Child is done.\\n"
+
+
+Command     : waitfor
+Description : Waits until one of a list of strings is received
+Syntax      : waitfor timeout "string1","string2","string3"...
+Notes       : Timeout is a floating time constant.  waitquiet returns
+Notes       : 0 for the first string received, 1 for the second, etc...
+Notes       : and -1 for a timeout.  Case is ignored by default unless
+Notes       : ignorecase is set to off.
+See Also    : get.
+Example:
+              :dial
+              send "atdt555-4411^m"
+              waitfor 60 "no carrier","busy","no dial tone","connect"
+              if % = -1 goto timedout
+              if % = 0 goto nocd
+              if % = 1 goto redial
+              if % = 2 goto error
+              if % = 3 goto connected
+
+
+Command     : waitquiet
+Description : Waits until communication line stops receiving for a time.
+Syntax      : waitquiet timeout quiettime
+Notes       : Both timeout and quiettime are floating time constants
+Notes       : with 1/100th sec. accuracy.  Usefull for "swallowing" 
+Notes       : incoming characters for a while or waiting for an 
+Notes       : unknown prompt.
+Example:
+              :closecon
+              send "logoff^m"
+              waitquiet 10 0.5
+              send "yes^m"
+.fi
+.
+.SS Integer functions
+.PP
+.nf
+I-Function  : Access
+Description : Verifies access rights to a file
+Syntax      : let x=access("/tmp/file","frwx")
+Notes       : The second string contains one or more of 
+Notes       : \'f\',\'r\',\'w\',\'x\' to repectively check 
+Notes       : existence, read, write and execute permissions.  
+Notes       : Under root id, the only useful check is \'f\', as
+Notes       : all others will return true.
+Return Value: 0 if the file exists, is readable, writable, 
+Return Value: executable, or -1 if not.
+See Also    : man access(2)
+
+I-Function  : baud
+Description : Returns current baudrate of communication line.
+Syntax      : let x=baud()
+Notes       : Does not necessarily match the modem connection speed.
+See Also    : $baud().
+
+I-Function  : len
+Description : Returns the length of a string.
+Syntax      : let x=len($s)
+Notes       : "" is zero.  Strings currently have a maximum length of
+Notes       : 1024 characters. gcom doesn\'t handle string overflow 
+Notes       : at all.
+
+I-Function  : htime
+Description : Returns hundreds of seconds since start of script.
+Syntax      : let x=htime()
+Notes       : Set to a specific value with hset.
+See Also    : hset.
+
+I-Function  : pid
+Description : Returns process ID number of current process (gcom)
+Syntax      : let x=pid()
+See Also    : ppid(), fork
+
+I-Function  : ppid
+Description : Returns process ID number of parent process.
+Syntax      : let x=ppid()
+Notes       : Can be used by forked child to detect parent 
+Notes       : process.
+
+I-Function  : time
+Description : Returns time in seconds since Jan 1, 00:00:00 1970 GMT.
+Syntax      : let x=time()
+Notes       : Used to calculate time differences.
+See Also    : $time()
+
+
+I-Function  : val
+Description : Returns value of string.
+Syntax      : let x=val($x)
+Notes       : String is not an expression; must only contain [0-9]
+Notes       : characters. Future versions of gcom will be able to 
+Notes       : evaluate expressions. (Maybe) (This was written 6 
+Notes       : years ago.)
+
+
+I-Function  : verbose
+Description : Returns value of verbose setting.
+Syntax      : let x=verbose()
+Notes       : 0=off, 1=on.
+.nf
+.
+.SS String functions
+.PP
+.nf
+S-Function  : basename
+Description : Returns basename part of path.
+Syntax      : let $x=$basename($p)
+Notes       : $basename("/usr/bin/more")="more"
+See Also    : $dirname().
+
+S-Function  : baud
+Description : Returns string representation of current baud rate.
+Syntax      : let $x=$baud()
+Notes       : Defined by "set com"
+See Also    : baud(), set com.
+
+S-Function  : cwd
+Description : Returns current working directory pathname.
+Syntax      : let $x=$cwd()
+See Also    : cd.
+
+S-Function  : dev
+Description : Returns current communication device pathname.
+Syntax      : let $x=$dev()
+Notes       : defined by "-d" command line argument or "open com"
+See Also    : open com.
+
+S-Function  : dirname
+Description : Returns directory name part of path.
+Syntax      : let $x=$dirname($p)
+Notes       : $dirname("/usr/bin/more")="/usr/bin"
+See Also    : $basename().
+
+S-Function  : env
+Description : Returns content of an environment variable
+Syntax      : let $x=$env("HOME")
+Notes       : Non-existant variables return an empty string.
+See Also    : putenv.
+
+S-Function  : hex
+Description : Converts value to hexadecimal representation
+Syntax      : let $x=$hex(x)
+Notes       : Letters a-f in lowercase, no preceding "0x"
+See Also    : $hexu(), $oct().
+
+S-Function  : hexu
+Description : Converts value to hexadecimal representation
+Syntax      : let $x=$hex(x)
+Notes       : Letters A-F in uppercase, no preceding "0x"
+See Also    : $hex(), $oct().
+
+S-Function  : hms
+Description : Converts number of seconds into time string
+Syntax      : let $x=$hms(x)
+Notes       : Format is "HH:MM:SS".  Useful for chronometer displays
+Notes       : Use with "time()", do not try to increment a variable 
+Notes       : every second using "sleep 1".  (See ISP script example)
+Notes       : Format becomes "HHH:MM:SS" after 99 hours, 59 minutes, 
+Notes       : 59s...
+See Also    : time().
+
+S-Function  : left
+Description : Returns left portion of a string
+Syntax      : let $x=$left($s,l)
+Notes       : $s=Source string, l=length
+Notes       : l must be less than the length of the string.
+See Also    : $right(), $mid().
+
+S-Function  : mid
+Description : Returns midsection of a string.
+Syntax      : let $x=$mid($s,s,l)
+Notes       : $s=Source string, s=start, l=length
+Notes       : s must be less than the length of the string, l can be
+Notes       : some huge number (9999) to return the right side of a 
+Notes       : string to the end.  the first character of a string is 
+Notes       : position 0, not 1.
+See Also    : $right(), $left().
+
+S-Function  : oct
+Description : Converts value to octal representation.
+Syntax      : let $x=$oct(x)
+See Also    : $hex(), $hexu().
+
+S-Function  : right
+Description : Returns right portion of a string.
+Syntax      : let $x=$right($s,l)
+Notes       : $s=Source string, l=length
+Notes       : l must be less than the length of the string.
+See Also    : $left(), $mid().
+
+S-Function  : rpipe
+Description : Returns the first line from a system piped command
+Syntax      : let $x=$rpipe("/bin/ls |grep myfile")
+Notes       : Not very useful unless used with head, tail, grep, 
+Notes       : etc...
+See Also    : system.
+
+S-Function  : time
+Description : Returns 24 character local time string
+Syntax      : let $x=$time()
+See Also    : time().
+Notes       : Time is in this format: Mon Apr  8 14:21:22 1996
+                                      012345678901234567890123
+                                                1         2
+
+S-Function  : tolower
+Description : Returns lowercase\'d string.
+Syntax      : let $x=$tolower($y)
+
+S-Function  : toupper
+Description : Returns uppercase\'d string.
+Syntax      : let $x=$toupper($y)
+.fi
+.
+.SS Test operators
+.PP
+.nf
+Operator Description       Example       Result
+=        equal             if 1+2=3      yes
+!=       not equal         if 1+2!=3     no
+<>       not equal         if 1+2<>3     no
+>        Greater than      if 1+3>3      yes
+<        Less than         if 1+3<3      no
+>=       Greater or equal  if 3>=3       yes
+<=       Greater or equal  if 2<=3       yes
+.nf
+.PP
+Strings can be compared using the same operators.
+.PP
+.nf
+"aaa" < "aab",  "aaaa" > "aaa", "Test" != "test", "One" = "One", 
+"A" > "a", "Fumble" <= "Fumigate", "Farsical" <> "Comedic"
+.fi
+.PP
+.B Note 
+that "set ignorecase on" does NOT apply to string comparisons.
+.
+.SS Expression operators
+.PP
+.nf
+Operator  Description      Example           Result
++         Addition         let a=2+2         4
++         Concatenation    let $b="aa"+"bb"  "aabb"
+-         Substraction     let e=2-5         -3
+*         Multiplication   let f=11*2        22
+/         Division         let g=34/11       3
+&         Bit-Wise AND     let h=42&7        2
+|         Bit-Wise OR      let a=42|5        47
+^         Bit-Wise XOR     let a=42^7        45
+.fi
+.PP
+Mixed expression examples:
+.PP
+.nf
+#Returns number of seconds since 00:00:00
+let $t=$time() #Take a snapshot.
+let a=(val(mid$($t,11,2))*3600)+(val(mid$($t,14,2))*60)+val(mid$($t,17,2))
+#Notice the extra sets of parenthesis because gcom\'s expression 
+#evaluator is brain-dead.
+#For example, 5-2+1 should give you 4, right?  Well, according to 
+#getvalue(), it actually gives 2, because it does it somewhat from 
+#right to left.
+#So to evaluate 5-2+1 correctly, use (5-2)+1.  If you\'re using 
+#simple, two-element calculations, don\'t worry about it.  
+#5-2 will give you 3.
+.PP
+#Concatenation  (Calls cu)
+exec "cu -l "+$dev()+" -s "+$baud()"
+.PP
+#In a test condition
+if a+c > strlen($c) goto toomuch
+.PP
+#String comparison
+let $t=$mid($time(),11,8)
+if $t > "19:59:59" print "Too late for that!\\n" goto toolate
+if $t < "08:00:00" print "Too early!\\n" goto tooearly
+if $t = "00:00:00" print "Oh god!  It\'s Twinkee time!\\n"
+.fi
+.
+.SH KNOWN "FEATURES"
+The getvalue() parser.  It makes me laugh so I think I\'ll leave it that way.
+- Daniel.Chouinard@pwc.utc.com
+.
+.SH AUTHORS
+.PP
+Daniel.Chouinard <Daniel.Chouinard@pwc.utc.com> wrote the original
+.B dcon
+utility.
+.PP
+Paul Hardwick <paul@peck.org.uk> updated it for the latest compilers, 
+provided the built-in script functionality and tested it against 
+GPRS and 3G datacards.
+.PP
+Martin Gregorie <martin@gregorie.org> wrote the original manpage for
+.B gcom 
+from the
+.B dcon
+documentation and packaged 
+.B gcom
+for distribution.
+.
+.SS History
+Daniel
+Chouinard wrote most (90%) of 
+.B dcon 
+back in 1989 when he started doing Unix Apps tech support mostly 
+by modem to customer
+systems.  He was tired of typing all those passwords and funny call-charging
+codes everytime he used cu.  Also, the company he worked for needed a system
+that would log call times and estimated costs.  Thus 
+.B dcon 
+was born.
+Six or seven years later (1996) and he was using pppd to connect to
+his ISP site.  He was more or less happy with 
+.B chat 
+but found it lacked flow control and multiple response checks 
+from "atdt...". 
+He wanted it to do different things for "no carrier", "no dial tone", 
+and "busy".
+Although he thought that 
+.B chat 
+would probably be enhanced someday, when he found dcon.c on one of his 
+old 45M tapes he 
+tried compiling it on his Linux box and, lo and behold, it did.
+In the end, he added a few things to it (kill, fork, wait, 1/100 sec. times)
+and left it at that.
+.PP
+A couple of years ago Paul Hardwick found the
+program,
+.B dcon 0.97, 
+last modified in 1996. The purpose of this
+program was to run scripts that would control Linux serial ports. The
+implementation was very similar to something he had written for
+Windows. Anyway, rather than reinvent he contacted the author, Daniel
+Chouinard, and asked his permission to reuse the code.
+Happily he gave permission and a basic but useful utility
+called 
+.B gcom 
+was created. Paul takes no credit for the engine, 
+apart from making it compatible with todays compilers.
+It is basically 
+.B dcon 
+repackaged.
+
+
diff --git a/gcom.c b/gcom.c
new file mode 100644 (file)
index 0000000..ab6c8be
--- /dev/null
+++ b/gcom.c
@@ -0,0 +1,1702 @@
+/*
+ *  gcom version 0.3 - 3G/GPRS datacard management utility
+ *
+ *  Copyright (C) 2003  Paul Hardwick <paul@peck.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  See gcom.doc for more configuration and usage information.
+ *
+ */
+ /***************************************************************************
+* $Id: gcom.c 10 2006-01-04 12:40:44Z paul $
+* $HeadURL: http://10.0.0.4/svn/gcom/gcom.c $
+ ****************************************************************************/
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <termio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include "gcom.h"
+
+#define MAXLABELS 3000  /* Maximum number of labels */
+#define MAXGOSUBS 128   /* Max depth */
+#define STRINGL 1024    /* String lengths.  Also, max script line length */
+#define MAXPATH 1024    /* Max filename length (less or equal to STRINGL) */
+#define MAXTOKEN 20     /* Maximum token or label length */
+#define GTDEVICE "/dev/modem"
+
+#define BOOL unsigned char
+#define NVARS 286       /* a-z, a0-z9 == 26*11 */
+
+extern char *optarg;
+extern int optind, opterr;
+FILE *filep;
+char *script;
+int scriptspace;
+BOOL ifres;
+int lastpc,pc; /* program "counters" */
+long resultcode=0; /* result code */
+int ignorecase=1;  /* no case sensitivity */
+BOOL comecho=0; /* echo what's comin' in */
+BOOL high_speed=0;
+long senddelay=0; /* 0/100th second character delay for sending */
+long number;  /* For getonearg() returning an long */
+char **label; /* Index of labels for goto and gosub */
+int *labelpc; /* Positions of said labels in script */
+int labels;   /* Number of labels found in script */
+long intvars[NVARS]; /* [a-z][0-9] integer variables */
+char string[STRINGL]; /* For getstring() returns and misc. use (misuse) */
+char *stringvars[NVARS]; /* $[a-z][0-9] string variables */
+char cspeed[10];  /* Ascii representation of baudrate */
+int speed=B0; /* Set to B110, B150, B300,..., B38400 */
+char device[MAXPATH]; /* Comm device.  May be "-" */
+char token[MAXTOKEN];   /* For gettoken() returns */
+char scriptfile[MAXPATH]; /* Script file name */
+BOOL verbose=0; /* Log actions */
+struct termio cons, stbuf, svbuf;  /* termios: svbuf=before, stbuf=while */
+int comfd=0; /* Communication file descriptor.  Defaults to stdin. */
+char msg[STRINGL]; /* Massage messages here */
+int preturn,returns[MAXGOSUBS];
+int clocal=0;
+int parity=0, bits=CS8, stopbits=0;
+unsigned long hstart,hset;
+char NullString[]={ "" };
+BOOL lastcharnl=1; /* Indicate that last char printed from getonebyte
+                               was a nl, so no new one is needed */
+
+
+//"open com \"/dev/modem\"\nset com 38400n81\nset senddelay 0.05\nsend \"ATi^m\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response :\",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\n\n";
+/* Prototypes. */
+unsigned long htime(void);
+void dormir(unsigned long microsecs);
+void dotestkey(void);
+void ext(long xtc);
+void vmsg(char *text);
+void skipline(void);
+void printwhere(void);
+void writecom(char *text);
+int getonebyte(void);
+void dodump(void);
+void serror(char *text, int exitcode);
+void skipspaces(void);
+void getopen(void);
+void getclose(void);
+int gettoken(void);
+void skiptoken(void);
+long getvalue(void);
+void getcomma(void);
+void gethardstring(void);
+void getstring(void);
+unsigned long getdvalue(void);
+void dolet(void);
+int dowaitquiet(void);
+int dowaitfor(void);
+BOOL getonoroff(void);
+void setcom(void);
+void doset(void);
+void dogoto(void);
+void dogosub(void);
+unsigned char getonearg(void);
+void doif(void);
+int getindex(void);
+int getintindex(void);
+int getstringindex(void);
+void doget(void);
+void doprint(int channel);
+void doclose(void);
+void opendevice(void);
+void doopen(void);
+int doscript(void);
+
+/* Returns hundreds of seconds */
+unsigned long htime(void) {
+  struct timeval timenow;
+  gettimeofday(&timenow,NULL);
+  return(100L*(timenow.tv_sec-hstart)+(timenow.tv_usec)/10000L-hset);
+}
+
+/* I use select() 'cause CX/UX 6.2 doesn't have usleep().
+   On Linux, usleep() uses select() anyway.
+*/
+void dormir(unsigned long microsecs) {
+  struct timeval timeout;
+  timeout.tv_sec=microsecs/1000000L;
+  timeout.tv_usec=microsecs-(timeout.tv_sec*1000000L);
+  select(1,0,0,0,&timeout);
+}
+
+/* Tests for ENTER key */
+void dotestkey(void) {
+  fd_set fds;
+  struct timeval timeout;
+  timeout.tv_sec=0L;
+  timeout.tv_usec=10000L;
+  FD_ZERO(&fds);
+  FD_SET(0,&fds);  /* Prepare to select() from stdin */
+  resultcode=select(1,&fds,0,0,&timeout);
+  if(resultcode) getchar();
+}
+
+/* Exit after resetting terminal settings */
+void ext(long xtc) {
+  ioctl(1, TCSETA, &cons);
+  exit(xtc);
+}
+
+/* Log message if verbose is on */
+void vmsg(char *text) {
+  time_t t;
+  char *ct;
+  if(verbose) {
+    if(lastcharnl==0) {
+      fprintf(stderr,"\n");
+      lastcharnl=1;
+    }
+    t=time(0);
+    ct=ctime(&t);
+    fprintf(stderr,"gcom %c%c:%c%c:%c%c -> %s\n",
+            ct[11],ct[12],ct[14],ct[15],ct[17],ct[18],
+            text);
+  }
+}
+
+/* Skip to next statement */
+void skipline(void) {
+  while(script[pc]!='\n' && script[pc]!=0) pc++;
+  if(script[pc]) pc++;
+}
+
+void printwhere(void) {
+  int a,b,c;
+  sprintf(msg,"@%04d ",pc);
+  a=pc;
+  skipline();
+  b=pc-1;
+  pc=a;
+  c=strlen(msg);
+  for(;a<b;a++) msg[c++]=script[a];
+  msg[c]=0;
+  vmsg(msg);
+}
+
+/* Write a null-terminated string to communication device */
+void writecom(char *text) {
+  int res;
+  unsigned int a;
+  char ch;
+  for(a=0;a<strlen(text);a++) {
+    ch=text[a];
+    res=write(comfd,&ch,1);
+    if(senddelay) dormir(senddelay);
+    if(res!=1) {
+      serror("Could not write to COM device",1);
+    }
+  }
+}
+
+/* Gets a single byte from comm. device.  Return -1 if none avail. */
+int getonebyte(void) {
+  fd_set rfds;
+  int res;
+  char ch;
+  comecho = 1;
+  struct timeval timeout;
+  timeout.tv_sec=0L;
+  timeout.tv_usec=10000;
+  FD_ZERO(&rfds);
+  FD_SET(comfd, &rfds);
+  res=select(comfd+1,&rfds,NULL,NULL,&timeout);
+  if(res) {
+    res=read(comfd,&ch,1);
+    if(res==1) {
+      if(comecho) {
+        if(ch=='\n') lastcharnl=1;
+        else {
+          if(ch!='\r') lastcharnl=0;
+        }
+        /*fputc(ch,stderr);*/
+      }
+      return(ch);
+    }
+  }
+  else {
+    return(-1); /* Nada. */
+  }
+  return(0);
+}
+
+void dodump(void) {
+  char lmsg[STRINGL];
+  int a,b,c;
+  c=verbose;
+  verbose=1;
+  sprintf(lmsg,"-- Integer variables --"); vmsg(lmsg);
+  for(a=0;a<26;a++) {
+    for(b=0;b<11;b++) {
+      if(intvars[b*26+a]) {
+        sprintf(lmsg,"   = %ld",intvars[b*26+a]);
+        lmsg[1]='a'+a;
+        lmsg[2]=' ';
+        if(b) lmsg[2]='0'+b-1;
+        vmsg(lmsg);
+      }
+    }
+  }
+  sprintf(lmsg,"-- String variables --"); vmsg(lmsg);
+  for(a=0;a<26;a++) {
+    for(b=0;b<11;b++) {
+      if(stringvars[b*26+a]!=NullString) {
+        sprintf(lmsg,"$  = \"%s\"",stringvars[b*26+a]);
+        lmsg[1]='a'+a;
+        lmsg[2]=' ';
+        if(b) lmsg[2]='0'+b-1;
+        vmsg(lmsg);
+      }
+    }
+  }
+  verbose=c;
+}
+
+/* Report script errors and quit */
+void serror(char *text, int exitcode) {
+  int a,line;
+  char lmsg[STRINGL];
+  verbose=1;
+  //dodump();
+  vmsg("-- Error Report --");
+  a=pc;     
+  pc=lastpc;
+  //printwhere();
+  pc=a;
+  while(pc!=0 && (script[pc]==' ' || script[pc]=='\t')) pc--;
+  strcpy(lmsg,"----> ");
+  for(a=6;a<STRINGL;a++) lmsg[a]=' ';
+  for(a=0;a<pc-lastpc;a++) {
+    if(script[a+lastpc]=='\t') lmsg[a+8]='\t';
+  }
+  a+=6;
+  lmsg[a++]='^';
+  lmsg[a]=0;
+  vmsg(lmsg);
+  a=0; line=1;
+  while(a<pc) {
+    if(script[a++]=='\n') {
+      if(a<pc) line++;
+    }
+  }
+  sprintf(lmsg,"Error @%d, line %d, %s. (%d)\n",pc,line,text,exitcode);
+  vmsg(lmsg);
+  ext(exitcode);
+}
+
+void skipspaces(void) {
+  while(script[pc]==' ' || script[pc]=='\t' ) pc++;
+}
+
+void getopen(void) {
+  int a;
+  a=pc;
+  skipspaces();
+  if(script[pc++]!='(') {
+    pc=a;
+    serror("Function requires open parenthesis",5);
+  }
+}
+
+void getclose(void) {
+  int a;
+  a=pc;
+  skipspaces();
+  if(script[pc++]!=')') {
+    pc=a;
+    serror("Function requires close parenthesis",5);
+  }
+}
+
+void skiptoken(void) {
+  skipspaces();
+  while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n' ) pc++;
+  skipspaces();
+}
+
+/* Parse script[pc] to get next statement.  Resolve comments and labels... */
+int gettoken(void) {
+  int tokenp=0;
+  skipspaces();
+  if(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') {
+    token[0]=0;
+    while(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') {
+      token[tokenp++]=script[pc++];
+    }
+    token[tokenp]=0;
+    return(0);
+  }
+  if(script[pc]=='#') {
+    strcpy(token,"rem");
+    pc++;
+    return(0);
+  }
+  if(script[pc]=='/' && script[pc+1]=='/') {
+    strcpy(token,"rem");
+    pc+=2;
+    return(0);
+  }
+  if(script[pc]==':') {
+    strcpy(token,"label");
+    pc++;
+    return(0);
+  }
+  while(script[pc]!=' ' && script[pc]!='\n' &&
+        script[pc]!='\t' && script[pc]!='(') {
+    token[tokenp]=script[pc++];
+    if(token[tokenp]>='A' && token[tokenp]<='Z') {
+      token[tokenp]=token[tokenp]-'A'+'a';
+    }
+    if(tokenp++==MAXTOKEN-1) serror("Token too long",5);
+  }
+  token[tokenp]=0;
+  if(strcmp(token,"then")==0) return(gettoken()); /* Ignore then for if */
+  return(0);
+}
+
+/* shitfaced recursive value parser. must write better one */
+long getvalue(void) {
+  unsigned long p=0;
+  int goone=1;
+  unsigned int a;
+  int base,amode;
+  skipspaces();
+  if(script[pc]=='(') {
+    pc++;
+    p=getvalue();
+    getclose();
+  }
+  else if(script[pc]==')') {
+    return(p);
+  }
+  else if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
+    serror("Did not expect a string",7);
+  }
+  else if( (script[pc]>='a' && script[pc]<='z' &&
+            script[pc+1]>='a' && script[pc+1]<='z') ||
+           (script[pc]>='A' && script[pc]<='Z' &&
+            script[pc+1]>='A' && script[pc+1]<='Z') ) {
+    gettoken();
+    getopen();
+    if(strcmp(token,"len")==0) {
+      char toto[STRINGL];
+      strcpy(toto,string);
+      getstring();
+      p=strlen(string);
+      strcpy(string,toto);
+    }
+    else if(strcmp(token,"htime")==0) {
+      p=htime();
+    }
+    else if(strcmp(token,"time")==0) {
+      p=time(0);
+    }
+    else if(strcmp(token,"pid")==0) {
+      p=getpid();
+    }
+    else if(strcmp(token,"ppid")==0) {
+      p=getppid();
+    }
+    else if(strcmp(token,"verbose")==0) {
+      p=verbose;
+    }
+    else if(strcmp(token,"isatty")==0) {
+      p=isatty(getvalue());
+    }
+    else if(strcmp(token,"baud")==0) {
+      p=atol(cspeed);
+    }
+    else if(strcmp(token,"access")==0) {
+      char toto[STRINGL];
+      char afile[STRINGL];
+      strcpy(toto,string);
+      getstring();
+      strcpy(afile,string);
+      getcomma();
+      getstring();
+      if(string[0]==0) serror("Missing access mode[s]",5);
+      amode=0;
+      for(a=0;a<strlen(string);a++) {
+        switch(string[a]) {
+          case 'R' :
+          case 'r' : amode|=R_OK; break;
+          case 'W' :
+          case 'w' : amode|=W_OK; break;
+          case 'X' :
+          case 'x' : amode|=X_OK; break;
+          case 'F' :
+          case 'f' : amode|=F_OK; break;
+          default : serror("Access modes are r,w,x, and f",5);
+        }
+      }
+      p=access(afile,amode);
+      strcpy(string,toto);
+    }
+    else if(strcmp(token,"val")==0 || strcmp(token,"atol")==0) {
+      char toto[STRINGL];
+      strcpy(toto,string);
+      getstring();
+      p=atol(string);
+      strcpy(string,toto);
+    }
+    else serror("Unknown Integer function",5);
+    getclose();
+  }
+  if(script[pc]=='%') {
+    pc++;
+    skipspaces();
+    p=resultcode;
+  }
+  while(goone) {
+    if(script[pc]=='+') {
+      pc++;
+      p+=getvalue();
+    }
+    else if(script[pc]=='-') {
+      pc++;
+      p-=getvalue();
+    }
+    else if(script[pc]=='^') {
+      pc++;
+      p^=getvalue();
+    }
+    else if(script[pc]=='&') {
+      pc++;
+      p&=getvalue();
+    }
+    else if(script[pc]=='|') {
+      pc++;
+      p|=getvalue();
+    }
+    else if(script[pc]=='*') {
+      pc++;
+      p*=getvalue();
+    }
+    else if(script[pc]=='/') {
+      pc++;
+      a=getvalue();
+      if(a==0) serror("Division by zero",6);
+      p/=a;
+    }
+    else if((script[pc]>='a' && script[pc]<='z') ||
+            (script[pc]>='A' && script[pc]<='Z') ) {
+      p=intvars[getintindex()];
+    }
+    else if(script[pc]>='0' && script[pc]<='9') {
+      base=10;
+      if(script[pc]=='0') {
+        base=8;
+        pc++;
+        if(script[pc]=='x' || script[pc]=='X') {
+          base=16;
+          pc++;
+        }
+        if(script[pc]=='%') {
+          base=2;
+          pc++;
+        }
+      }
+      while((script[pc]>='0' && script[pc]<='9') ||
+            (script[pc]>='a' && script[pc]<='f') ||
+            (script[pc]>='A' && script[pc]<='F')) {
+        if(script[pc]>='a' && script[pc]<='f') {
+          p=p*base+script[pc++]-'a'+10;
+        }
+        else if(script[pc]>='A' && script[pc]<='F') {
+          p=p*base+script[pc++]-'A'+10;
+        }
+        else {
+          p=p*base+script[pc++]-'0';
+        }
+      }
+    }
+    else {
+      goone=0;
+    }
+  }
+  return(p);
+}
+
+void getcomma(void) {
+  skipspaces();
+  if(script[pc++]!=',') serror("Comma expected",5);
+}
+
+void gethardstring(void) {
+  int a=0;
+  skipspaces();
+  while(script[pc]!=0 && script[pc]!=' ' && script[pc]!='\t' &&
+        script[pc]!='\n') {
+    string[a++]=script[pc++];
+  }
+  string[a]=0;
+}
+
+/* Parse a string from script[pc] */
+void getstring(void) {
+  FILE *fp;
+  time_t t;
+  unsigned int a,b;
+  int c,p=0;
+  unsigned char ch,match;
+  string[0]=0;
+  skipspaces();
+  if(script[pc]!='"' && script[pc]!='\'' && script[pc]!='$' ) {
+    serror("Expected a string",7);
+  }
+  while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n' && script[pc]!=','  && script[pc]!=')' && script[pc]!='=' && script[pc]!='<' && script[pc]!='>' && script[pc]!='!' ) {
+    if(script[pc]=='+') pc++;
+    skipspaces();
+    if( (script[pc]=='$' && script[pc+1]>='a' && script[pc+1]<='z' &&
+         script[pc+2]>='a' && script[pc+2]<='z') ||
+        (script[pc]=='$' && script[pc+1]>='A' && script[pc+1]<='Z' &&
+         script[pc+2]>='A' && script[pc+2]<='Z') ) {
+      pc++;
+      gettoken();
+      getopen();
+      if(strcmp(token,"time")==0) {
+        t=time(0);
+        strcat(string,ctime(&t));
+        string[strlen(string)-1]=0;
+      }
+      else if(strcmp(token,"rpipe")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        if((fp=popen(string,"r"))==NULL) serror("Could not popen!",4);
+        fgets(string,STRINGL-1,fp);
+        string[strlen(string)-1]=0;
+        pclose(fp);
+        strcat(toto,string);
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"env")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        if(getenv(string)) strcat(toto,(char *)getenv(string));
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"hms")==0) {
+        long sec,min,hour;
+        sec=getvalue();
+        min=sec/60L;
+        sec-=min*60L;
+        hour=min/60L;
+        min-=hour*60L;
+        sprintf(string,"%s%02ld:%02ld:%02ld",string,hour,min,sec);
+      }
+      else if(strcmp(token,"dev")==0) {
+        strcat(string,device);
+      }
+      else if(strcmp(token,"cwd")==0) {
+        getcwd(string,STRINGL);
+      }
+      else if(strcmp(token,"baud")==0) {
+        strcat(string,cspeed);
+      }
+      else if(strcmp(token,"str")==0 || strcmp(token,"ltoa")==0) {
+        sprintf(string,"%s%ld",string,getvalue());
+      }
+      else if(strcmp(token,"hexu")==0) {
+        sprintf(string,"%s%lX",string,getvalue());
+      }
+      else if(strcmp(token,"hex")==0) {
+        sprintf(string,"%s%lx",string,getvalue());
+      }
+      else if(strcmp(token,"oct")==0) {
+        sprintf(string,"%s%lo",string,getvalue());
+      }
+      else if(strcmp(token,"dirname")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        b=0;
+        for(a=0;a<strlen(string);a++) {
+          if(string[a]=='/' || string[a]=='\\') b=a;
+        }
+        string[b]=0;
+        strcat(toto,string);
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"tolower")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        for(a=0;a<strlen(string);a++) {
+          if(string[a]>='A' && string[a]<='Z' ) string[a]=string[a]-'A'+'a';
+        }
+        strcat(toto,string);
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"toupper")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        for(a=0;a<strlen(string);a++) {
+          if(string[a]>='a' && string[a]<='z' ) string[a]=string[a]-'a'+'A';
+        }
+        strcat(toto,string);
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"basename")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        b=0;
+        for(a=0;a<strlen(string);a++) {
+          if(string[a]=='/' || string[a]=='\\') b=a+1;
+        }
+        a=strlen(toto);
+        while(string[b]) toto[a++]=string[b++];
+        toto[a]=0;
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"script")==0) {
+        strcat(string,scriptfile);
+      }
+      else if(strcmp(token,"right")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        getcomma();
+        b=getvalue();
+        if(b>strlen(string)) serror("String is shorter than second argument",7);
+        c=strlen(toto);
+        a=strlen(string)-b;
+        while(b!=0 && string[a]!=0) {
+          toto[c++]=string[a++];
+          b--;
+        }
+        toto[c]=0;
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"left")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        getcomma();
+        b=getvalue();
+        if(b>strlen(string)) serror("String is shorter than second argument",7);
+        c=strlen(toto);
+        a=0;
+        while(b!=0 && string[a]!=0) {
+          toto[c++]=string[a++];
+          b--;
+        }
+        toto[c]=0;
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"mid")==0) {
+        char toto[STRINGL];
+        strcpy(toto,string);
+        getstring();
+        getcomma();
+        a=getvalue();
+        getcomma();
+        b=getvalue();
+        if(a>strlen(string)) serror("String is shorter than second argument",7);
+        c=strlen(toto);
+        while(b!=0 && string[a]!=0) {
+          toto[c++]=string[a++];
+          b--;
+        }
+        toto[c]=0;
+        strcpy(string,toto);
+      }
+      else if(strcmp(token,"sex")==0) {
+        strcat(string,"You're a naughty boy, you!");
+      }
+      else serror("Invalid string funtion",5);
+      getclose();
+    }
+    else if(script[pc]=='$') {
+      strcat(string,stringvars[getstringindex()]);
+    }
+    else if(script[pc]=='"' || script[pc]=='\'') {
+      match=script[pc++];
+      while(script[pc]!=match) {
+        ch=script[pc++];
+        if(ch==0) serror("Umatched quote.",5);
+        if(ch=='\\') {
+          if(script[pc]<='7' && script[pc]>='0' &&
+            script[pc+1]<='7' && script[pc+1]>='0' ) {
+            ch=0;
+            while(script[pc]>='0' && script[pc]<='7') {
+              ch=8*ch+script[pc++]-'0';
+            }
+          }
+          else {
+            switch(script[pc]) {
+              case 'T' :
+              case 't' : ch=9;  break;
+              case 'R' :
+              case 'r' : ch=13; break;
+              case 'N' :
+              case 'n' : ch=10; break;
+              case 'B' :
+              case 'b' : ch=8;  break;
+              case 'F' :
+              case 'f' : ch=12; break;
+              case '"' :
+              case '^' :
+              case '\'' :
+              case '\\' : ch=script[pc]; break;
+              default :  serror("Malformed escaped character",5);
+            }
+            pc++;
+          }
+        }
+        else if(ch=='^') {
+          ch=script[pc];
+          if(ch!='^' && ch!='"' && ch!='\'' && ch!='\\' ) {
+            ch=ch&31; /* Control char */
+          }
+          pc++;
+        }
+        p=strlen(string);
+        string[p++]=ch;
+        string[p]=0;
+      }
+      pc++; /* Space over quote */
+    }
+    else {
+      p=strlen(string);
+      string[p++]=script[pc++];
+      string[p]=0;
+    }
+  }
+}
+
+/* Get a value, multiply by a hundred (for time values) */
+unsigned long getdvalue(void) {
+  float f;
+  gettoken();
+  skipspaces();
+  sscanf(token,"%f",&f);
+  f+=0.00001; /* Rounding errors */
+  return(100.0*f);
+}
+
+void dolet(void) {
+  int index;
+  BOOL svar=0;
+  skipspaces();
+  if(script[pc]=='$') {
+    svar=1;
+    index=getstringindex();
+  }
+  else index=getintindex();
+  skipspaces();
+  gettoken();
+  if(strcmp(token,"=")!=0) serror("Bad LET assignment, '=' missing",5);
+  skipspaces();
+  if(svar) {
+    getstring();
+    strcpy(stringvars[index],string);
+  }
+  else {
+    intvars[index]=getvalue();
+  }
+}
+
+/* See documentation for doXXX() functions */
+int dowaitquiet(void) {
+  unsigned long timeout,timequiet,quiet,now;
+  int c,quit;
+  timeout=htime()+getdvalue();
+  quiet=getdvalue();
+  timequiet=htime()+quiet;
+  quit=1;
+  while(quit==1) {
+    now=htime();
+    c=getonebyte();
+    if(c!= -1) timequiet=now+quiet;
+    if(now>=timequiet) quit=0;
+    if(now>=timeout) quit=255;
+  }
+  return(quit);
+}
+
+int dowaitfor(void) {
+  char strings[20][80];
+  char buffer[128];
+  unsigned long timeout;
+  unsigned int a;
+  int b,c;
+  b=0;
+  buffer[127]=0;
+  skipspaces();
+  timeout=htime()+getdvalue();
+  while(script[pc]==',' || script[pc]=='$' || script[pc]=='"' ||
+        script[pc]=='\'' ) {
+    if(script[pc]==',') pc++;
+    getstring();
+    skipspaces();
+    strcpy(strings[b],string);
+    if(ignorecase) {
+      for(a=0;a<strlen(strings[b]);a++) {
+        if(strings[b][a]>='A' && strings[b][a]<='Z') {
+          strings[b][a]=strings[b][a]-'A'+'a';
+        }
+      }
+    }
+    b++;
+  }
+  strings[b][0]=0;
+  while(htime()<timeout) {
+    c=getonebyte();
+    //printf("Byte \"%c\" ",c);
+    if(c!= -1) {
+      if(ignorecase) {
+        if(c>='A' && c<='Z') c=c-'A'+'a';
+      }
+      for(a=0;a<127;a++) buffer[a]=buffer[a+1]; //shuffle down
+      buffer[126]=c;
+      b=0;
+      while(strings[b][0]) {
+        c=strlen(strings[b]);
+        if (strcmp(strings[b],&buffer[127-c]) == 0){
+          return(b);
+        }
+        b++;
+      }
+    }
+  }
+  return(-1);
+}
+
+/* Parse script for "on" or "off" wich are tokens, not strings */
+BOOL getonoroff(void) {
+  int a,b;
+  b=pc;
+  gettoken();
+  if(strcmp(token,"on")==0) return(1);
+  if(strcmp(token,"off")==0) return(0);
+  pc=b;
+  a=getvalue();
+  if(a!=0 && a!=1) serror("Bad value (should be on or off, 1 or 0.)",5);
+  return(a);
+}
+
+void setcom(void) {
+  stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
+  stbuf.c_cflag |= (speed | bits | CREAD | clocal | parity | stopbits );
+  if (ioctl(comfd, TCSETA, &stbuf) < 0) {
+    serror("Can't ioctl set device",1);
+  }
+}
+
+void doset(void) {
+  struct termio console;
+  int a,b;
+  gettoken();
+  if(strcmp(token,"echo")==0) {
+    a=0;
+    if(getonoroff()) a=ECHO|ECHOE;
+    if(ioctl(0, TCGETA, &console)<0) {
+      serror("Can't ioctl FD zero!\n",2);
+    }
+    console.c_lflag &= ~(ECHO | ECHOE);
+    console.c_lflag |= a;
+    ioctl(0, TCSETA, &console);
+  }
+  else if(strcmp(token,"senddelay")==0) {
+    senddelay=10000L*getdvalue();
+  }
+  else if(strcmp(token,"clocal")==0) {
+    clocal=0;
+    if(getonoroff()) clocal=CLOCAL;
+    setcom();
+  }
+  else if(strcmp(token,"umask")==0) {
+    umask(getvalue()&0777);
+  }
+  else if(strcmp(token,"verbose")==0) {
+    verbose=getonoroff();
+  }
+  else if(strcmp(token,"comecho")==0) {
+    comecho=getonoroff();
+  }
+  else if(strcmp(token,"ignorecase")==0) {
+    ignorecase=getonoroff();
+  }
+  else if(strcmp(token,"com")==0) {
+    skipspaces();
+    if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') {
+      getstring();
+      strcpy(token,string);
+    }
+    else gettoken();
+    a=0;
+    b=0;
+    while(token[b]>='0' && token[b]<='9') {
+      a=10*a+token[b++]-'0';
+    }
+    if(token[b]) {
+      switch(token[b]) {
+        case 'n': parity=0; break;
+        case 'e': parity=PARENB; break;
+        case 'o': parity=PARENB|PARODD; break;
+        default : serror("Parity can only ben E, N, or O",5);
+      }
+      b++;
+      if(token[b]) {
+        switch(token[b]) {
+          case '5' : bits=CS5; break;
+          case '6' : bits=CS6; break;
+          case '7' : bits=CS7; break;
+          case '8' : bits=CS8; break;
+          default : serror("Bits can only be 5, 6, 7, or 8",5);
+        }
+        b++;
+        if(token[b]) {
+          switch(token[b]) {
+            case '1': stopbits=0; break;
+            case '2': stopbits=CSTOPB; break;
+            default : serror("Stop bits can only be 1 or 2",5);
+          }
+        }
+      }
+    }
+    sprintf(cspeed,"%d",a);
+    switch(a) {
+      case 0: speed = B0;break;
+      case 50: speed = B50;break;
+      case 75: speed = B75;break;
+      case 110: speed = B110;break;
+      case 150: speed = B150;break;
+      case 300: speed = B300;break;
+      case 600: speed = B600;break;
+      case 1200: speed = B1200;break;
+      case 2400: speed = B2400;break;
+      case 4800: speed = B4800;break;
+      case 9600: speed = B9600;break;
+      case 19200: speed = B19200;break;
+      case 38400: speed = B38400;break;
+      case 57600: speed = B57600;break;
+      case 115200: {
+                    if(high_speed == 0) speed = B115200;
+                    else speed = B57600;
+                    break;
+                  }
+      case 460800: speed = B460800; break;
+      default: serror("Invalid baudrate",1);
+    }
+    setcom();
+  }
+}
+
+void dogoto(void) {
+  int a,originalpos;
+  originalpos=pc;
+  gettoken();
+  for(a=0;a<labels;a++) {
+    if(strcmp(token,label[a])==0) break;
+  }
+  if(a>=labels) {
+    pc=originalpos;
+    sprintf(msg,"Label \"%s\" not found",token);
+    serror(msg,5);
+  }
+  else {
+    pc=labelpc[a];
+  }
+}
+
+void dogosub(void) {
+  int a;
+  if(preturn==MAXGOSUBS) serror("Reached maximum GOSUB depth",3);
+  a=pc;
+  gettoken();
+  returns[preturn++]=pc;
+  pc=a;
+  dogoto();
+}
+
+/* Gets arguments and returns 0 for a string, 1 for an int. Used with if */
+BOOL getonearg(void) {
+  if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
+    getstring();
+    return(0);
+  }
+  else {
+    number=getvalue();
+    return(1);
+  }
+}
+
+void doif(void) {
+  char stringarg[STRINGL];
+  char tokencopy[MAXTOKEN];
+  int intarg;
+  skipspaces();
+  ifres=0;
+  if(getonearg()) {
+    intarg=number;
+    gettoken();
+    skipspaces();
+    if(getonearg()!=1) serror("Comparison mis-match",7);
+    if(strcmp(token,"<")==0) {
+      if(intarg<number) ifres=1;
+    }
+    if(strcmp(token,"<=")==0) {
+      if(intarg<=number) ifres=1;
+    }
+    else if(strcmp(token,"=")==0) {
+      if(intarg==number) ifres=1;
+    }
+    else if(strcmp(token,">")==0) {
+      if(intarg>number) ifres=1;
+    }
+    else if(strcmp(token,">=")==0) {
+      if(intarg>=number) ifres=1;
+    }
+    else if(strcmp(token,"<>")==0) {
+      if(intarg!=number) ifres=1;
+    }
+    else if(strcmp(token,"!=")==0 || strcmp(token,"<>")==0) {
+      if(intarg!=number) ifres=1;
+    }
+  }
+  else {
+    strcpy(stringarg,string);
+    gettoken();
+    strcpy(tokencopy,token);
+    skipspaces();
+    if(getonearg()!=0) serror("Comparison mis-match",7);
+    if(strcmp(tokencopy,"<")==0) {
+      if(strcmp(stringarg,string)<0) ifres=1;
+    }
+    if(strcmp(tokencopy,"<=")==0) {
+      if(strcmp(stringarg,string)<=0) ifres=1;
+    }
+    else if(strcmp(tokencopy,"=")==0) {
+      if(strcmp(stringarg,string)==0) ifres=1;
+    }
+    else if(strcmp(tokencopy,">")==0) {
+      if(strcmp(stringarg,string)>0) ifres=1;
+    }
+    else if(strcmp(tokencopy,">=")==0) {
+      if(strcmp(stringarg,string)>=0) ifres=1;
+    }
+    else if(strcmp(tokencopy,"!=")==0 || strcmp(tokencopy,"<>")==0) {
+      if(strcmp(stringarg,string)!=0) ifres=1;
+    }
+  }
+  if(!ifres) skipline();
+}
+
+int getindex(void) {
+  int index;
+  index=script[pc++];
+  if(index>='A' && index<='Z') index=index-'A'+'a';
+  if(index>'z' || index<'a') serror("Malformed variable name",7);
+  index=index-'a';
+  if(script[pc]>='0' && script[pc]<='9') {
+    index=index+(1+script[pc++]-'0')*26;
+  }
+  return(index);
+}
+
+/* Parse script to find integer variable index */
+int getintindex(void) {
+  skipspaces();
+  if(script[pc]=='$') serror("Integer variable expected",7);
+  return(getindex());
+}
+
+/* Parse script to find string variable index and allocate memory for storage
+   as needed. */
+int getstringindex(void) {
+  int index;
+  skipspaces();
+  if(script[pc++]!='$') serror("String variable expected",7);
+  index=getindex();
+  if(stringvars[index]==NullString) {
+    stringvars[index]=(char *)malloc(STRINGL);
+    if(stringvars[index]==NULL) serror("Could not malloc",3);
+    stringvars[index][0]=0;
+  }
+  return(index);
+}
+
+void doget(void) {
+  char terminators[STRINGL];
+  unsigned int a;
+  int b,c,index;
+  int goahead=1;
+  unsigned long timeout;
+  timeout=htime()+getdvalue();
+  getstring();
+  strcpy(terminators,string);
+  index=getstringindex();
+  string[0]=0;
+  b=0;
+  resultcode=0;
+  while(goahead && htime()<timeout) {
+    c=getonebyte();
+    if(c!= -1) {
+      for(a=0;a<strlen(terminators);a++) {
+        if(c==terminators[a]) goahead=0;
+      }
+      if(goahead==0 && b==0) goahead=1; /* Ignore terminators if nothing yet */
+      else if(goahead) {
+        string[b++]=c;
+        string[b]=0;
+      }
+    }
+  }
+  if(goahead) resultcode= -1;
+  strcpy(stringvars[index],string);
+}
+
+void doprint(int channel) {
+  skipspaces();
+  msg[0]=0;
+  while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n') {
+    if(script[pc]==',') pc++;
+    else {
+      if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
+        getstring();
+        strcat(msg,string);
+      }
+      else {
+        sprintf(string,"%ld",getvalue());
+        strcat(msg,string);
+      }
+    }
+  }
+  switch(channel) {
+    case 1: printf("%s",msg); fflush(stdout); break;
+    case 2: fputs(msg,stderr); break;
+    case 3:
+      if(msg[strlen(msg)-1]=='\n') msg[strlen(msg)-1]=0;
+      vmsg(msg);
+      break;
+    case 4:
+      if(filep==NULL) serror("File not opened",4);
+      fputs(msg,filep);
+      break;
+  }
+}
+
+void doclose(void) {
+  gettoken();
+  if(strcmp(token,"hardcom")==0) {
+    if(comfd== -1) serror("Com device not open",1);
+    vmsg("Closing device");
+    if (ioctl(comfd, TCSETA, &svbuf) < 0) {
+      sprintf(msg,"Can't ioctl set device %s.\n",device);
+      serror(msg,1);
+    }
+    close(comfd);
+    comfd= -1;
+  }
+  else if(strcmp(token,"com")==0) {
+    if(comfd== -1) serror("Com device not open",1);
+    vmsg("Closing com fd");
+    close(comfd);
+    comfd= -1;
+  }
+  else if(strcmp(token,"file")==0) {
+    if(filep==NULL) serror("Log file not open",4);
+    fclose(filep);
+    filep=NULL;
+  }
+}
+
+void opengt(void) {
+  if(strcmp(device,"-")!=0) {
+    if ((comfd = open(device, O_RDWR|O_EXCL|O_NONBLOCK|O_NOCTTY)) <0) { //O_NONBLOCK|O_NOCTTY)) <0) {//
+      sprintf(msg,"Can't open GlobeTrotter %s.\n",device);
+      printf(msg);
+      ext(1);
+    }
+  }
+  else comfd=0;
+  if (ioctl (comfd, TCGETA, &svbuf) < 0) {
+    sprintf(msg,"Can't control %s, please try again.\n",device);
+    serror(msg,1);
+  }
+  ioctl(comfd, TCGETA, &stbuf);
+  speed=stbuf.c_cflag & CBAUD;
+  if (high_speed == 0)  strcpy(cspeed,"115200");
+  else strcpy(cspeed,"57600");
+  bits=stbuf.c_cflag & CSIZE;
+  clocal=stbuf.c_cflag & CLOCAL;
+  stopbits=stbuf.c_cflag & CSTOPB;
+  parity=stbuf.c_cflag & (PARENB | PARODD);
+  stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
+  stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
+  stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
+  stbuf.c_lflag &= ~(ECHO | ECHOE);
+  stbuf.c_cc[VMIN] = 1;
+  stbuf.c_cc[VTIME] = 0;
+  stbuf.c_cc[VEOF] = 1;
+  setcom();
+  dormir(200000); /* Wait a bit (DTR raise) */
+  sprintf(msg,"Opened %s as FD %d",device,comfd);
+  vmsg(msg);
+}
+  
+void opendevice(void) {
+  if(strcmp(device,"-")!=0) {
+    if ((comfd = open(device, O_RDWR|O_EXCL|O_NONBLOCK|O_NOCTTY)) <0) { //O_NONBLOCK|O_NOCTTY)) <0) {//
+      sprintf(msg,"Can't open device %s.\n",device);
+      printf(msg);
+      ext(1);
+    }
+  }
+  else comfd=0;
+  if (ioctl (comfd, TCGETA, &svbuf) < 0) {
+    sprintf(msg,"Can't ioctl get device %s.\n",device);
+    serror(msg,1);
+  }
+  ioctl(comfd, TCGETA, &stbuf);
+  speed=stbuf.c_cflag & CBAUD;
+  switch(speed) {
+    case B0: strcpy(cspeed,"0");break;
+    case B50: strcpy(cspeed,"50");break;
+    case B75: strcpy(cspeed,"75");break;
+    case B110: strcpy(cspeed,"110");break;
+    case B300: strcpy(cspeed,"300");break;
+    case B600: strcpy(cspeed,"600");break;
+    case B1200: strcpy(cspeed,"1200");break;
+    case B2400: strcpy(cspeed,"2400");break;
+    case B4800: strcpy(cspeed,"4800");break;
+    case B9600: strcpy(cspeed,"9600");break;
+    case B19200: strcpy(cspeed,"19200");break;
+    case B38400: strcpy(cspeed,"38400");break;
+    case B115200: 
+                {
+                  if (high_speed == 0) strcpy(cspeed,"115200");
+                  else strcpy(cspeed,"57600");
+                  break;
+                }
+    case B460800: strcpy(cspeed, "460800");break;
+  }
+  bits=stbuf.c_cflag & CSIZE;
+  clocal=stbuf.c_cflag & CLOCAL;
+  stopbits=stbuf.c_cflag & CSTOPB;
+  parity=stbuf.c_cflag & (PARENB | PARODD);
+  stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
+  stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
+  stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
+  stbuf.c_lflag &= ~(ECHO | ECHOE);
+  stbuf.c_cc[VMIN] = 1;
+  stbuf.c_cc[VTIME] = 0;
+  stbuf.c_cc[VEOF] = 1;
+  setcom();
+  dormir(200000); /* Wait a bit (DTR raise) */
+  sprintf(msg,"Opened %s as FD %d",device,comfd);
+  vmsg(msg);
+}
+
+void doopen(void) {
+  gettoken();
+  if(strcmp(token,"com")==0) {
+    skipspaces();
+    if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') {
+      getstring();
+    }
+    else gethardstring();
+    strcpy(device,string);
+    opendevice();
+  }
+  else if (strcmp(token,"file")==0) {
+    if(filep!=NULL) serror("File already open",4);
+    getstring();
+    if((filep=fopen(string,"a"))==NULL) serror("Could not open file",4);
+  }
+  else serror("OPEN only takes com or file argument",5);
+}
+
+int doscript(void) {
+  int a,b;
+  int exitcode=0;
+  char line[STRINGL];
+  pc=0;
+  while(script[pc]) {
+    if(script[pc]=='\n') pc++;
+    lastpc=pc;
+    skipspaces();
+    if(verbose) printwhere();
+    if(gettoken()) serror("Could not gettoken()",5);
+    if(strcmp(token,"rem")==0) {
+      skipline();
+    }
+    else if (strcmp(token,"label")==0) {
+      skiptoken(); /* Get rid of keyword */
+    }
+    else if(strcmp(token,"open")==0) {
+      doopen();
+    }
+    else if(strcmp(token,"opengt")==0) {
+      opengt();
+    }
+    else if(strcmp(token,"close")==0) {
+      doclose();
+    }
+    else if(strcmp(token,"exec")==0) {
+      getstring();
+      strcpy(msg,"exec ");
+      strcat(msg,string); /* Let sh do all the command line work! */
+      execl("/bin/sh","sh","-c",msg,(char *)0);
+      serror("Could not execl /bin/sh!",8);
+    }
+    else if(strcmp(token,"exit")==0) {
+      ext(getvalue());
+    }
+    else if(strcmp(token,"testkey")==0) {
+      dotestkey();
+    }
+    else if(strcmp(token,"kill")==0) {
+      a=getvalue();
+      resultcode=kill(getvalue(),a);
+    }
+    else if(strcmp(token,"fork")==0) {
+      resultcode=fork();
+    }
+    else if(strcmp(token,"hset")==0) {
+      hset=0;
+      hstart=time(0);
+      hset=htime()-getvalue();
+    }
+    else if(strcmp(token,"cd")==0) {
+      getstring();
+      resultcode=chdir(string);
+    }
+    else if(strcmp(token,"putenv")==0) {
+      getstring();
+      strcpy(line,string);
+      resultcode=putenv(line); /* putenv can't read from global string[] */
+    }
+    else if(strcmp(token,"wait")==0) {
+      resultcode=wait(0);
+    }
+    else if(strcmp(token,"system")==0) {
+      getstring();
+      system(string);
+    }
+    else if(strcmp(token,"input")==0) {
+      FILE *infd = fdopen(0,"r");
+      fgets(stringvars[getstringindex()],1024,infd);
+      //fclose(infd);
+    }
+    else if(strcmp(token,"get")==0) {
+      doget();
+    }
+    else if(strcmp(token,"print")==0) {
+      doprint(1);
+    }
+    else if(strcmp(token,"eprint")==0) {
+      doprint(2);
+    }
+    else if(strcmp(token,"lprint")==0) {
+      doprint(3);
+    }
+    else if(strcmp(token,"fprint")==0) {
+      doprint(4);
+    }
+    else if(strcmp(token,"if")==0) {
+      doif();
+    }
+    else if(strcmp(token,"else")==0) {
+      if(ifres) skipline();
+    }
+    else if(strcmp(token,"gosub")==0) {
+      dogosub();
+    }
+    else if(strcmp(token,"return")==0) {
+      if(preturn==0) serror("RETURN without gosub",5);
+      pc=returns[--preturn];
+    }
+    else if(strcmp(token,"goto")==0) {
+      dogoto();
+    }
+    else if(strcmp(token,"waitfor")==0) {
+      resultcode=dowaitfor();
+    }
+    else if(strcmp(token,"waitquiet")==0) {
+      resultcode=dowaitquiet();
+    }
+    else if(strcmp(token,"set")==0) {
+      doset();
+    }
+    else if(strcmp(token,"dec")==0) {
+      intvars[getintindex()]--;
+    }
+    else if(strcmp(token,"inc")==0) {
+      intvars[getintindex()]++;
+    }
+    else if(strcmp(token,"let")==0) {
+      dolet();
+    }
+    else if(strcmp(token,"dump")==0) {
+      dodump();
+    }
+    else if(strcmp(token,"abort")==0) {
+      vmsg("Aborting");
+      abort();
+    }
+    else if(strcmp(token,"send")==0) {
+      getstring();
+      writecom(string);
+    }
+    else if(strcmp(token,"flash")==0) {
+      b=speed;
+      speed=0;
+      setcom();
+      a=getdvalue();
+      dormir(10000L*a);
+      speed=b;
+      setcom();
+    }
+    else if(strcmp(token,"sleep")==0) {
+      a=getdvalue();
+      if(a<10000) dormir(10000L*a);
+      else sleep(a/100); /* I guess it's the same.  Oh well, past 100 secs,
+                            use sleep instead.  */
+    }
+    else {
+      /* Humour is the spice of life. */
+      switch(time(0)&7) {
+        case 0 : serror("That's human mumbo-jumbo to me",5); break;
+        case 1 : serror("Lovely but incomprehensible",5); break;
+        case 2 : serror("What's that, governor?",5); break;
+        case 3 : serror("Very funny.  I don't get it",5); break;
+        case 4 : serror("Huh?",5); break;
+        case 5 : serror("gcom doesn't speak spanish",5); break;
+        case 6 : serror("Mais, qu'est-ce que vous dites?",5); break;
+        default: serror("%E-6837-% : Corrupted human data detected",5); break;
+      }
+    }
+    skipspaces();
+    while(script[pc]=='\n') pc++;
+  }
+  return(exitcode);
+}
+
+int main(int argc,char **argv) {
+  unsigned int a;
+  int aa,b,i,skip_default;
+  unsigned char ch;
+  unsigned char terminator='\n';
+  char line[STRINGL];
+  
+  strcpy(device,GTDEVICE);
+  FILE *fp;
+  hstart=time(0);
+  hset=htime();
+  preturn=0;
+  skip_default=0;
+  filep=NULL;
+  scriptspace=4096;
+  ioctl(1, TCGETA, &cons);
+  if((script=( char *)malloc(scriptspace))==NULL) {
+    serror("Could not malloc()",3);
+  }
+  for(a=0;a<NVARS;a++) {
+    intvars[a]=0;
+    stringvars[a]=NullString;
+  }
+  strcpy(cspeed,"0");
+  scriptfile[0]=0;
+  b=0; a=0;
+  for(a=0;a<strlen(argv[0]);a++) {
+    if(argv[0][a]=='/') b=a+1;
+  }
+  while((aa=getopt(argc,argv,"xhevd:t:sb:"))!= -1) {
+    switch(aa) {
+      case 0:
+        ext(0);
+        break;
+      case 't':
+        terminator=optarg[0];
+        sprintf(msg,"Alternate line terminator set to \"%c\"",terminator);
+        vmsg(msg);
+        break;
+      case 'd':
+        strcpy(device,optarg);
+        //opendevice();
+        break;
+      case 'e':
+        comecho=1;
+        vmsg("Communication echo turned on");
+        break;
+      case 'v':
+        verbose=1;
+        vmsg("Verbose output enabled");
+        break;
+      case 's':
+        skip_default=1;
+        break;
+      case 'h':
+        printf("gcom version 0.3 Copyright Paul Hardwick (c) 2005 \n");
+        printf("\nType 'gcom help' for more information\n");
+        ext(1);
+        break;
+      case 'x':
+        printf("High speed overide (115200 is now 57600).\n");
+        high_speed =1;
+        break;
+      default:
+        ext(1);
+    }
+  }
+  if(optind<argc) {
+    strcpy(scriptfile,argv[optind++]);
+    sprintf(msg,"Script file: %s",scriptfile);
+    vmsg(msg);
+  }
+
+  char * code;
+  code = get_code(scriptfile);
+  if (code != NULL){
+    scriptspace=strlen(code)+2;
+    if((script=( char *)realloc(script,scriptspace))==0) {
+       serror("Could not malloc()",3);
+       }
+       strcpy(script,code);
+      for(aa=0;aa<scriptspace;aa++) {
+         if(script[aa]==terminator) script[aa]='\n';
+      }
+      //scriptfile[0] = '\0';
+    }
+  else if (scriptfile[0]) {
+       code = get_code("default");
+       if (code != NULL && !skip_default){
+               scriptspace=strlen(code)+2;
+               if((script=( char *)realloc(script,scriptspace))==0) {
+                               serror("Could not malloc()",3);
+                       }
+                       strcpy(script,code);
+                       for(aa=0;aa<scriptspace;aa++) {
+                       if(script[aa]==terminator) script[aa]='\n';
+               }
+      //scriptfile[0] = '\0';
+    }  
+    if((fp=fopen(scriptfile,"r"))==NULL) {
+      sprintf(msg,"Could not open scriptfile \"%s\".\n",scriptfile);
+      serror(msg,1);
+    }
+    i=strlen(script);
+    if(i) {
+      script[i++]='\n'; script[i]=0;
+    }
+    while((fgets(line,STRINGL-1,fp))!=NULL) {
+      b=strlen(line);
+      if((scriptspace-i)<STRINGL) {
+        scriptspace+=STRINGL+STRINGL;
+        if((script=(char *)realloc(script,scriptspace))==NULL) {
+          serror("Could not realloc()",3);
+        }
+      }
+      for(aa=0;aa<b;aa++) {
+        script[i]=line[aa];
+        if(script[i]==terminator) script[i]='\n';
+        i++;
+      }
+    }
+    script[i]=0;
+    fclose(fp);
+  }
+
+  if(script[0]) {
+    i=strlen(script)-1;
+    while((script[i]=='\n' || script[i]==' ' || script[i]=='\t') && i!=0) i--;
+    script[++i]='\n';
+    script[++i]=0;
+  }
+  i=strlen(script); /* Script is one huge string */
+  /* Indexing labels */
+  label=(char **)malloc(sizeof(char *)*MAXLABELS);
+  labelpc=(int *)malloc(sizeof(int *)*MAXLABELS);
+  if(label==NULL || labelpc==NULL) {
+    serror("Can't malloc",3);
+  }
+  labels=0;
+  pc=0;
+  while(script[pc]) {
+    lastpc=pc;
+    gettoken();
+    if(strcmp(token,"label")==0) {
+      gettoken();
+      for(aa=0;aa<labels;aa++) {
+        if(strcmp(token,label[aa])==0) {
+          pc=lastpc;
+          serror("Duplicate label",5);
+        }
+      }
+      if(labels==MAXLABELS) serror("Maximum number of labels reached",3);
+      labelpc[labels]=lastpc;
+      label[labels]=(char *)malloc(strlen(token)+1);
+      if(label[labels]==NULL) serror("Can't malloc one label",3);
+      strcpy(label[labels],token);
+      labels++;
+    }
+    skipline();
+  }
+  //printf(script);
+  if(verbose) {
+    sprintf(msg,"argc:%d",argc);
+    vmsg(msg);
+    for(aa=0;aa<argc;aa++) {
+      sprintf(msg,"argv[%d]=%s",aa,argv[aa]);
+      vmsg(msg);
+    }
+    vmsg(" ---Script---");
+    aa=0; b=0; ch='\n';
+    while(aa<i) {
+      if(ch=='\n' && script[aa]!=0) {
+        fprintf(stderr,"%4d@%04d ",++b,aa);
+      }
+      ch=script[aa++];
+      fputc(ch,stderr);
+    }
+    vmsg(" ---End of script---");
+  }
+
+  if(script[0]==0) {
+    fprintf(stderr,"No script!\n");
+    ext(1);
+  }
+
+  a=doscript();
+  dormir(200000);
+  if(comfd!= -1) close(comfd);
+  sprintf(msg,"Exit with code %d.\n",a);
+  vmsg(msg);
+  ext(a);
+}
diff --git a/gcom.h b/gcom.h
new file mode 100644 (file)
index 0000000..76a93f8
--- /dev/null
+++ b/gcom.h
@@ -0,0 +1,432 @@
+/***************************************************************************
+ *  gcom.h - 3G/GPRS datacard management utility header file
+ *
+ *  Copyright (C) 2003  Paul Hardwick <paul@peck.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ ***************************************************************************/
+
+/***************************************************************************
+* $Id: gcom.h 10 2006-01-04 12:40:44Z paul $
+* $HeadURL: http://10.0.0.4/svn/gcom/gcom.h $
+****************************************************************************/
+
+
+char _default_code[] = 
+    "opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    send \"AT+CFUN=1^m\"\n\
+    waitquiet 1 0.2\n\
+  :start\n\
+    flash 0.1\n\
+    send \"AT+CPIN?^m\"\n\
+    waitfor 30 \"SIM PUK\",\"SIM PIN\",\"READY\",\"ERROR\",\"ERR\"\n\
+    if % = -1 goto error\n\
+    if % = 0 goto ready\n\
+    if % = 1 goto getpin\n\
+    if % = 2 goto ready\n\
+    if % = 3 goto error\n\
+    if % = 4 goto error\n\
+  :error\n\
+    print $s,\" ***SIM ERROR***\n\"\n\
+    print \"Check device port configuration.\nCheck SIM is inserted\nTest SIM in a mobile phone?\n\"\n\
+    exit 1\n\
+  :getpin\n\
+    #handle case where Vodafone 3 generates wrong response\n\
+    waitfor 1 \"2\"\n\
+    if % = 0 goto ready\n\
+    print \"\nEnter PIN number: \"\n\
+    input $x\n\
+    let a=len($x)\n\
+    if a<>5 goto getpin\n\
+    let c=0\n\
+  :test\n\
+    let $c=$mid($x,c,1)\n\
+    if $c<\"0\" goto getpin\n\
+    if $c>\"9\" goto getpin\n\
+    inc c\n\
+    if c<4 goto test\n\
+    let a=val($x)\n\
+    if a<0 goto getpin\n\
+    if a>9999 goto getpin\n\
+    let $c=$left($x,4)\n\
+  :enterpin\n\
+    send \"AT+CPIN=\\\"\"\n\
+    send $c\n\
+    send \"\\\"^m\"\n\
+    waitfor 20 \"OK\",\"ERR\"\n\
+    if % = -1 goto timeerror\n\
+    if % = 0 goto cont\n\
+    if % = 1 goto pinerror\n\
+  :pinerror\n\
+  :timeerror\n\
+    print \"ERROR entering PIN code\n\"\n\
+    print \"Caution! - entering the wrong PIN code three times will lock the SIM\n\"\n\
+    exit 1\n\
+  :ready\n\
+    print \"SIM ready\n\"\n\
+  :cont\n\
+    print \"Waiting for Registration..(120 sec max)\"\n\
+    let c = 0\n\
+  :waitreg\n\
+    send \"AT+CREG?^m\"\n\
+    waitfor 2 \"+CREG: 0,1\",\"+CREG: 0,5\"\n\
+    if % = -1 goto regagain\n\
+    if % = 0 goto homereg\n\
+    if % = 1 goto roamreg\n\
+  :regagain\n\
+    if c > 120 goto regtimeout\n\
+    let c=c+2\n\
+    print \".\"\n\
+    goto waitreg\n\
+  :regtimeout\n\
+    print \"\nFailed to register\n\"\n\
+    exit 1\n\
+  :homereg\n\
+    print \"\nRegistered on Home network: \"\n\
+    goto registered\n\
+  :roamreg\n\
+    print \"\nRegistered on Roaming network: \"\n\
+    goto registered\n\
+  :registered\n\
+    waitquiet 1 0.1\n\
+    send \"AT+COPS?^m\"\n\
+    get 2 \"^m\" $s\n\
+    get 2 \"^m\" $s\n\
+    let a=len($s)\n\
+    let b=a-12\n\
+    if b < 1 goto regtimeout\n\
+    let $c=$right($s,b)\n\
+    print $c,\"\n\"\n\
+    let c=0\n\
+  :signal\n\
+    waitquiet 1 0.1\n\
+    send \"AT+CSQ^m\"\n\
+    get 2 \"^m\" $s\n\
+    get 2 \"^m\" $s\n\
+    let a=len($s)\n\
+    let a=a-6\n\
+    let $s=$right($s,a)\n\
+    if $s <> \"0,0\" goto sigcont\n\
+    if c > 3 goto sigexit\n\
+    let c=c+1\n\
+    pause 1\n\
+    goto signal\n\
+  :sigexit\n\
+    print \"Signal strength measure 0,0 too low!\"\n\
+    exit 1\n\
+  :sigcont\n\
+    print \"Signal Quality:\",$s,\"\\n\"\n\
+    waitquiet 1 0.1\n";
+
+char _info_code[]  = 
+    "print \"##### GlobeTrotter Configuration #####\\n\"\n\
+    opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 2 0.5\n\
+  :manf\n\
+    print \"Manufacturer Text:      \"\n\
+    send \"AT+cgmi^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    let x=len($s)\n\
+    dec x\n\
+    let $s=$right($s,x)\n\
+    print $s,\"\\n\"\n\
+  :imei_serial\n\
+    waitquiet 5 0.1\n\
+    print \"IMEI and Serial Number: \"\n\
+    send \"AT+GSN^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    let x=len($s)\n\
+    dec x\n\
+    let $s=$right($s,x)\n\
+    print ,$s,\"\\n\"\n\
+  :firmware\n\
+    waitquiet 5 0.1\n\
+    print \"Manufacturer\'s Revision: \"\n\
+    send \"AT+GMR^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \"^m\" $s\n\
+    print $s,\"\\n\"\n\
+  :hardware\n\
+    waitquiet 5 0.1\n\
+    print \"Hardware Revision:      \"\n\
+    send \"AT_OHWV^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    print $s,\"\\n\"\n\
+  :networklock\n\
+    waitquiet 5 0.1\n\
+    print \"Network Locked:         \"\n\
+    send \"AT+clck=\\\"PN\\\",2^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    print $s,\"\\n\"\n\
+    waitquiet 5 0.1\n\
+  :customized\n\
+    print \"Customisation:          \"\n\
+    send \"AT_ocst^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \",^m\" $s\n\
+    print $s,\"\\n\"\n\
+  :bandsettings\n\
+    waitquiet 5 0.1\n\
+    print \"Band settings:          \"\n\
+    send \"AT_OSBM?^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    if $s=\"4\" print \"Europe 900/1800MHz \"\n\
+    if $s=\"5\" print \"USA 900/1900MHz \"\n\
+    print \"(\",$s,\")\\n\" \n\
+  :autoattach\n\
+    waitquiet 5 0.1\n\
+    print \"Auto Attach:            \"\n\
+    send \"AT_OCGAA?^m\"\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    get 2 \" ^m\" $s\n\
+    print $s,\"\\n\" \n\
+    waitquiet 5 0.1  \n\
+    print \"##### END #####\\n\"" ;
+
+
+char _USA_code[]= 
+    "print \"##### Band Change to USA operation #####\\n\"\n\
+    opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 2 0.5\n\
+    send \"AT_OSBM=5^m\"\n\
+    waitfor 10 \"OK\",\"ERR\"\n\
+    if % = -1 goto timeout\n\
+    if % = 0 goto cont\n\
+    if % = 1 goto error\n\
+  :timeout\n\
+    print \"Timeout Error communicating with device.\n\"\n\
+    exit 1\n\
+  :error\n\
+    print \"Error response from device.\n\"\n\
+    exit 1\n\
+  :cont\n\
+    print \"Complete\\n\"\n";
+
+char _Europe_code[]  = 
+    "print \"##### Band Change to European operation #####\\n\"\n\
+    opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 2 0.5\n\
+    send \"AT_OSBM=4^m\"\n\
+    waitfor 10 \"OK\",\"ERR\"\n\
+    if % = -1 goto timeout\n\
+    if % = 0 goto cont\n\
+    if % = 1 goto error\n\
+  :timeout\n\
+    print \"Timeout Error communicating with device.\n\"\n\
+    exit 1\n\
+  :error\n\
+    print \"Error response from device.\n\"\n\
+    exit 1\n\
+  :cont\n\
+    print \"Complete\\n\"\n";
+
+char _sig_code[]  = 
+    "opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 2 0.5\n\
+    let c=0\n\
+  :signal\n\
+    waitquiet 1 0.1\n\
+    send \"AT+CSQ^m\"\n\
+    get 2 \"^m\" $s\n\
+    get 2 \"^m\" $s\n\
+    let a=len($s)\n\
+    let a=a-6\n\
+    let $s=$right($s,a)\n\
+    if $s <> \"0,0\" goto sigcont\n\
+    if c > 3 goto sigexit\n\
+    let c=c+1\n\
+    pause 1\n\
+    goto signal\n\
+  :sigexit\n\
+    print \"Signal strength measure 0,0 too low!\"\n\
+    exit 1\n\
+  :sigcont\n\
+    print \"Signal Quality:\",$s,\"\\n\"\n\
+    waitquiet 1 0.1\n\
+    exit 0\n";
+
+char _reg_code[]  =
+    "opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 2 0.5\n\
+    print \"Waiting for Registration\"\n\
+    let c = 0\n\
+  :waitreg\n\
+    send \"AT+CREG?^m\"\n\
+    waitfor 2 \"+CREG: 0,1\",\"+CREG: 0,5\"\n\
+    if % = -1 goto regagain\n\
+    if % = 0 goto homereg\n\
+    if % = 1 goto roamreg\n\
+  :regagain\n\
+    if c > 120 goto regtimeout\n\
+    let c=c+2\n\
+    print \".\"\n\
+    goto waitreg\n\
+  :regtimeout\n\
+    print \"\nFailed to register\n\"\n\
+    exit 1\n\
+  :homereg\n\
+    print \"\nRegistered on Home network: \"\n\
+    goto registered\n\
+  :roamreg\n\
+    print \"\nRegistered on Roaming network: \"\n\
+    goto registered\n\
+  :registered\n\
+    waitquiet 1 0.1\n\
+    send \"AT+COPS?^m\"\n\
+    get 2 \"^m\" $s\n\
+    get 2 \"^m\" $s\n\
+    let a=len($s)\n\
+    let b=a-12\n\
+    if b < 1 goto regtimeout\n\
+    let $c=$right($s,b)\n\
+    print $c,\"\n\"\n";
+
+char _3G2G_mode_code[] =
+    "opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 1 0.2\n\
+    send \"AT_OPSYS=3^m\"\n\
+    waitfor 10 \"OK\",\"ERR\"\n\
+    if % = -1 goto timeout\n\
+    if % = 0 goto cont\n\
+    if % = 1 goto error\n\
+  :timeout\n\
+    print \"Timeout Error communicating with device.\n\"\n\
+    exit 1\n\
+  :error\n\
+    print \"Error response from device.\n\"\n\
+    exit 1\n\
+  :cont\n\
+    print \"Set 3G preferred mode\\n\"\n";
+
+
+char _3G_mode_code[] =
+    "opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 1 0.2\n\
+    send \"AT_OPSYS=1^m\"\n\
+    waitfor 10 \"OK\",\"ERR\"\n\
+    if % = -1 goto timeout\n\
+    if % = 0 goto cont\n\
+    if % = 1 goto error\n\
+  :timeout\n\
+    print \"Timeout Error communicating with device.\n\"\n\
+    exit 1\n\
+  :error\n\
+    print \"Error response from device.\n\"\n\
+    exit 1\n\
+  :cont\n\
+    print \"Set 3G only mode\\n\"\n";
+    
+char _2G_mode_code[] =
+    "opengt\n\
+    set com 115200n81\n\
+    set senddelay 0.05\n\
+    waitquiet 1 0.2\n\
+    send \"AT_OPSYS=0^m\"\n\
+    waitfor 10 \"OK\",\"ERR\"\n\
+    if % = -1 goto timeout\n\
+    if % = 0 goto cont\n\
+    if % = 1 goto error\n\
+  :timeout\n\
+    print \"Timeout Error communicating with device.\n\"\n\
+    exit 1\n\
+  :error\n\
+    print \"Error response from device.\n\"\n\
+    exit 1\n\
+  :cont\n\
+    print \"Set 2G only mode\\n\"\n";
+    
+char _GTEDGE_code[] = 
+    "opengt\n\
+    set com 57600n81\n\
+    send \"AT+CFUN=1^m\"\n\
+    waitquiet 5 0.2";
+
+char _help_code[]  = 
+    "print \"gcom Version 0.3\n Usage: \"\n\
+    print \"gcom [options] [built in script]'|[external script]\n\n\"\n\
+    print \"Built in scripts -\n\"\n\
+    print \"  gcom [default]           Checks SIM status (requests PIN if required),\n\"\n\
+    print \"                           registration and signal strength reported by\n\"\n\
+    print \"                           datacard.\n\"\n\
+    print \"  gcom info                Display configuration of datacard.\n\"\n\
+    print \"  gcom sig                 Report Signal strength.\n\"\n\
+    print \"  gcom reg                 Report Registration status.\n\"\n\
+    print \"\n  Valid for GlobeTrotter GPRS only:\n\"\n\
+    print \"      gcom USA                 Switch to 900/1900 MHz band for USA operation.\n\"\n\
+    print \"      gcom Europe              Switch to 900/1800 MHz band for Europen operation.\n\"\n\
+    print \"\n  Valid for GlobeTrotter EDGE and Combo EDGE only:\n\"\n\
+    print \"      gcom GTEDGE             Switch on radio interface.\n\"\n\
+    print \"\n  Valid for Vodafone 3G, GlobeTrotter Fusion :\n\"\n\
+    print \"      gcom 2G             2G networks only.\n\"\n\
+    print \"      gcom 3G             3G networks only\n\"\n\
+    print \"      gcom 3G2G           3G network preferred\n\"\n\
+    print \"\nCommand line options (must be before script name) - \\n\"\n\
+    print \"  -d device                Use alternative device. e.g -d /dev/ttyUSB0\n\"\n\
+    print \"  -e                       Turn on communication echo.\n\"\n\
+    print \"  -h                       Help.\n\"\n\
+    print \"  -s                       Don't run internal 'default' script before running\n\"\n\
+    print \"                           external script.\n\"\n\
+    print \"  -t=\"\\n\"                    Set alternative line terminator (default=\"\\n\").\n\"\n\
+    print \"  -v                       Verbose mode. Print lots of trace info.\n\"\n\
+    print \"  -x                       Speed exchange. 115200 replaced by 57600.\n\"\n\
+    print \"                           ***used for GlobeTrotter EDGE and Combo EDGE***\n\"\n\
+    print \"NOTES:\ngcom assumes that the GlobeTrotter device is /dev/modem (create a logical link\n\"\n\
+    print \"to actual device or use -d switch). Unless you use the '-s' switch gcom will\n\"\n\
+    print \"run the internal 'default' script first before running an external script file.\n\"\n" ;
+
+char *get_code(char* name){
+  if(strlen(name)==0) return(_default_code);
+  if (strcmp(name,"default")==0) return (_default_code);
+  if (strcmp(name,"help")==0) return (_help_code);
+  if (strcmp(name,"info")==0) return (_info_code);
+  if (strcmp(name,"USA")==0) return (_USA_code);
+  if (strcmp(name,"Europe")==0) return (_Europe_code);
+  if (strcmp(name,"sig")==0) return (_sig_code); 
+  if (strcmp(name,"reg")==0) return (_reg_code); 
+  if (strcmp(name,"GTEDGE")==0) return (_GTEDGE_code); 
+  if (strcmp(name,"2G")==0) return (_2G_mode_code);
+  if (strcmp(name,"3G")==0) return (_3G_mode_code);
+  if (strcmp(name,"3G2G")==0) return (_3G2G_mode_code);
+  return(NULL);
+}    
+
diff --git a/gpl.txt b/gpl.txt
new file mode 100644 (file)
index 0000000..5b6e7c6
--- /dev/null
+++ b/gpl.txt
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/operator b/operator
new file mode 100644 (file)
index 0000000..772ed2c
--- /dev/null
+++ b/operator
@@ -0,0 +1,84 @@
+############################################################################
+#  operator - a gcom script for viewing and selecting networks
+#
+#           An example of how you might do operator selection when travelling
+#           in a foreign country.
+#           Big ToDo - improve the interface!!!
+#
+#  Copyright (C) 2003  Paul Hardwick <paul@peck.org>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+###########################################################################
+
+############################################################################
+# $Id: gcom.h 10 2006-01-04 12:40:44Z paul $
+# $HeadURL: http://10.0.0.4/svn/gcom/gcom.h $
+############################################################################
+opengt
+set com 115200n81
+set senddelay 0.05
+waitquiet 2 0.5
+  :operator
+    send "AT+COPS=?^m"
+    waitfor 20 "+COPS=?","Error"
+    if % = -1 goto timeout
+    if % = 0 goto getlist
+    print "Error response from device\n"
+    exit 1
+  :getlist
+    let c=0
+    print "Getting Operator list: "
+  :waiting    
+    print "."
+    get 2 "^m" $s
+    if % = -1 goto stillwaiting
+    waitquiet 1 0.2
+    print "\n"
+    print $s,"\n\n==============================================================\n"
+    print "Format: (Access,Long Name, Short Name, Network ID [,Technology])\n"
+    print "Access: 2 - Registered, 1 - Available, 3 - Forbidden\n"
+    print "Technology: 0 - GSM/GPRS, 2 - UMTS (Not available on all cards)\n"
+    print "\nEnter the Network ID to attempt manual registration\n [blank = automatic selection]:"
+    input $a
+    let a=len($a)
+    dec a
+    let $a=$left($a,a)
+    if $a = "" goto automatic
+    let $b="AT+COPS=1,2,\""+$a
+    let $b=$b+"\"^m"
+    send $b
+    goto waitresult
+  :automatic
+    let $b="AT+COPS=0^m"
+    send $b   
+  :waitresult
+    waitfor 60 "OK","ERR"
+    if % = -1 goto timeout
+    if % = 2 goto failedreg
+    print "Registration request accepted\n"
+    print "Command was: ",$b,"\n"    
+    exit 0
+  :failedreg
+    print "Registration request refused\n"
+    print "Command was: ",$b,"\n"
+    exit 1
+  :stillwaiting
+    if c > 60 goto timeout
+    let c=c+1
+    goto waiting
+  :timeout
+    print "Network Search Timeout\n"
+    exit 1
diff --git a/sigmon b/sigmon
new file mode 100755 (executable)
index 0000000..1942abc
--- /dev/null
+++ b/sigmon
@@ -0,0 +1,50 @@
+#
+# sigmon - 3G/GPRS datacard signal strength monitor
+#
+if [ $# -eq 1 ]
+then
+       if [ "$1" == '-?' ] 
+       then
+               echo "Syntax:   sigmon"
+               echo "Function: 3G/GPRS datacard signal strength monitor"
+               echo "Options:  none"
+       else
+               echo "Invalid option - $1"
+       fi
+       exit 1
+else
+       if [ $# -gt 1 ]
+       then
+               echo "Error: only one option permitted"
+               exit 1
+       fi
+fi
+
+echo "Use Ctrl/C to terminate monitoring"
+
+while true
+do
+       gcom -d /dev/ttyUSB2 sig
+       sleep 5
+done
+#
+#   sigmon - use gmon to continuously monitor signal strength
+#   Copyright (C) 2005  Martin Gregorie
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#    martin@gregorie.org
+#
+
diff --git a/sigmon.1 b/sigmon.1
new file mode 100644 (file)
index 0000000..63d1fa9
--- /dev/null
+++ b/sigmon.1
@@ -0,0 +1,40 @@
+.\" Paul Hardwick 
+.\" paul@peck.org.uk
+.TH sigmon 1 "22 January, 2005"
+.LO 1
+.SH NAME
+sigmon \- Vodafone 3G/GPRS datacard signal strength monitor
+.SH SYNOPSIS
+.B sigmon -?
+
+.SH OPTIONS
+.in +5
+.B \-?
+.in +10
+gives brief usage details
+.in -10
+
+.SH DESCRIPTION
+.B sigmon 
+is a command line tool for monitoring the signal strength seen by a Vodafone
+3G/GPRS datacard. Once started, it queries the datacard for the signal 
+strength and displays it every 5 seconds. Use 
+.I Ctrl/C
+to stop the signal strength display and exit from 
+.B sigmon 
+
+.SH BUGS
+.B sigmon
+is a simple script that assumes that the third port of the datacard is
+/dev/ttyUSB2. If the datacard is not the first USB device registered the
+script must be modified to correct the port name. Read /var/log/messages
+to find the correct port name.
+
+.SH DEPENDENCIES
+.B sigmon
+requires 
+.I gcom
+to be installed so that it appears in the current search path when 
+.B sigmon
+is run.
+