Initial revision

This commit is contained in:
MelwareDE 2005-06-02 18:28:35 +00:00
parent e5a74c85d6
commit fa6be5da46
33 changed files with 12777 additions and 0 deletions

25
BUGREPORT Normal file
View File

@ -0,0 +1,25 @@
As this software is in the Alpha state, there are still some bugs or
problems. If you encountered one please include following informations when
reporting it:
- The version you are using.
- Your `Config', `config.h' and `yaps.rc' file.
- Call `yaps -V' and redirect the output into a file. Include this file.
- A command to reproduce the bug.
- The output with the highest verbosity. This can be
done by starting yaps with several -v's (at least 4) and
redirecting stdout and stderr into a file, e.g.:
yaps -vvvv [your options] &> bug [bash]
- or -
yaps -vvvv [your options] >bug 2>&1 [sh]
- or -
see your shell manual.
- If the program terminates recompile it with debug information
(if not already done). Reproduce the problem. Start the program
under the control of the debugger. Save the location and the stack
frame into a file. Send the file. If a core file is generated,
start the debugger on the program/core pair, print the location
and the stack frame into a file. Send the file.
- DO NOT SEND CORE FILES!!!
Send these information either to <yaps@nitmar.tnet.de> (preferred) or
<ud@cube.net>.

339
COPYING.GPL Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, 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.
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.)
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.
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.
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
Appendix: 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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.

17
COPYRIGHT Normal file
View File

@ -0,0 +1,17 @@
Copyright (c) 1997 Ulrich Dessauer
All rights reserved.
You may distribute under the terms of the GNU General Public
License.
IN NO EVENT SHALL ULRICH DESSAUER BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ULRICH DESSAUER
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ULRICH DESSAUER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
BASIS, AND ULRICH DESSAUER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

65
Config Normal file
View File

@ -0,0 +1,65 @@
# -*- sh -*-
# SECTION A.) Global configuration
# Select compiler command
CC = gcc
#
CFLAGS = -Wall -Wno-parentheses -Wshadow -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =
EXLIBS =
#
# Select scripting language(s)
# SLang (ftp://space.mit.edu/pub/davis/slang/)
#SLANG = True
# LUA (ftp://ftp.icad.puc-rio.br/pub/lua/)
#LUA = True
#
# Define this to disable debugging
#NDEBUG = True
#
#
#
# SECTION B.) yaps configuration
# Name and location of global configuration file
YAPS_CFGFILE = /etc/yaps.rc
# Name of local configuration file (location is $HOME.)
YAPS_LCFGFILE = .yapsrc
# Directory for installing the binary
YAPS_BINDIR = /usr/local/bin
# Directory for optional support files
YAPS_LIBDIR = /usr/local/lib/yaps
# User/Group/Mode for yaps
YAPS_USER = bin
YAPS_GROUP = uucp
YAPS_MODE = 2711
# User/Group/Mode for global configuration file
YAPS_RCUSER = bin
YAPS_RCGROUP = bin
YAPS_RCMODE = 644
#
# End of Configuration, the rest is for automatic
# configuration depending on settings above
LDEFS =
LLIBS =
ifdef SLANG
LDEFS += -DSCRIPT_SLANG
LLIBS += -lslang
MATH = True
endif
ifdef LUA
LDEFS += -DSCRIPT_LUA
LLIBS += -llualib -llua
MATH = True
endif
ifdef MATH
LLIBS += -lm
endif
#
ifdef NDEBUG
DDEFS = -DNDEBUG
G = -O
else
G = -g
endif
#
CFLAGS := $G $(CFLAGS) $(LDEFS) $(DDEFS)
LDFLAGS := $G $(LDFLAGS)

1
INSTALL Normal file
View File

@ -0,0 +1 @@
Read the Installation section in the README file!

65
Makefile Normal file
View File

@ -0,0 +1,65 @@
# -*- sh -*-
#
include Config
#
#CFLAGS := -include mem.h $(CFLAGS)
CFLAGS := $(CFLAGS)
#
DEFS = -DCFGFILE=\"$(YAPS_CFGFILE)\" -DLCFGFILE=\"$(YAPS_LCFGFILE)\" \
-DLIBDIR=\"$(YAPS_LIBDIR)\"
LIBS = -L. -lpager $(LLIBS)
OBJS = data.o util.o cfg.o tty.o cv.o asc.o scr.o tap.o ucp.o \
slang.o lua.o #mem.o
YOBJS = yaps.o valid.o
DSTFLE = $(YAPS_BINDIR)/yaps
all: yaps yaps.doc
@if [ -f contrib/Makefile ]; then \
$(MAKE) -C contrib all ; \
fi
yaps: libpager.a $(YOBJS)
$(CC) $(LDFLAGS) $(YOBJS) -o $@ $(LIBS)
libpager.a: $(OBJS)
rm -f $@
ar rc $@ $(OBJS)
ranlib $@
yaps.o: yaps.c pager.h
$(CC) $(CFLAGS) $(DEFS) $< -c -o $@
yaps.doc: yaps.html
lynx -cfg=/dev/null -nolist -dump $< > $@
install: $(DSTFLE) $(CFGFILE)
if [ ! -d $(YAPS_LIBDIR) ]; then \
install -d -m 755 -o $(YAPS_USER) -g $(YAPS_GROUP) $(YAPS_LIBDIR) ; \
fi
@if [ -f contrib/Makefile ]; then \
$(MAKE) -C contrib install ; \
fi
$(DSTFLE): yaps
install -o $(YAPS_USER) -g $(YAPS_GROUP) -m $(YAPS_MODE) -s yaps $@
$(CFGFILE): yaps.rc
@if [ ! -f $@ ]; then \
install -o $(YAPS_RCUSER) -g $(YAPS_RCGROUP) -m $(YAPS_RCMODE) -s yaps.rc $@ ; \
fi
clean:
rm -f *.[oa] *~ .*~ yaps core .depend
@if [ -f contrib/Makefile ]; then \
$(MAKE) -C contrib clean ; \
fi
depend:
$(CPP) $(CFLAGS) -MM *.c > .depend
@if [ -f contrib/Makefile ]; then \
$(MAKE) -C contrib depend ; \
fi
ifeq (.depend,$(wildcard .depend))
include .depend
endif

113
README Normal file
View File

@ -0,0 +1,113 @@
yaps -or- Yet Another Pager Software
=====================================
This software is primary designed to send message to so called pager devices
including cellular phones which are able to receive textual messages
(sometimes called SMS, short message system/service.)
This is a simple command line driven program with a global and a personal
configuration file, but the protocol implementation is kept as a seperate
library, with which one may somedays write a client/server system.
Copyright:
~~~~~~~~~~
Copyright (c) 1997 Ulrich Dessauer
All rights reserved.
You may distribute under the terms of the GNU General Public
License.
IN NO EVENT SHALL ULRICH DESSAUER BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ULRICH DESSAUER
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ULRICH DESSAUER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
BASIS, AND ULRICH DESSAUER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Installation:
~~~~~~~~~~~~~
You need a system supporting the Posix system calls and library functions
(every modern Unix like OS should have this support) and you need an install
program, otherwise you have to install the result by hand. Gnumake and GCC
are a plus, otherwise you may have to tweak the Makefile and some source
files a bit.
1.) Edit Config (which will be included by make) & edit config.h
1a.) If you do not have the SLang library installed, comment out
the line `SLANG = True' in Config or install it somewhere
the compiler can find it (/usr/local/{lib,include} seems to
be a not-to-bad place). READ THE ATTACHED COPYRIGHT NOTICE!
1b.) Dito for lua.
2.) Edit config.h. Comments should explain enough.
3.) `make depend'
4.) `make'
If the program compiles fine:
5.) `make install' as root (if you have permissons). If you do not have
an install program, install it by hand:
a.) Copy the executable `yaps' to somewhere in your path
b.) Install yaps.rc as /etc/yaps.rc or as ~/.yapsrc
6.) edit `/etc/yaps.rc' for global settings
7.) Optional edit ~/.yapsrc for your private settings
An example `yaps.rc' file is included and can be used directly for some
services available in Germany. Others may be added. See the `yaps.doc' file
for a complete description of the configuration files.
Implementation:
~~~~~~~~~~~~~~~
The current implementation allows sending messages to pager, where the
service company offers a modem gateway. Paging via Internet or other online
services is currently not supported, as they are mostly quite simple to
realize (sending an e-mail to a specific address, calling an URL, etc.)
Following protocols are implemented:
- ASCII based. This could also be handled by programs like `chat', but is
included for completness. You can use simple send/expect strings to define
the communication.
- SCRIPT based. This could be considered as an enhanced ASCII mode and
depends on the available scripting languages, that are integrated.
Currently SLang and Lua are supported, others may follow.
- TAP (Telocator Alphanumeric Protocol). This is the result of the earlier
used IXO and PET protocols. The documentation for this protocol is
available via the Web:
http://www.mot.com/MIMS/MSPG/pcia_protocols/tap_v1p8/table_of_contents.html
(Thanks a lot to Motorola!)
- UCP (Universal Computer Protocol). D2privat has kindly made the
description available to me, thanks a lot to Mannesmann Mobilfunk! Lots of
the protocol is NOT implemented, as this makes not much sense on dialup
lines.
ATTENTION: If someone has the complete documentation for any other used
protocol for pager like devices, I would be glad if she/he could make them
available for me. If I had a testing possibility I'll try to implement that
protocol.
Bugs, Problems, Comments:
~~~~~~~~~~~~~~~~~~~~~~~~~
Please send any bug report, any encountered problem (with a detailed
description as possible) and any comments to <yaps@nitmar.tnet.de> or
<ud@cube.net>.
Files:
~~~~~~
README: This file
COPYING.GPL, COPYRIGHT: About distributing the software
INSTALL: A pointer into the README file
BUGREPORT: How to report a bug
Makefile, Config: Make rules
yaps.rc: Sample configuration file
yaps.c: The driver program
valid.c, valid.h: Support routines for the driver program
remaining *.c, *.h: The paging library
yaps.html, yaps.doc: Documentation in HTML and plain text
yaps.1: A minimal manual page
yaps.lsm: The Linux Software Map entry
contrib/: Files not supported by the author

372
asc.c Normal file
View File

@ -0,0 +1,372 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include "pager.h"
/*{{{ typedefs */
typedef struct {
# ifndef NDEBUG
# define MAGIC MKMAGIC('a', 's', 'c', '\0')
long magic;
# endif /* NDEBUG */
void *sp;
void *ctab;
void (*logger) (char, char *, ...);
char *callid;
int deftout;
char *alogin;
char *alogout;
char *apid;
char *amsg;
char *anext;
char *async;
date_t delay;
date_t expire;
Bool rds;
} asc;
/*}}}*/
/*{{{ convert */
static char *
escape_string (asc *a, char *str)
{
int c;
char ch, prev;
char *ret;
int n;
if (ret = malloc (strlen (str) * 2 + 16)) {
prev = '\0';
ch = '\0';
for (n = 0; *str; prev = ch) {
c = cv_conv (a -> ctab, (char_t) *str++);
if (c < 0)
continue;
ch = (char) c;
if ((ch == '<') && isspace (prev)) {
ret[n++] = '\\';
ret[n++] = '<';
} else if (ch == ' ') {
ret[n++] = '\\';
ret[n++] = 's';
} else if (ch == '\a') {
ret[n++] = '\\';
ret[n++] = 'a';
} else if (ch == '\b') {
ret[n++] = '\\';
ret[n++] = 'b';
} else if (ch == '\f') {
ret[n++] = '\\';
ret[n++] = 'f';
} else if (ch == '\n') {
ret[n++] = '\\';
ret[n++] = 'n';
} else if (ch == '\r') {
ret[n++] = '\\';
ret[n++] = 'r';
} else if (ch == '\t') {
ret[n++] = '\\';
ret[n++] = 't';
} else if (ch) {
if ((ch == '\\') || (ch == '^') || (ch == '%'))
ret[n++] = '\\';
ret[n++] = ch;
}
}
ret[n] = '\0';
}
return ret;
}
static char *
convert_asc (asc *a, char *pat, char *pid, char *msg)
{
char *str;
int siz, len;
char *ptr;
int plen;
char scr[32];
str = NULL;
siz = 0;
len = 0;
while (*pat) {
if (len + 2 >= siz) {
siz += 32;
if (! (str = Realloc (str, siz + 2)))
break;
}
if (*pat == '\\') {
++pat;
if (*pat) {
ptr = NULL;
switch (*pat) {
case 'C': ptr = a -> callid; break;
case 'P': ptr = pid; break;
case 'M': ptr = msg; break;
case 'R':
strcpy (scr, (a -> rds ? "1" : "0"));
ptr = scr;
break;
default:
str[len++] = '\\';
str[len++] = *pat;
break;
}
if (ptr && (ptr = escape_string (a, ptr))) {
if (plen = strlen (ptr)) {
if (len + plen + 2 >= siz) {
siz = len + plen + 32;
if (! (str = Realloc (str, siz)))
break;
}
strcpy (str + len, ptr);
len += plen;
}
free (ptr);
}
++pat;
}
} else if (! iscntrl (*pat))
str[len++] = *pat++;
else {
str[len++] = ' ';
++pat;
}
}
if (str)
str[len] = '\0';
return str;
}
/*}}}*/
/*{{{ general sending routine */
static int
do_send (asc *a, char *what, char *pat, char *pid, char *msg)
{
int ret;
char *str;
ret = ERR_FAIL;
if (a && a -> sp)
if (pat && *pat) {
if (str = convert_asc (a, pat, pid, msg)) {
if (tty_send_expect (a -> sp, a -> deftout, str, NULL) != -1) {
V (1, ("Ascii %s sent\n", what));
ret = NO_ERR;
} else
V (1, ("Unable to send %s\n", what));
free (str);
}
} else
ret = NO_ERR;
return ret;
}
/*}}}*/
/*{{{ login/logout/transmit/next/sync */
int
asc_login (void *ap, string_t *cid)
{
asc *a = (asc *) ap;
MCHK (a);
if (a) {
if (a -> callid)
free (a -> callid);
a -> callid = sextract (cid);
}
return a ? do_send (a, "login", a -> alogin, NULL, NULL) : ERR_ABORT;
}
int
asc_logout (void *ap)
{
asc *a = (asc *) ap;
MCHK (a);
return a ? do_send (a, "logout", a -> alogout, NULL, NULL) : ERR_FATAL;
}
int
asc_transmit (void *ap, char *pid, char *msg)
{
asc *a = (asc *) ap;
int n;
MCHK (a);
if (! a)
return ERR_FATAL;
if ((n = do_send (a, "pagerid", a -> apid, pid, NULL)) != NO_ERR)
return n;
return do_send (a, "message", a -> amsg, NULL, msg);
}
int
asc_next (void *ap)
{
asc *a = (asc *) ap;
MCHK (a);
return a ? do_send (a, "next", a -> anext, NULL, NULL) : ERR_FATAL;
}
int
asc_sync (void *ap)
{
asc *a = (asc *) ap;
MCHK (a);
return a ? do_send (a, "sync", a -> async, NULL, NULL) : ERR_FATAL;
}
/*}}}*/
/*{{{ config */
void
asc_config (void *ap, void (*logger) (char, char *, ...),
int deftout, char *alogin, char *alogout, char *apid, char *amsg, char *anext, char *async,
date_t *delay, date_t *expire, Bool rds)
{
asc *a = (asc *) ap;
MCHK (a);
if (a) {
a -> logger = logger;
if (deftout != -1)
a -> deftout = deftout;
if (alogin) {
if (a -> alogin)
free (a -> alogin);
a -> alogin = strdup (alogin);
}
if (alogout) {
if (a -> alogout)
free (a -> alogout);
a -> alogout = strdup (alogout);
}
if (apid) {
if (a -> apid)
free (a -> apid);
a -> apid = strdup (apid);
}
if (amsg) {
if (a -> amsg)
free (a -> amsg);
a -> amsg = strdup (amsg);
}
if (anext) {
if (a -> anext)
free (a -> anext);
a -> anext = strdup (anext);
}
if (async) {
if (a -> async)
free (a -> async);
a -> async = strdup (async);
}
if (delay)
a -> delay = *delay;
else
dat_clear (& a -> delay);
if (expire)
a -> expire = *expire;
else
dat_clear (& a -> expire);
a -> rds = rds;
}
}
void
asc_set_convtable (void *ap, void *ctab)
{
asc *a = (asc *) ap;
MCHK (a);
if (a) {
if (a -> ctab)
cv_free (a -> ctab);
a -> ctab = ctab;
}
}
void
asc_add_convtable (void *ap, void *ctab)
{
asc *a = (asc *) ap;
MCHK (a);
if (a) {
if (! a -> ctab)
a -> ctab = cv_new ();
if (a -> ctab)
cv_merge (a -> ctab, ctab, True);
}
}
/*}}}*/
/*{{{ new/free/etc */
void *
asc_new (void *sp)
{
asc *a;
if (a = (asc *) malloc (sizeof (asc))) {
# ifndef NDEBUG
a -> magic = MAGIC;
# endif /* NDEBUG */
a -> sp = sp;
a -> ctab = NULL;
a -> logger = NULL;
a -> callid = NULL;
a -> deftout = 10;
a -> alogin = NULL;
a -> alogout = NULL;
a -> apid = NULL;
a -> amsg = NULL;
a -> anext = NULL;
a -> async = NULL;
dat_clear (& a -> delay);
dat_clear (& a -> expire);
a -> rds = False;
}
return (void *) a;
}
void *
asc_free (void *ap)
{
asc *a = (asc *) ap;
MCHK (a);
if (a) {
if (a -> ctab)
cv_free (a -> ctab);
if (a -> callid)
free (a -> callid);
if (a -> alogin)
free (a -> alogin);
if (a -> alogout)
free (a -> alogout);
if (a -> apid)
free (a -> apid);
if (a -> amsg)
free (a -> amsg);
if (a -> anext)
free (a -> anext);
if (a -> async)
free (a -> async);
free (a);
}
return NULL;
}
int
asc_preinit (void)
{
return 0;
}
void
asc_postdeinit (void)
{
}
/*}}}*/

553
cfg.c Normal file
View File

@ -0,0 +1,553 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include "pager.h"
/*{{{ typedefs */
typedef unsigned long hash_t;
typedef struct _entry {
hash_t hval;
char *var;
char *val;
struct _entry
*next;
} entry;
typedef struct _charc {
hash_t hval;
char *name;
struct _charc
*next;
} charc;
typedef struct _block {
# ifndef NDEBUG
# define MAGIC MKMAGIC ('c', 'f', 'g', '\0')
long magic;
# endif /* NDEBUG */
hash_t hval;
char *name;
charc *use;
Bool done;
entry *e;
char *sep;
int seplen;
struct _block
*next;
} block;
typedef struct _fifo {
void *dat;
struct _fifo
*next;
} fifo;
typedef struct _fpstack {
FILE *fp;
struct _fpstack
*up;
} fpstack;
/*}}}*/
/*{{{ support routines */
static hash_t
calc_hash (char *str)
{
hash_t hval;
for (hval = 0; *str; ) {
hval <<= 2;
hval += *str++ & 0xff;
hval >>= 1;
}
return hval;
}
static Bool
issame (hash_t h1, char *s1, hash_t h2, char *s2)
{
if (h1 == h2)
if ((! s1) && (! s2))
return True;
else if (s1 && s2 && (s1[0] == s2[0]) && (! strcmp (s1, s2)))
return True;
return False;
}
static block *
new_block (char *bname, hash_t hval, char *sep)
{
block *b;
if (b = (block *) malloc (sizeof (block))) {
b -> name = NULL;
if ((! bname) || (b -> name = strdup (bname))) {
b -> sep = NULL;
b -> seplen = 0;
if ((! sep) || (b -> sep = strdup (sep))) {
# ifndef NDEBUG
b -> magic = MAGIC;
# endif /* NDEBUG */
b -> hval = hval;
b -> use = NULL;
b -> done = False;
b -> e = NULL;
b -> next = NULL;
} else {
if (b -> name)
free (b -> name);
free (b);
b = NULL;
}
} else {
free (b);
b = NULL;
}
}
return b;
}
static void
add_entry (block *base, block *b, char *var, char *val)
{
hash_t hval;
entry *e, *etmp;
Bool add;
char *sav;
if (b && var) {
if (*var == '+') {
++var;
add = True;
} else
add = False;
hval = calc_hash (var);
for (e = b -> e; e; e = e -> next)
if (issame (hval, var, e -> hval, e -> var))
break;
if (e) {
if (e -> val)
if (add) {
if (val && *val) {
sav = e -> val;
if (e -> val = malloc (strlen (sav) + strlen (val) + base -> seplen + 2)) {
sprintf (e -> val, "%s%s%s", sav, (base -> sep ? base -> sep : ""), val);
free (sav);
val = NULL;
} else
e -> val = sav;
}
} else {
free (e -> val);
e -> val = NULL;
}
} else if (e = (entry *) malloc (sizeof (entry)))
if (e -> var = strdup (var)) {
e -> hval = hval;
e -> val = NULL;
e -> next = b -> e;
b -> e = e;
} else {
free (e);
e = NULL;
}
if (e && (! e -> val) && val && *val) {
if (add && (base != b)) {
for (etmp = base -> e; etmp; etmp = etmp -> next)
if (issame (hval, var, etmp -> hval, etmp -> var))
break;
if (etmp && etmp -> val)
if (e -> val = malloc (strlen (etmp -> val) + strlen (val) + base -> seplen + 2))
sprintf (e -> val, "%s%s%s", etmp -> val, (base -> sep ? base -> sep : ""), val);
}
if (! e -> val)
e -> val = strdup (val);
}
}
}
/*}}}*/
/*{{{ read configuration */
void *
cfg_new (char *sep)
{
return (void *) new_block (NULL, 0, sep);
}
void *
cfg_read (char *fname, void *bp, char *sep)
{
FILE *fp;
fpstack *fcur, *ftmp;
char *gline, *line;
char *ptr, *use;
charc *prv, *tmp;
block *base, *prev, *cur;
hash_t hval;
char *var, *val;
int plen;
Bool done;
int siz, len;
char *temp;
if (bp)
base = (block *) bp;
else
if (! (base = new_block (NULL, 0, sep)))
return NULL;
cur = base;
if (fp = fopen (fname, "r"))
if (fcur = (fpstack *) malloc (sizeof (fpstack))) {
fcur -> fp = fp;
fcur -> up = NULL;
while (fcur) {
while (gline = getline (fcur -> fp, True)) {
for (line = gline; isspace (*line); ++line)
;
if ((! *line) || (*line == '#')) {
free (gline);
continue;
}
if (*line == '[') {
use = NULL;
if (ptr = strchr (line, ']')) {
*ptr++ = '\0';
while (isspace (*ptr))
++ptr;
if (*ptr)
use = ptr;
}
ptr = line + 1;
if (! *ptr)
cur = base;
else {
hval = calc_hash (ptr);
for (cur = base, prev = NULL; cur; cur = cur -> next)
if (issame (hval, ptr, cur -> hval, cur -> name))
break;
else
prev = cur;
if ((! cur) && (cur = new_block (ptr, hval, NULL)))
if (prev)
prev -> next = cur;
if (cur && use) {
if (cur -> use)
for (prv = cur -> use; prv -> next; prv = prv -> next)
;
else
prv = NULL;
while (*use) {
ptr = use;
use = skipch (ptr, ',');
if (tmp = (charc *) malloc (sizeof (charc)))
if (tmp -> name = strdup (ptr)) {
tmp -> hval = 0;
tmp -> next = NULL;
if (prv)
prv -> next = tmp;
else
cur -> use = tmp;
prv = tmp;
} else
free (tmp);
}
}
}
if (! cur) {
free (gline);
break;
}
} else if (*line == '|') {
++line;
while (isspace (*line))
++line;
if (fp = fopen (line, "r"))
if (ftmp = (fpstack *) malloc (sizeof (fpstack))) {
ftmp -> fp = fp;
ftmp -> up = fcur;
fcur = ftmp;
} else
fclose (fp);
} else {
var = line;
val = skip (var);
if (var = strdup (var)) {
temp = NULL;
if ((*val == '{') && (! *(val + 1))) {
done = False;
siz = 0;
len = 0;
while (ptr = getline (fcur -> fp, False)) {
if ((*ptr != '}') || *(ptr + 1)) {
plen = strlen (ptr);
if (len + plen + 2 >= siz) {
siz = len + plen + 256;
if (! (temp = Realloc (temp, siz + 2))) {
siz = 0;
done = True;
}
}
if (len + plen < siz) {
if (len)
temp[len++] = '\n';
strcpy (temp + len, ptr);
len += plen;
}
} else
done = True;
free (ptr);
if (done)
break;
}
if (temp) {
temp[len] = '\0';
val = temp;
} else
val = NULL;
} else if (*val == '\\')
++val;
add_entry (base, cur, var, val);
if (temp)
free (temp);
free (var);
}
}
free (gline);
}
ftmp = fcur;
fcur = fcur -> up;
fclose (ftmp -> fp);
free (ftmp);
}
} else
fclose (fp);
return (void *) base;
}
/*}}}*/
/*{{{ add/change configuration */
void
cfg_modify (void *bp, char *bname, char *var, char *val)
{
block *base = (block *) bp;
block *use, *prv;
hash_t hval;
MCHK (base);
if (base) {
if (! bname)
use = base;
else {
hval = calc_hash (bname);
for (use = base -> next, prv = base; use; use = use -> next)
if (issame (hval, bname, use -> hval, use -> name))
break;
else
prv = use;
if (! use)
use = new_block (bname, hval, NULL);
}
if (use)
add_entry (base, use, var, val);
}
}
/*}}}*/
/*{{{ end (free up) configuration */
void *
cfg_end (void *bp)
{
block *b = (block *) bp;
block *tmp;
charc *run;
entry *e;
MCHK (b);
while (b) {
if (b -> name)
free (b -> name);
while (b -> use) {
run = b -> use;
b -> use = b -> use -> next;
if (run -> name)
free (run -> name);
free (run);
}
while (b -> e) {
e = b -> e;
b -> e = b -> e -> next;
if (e -> var)
free (e -> var);
if (e -> val)
free (e -> val);
free (e);
}
if (b -> sep)
free (b -> sep);
tmp = b;
b = b -> next;
free (tmp);
}
return NULL;
}
/*}}}*/
/*{{{ retrieving */
static char *
do_get (void *bp, char *bname, char *var, Bool glob, char *dflt)
{
block *b = (block *) bp;
block *run, *tmp;
entry *e;
fifo *f, *l, *ft;
charc *use;
char *ptr, *sav;
charc *vars, *vprv, *vtmp, *vrun;
Bool first;
hash_t hval;
MCHK (b);
if (! (var = strdup (var)))
return NULL;
vars = NULL;
vprv = NULL;
for (ptr = var; *ptr; ) {
sav = ptr;
ptr = skipch (ptr, ',');
if (vtmp = (charc *) malloc (sizeof (charc)))
if (vtmp -> name = strdup (sav)) {
vtmp -> hval = calc_hash (vtmp -> name);
vtmp -> next = NULL;
if (vprv)
vprv -> next = vtmp;
else
vars = vtmp;
vprv = vtmp;
} else
free (vtmp);
}
free (var);
if (! vars)
return NULL;
e = NULL;
f = NULL;
l = NULL;
first = True;
while ((! e) && bname) {
hval = calc_hash (bname);
for (run = b -> next; run; run = run -> next)
if (issame (hval, bname, run -> hval, run -> name))
break;
bname = NULL;
if (run && (first || (! run -> done))) {
for (vrun = vars; vrun; vrun = vrun -> next) {
for (e = run -> e; e; e = e -> next)
if (issame (vrun -> hval, vrun -> name, e -> hval, e -> var))
break;
if (e)
break;
}
if (! e) {
if (use = run -> use) {
if (first) {
for (tmp = b -> next; tmp; tmp = tmp -> next)
tmp -> done = False;
first = False;
}
for (; use; use = use -> next)
if (ft = (fifo *) malloc (sizeof (fifo))) {
ft -> dat = (void *) use;
ft -> next = NULL;
if (l)
l -> next = ft;
else {
f = ft;
l = ft;
}
} else
break;
}
if (f) {
ft = f;
f = f -> next;
if (! f)
l = NULL;
use = (charc *) ft -> dat;
bname = use -> name;
free (ft);
} else
bname = NULL;
run -> done = True;
}
}
}
if ((! e) && glob)
for (vrun = vars; vrun; vrun = vrun -> next) {
for (e = b -> e; e; e = e -> next)
if (issame (vrun -> hval, vrun -> name, e -> hval, e -> var))
break;
if (e)
break;
}
while (vars) {
vtmp = vars;
vars = vars -> next;
free (vtmp -> name);
free (vtmp);
}
return e ? e -> val : dflt;
}
static int
do_iget (void *bp, char *bname, char *var, Bool glob, int dflt)
{
char *ret;
ret = do_get (bp, bname, var, glob, NULL);
return ret ? atoi (ret) : dflt;
}
static Bool
do_bget (void *bp, char *bname, char *var, Bool glob, int dflt)
{
char *ret;
ret = do_get (bp, bname, var, glob, NULL);
return ret ? ((*ret && strchr ("TtYy1+", *ret)) ? True : False) : dflt;
}
char *
cfg_get (void *bp, char *bname, char *var, char *dflt)
{
return do_get (bp, bname, var, True, dflt);
}
int
cfg_iget (void *bp, char *bname, char *var, int dflt)
{
return do_iget (bp, bname, var, True, dflt);
}
Bool
cfg_bget (void *bp, char *bname, char *var, Bool dflt)
{
return do_bget (bp, bname, var, True, dflt);
}
char *
cfg_block_get (void *bp, char *bname, char *var, char *dflt)
{
return do_get (bp, bname, var, False, dflt);
}
int
cfg_block_iget (void *bp, char *bname, char *var, int dflt)
{
return do_iget (bp, bname, var, False, dflt);
}
Bool
cfg_block_bget (void *bp, char *bname, char *var, Bool dflt)
{
return do_bget (bp, bname, var, False, dflt);
}
/*}}}*/

134
config.h Normal file
View File

@ -0,0 +1,134 @@
/* -*- mode: c; mode: fold -*- */
# ifndef __CONFIG_H
# define __CONFIG_H 1
/*{{{ changeable configuration */
/*
* Define signal handling:
* POSIX_SIGNAL if you have the Posix sigaction() family
* BSD_SIGNAL if you have BSD like signal() handling
* SYSV_SIGNAL if you have SysV like signal() handling
* SIG_VOID_RETURN if your signal handler returns void
* SIG_INT_RETURN if your signal handler returns int
*/
# define POSIX_SIGNAL 1
# define BSD_SIGNAL 0
# define SYSV_SIGNAL 0
# define SIG_VOID_RETURN 1
# define SIG_INT_RETURN 0
/*
* Set each define to 1, if you have the matching header file, otherwise
* set it to 0. Remember, that some features may not available, if the
* header file is not available.
*/
/*
* Needed only by some systems, which do not define FD_SET etc.
* in sys/time.h
*/
# define HAVE_SYS_SELECT_H 0
/*
* If you have locales set this. This is useful to for character
* conversion/classification
*/
# define HAVE_LOCALE_H 0
/*
* If you have Posix regular expressions, set this. Otherwise a
* very weak replacement is used to find matching services
*/
# define HAVE_REGEX_H 0
/*
* one of these is required for SysV like lockfiles
*/
# define HAVE_SYS_SYSMACROS_H 1
# define HAVE_SYS_MKDEV_H 0
/*
* Some system do not define the getopt stuff in unistd.h, but in
* a own include file getopt.h. Or (like the GNU libc) defines there
* the extended getopt_long version.
*/
# define HAVE_GETOPT_H 0
/*
* Set each define to 1, if your library supports the function, otherwise
* set it to 0. See above for note.
*/
/*
* If the library contains this function, a call to it is required
* to get valid return values from localtime
*/
# define HAVE_TZSET 0
/*
* If these are not set, chmod()/chown() are used
*/
# define HAVE_FCHMOD 0
# define HAVE_FCHOWN 0
/*
* If you have sigsetjmp() you definitly want to set this, otherwise
* longjmp() from the signal handler leads into chaos
*/
# define HAVE_SIGSETJMP 0
/*
* Memory access functions. Nearly everybody has memcpy()/memset(), so
* choose the bcopy()/bzero() part only if you are missing the other two
*/
# define HAVE_MEMCPY 1
# define HAVE_BCOPY 0
# define HAVE_MEMSET 1
# define HAVE_BZERO 0
/*
* If your library supports getopt at all
*/
# define HAVE_GETOPT 1
/*
* If your library supports long options (getopt_long(3)), then set this
* to one
*/
# define HAVE_GETOPT_LONG 0
/*
* If you have getopt(3), but your headerfile(s) does not declare
* optind/optarg set this to 1, otherwise to 0
*/
# define NEED_OPTIND_OPTARG 0
/*
* If your realloc(3) function cannot handle realloc (NULL, size), then
* set this to 1, otherwise to 0
*/
# define BROKEN_REALLOC 1
/* -------------- END OF CHANGEABLE PART ------------------ */
/*}}}*/
/*{{{ auto configuration part */
/*
* Autoconfiguration
*/
# if ! HAVE_MEMCPY
# if HAVE_BCOPY
# define memcpy(aa,bb,cc) bcopy((bb),(aa),(cc))
# else /* HAVE_BCOPY */
# error "Neither memcopy() nor bcopy() available, aborted"
# endif /* HAVE_BCOPY */
# endif /* BSD */
# if BROKEN_REALLOC
# define Realloc(ppp,sss) ((ppp) ? realloc ((ppp), (sss)) : malloc ((sss)))
# else /* BROKEN_REALLOC */
# define Realloc realloc
# endif /* BROKEN_REALLOC */
# ifndef __GCC__
# define inline
# endif /* __GCC__ */
/*}}}*/
# endif /* __CONFIG_H */

12
contrib/Makefile Normal file
View File

@ -0,0 +1,12 @@
# -*- sh -*-
all:
@echo -n
clean:
rm -f *~ core
install:
@echo -n
depend:
@echo -n

10
contrib/README Normal file
View File

@ -0,0 +1,10 @@
Here all available contributed files, a short description and
the author:
m2y.pl: Simple perl script to use yaps in a mail to pager
enviroment. Just an example, for real use you have
to enhance it significant. (Ulrich Dessauer)
tap.sl: Example for usage of scripting as a protocol
replacement. This implements a minimal subset
of TAP.

60
contrib/m2y.pl Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/perl
# -*- perl -*-
# Untested mail -> yaps gateway (just an example)
# (C) by Ulrich Dessauer
# Create some receiver address, e.g. <nr>@yaps.<yourdomain> and
# instruct your mailer to forward each mail to this address to
# this script. Ensure that there is only one receiver per mail.
#
# To be really useful, the script must be expanded to check for
# illegal characters in receiver/message (in this case the >'<
# as this is used as quoting in the system() call) and handling
# of multiple receivers in one call, etc. Happy Hacking!
#
# Markus <markus@mail.yezz.de> made some comments and improvments
# to make this script slowly useful.
#
$yaps = "/usr/local/bin/yaps";
$mailer = "/usr/lib/sendmail -t";
$send_response = 1;
#
$recv = $ARGV[0];
$recv = (split ('@', $recv))[0];
die "No receiver given\n"
unless $recv;
undef $msg;
undef $from;
while (<STDIN>) {
chomp;
if ($_ =~ /^Subject: /i) {
$msg = $_;
$msg =~ s/^Subject: //i;
undef $msg
if $msg eq "";
} elsif ($_ =~ /^From: /i) {
$from = $_;
$from =~ s/^From: //i;
}
}
die "No message found\n"
unless $msg;
die "No sender found\n"
unless $from;
#
# Avoid apostroph in command line (otherwise the shell will stumble)
$recv =~ s/\'/\`/g;
$msg =~ s/\'/\`/g;
$from =~ s/\'/\`/g;
$n = system ("$yaps '$recv' '(EMail from $from) $msg'");
die "Unable to send message to $recv\n"
if $n;
if ($send_response) {
die "Unable to invoke mailer for response\n"
unless open (OUT, "|$mailer");
print OUT "From: yaps-mail\n";
print OUT "To: $from\n";
print OUT "Subject: Message sent to $recv\n";
print OUT "\n";
print OUT "Your message $msg\nto $recv has been sent\n";
close (OUT);
}

122
contrib/tap.sl Normal file
View File

@ -0,0 +1,122 @@
% -*- slang -*-
%
% (C) by Ulrich Dessauer
%
% This is an example for scripting by re-implementing TAP
% using SLang. This is a minimal implementation and has not
% all the fancy features the internal version has, but it
% should only be an example for the usage of scripting.
%
%
% Add these lines if you want to use it in your yaps.rc
% protocol script
% use-call-id False
% script-type SLang
% script-name /path/to/this/file/tap.sl
% scr-login tap_login
% scr-logout tap_logout
% scr-pagerid tap_pagerid
% scr-message tap_message
% scr-next tap_next
% scr-sync tap_sync
%
variable tap_pid = Null_String;
variable tap_t1 = 2;
variable tap_t3 = 10;
define
tap_login (callid)
{
variable n, ep;
for (n = 0; n < 3; ++n) {
!if (send ("\r"))
return (ERR_FATAL);
if (expect (tap_t1, "ID=", 1) == 1)
break;
}
if (n == 3)
return (ERR_FATAL);
for (n = 0; n < 3; ++n) {
!if (send ("\033PG1\r"))
return (ERR_FATAL);
ep = expect (tap_t3, "\x06\r", "\x15\r", "\x1b\x04\r", 3);
if (ep == 1)
break;
else if ((ep == 2) or (ep == 3))
return (ERR_ABORT);
}
if (n == 3)
return (ERR_FATAL);
if (expect (tap_t3, "\x1b[p\r", 1) != 1)
return (ERR_ABORT);
return (NO_ERR);
}
define
tap_logout (dummy)
{
variable n, ep;
for (n = 0; n < 3; ++n) {
!if (send ("\x04\r"))
return (ERR_FATAL);
ep = expect (tap_t3, "\x1b\x04\r", "\x1e\r", 2);
if (ep == 1)
break;
else if (ep != 2)
return (ERR_FATAL);
}
if (n == 3)
return (ERR_FATAL);
return (NO_ERR);
}
define
tap_pagerid (pid)
{
tap_pid = conv (pid);
return (NO_ERR);
}
define
tap_message (msg)
{
variable str;
variable chk;
variable n, ep, len;
str = "\x02" + tap_pid + "\r" + conv (msg) + "\r" + "\x03";
len = strlen (str);
chk = 0;
for (n = 0; n < len; ++n)
chk = chk + (str[n] & 0xff);
str = str + Sprintf ("%c%c%c\r", ((chk shr 8) & 0xf) + 0x30, ((chk shr 4) & 0xf) + 0x30, (chk & 0xf) + 0x30, 3);
for (n = 0; n < 3; ++n) {
!if (send (str))
return (ERR_FATAL);
ep = expect (tap_t3, "\x06\r", "\x15\r", "\x1e\r", "\x1b\x04\r", 4);
if (ep == 1)
break;
else if ((ep == 2) or (ep == 3))
return (ERR_FATAL);
else if (ep == 4)
return (ERR_ABORT);
}
if (n == 3)
return (ERR_FATAL);
return (NO_ERR);
}
define
tap_next (dummy)
{
return (NO_ERR);
}
define
tap_sync (dummy)
{
return (ERR_FATAL);
}

221
cv.c Normal file
View File

@ -0,0 +1,221 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include "pager.h"
/*{{{ typedefs */
typedef struct {
# ifndef NDEBUG
# define MAGIC MKMAGIC ('c', 'o', 'n', 'v')
long magic;
# endif /* NDEBUG */
int c[256]; /* the conversion table */
} conv;
/*}}}*/
/*{{{ new/free */
void *
cv_new (void)
{
conv *c;
int n;
if (c = (conv *) malloc (sizeof (conv))) {
# ifndef NDEBUG
c -> magic = MAGIC;
# endif /* NDEBUG */
for (n = 0; n < 256; ++n)
c -> c[n] = n;
}
return (void *) c;
}
void *
cv_free (void *cv)
{
conv *c = (conv *) cv;
MCHK (c);
if (c)
free (c);
return NULL;
}
/*}}}*/
/*{{{ reverse */
void *
cv_reverse (void *src)
{
conv *s = (conv *) src;
conv *c;
int n;
MCHK (s);
if (c = (conv *) cv_new ())
for (n = 0; n < 256; ++n)
if (s -> c[n] != -1)
c -> c[s -> c[n]] = n;
return (void *) c;
}
/*}}}*/
/*{{{ define/undefine */
static char_t
getval (char *str)
{
char_t ret;
if (isdigit (*str))
ret = (char_t) strtol (str, NULL, 0);
else if (! *(str + 1))
ret = (char_t) *str;
else if (*str == '^') {
++str;
ret = (char_t) (*str == '?' ? 0x7f : (*str & 0x1f));
} else if (*str == '\\') {
++str;
switch (*str) {
case 'a': ret = (char_t) '\a'; break;
case 'b': ret = (char_t) '\b'; break;
case 'e': ret = (char_t) '\x1b'; break;
case 'f': ret = (char_t) '\f'; break;
case 'l': ret = (char_t) '\012'; break;
case 'n': ret = (char_t) '\n'; break;
case 'r': ret = (char_t) '\r'; break;
case 's': ret = (char_t) ' '; break;
case 't': ret = (char_t) '\t'; break;
case 'v': ret = (char_t) '\v'; break;
default: ret = (char_t) *str; break;
}
} else
ret = (char_t) *str;
return ret;
}
void
cv_define (void *cv, char_t src, char_t dst)
{
conv *c = (conv *) cv;
MCHK (c);
if (c)
c -> c[src] = dst;
}
void
cv_sdefine (void *cv, char *src, char *dst)
{
cv_define (cv, getval (src), getval (dst));
}
void
cv_undefine (void *cv, char_t ch)
{
conv *c = (conv *) cv;
MCHK (c);
if (c)
c -> c[ch] = ch;
}
void
cv_sundefine (void *cv, char *ch)
{
cv_undefine (cv, getval (ch));
}
void
cv_invalid (void *cv, char_t ch)
{
conv *c = (conv *) cv;
MCHK (c);
if (c)
c -> c[ch] = -1;
}
void
cv_sinvalid (void *cv, char *ch)
{
cv_invalid (cv, getval (ch));
}
/*}}}*/
/*{{{ read/write table */
int
cv_read_table (void *cv, char *fname)
{
conv *c = (conv *) cv;
FILE *fp;
char *line;
char *sp, *dp;
MCHK (c);
if ((! c) || (! (fp = fopen (fname, "r"))))
return -1;
while (line = getline (fp, True)) {
for (sp = line; isspace (*sp); ++sp)
;
if (*sp && (*sp != '#')) {
dp = skip (sp);
skip (dp);
if (*sp)
if (*dp)
c -> c[getval (sp)] = getval (dp);
else
c -> c[getval (sp)] = -1;
}
free (line);
}
fclose (fp);
return 0;
}
int
cv_write_table (void *cv, char *fname)
{
conv *c = (conv *) cv;
FILE *fp;
int n;
MCHK (c);
if ((! c) || (! (fp = fopen (fname, "w"))))
return -1;
fprintf (fp, "#\tThis file is generated automatically\n");
for (n = 0; n < 256; ++n) {
if ((! (n & 0x80)) && isprint (n))
fprintf (fp, "#\t%c\n", (char) n);
if (c -> c[n] != -1)
fprintf (fp, "0x%02x\t0x%02x\n", n, c -> c[n]);
else
fprintf (fp, "0x%02x\n", n);
}
fclose (fp);
return 0;
}
/*}}}*/
/*{{{ merging */
void
cv_merge (void *cv, void *in, Bool second)
{
conv *c = (conv *) cv,
*i = (conv *) in;
int n;
MCHK (c);
MCHK (i);
if (c && i)
for (n = 0; n < 256; ++n)
if (second || (c -> c[n] == n))
c -> c[n] = i -> c[n];
}
/*}}}*/
/*{{{ converting */
int
cv_conv (void *cv, char_t ch)
{
conv *c = (conv *) cv;
MCHK (c);
return c ? c -> c[ch] : (int) ch;
}
/*}}}*/

6
data.c Normal file
View File

@ -0,0 +1,6 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include "pager.h"
int verbose = 0;
int (*verbout) (char *, ...) = verbose_out;

442
lua.c Normal file
View File

@ -0,0 +1,442 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# ifdef SCRIPT_LUA
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <lua.h>
# include <lualib.h>
# include "pager.h"
# include "script.h"
# define STARTUP "Startup.lua"
/*{{{ statics & callable functions */
static Bool isinit = False;
static double lua_no_err = (double) NO_ERR,
lua_err_fail = (double) ERR_FAIL,
lua_err_fatal = (double) ERR_FATAL,
lua_err_abort = (double) ERR_ABORT;
static script *ls = NULL;
static char *lline = NULL;
static int lsiz = 0;
static char *lcb = NULL;
static void
lua_logger (void)
{
lua_Object obj;
char *sav, *str;
char typ;
if (((obj = lua_getparam (1)) != LUA_NOOBJECT) &&
(str = lua_getstring (obj)) &&
(sav = strdup (str))) {
typ = *sav;
if (((obj = lua_getparam (2)) == LUA_NOOBJECT) ||
(! (str = lua_getstring (obj)))) {
str = sav;
typ = LG_INF;
}
if (ls && ls -> logger)
(*ls -> logger) (typ, "%s\n", str);
free (sav);
}
}
static void
lua_callback (void *sp, string_t *s, char_t sep, void *data)
{
int len;
char *str;
lua_Object obj;
if (str = sextract (s)) {
len = strlen (str);
if (len + 2 >= lsiz) {
lsiz = len + 64;
if (! (lline = Realloc (lline, lsiz + 4)))
lsiz = 0;
}
if (lline) {
sprintf (lline, "%s%c", str, (char) sep);
if (lcb && (obj = lua_getglobal (lcb)) && lua_isfunction (obj)) {
lua_pushstring (lline);
lua_callfunction (obj);
}
}
free (str);
}
}
static void
lua_setcb (void)
{
lua_Object obj1, obj2;
char *sep, *func;
if ((obj1 = lua_getparam (1)) != LUA_NOOBJECT)
obj2 = lua_getparam (2);
else
obj2 = LUA_NOOBJECT;
if (lcb) {
free (lcb);
lcb = NULL;
}
if ((obj1 == LUA_NOOBJECT) || (! lua_isstring (obj1)) || (! (sep = lua_getstring (obj1)))) {
if (ls && ls -> sp)
tty_set_line_callback (ls -> sp, NULL, NULL, NULL);
} else {
if (ls && ls -> sp)
tty_set_line_callback (ls -> sp, lua_callback, sep, NULL);
if ((obj2 != LUA_NOOBJECT) && lua_isstring (obj2) && (func = lua_getstring (obj2)))
lcb = strdup (func);
}
}
static void
lua_get_line (void)
{
if (lline)
lua_pushstring (lline);
else
lua_pushnil ();
}
static void
lua_hangup (void)
{
lua_Object obj;
double sec;
int msec;
if (((obj = lua_getparam (1)) != LUA_NOOBJECT) &&
lua_isnumber (obj)) {
sec = lua_getnumber (obj);
msec = (int) (sec * 1000.0);
} else
msec = 500;
if (ls && ls -> sp)
tty_hangup (ls -> sp, msec);
}
static void
do_send (Bool dcv)
{
int ret;
lua_Object obj;
char *str;
ret = 0;
if (((obj = lua_getparam (1)) != LUA_NOOBJECT) &&
lua_isstring (obj) && (str = lua_getstring (obj)))
if (ls && ls -> sp) {
if (dcv)
str = scr_convert (ls, str);
if (str) {
if (tty_send_string (ls -> sp, str) != -1)
ret = 1;
if (dcv)
free (str);
}
}
if (ret)
lua_pushnumber (1.0);
else
lua_pushnil ();
}
static void
lua_send (void)
{
do_send (False);
}
static void
lua_csend (void)
{
do_send (True);
}
static void
lua_expect (void)
{
int ret;
lua_Object obj;
int tout;
char *str;
int cnt, siz;
char **ex;
int *len;
int start;
int n;
if (((obj = lua_getparam (1)) != LUA_NOOBJECT) && lua_isnumber (obj)) {
tout = (int) lua_getnumber (obj);
start = 2;
} else {
tout = 5;
start = 1;
}
ex = NULL;
cnt = 0;
siz = 0;
while (((obj = lua_getparam (start)) != LUA_NOOBJECT) &&
lua_isstring (obj) && (str = lua_getstring (obj))) {
if (cnt >= siz) {
siz += 4;
if (! (ex = (char **) Realloc (ex, (siz + 2) * sizeof (char *))))
break;
}
if (ex[cnt] = strdup (str))
++cnt;
}
ret = -1;
if (ex) {
ex[cnt] = NULL;
if ((cnt > 0) && (len = (int *) malloc ((cnt + 1) * sizeof (int)))) {
for (n = 0; n < cnt; ++n)
len[n] = strlen (ex[n]);
len[cnt] = 0;
if (ls && ls -> sp)
ret = tty_expect_list (ls -> sp, tout, ex, len);
free (len);
for (n = 0; n < cnt; ++n)
free (ex[n]);
}
free (ex);
}
lua_pushnumber ((double) ret);
}
static void
lua_send_expect (void)
{
int ret;
lua_Object obj;
int tout;
char *str;
ret = 0;
if ((obj = lua_getparam (1)) != LUA_NOOBJECT) {
if (lua_isnumber (obj)) {
tout = (int) lua_getnumber (obj);
obj = lua_getparam (2);
}
if ((obj != LUA_NOOBJECT) && lua_isstring (obj) && (str = lua_getstring (obj)))
if (ls && ls -> sp && (tty_send_expect (ls -> sp, tout, str, NULL) != -1))
ret = 1;
}
if (ret)
lua_pushnumber (1.0);
else
lua_pushnil ();
}
static void
lua_drain (void)
{
lua_Object obj;
int sec;
if (((obj = lua_getparam (1)) != LUA_NOOBJECT) && lua_isnumber (obj))
sec = (int) lua_getnumber (obj);
else
sec = 1;
if (ls && ls -> sp)
tty_drain (ls -> sp, sec);
}
static void
lua_cvdef (void)
{
lua_Object obj1, obj2;
char *src, *dst;
int n;
if (ls) {
if (! ls -> ctab)
ls -> ctab = cv_new ();
if (ls -> ctab)
if (((obj1 = lua_getparam (1)) != LUA_NOOBJECT) && lua_isstring (obj1) && (src = lua_getstring (obj1))) {
if ((obj2 = lua_getparam (2)) == LUA_NOOBJECT)
cv_undefine (ls -> ctab, (char_t) *src);
else if (lua_isstring (obj2) && (dst = lua_getstring (obj2)))
cv_define (ls -> ctab, (char_t) *src, (char_t) *dst);
else if (lua_isnumber (obj2)) {
n = (int) lua_getnumber (obj2);
if (n < 0)
cv_invalid (ls -> ctab, (char_t) *src);
else
cv_define (ls -> ctab, (char_t) *src, (char_t) n);
}
}
}
}
static void
lua_conv (void)
{
char *ret;
lua_Object obj;
char *str;
ret = NULL;
if (((obj = lua_getparam (1)) != LUA_NOOBJECT) && lua_isstring (obj) && (str = lua_getstring (obj)))
if (ls)
ret = scr_convert (ls, str);
if (ret) {
lua_pushstring (ret);
free (ret);
} else
lua_pushnil ();
}
/*}}}*/
/*{{{ init/deinit */
static int
lua_init (script *s, char *libdir)
{
char *fname;
if (! isinit) {
iolib_open ();
strlib_open ();
mathlib_open ();
lua_pushnumber (lua_no_err); lua_storeglobal ("NO_ERR");
lua_pushnumber (lua_err_fail); lua_storeglobal ("ERR_FAIL");
lua_pushnumber (lua_err_fatal); lua_storeglobal ("ERR_FATAL");
lua_pushnumber (lua_err_abort); lua_storeglobal ("ERR_ABORT");
/* void logger (string str); */
lua_register ("logger", lua_logger);
/* void setcb ([string sep[, string|function func]]); */
lua_register ("setcb", lua_setcb);
/* string|nil get_line (void); */
lua_register ("get_line", lua_get_line);
/* void hangup ([num sec]); */
lua_register ("hangup", lua_hangup);
/* num|nil send (string line); */
lua_register ("send", lua_send);
/* num|nil csend (string line); */
lua_register ("csend", lua_csend);
/* num expect (num tout, string, s1, ..., string sn); */
lua_register ("expect", lua_expect);
/* num|nil send_expect (num tout, string str); */
lua_register ("send_expect", lua_send_expect);
/* void drain ([num sec]); */
lua_register ("drain", lua_drain);
/* void cvdef (string src[, string|num dst]); */
lua_register ("cvdef", lua_cvdef);
/* string|nil conv (string str); */
lua_register ("conv", lua_conv);
if (libdir && (fname = malloc (strlen (libdir) + sizeof (STARTUP) + 4))) {
sprintf (fname, "%s/%s", libdir, STARTUP);
if (access (fname, R_OK) != -1)
lua_dofile (fname);
free (fname);
}
lline = NULL;
lsiz = 0;
isinit = True;
}
return NO_ERR;
}
static void
lua_deinit (script *s)
{
if (lline) {
free (lline);
lline = NULL;
lsiz = 0;
}
}
/*}}}*/
/*{{{ execution */
static int
lua_execute (script *s, char *func, char *parm)
{
int err;
lua_Object obj;
double ret;
err = NO_ERR;
if ((obj = lua_getglobal (func)) && lua_isfunction (obj)) {
ls = s;
lua_beginblock ();
lua_pushnumber ((double) s -> delay.day); lua_storeglobal ("delay_day");
lua_pushnumber ((double) s -> delay.mon); lua_storeglobal ("delay_mon");
lua_pushnumber ((double) s -> delay.year); lua_storeglobal ("delay_year");
lua_pushnumber ((double) s -> delay.hour); lua_storeglobal ("delay_hour");
lua_pushnumber ((double) s -> delay.min); lua_storeglobal ("delay_min");
lua_pushnumber ((double) s -> delay.sec); lua_storeglobal ("delay_sec");
lua_pushnumber ((double) s -> expire.day); lua_storeglobal ("expire_day");
lua_pushnumber ((double) s -> expire.mon); lua_storeglobal ("expire_mon");
lua_pushnumber ((double) s -> expire.year); lua_storeglobal ("expire_year");
lua_pushnumber ((double) s -> expire.hour); lua_storeglobal ("expire_hour");
lua_pushnumber ((double) s -> expire.min); lua_storeglobal ("expire_min");
lua_pushnumber ((double) s -> expire.sec); lua_storeglobal ("expire_sec");
lua_pushnumber ((double) s -> rds); lua_storeglobal ("rds");
if (parm)
lua_pushstring (parm);
else
lua_pushnil ();
if (lua_callfunction (obj))
err = ERR_FATAL;
else if ((obj = lua_getresult (1)) && (obj != LUA_NOOBJECT)) {
ret = lua_getnumber (obj);
if (ret == lua_no_err)
err = NO_ERR;
else if (ret == lua_err_fail)
err = ERR_FAIL;
else if (ret == lua_err_fatal)
err = ERR_FATAL;
else if (ret == lua_err_abort)
err = ERR_ABORT;
}
lua_endblock ();
if (ls -> sp)
tty_set_line_callback (ls -> sp, NULL, NULL, NULL);
ls = NULL;
}
return err;
}
/*}}}*/
/*{{{ loading */
static int
lua_load_string (script *s, char *scr)
{
return lua_dostring (scr) ? ERR_FATAL : NO_ERR;
}
static int
lua_load_file (script *s, char *fname)
{
return lua_dofile (fname) ? ERR_FATAL : NO_ERR;
}
/*}}}*/
/*{{{ preinit/postdeinit/scriptentry */
static int
lua_preinit (char *libdir)
{
return lua_init (NULL, libdir);
}
static void
lua_postdeinit (void)
{
lua_deinit (NULL);
}
funcs flua = {
"Lua",
lua_init,
lua_deinit,
lua_execute,
lua_load_string,
lua_load_file,
lua_preinit,
lua_postdeinit
};
/*}}}*/
# endif /* SCRIPT_LUA */

207
pager.h Normal file
View File

@ -0,0 +1,207 @@
/* -*- mode: c; mode: fold -*- */
# ifndef __PAGER_H
# define __PAGER_H 1
# include <stdio.h>
/*{{{ definitions, macros */
# ifndef NDEBUG
# define V(lvl,msg) ((void) (((lvl) <= verbose) && verbout ? (*verbout) msg, fflush (stdout) : 0))
# define MCHK(xxx) ((void) ((xxx) && ((xxx) -> magic != MAGIC) ? fprintf (stderr, "Invalid magic: expect %ld got %ld in %s:%d\n", MAGIC, (xxx) -> magic, __FILE__, __LINE__) : 0))
# define MKMAGIC(ch1,ch2,ch3,ch4) \
((long) ((((unsigned char) (ch1)) << 24) | \
(((unsigned char) (ch2)) << 16) | \
(((unsigned char) (ch3)) << 8) | \
((unsigned char) (ch4))))
# else /* NDEBUG */
# define V(lvl,msg)
# define MCHK(xxx)
# endif /* NDEBUG */
# define NO_ERR 0
# define ERR_FAIL (-1)
# define ERR_FATAL (-2)
# define ERR_ABORT (-3)
# define ECONT(xxx) (((xxx) == NO_ERR) || ((xxx) == ERR_FAIL))
# define ESTOP(xxx) (((xxx) == ERR_FATAL) || ((xxx) == ERR_ABORT))
# define LGS_SENT '+'
# define LGF_SENT '-'
# define LGS_INF '*'
# define LGF_INF '/'
# define LG_INF 'i'
# define LG_COST 'c'
# define LG_SSESSION 's'
# define LG_ESESSION 'e'
# define LG_PROTO 'p'
/*}}}*/
/*{{{ typedefs */
typedef enum {
False = 0,
True = ! False
} Bool;
typedef enum {
Unknown,
Ascii,
Script,
Tap,
Ucp
} Protocol;
typedef unsigned char char_t;
typedef struct {
char_t *str; /* the string itself */
int len; /* the current length */
int size; /* the allocated size */
} string_t;
typedef struct {
int day, mon, year;
int hour, min, sec;
} date_t;
/*}}}*/
/*{{{ prototypes */
/*{{{ utility */
extern char *skip (char *str);
extern char *skipch (char *str, char ch);
extern char *getline (FILE *fp, Bool cont);
extern int verbose_out (char *, ...);
/*}}}*/
/*{{{ string handling */
extern string_t *snewc (char *str);
extern string_t *snew (char_t *str, int len);
extern Bool sexpand (string_t *s, int nsize);
extern Bool scopy (string_t *dst, string_t *src);
extern Bool scat (string_t *dst, string_t *src);
extern Bool scopyc (string_t *dst, char *src);
extern Bool scatc (string_t *dst, char *src);
extern string_t *scut (string_t *str, int start, int len);
extern void sdel (string_t *str, int start, int len);
extern Bool sput (string_t *str, string_t *ins, int pos, int len);
extern Bool sputc (string_t *str, char *ins, int pos, int len);
extern char *sextract (string_t *s);
extern char *schar (string_t *s);
extern void *sfree (string_t *s);
extern void srelease (string_t *s);
extern Bool siscntrl (string_t *s, int pos);
extern Bool sisspace (string_t *s, int pos);
extern Bool sisdigit (string_t *s, int pos);
extern int stoi (string_t *s);
/*}}}*/
/*{{{ date handling */
extern date_t *dat_free (date_t *d);
extern date_t *dat_parse (char *str);
extern int dat_diff (date_t *d1, date_t *d2);
extern void dat_clear (date_t *d);
extern void dat_localtime (date_t *d);
/*}}}*/
/*{{{ tty handling */
extern void *tty_open (char *dev, char *lckprefix, char *lckmethod);
extern void *tty_close (void *sp);
extern Bool tty_reopen (void *s, int msec);
extern void tty_hangup (void *sp, int msec);
extern int tty_fd (void *sp);
extern int tty_setup (void *sp, Bool raw, Bool modem, int speed, int bpb, int sb, char parity);
extern void tty_set_line_callback (void *sp, void (*func) (void *, string_t *, char_t, void *), char *sep, void *data);
extern void tty_suspend_callback (void *sp, Bool susp);
extern int tty_send (void *sp, char *str, int len);
extern int tty_send_string (void *sp, char *str);
extern int tty_expect (void *sp, int tout, ...);
extern int tty_expect_list (void *sp, int tout, char **strs, int *lens);
extern int tty_expect_string (void *sp, int tout, char *str);
extern int tty_send_expect (void *sp, int deftout, char *str, char **opts);
extern void tty_mdrain (void *sp, int msecs);
extern void tty_drain (void *sp, int secs);
/*}}}*/
/*{{{ configuration */
extern void *cfg_new (char *sep);
extern void *cfg_read (char *fname, void *bp, char *sep);
extern void *cfg_end (void *bp);
extern void cfg_modify (void *bp, char *bname, char *var, char *val);
extern char *cfg_get (void *bp, char *bname, char *var, char *dflt);
extern int cfg_iget (void *bp, char *bname, char *var, int dflt);
extern Bool cfg_bget (void *bp, char *bname, char *var, Bool dflt);
extern char *cfg_block_get (void *bp, char *bname, char *var, char *dflt);
extern int cfg_block_iget (void *bp, char *bname, char *var, int dflt);
extern Bool cfg_block_bget (void *bp, char *bname, char *var, Bool dflt);
/*}}}*/
/*{{{ converting */
extern void *cv_new (void);
extern void *cv_free (void *cv);
extern void *cv_reverse (void *src);
extern void cv_define (void *cv, char_t src, char_t dst);
extern void cv_sdefine (void *cv, char *src, char *dst);
extern void cv_undefine (void *cv, char_t ch);
extern void cv_sundefine (void *cv, char *ch);
extern void cv_invalid (void *cv, char_t ch);
extern void cv_sinvalid (void *cv, char *ch);
extern int cv_read_table (void *cv, char *fname);
extern int cv_write_table (void *cv, char *fname);
extern void cv_merge (void *cv, void *in, Bool second);
extern int cv_conv (void *cv, char_t ch);
/*}}}*/
/*{{{ ASCII protocol */
extern int asc_login (void *ap, string_t *callid);
extern int asc_logout (void *ap);
extern int asc_transmit (void *ap, char *pid, char *msg);
extern int asc_next (void *ap);
extern int asc_sync (void *ap);
extern void asc_config (void *ap, void (*logger) (char, char *, ...),
int deftout, char *alogin, char *alogout, char *apid, char *amsg, char *anext, char *async,
date_t *delay, date_t *expire, Bool rds);
extern void asc_set_convtable (void *ap, void *ctab);
extern void asc_add_convtable (void *ap, void *ctab);
extern void *asc_new (void *sp);
extern void *asc_free (void *ap);
extern int asc_preinit (void);
extern void asc_postdeinit (void);
/*}}}*/
/*{{{ scripting protocol */
extern int scr_execute (void *sp, char *label, char *parm);
extern int scr_load_string (void *sp, char *scr);
extern int scr_load_file (void *sp, char *fname);
extern void scr_config (void *sp, void (*logger) (char, char *, ...), date_t *delay, date_t *expire, Bool rds);
extern void scr_set_convtable (void *sp, void *ctab);
extern void scr_add_convtable (void *sp, void *ctab);
extern void *scr_new (void *sp, char *typ, char *libdir);
extern void *scr_free (void *sp);
extern int scr_preinit (char *libdir);
extern void scr_postdeinit (void);
/*}}}*/
/*{{{ Telocator Alphanumeric Protocol */
extern int tap_login (void *tp, char *stype, char ttype, char *passwd, string_t *callid);
extern int tap_logout (void *tp);
extern int tap_transmit (void *tp, string_t **field, Bool last);
extern void tap_config (void *tp, void (*logger) (char, char *, ...), Bool pre16);
extern void tap_timeouts (void *tp, int t1, int t2, int t3, int t4, int t5);
extern void tap_retries (void *tp, int n1, int n2, int n3, int licnt, int locnt);
extern void tap_set_convtable (void *tp, void *ctab);
extern void tap_add_convtable (void *tp, void *ctab);
extern void *tap_new (void *sp);
extern void *tap_free (void *tp);
extern int tap_preinit (void);
extern void tap_postdeinit (void);
/*}}}*/
/*{{{ Universal Computer Protocol */
extern int ucp_login (void *up, string_t *callid);
extern int ucp_logout (void *up);
extern int ucp_transmit (void *up, string_t *pagerid, string_t *msg, Bool last);
extern void ucp_config (void *up, void (*logger) (char, char *, ...),
Bool xtend, int stout, int retry, int rtout,
date_t *delay, date_t *expire, Bool rds);
extern void ucp_set_convtable (void *up, void *ctab);
extern void ucp_add_convtable (void *up, void *ctab);
extern void *ucp_new (void *sp);
extern void *ucp_free (void *up);
extern int ucp_preinit (void);
extern void ucp_postdeinit (void);
/*}}}*/
/*}}}*/
/*{{{ global variables */
extern int verbose;
extern int (*verbout) (char *, ...);
/*}}}*/
# endif /* __PAGER_H */

189
scr.c Normal file
View File

@ -0,0 +1,189 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include "pager.h"
# include "script.h"
/*{{{ available scripts */
static funcs *flist[] = {
# ifdef SCRIPT_SLANG
& fslang,
# endif /* SCRIPT_SLANG */
# ifdef SCRIPT_LUA
& flua,
# endif /* SCRIPT_LUA */
NULL
};
/*}}}*/
/*{{{ convert */
char *
scr_convert (script *s, char *str)
{
char *ret;
int n, m;
int c;
if (ret = malloc (strlen (str) + 1)) {
for (n = 0, m = 0; str[n]; ++n)
if ((c = cv_conv (s -> ctab, (char_t) str[n])) > 0)
ret[m++] = (char) c;
ret[m] = '\0';
}
return ret;
}
/*}}}*/
/*{{{ execute */
int
scr_execute (void *sp, char *label, char *parm)
{
script *s = (script *) sp;
MCHK (s);
if ((! s) || (! s -> f) || (! s -> f -> fexec))
return ERR_FATAL;
return (*s -> f -> fexec) (s, label, parm);
}
/*}}}*/
/*{{{ script loading */
int
scr_load_string (void *sp, char *scr)
{
script *s = (script *) sp;
MCHK (s);
if ((! s) || (! s -> f) || (! s -> f -> fsload))
return ERR_FATAL;
return (*s -> f -> fsload) (s, scr);
}
int
scr_load_file (void *sp, char *fname)
{
script *s = (script *) sp;
MCHK (s);
if ((! s) || (! s -> f) || (! s -> f -> ffload))
return ERR_FATAL;
return (*s -> f -> ffload) (s, fname);
}
/*}}}*/
/*{{{ configuration */
void
scr_config (void *sp, void (*logger) (char, char *, ...), date_t *delay, date_t *expire, Bool rds)
{
script *s = (script *) sp;
MCHK (s);
if (s) {
s -> logger = logger;
if (delay)
s -> delay = *delay;
else
dat_clear (& s -> delay);
if (expire)
s -> expire = *expire;
else
dat_clear (& s -> expire);
s -> rds = False;
}
}
void
scr_set_convtable (void *sp, void *ctab)
{
script *s = (script *) sp;
MCHK (s);
if (s) {
if (s -> ctab)
cv_free (s -> ctab);
s -> ctab = ctab;
}
}
void
scr_add_convtable (void *sp, void *ctab)
{
script *s = (script *) sp;
MCHK (s);
if (s) {
if (! s -> ctab)
s -> ctab = cv_new ();
if (s -> ctab)
cv_merge (s -> ctab, ctab, True);
}
}
/*}}}*/
/*{{{ new/free/etc */
void *
scr_new (void *sp, char *typ, char *libdir)
{
script *s;
int n;
if (s = (script *) malloc (sizeof (script))) {
# ifndef NDEBUG
s -> magic = MAGIC;
# endif /* NDEBUG */
s -> sp = sp;
s -> ctab = NULL;
s -> logger = NULL;
dat_clear (& s -> delay);
dat_clear (& s -> expire);
s -> rds = False;
s -> priv = NULL;
for (n = 0; flist[n]; ++n)
if (flist[n] -> typ && (! strcmp (flist[n] -> typ, typ)))
break;
if (flist[n]) {
s -> f = flist[n];
if (s -> f -> finit)
if ((*s -> f -> finit) (s, libdir) < 0)
s = scr_free (s);
} else
s = scr_free (s);
}
return s;
}
void *
scr_free (void *sp)
{
script *s = (script *) sp;
MCHK (s);
if (s) {
if (s -> f && s -> f -> fdeinit)
(*s -> f -> fdeinit) (s);
if (s -> ctab)
cv_free (s -> ctab);
free (s);
}
return NULL;
}
int
scr_preinit (char *libdir)
{
int n;
for (n = 0; flist[n]; ++n)
if (flist[n] -> fpreinit)
if ((*flist[n] -> fpreinit) (libdir) < 0)
return -1;
return 0;
}
void
scr_postdeinit (void)
{
int n;
for (n = 0; flist[n]; ++n)
if (flist[n] -> fpostdeinit)
(*flist[n] -> fpostdeinit) ();
}
/*}}}*/

41
script.h Normal file
View File

@ -0,0 +1,41 @@
/* -*- mode: c; mode: fold -*- */
# ifndef __SCRIPT_H
# define __SCRIPT_H 1
/*{{{ typedefs */
typedef struct script script;
typedef struct {
char *typ;
int (*finit) (script *, char *);
void (*fdeinit) (script *);
int (*fexec) (script *, char *, char *);
int (*fsload) (script *, char *);
int (*ffload) (script *, char *);
int (*fpreinit) (char *);
void (*fpostdeinit) (void);
} funcs;
struct script {
# ifndef NDEBUG
# define MAGIC MKMAGIC ('s', 'c', 'r', '\0')
long magic;
# endif /* NDEBUG */
void *sp;
void *ctab;
void (*logger) (char, char *, ...);
date_t delay;
date_t expire;
Bool rds;
void *priv;
funcs *f;
};
/*}}}*/
extern char *scr_convert (script *s, char *str);
# ifdef SCRIPT_SLANG
extern funcs fslang;
# endif /* SCRIPT_SLANG */
# ifdef SCRIPT_LUA
extern funcs flua;
# endif /* SCRIPT_LUA */
# endif /* __SCRIPT_H */

692
slang.c Normal file
View File

@ -0,0 +1,692 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# ifdef SCRIPT_SLANG
# ifndef FLOAT_TYPE
# define FLOAT_TYPE
# endif /* FLOAT_TYPE */
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <slang.h>
# include "pager.h"
# include "script.h"
# define STARTUP "Startup.sl"
/*{{{ string class */
static char *ifmt = NULL;
static char *ffmt = NULL;
static inline char *
make_scratch (unsigned char typ, VOID_STAR p)
{
char buf[128];
buf[0] = '\0';
switch (typ) {
case INT_TYPE:
sprintf (buf, (ifmt ? ifmt : "%d"), *(int *) p);
break;
case FLOAT_TYPE:
sprintf (buf, (ffmt ? ffmt : "%f"), (double) (*(float64 *) p));
break;
}
return strdup (buf);
}
static int
binop_string (int op, unsigned char atyp, unsigned char btyp,
VOID_STAR ap, VOID_STAR bp)
{
char *scratch;
char *a, *b;
int la, lb;
int len;
int n;
char *ptr;
char *res;
scratch = NULL;
if ((atyp == STRING_TYPE) && (btyp == STRING_TYPE)) {
a = (char *) ap;
b = (char *) bp;
} else if (atyp == STRING_TYPE) {
a = (char *) ap;
scratch = make_scratch (btyp, bp);
b = scratch;
} else {
b = (char *) ap;
scratch = make_scratch (atyp, ap);
a = scratch;
}
if (! (a && b))
return 0;
res = NULL;
switch (op) {
case SLANG_PLUS:
la = strlen (a);
lb = strlen (b);
if (res = SLMALLOC (la + lb + 1)) {
strcpy (res, a);
strcat (res, b);
}
break;
case SLANG_MINUS:
la = strlen (a);
lb = strlen (b);
if (ptr = strstr (a, b)) {
if (res = SLMALLOC (la - lb + 1)) {
len = (int) ((unsigned long) ptr - (unsigned long) a);
strncpy (res, a, len);
res[len] = '\0';
strcat (res, a + len + lb);
}
} else if (res = SLMALLOC (la + 1))
strcpy (res, a);
break;
case SLANG_TIMES:
la = strlen (a);
if ((n = atoi (b)) > 0) {
if (res = SLMALLOC (la * n + 1)) {
ptr = res;
while (n-- > 0) {
strcpy (ptr, a);
while (*ptr)
++ptr;
}
}
} else if (res = SLMALLOC (2))
res[0] = '\0';
break;
case SLANG_DIVIDE:
for (ptr = a; *ptr; ++ptr)
if (! strchr (b, *ptr))
break;
if (res = SLMALLOC (strlen (ptr) + 1)) {
strcpy (res, ptr);
if (res[0]) {
for (ptr = res; *ptr; ++ptr)
;
--ptr;
while (ptr != res)
if (strchr (b, *ptr))
*ptr-- = '\0';
else
break;
}
}
break;
case SLANG_EQ:
SLang_push_integer (strcmp (a, b) == 0 ? 1 : 0);
break;
case SLANG_NE:
SLang_push_integer (strcmp (a, b) ? 1 : 0);
break;
case SLANG_GT:
SLang_push_integer (strcmp (a, b) > 0 ? 1 : 0);
break;
case SLANG_GE:
SLang_push_integer (strcmp (a, b) >= 0 ? 1 : 0);
break;
case SLANG_LT:
SLang_push_integer (strcmp (a, b) < 0 ? 1 : 0);
break;
case SLANG_LE:
SLang_push_integer (strcmp (a, b) <= 0 ? 1 : 0);
break;
default:
return 0;
}
if (scratch)
free (scratch);
if (res)
SLang_push_malloced_string (res);
return 1;
}
static int
unop_string (int op, unsigned char typ, VOID_STAR p)
{
char *s;
char *r;
int len;
s = (char *) p;
switch (op) {
case SLANG_ABS:
SLang_push_integer (strlen (s));
break;
case SLANG_SIGN:
SLang_push_integer (*s ? 1 : 0);
break;
case SLANG_SQR:
break;
case SLANG_MUL2:
len = strlen (s);
if (r = SLMALLOC (len * 2 + 1)) {
strcpy (r, s);
strcat (r, s);
SLang_push_malloced_string (r);
}
break;
case SLANG_CHS:
SLang_push_string (s);
break;
default:
return 0;
}
return 1;
}
static void
get_format (char **var)
{
char *fmt;
int fre;
if (*var) {
free (*var);
*var = NULL;
}
if (SLang_pop_string (& fmt, & fre))
return;
*var = strdup (fmt);
if (fre)
SLFREE (fmt);
}
static void
str_iformat (void)
{
get_format (& ifmt);
}
static void
str_fformat (void)
{
get_format (& ffmt);
}
static SLang_Name_Type avail_string[] = {
/* void str_iformat (string format); */
MAKE_INTRINSIC (".str_iformat", str_iformat, VOID_TYPE, 0),
/* void str_fformat (string format); */
MAKE_INTRINSIC (".str_fformat", str_fformat, VOID_TYPE, 0),
/*
MAKE_INTRINSIC (".", , _TYPE, 0),
MAKE_INTRINSIC (".function_name", c_function, TYPE, 0),
MAKE_VARIABLE (".", & , TYPE, ),
MAKE_VARIABLE (".var", &c_variable, TYPE, flag),
*/
SLANG_END_TABLE
};
static int
string_class (void)
{
if ((! SLang_register_class (STRING_TYPE, NULL, NULL)) ||
(! SLang_add_binary_op (STRING_TYPE, STRING_TYPE,
(VOID_STAR) binop_string)) ||
(! SLang_add_binary_op (STRING_TYPE, INT_TYPE,
(VOID_STAR) binop_string)) ||
(! SLang_add_binary_op (STRING_TYPE, FLOAT_TYPE,
(VOID_STAR) binop_string)) ||
(! SLang_add_unary_op (STRING_TYPE,
(VOID_STAR) unop_string)) ||
(! SLang_add_table (avail_string, "string")))
return 0;
return 1;
}
/*}}}*/
/*{{{ statics */
static Bool isinit = False;
static script *sls = NULL;
static char *slline = NULL;
static int slsiz = 0;
static SLang_Name_Type *slcb = NULL;
/*}}}*/
/*{{{ callable functions and variables */
static void
sllogger (void)
{
char *str;
int fre;
int typ;
if (SLang_pop_string (& str, & fre) ||
SLang_pop_integer (& typ))
return;
if (sls && sls -> logger) {
if (! typ)
typ = LG_INF;
(*sls -> logger) ((char) typ, "%s\n", str);
}
if (fre)
SLFREE (str);
}
static void
slcallback (void *sp, string_t *s, char_t sep, void *data)
{
int len;
char *str;
if (str = sextract (s)) {
len = strlen (str);
if (len + 2 >= slsiz) {
slsiz = len + 64;
if (! (slline = Realloc (slline, slsiz + 4)))
slsiz = 0;
}
if (slline) {
sprintf (slline, "%s%c", str, (char) sep);
if (slcb) {
SLang_push_string (slline);
SLexecute_function (slcb);
}
}
free (str);
}
}
static void
slsetcb (void)
{
char *func, *sep;
int fr1, fr2;
if (SLang_pop_string (& sep, & fr2) ||
SLang_pop_string (& func, & fr1))
return;
if (func && *func)
slcb = SLang_get_function (func);
else
slcb = NULL;
if (sls && sls -> sp)
tty_set_line_callback (sls -> sp, slcallback, sep, NULL);
if (fr1)
SLFREE (func);
if (fr2)
SLFREE (sep);
}
static void
slclrcb (void)
{
slcb = NULL;
if (sls && sls -> sp)
tty_set_line_callback (sls -> sp, NULL, NULL, NULL);
}
static void
slget_line (void)
{
SLang_push_string (slline ? slline : "");
}
static void
slhangup (void)
{
int msec;
if (SLang_pop_integer (& msec))
return;
if (sls && sls -> sp)
tty_hangup (sls -> sp, msec);
}
static int
slsend (void)
{
int ret;
char *str;
int fre;
if (SLang_pop_string (& str, & fre))
return 0;
ret = 0;
if (sls && sls -> sp)
if (tty_send_string (sls -> sp, str) != -1)
ret = 1;
if (fre)
SLFREE (str);
return ret;
}
static int
slcsend (void)
{
int ret;
char *str;
int fre;
char *rstr;
if (SLang_pop_string (& str, & fre))
return 0;
ret = 0;
if (sls && sls -> sp)
if (rstr = scr_convert (sls, str)) {
if (tty_send_string (sls -> sp, rstr) != -1)
ret = 1;
free (rstr);
}
if (fre)
SLFREE (str);
return ret;
}
static int
slexpect (void)
{
int ret;
int cnt;
char **str;
int *fre;
int *len;
int tout;
int n;
if (SLang_pop_integer (& cnt))
return -1;
ret = -1;
if ((str = (char **) malloc ((cnt + 2) * sizeof (char *))) &&
(fre = (int *) malloc ((cnt + 2) * sizeof (int))) &&
(len = (int *) malloc ((cnt + 2) * sizeof (int)))) {
for (n = cnt - 1; n >= 0; --n)
if (SLang_pop_string (& str[n], & fre[n]))
return -1;
else
len[n] = strlen (str[n]);
str[cnt] = NULL;
len[cnt] = 0;
if (SLang_pop_integer (& tout))
return -1;
if (sls && sls -> sp)
ret = tty_expect_list (sls -> sp, tout, str, len);
for (n = 0; n < cnt; ++n)
if (fre[n])
SLFREE (str[n]);
free (str);
free (fre);
free (len);
}
return ret;
}
static int
slsend_expect (void)
{
int tout;
char *str;
int fre;
int ret;
if (SLang_pop_string (& str, & fre) ||
SLang_pop_integer (& tout))
return 0;
ret = 0;
if (sls && sls -> sp)
if (tty_send_expect (sls -> sp, tout, str, NULL) != -1)
ret = 1;
if (fre)
SLFREE (str);
return ret;
}
static void
sldrain (void)
{
int secs;
if (SLang_pop_integer (& secs))
return;
if (sls && sls -> sp)
tty_drain (sls -> sp, secs);
}
static void
slcvdef (void)
{
int src, dst;
if (SLang_pop_integer (& dst) ||
SLang_pop_integer (& src))
return;
if (sls) {
if (! sls -> ctab)
sls -> ctab = cv_new ();
if (sls -> ctab)
cv_define (sls -> ctab, (char_t) src, (char_t) dst);
}
}
static void
slcvundef (void)
{
int ch;
if (SLang_pop_integer (& ch))
return;
if (sls && sls -> ctab)
cv_undefine (sls -> ctab, (char_t) ch);
}
static void
slcvinval (void)
{
int ch;
if (SLang_pop_integer (& ch))
return;
if (sls) {
if (! sls -> ctab)
sls -> ctab = cv_new ();
if (sls -> ctab)
cv_invalid (sls -> ctab, (char_t) ch);
}
}
static void
slconv (void)
{
char *str;
int fre;
char *rstr;
if (SLang_pop_string (& str, & fre))
return;
if (sls)
rstr = scr_convert (sls, str);
else
rstr = NULL;
SLang_push_string (rstr ? rstr : str);
if (rstr)
free (rstr);
if (fre)
SLFREE (str);
}
static int no_err = NO_ERR,
err_fail = ERR_FAIL,
err_fatal = ERR_FATAL,
err_abort = ERR_ABORT;
static date_t sldelay, slexpire;
static int slrds = 0;
static int xFalse = (int) False,
xTrue = (int) True;
static char xNull_String[2] = "";
/*}}}*/
/*{{{ function/variable table */
static SLang_Name_Type avail[] = {
/* void logger (string str); */
MAKE_INTRINSIC (".logger", sllogger, VOID_TYPE, 0),
/* void setcb (string func, string sep); */
MAKE_INTRINSIC (".setcb", slsetcb, VOID_TYPE, 0),
/* void clrcb (void); */
MAKE_INTRINSIC (".clrcb", slclrcb, VOID_TYPE, 0),
/* string line (void); */
MAKE_INTRINSIC (".line", slget_line, VOID_TYPE, 0),
/* void hangup (int msec); */
MAKE_INTRINSIC (".hangup", slhangup, VOID_TYPE, 0),
/* int send (string str); */
MAKE_INTRINSIC (".send", slsend, INT_TYPE, 0),
/* int csend (string str); */
MAKE_INTRINSIC (".csend", slcsend, INT_TYPE, 0),
/* int expect (int tout, string e1, ..., string en,
int cnt); */
MAKE_INTRINSIC (".expect", slexpect, INT_TYPE, 0),
/* int send_expect (int tout, string str); */
MAKE_INTRINSIC (".send_expect", slsend_expect, INT_TYPE, 0),
/* void drain (int secs); */
MAKE_INTRINSIC (".drain", sldrain, INT_TYPE, 0),
/* void cvdef (int src, int dst); */
MAKE_INTRINSIC (".cvdef", slcvdef, VOID_TYPE, 0),
/* void cvundef (int ch); */
MAKE_INTRINSIC (".cvundef", slcvundef, VOID_TYPE, 0),
/* void cvinval (int ch); */
MAKE_INTRINSIC (".cvinval", slcvinval, VOID_TYPE, 0),
/* string conv (string str); */
MAKE_INTRINSIC (".conv", slconv, VOID_TYPE, 0),
MAKE_VARIABLE (".NO_ERR", & no_err, INT_TYPE, 1),
MAKE_VARIABLE (".ERR_FAIL", & err_fail, INT_TYPE, 1),
MAKE_VARIABLE (".ERR_FATAL", & err_fatal, INT_TYPE, 1),
MAKE_VARIABLE (".ERR_ABORT", & err_abort, INT_TYPE, 1),
MAKE_VARIABLE (".delay_day", & sldelay.day, INT_TYPE, 1),
MAKE_VARIABLE (".delay_mon", & sldelay.mon, INT_TYPE, 1),
MAKE_VARIABLE (".delay_year", & sldelay.year, INT_TYPE, 1),
MAKE_VARIABLE (".delay_hour", & sldelay.hour, INT_TYPE, 1),
MAKE_VARIABLE (".delay_min", & sldelay.min, INT_TYPE, 1),
MAKE_VARIABLE (".delay_sec", & sldelay.sec, INT_TYPE, 1),
MAKE_VARIABLE (".expire_day", & slexpire.day, INT_TYPE, 1),
MAKE_VARIABLE (".expire_mon", & slexpire.mon, INT_TYPE, 1),
MAKE_VARIABLE (".expire_year", & slexpire.year, INT_TYPE, 1),
MAKE_VARIABLE (".expire_hour", & slexpire.hour, INT_TYPE, 1),
MAKE_VARIABLE (".expire_min", & slexpire.min, INT_TYPE, 1),
MAKE_VARIABLE (".expire_sec", & slexpire.sec, INT_TYPE, 1),
MAKE_VARIABLE (".rds", & slrds, INT_TYPE, 1),
MAKE_VARIABLE (".False", & xFalse, INT_TYPE, 1),
MAKE_VARIABLE (".True", & xTrue, INT_TYPE, 1),
MAKE_VARIABLE (".Null_String", & xNull_String, STRING_TYPE, 1),
/*
MAKE_INTRINSIC (".", , _TYPE, 0),
MAKE_INTRINSIC (".function_name", c_function, TYPE, 0),
MAKE_VARIABLE (".", & , TYPE, ),
MAKE_VARIABLE (".var", &c_variable, TYPE, flag),
*/
SLANG_END_TABLE
};
/*}}}*/
/*{{{ init/deinit */
static int
slang_init (script *s, char *libdir)
{
char *fname;
if (! isinit) {
if ((! init_SLang ()) || (! init_SLmath ()) ||
(! init_SLunix ()) || (! init_SLfiles ()) ||
(! string_class ()) || (! SLang_add_table (avail, "yaps")))
return -1;
if (libdir && (fname = malloc (strlen (libdir) + sizeof (STARTUP) + 4))) {
sprintf (fname, "%s/%s", libdir, STARTUP);
if (access (fname, R_OK) != -1)
if ((! SLang_load_file (fname)) || SLang_Error)
SLang_restart (1);
free (fname);
}
isinit = True;
}
if (slline)
slline[0] = '\0';
return NO_ERR;
}
static void
slang_deinit (script *s)
{
if (slline) {
free (slline);
slline = NULL;
}
slsiz = 0;
}
/*}}}*/
/*{{{ execute */
static int
slang_execute (script *s, char *label, char *parm)
{
SLang_Name_Type *func;
int ret;
ret = NO_ERR;
if (func = SLang_get_function (label)) {
SLang_push_string (parm ? parm : "");
sldelay = s -> delay;
slexpire = s -> expire;
slrds = s -> rds;
sls = s;
SLexecute_function (func);
if (sls -> sp)
tty_set_line_callback (sls -> sp, NULL, NULL, NULL);
sls = NULL;
if (SLang_Error || SLang_pop_integer (& ret)) {
ret = ERR_FATAL;
SLang_restart (1);
}
}
return ret;
}
/*}}}*/
/*{{{ loading */
static int
slang_load_string (script *s, char *scr)
{
int err;
err = ERR_FATAL;
if (SLang_load_string (scr) && (! SLang_Error))
err = NO_ERR;
else
SLang_restart (1);
return err;
}
static int
slang_load_file (script *s, char *fname)
{
int err;
err = ERR_FATAL;
if (SLang_load_file (fname) && (! SLang_Error))
err = NO_ERR;
else
SLang_restart (1);
return err;
}
/*}}}*/
/*{{{ preinit/postdeinit/scriptentry */
static int
slang_preinit (char *libdir)
{
return slang_init (NULL, libdir);
}
static void
slang_postdeinit (void)
{
slang_deinit (NULL);
}
funcs fslang = {
"SLang",
slang_init,
slang_deinit,
slang_execute,
slang_load_string,
slang_load_file,
slang_preinit,
slang_postdeinit
};
/*}}}*/
# endif /* SCRIPT_SLANG */

725
tap.c Normal file
View File

@ -0,0 +1,725 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include "pager.h"
/*{{{ definitions & typedefs */
# define DEF_SERVICE_TYPE "PG"
# define DEF_TERMINAL_TYPE '1'
# define CHKTYPE(sss,ccc) ((((sss)[0] & 0xff) << 16) | (((sss)[1] & 0xff) << 8) | ((ccc) & 0xff))
# define CHKSTYPE(cc1,cc2,cc3) ((((cc1) & 0xff) << 16) | (((cc2) & 0xff) << 8) | ((cc3) & 0xff))
typedef enum {
None,
PG1
} Type;
typedef struct _rmsg {
string_t *str;
int rnr;
struct _rmsg *next;
} rmsg;
typedef struct {
# ifndef NDEBUG
# define MAGIC MKMAGIC ('t', 'a', 'p', '\0')
long magic;
# endif /* NDEBUG */
void *sp; /* the serial connection */
void *ctab; /* the conversion table */
void (*logger) (char, char *, ...);
string_t
*callid; /* caller id */
Type typ; /* the connection type */
Bool pre16; /* if p.version before 1.6 is used */
/* timing and retry values */
int t1, t2, t3, t4, t5;
int n1, n2, n3;
int licnt, locnt;
rmsg *r, *prv; /* response message(s) on callback */
} tap;
/*}}}*/
/*{{{ convert */
static int
field_convert (tap *t, string_t *ptr, string_t *cf)
{
int n;
int ch;
cf -> str = NULL;
cf -> size = ptr -> len + 32;
if (! (cf -> str = malloc (cf -> size + 2)))
return ERR_FATAL;
for (n = 0, cf -> len = 0; n < ptr -> len; ++n) {
if (cf -> len + 2 >= cf -> size)
if (! sexpand (cf, cf -> size + 32))
return ERR_FATAL;
ch = cv_conv (t -> ctab, ptr -> str[n]);
if (ch != -1)
switch ((char_t) ch) {
case '\x0d': case '\x0a': case '\x1b':
case '\x02': case '\x03': case '\x1f':
case '\x17': case '\x04': case '\x1a':
if (! t -> pre16) {
cf -> str[cf -> len++] = '\x1a';
cf -> str[cf -> len++] = (char_t) (ch + 0x40);
}
break;
default:
cf -> str[cf -> len++] = (char_t) ch;
break;
}
}
if (cf -> str) {
cf -> str[cf -> len] = '\0';
return NO_ERR;
}
return ERR_FATAL;
}
static char chkstr[] = "0123456789:;<=>?";
static string_t **
convert_tap (tap *t, string_t **field)
{
string_t **ret;
int fcnt;
string_t *cf;
char_t *ptr;
int cnt, siz;
char_t tmp[260];
Bool needchk;
unsigned long chk;
int fld, off, len;
int n, m;
ret = NULL;
for (fcnt = 0; field[fcnt]; ++fcnt)
;
if (cf = (string_t *) malloc ((fcnt + 1) * sizeof (string_t))) {
for (fld = 0; fld < fcnt; ++fld)
if (field_convert (t, field[fld], & cf[fld]) != NO_ERR) {
while (--fld >= 0)
free (cf[fld].str);
free (cf);
break;
}
if (fld < fcnt)
return NULL;
cnt = 0;
siz = 0;
n = 0;
needchk = False;
for (fld = 0, off = 0; fld < fcnt; ) {
ptr = cf[fld].str + off;
len = cf[fld].len - off;
do {
if (! n)
tmp[n++] = '\x02';
if (len) {
tmp[n++] = *ptr++;
--len;
++off;
}
if (! len) {
off = 0;
++fld;
tmp[n++] = '\r';
if (fld == fcnt) {
tmp[n++] = '\x03';
needchk = True;
} else if (n >= 230) {
tmp[n++] = '\x17';
needchk = True;
}
} else if (n >= 250) {
tmp[n++] = '\x1f';
needchk = True;
}
if (needchk) {
needchk = False;
for (m = 0, chk = 0; m < n; ++m)
chk += tmp[m] & 0xff;
tmp[n++] = chkstr[(chk >> 8) & 0xf];
tmp[n++] = chkstr[(chk >> 4) & 0xf];
tmp[n++] = chkstr[chk & 0xf];
tmp[n++] = '\r';
tmp[n] = '\0';
if (cnt >= siz) {
siz += 4;
if (! (ret = (string_t **) Realloc (ret, (siz + 1) * sizeof (string_t *))))
return NULL;
}
if (! (ret[cnt] = snew (tmp, n))) {
while (--cnt >= 0)
sfree (ret[cnt]);
free (ret);
return NULL;
}
++cnt;
ret[cnt] = NULL;
n = 0;
}
} while (len);
}
for (fld = 0; fld < fcnt; ++fld)
free (cf[fld].str);
free (cf);
}
return ret;
}
/*}}}*/
/*{{{ callback interface for receiving response numbers */
static void
getresponse (void *sp, string_t *s, char_t ch, void *data)
{
tap *t = (tap *) data;
rmsg *r;
if (t && (! t -> pre16) && s && (s -> len > 0))
if (sisdigit (s, 0)) {
if (r = (rmsg *) malloc (sizeof (rmsg)))
if (r -> str = snew (s -> str, s -> len + 2)) {
r -> rnr = stoi (r -> str);
r -> next = NULL;
if (t -> prv)
t -> prv -> next = r;
else
t -> r = r;
t -> prv = r;
} else
free (r);
} else if ((! siscntrl (s, 0)) && (r = t -> prv) && scatc (r -> str, "\n")) {
if (sisspace (s, 0))
sdel (s, 0, 1);
scat (r -> str, s);
}
}
static void
free_resp (tap *t)
{
rmsg *tmp;
if (t) {
while (t -> r) {
tmp = t -> r;
t -> r = t -> r -> next;
sfree (tmp -> str);
free (tmp);
}
t -> prv = NULL;
}
}
static void
setcb (tap *t)
{
if (! t -> pre16) {
free_resp (t);
tty_suspend_callback (t -> sp, False);
}
}
static void
clrcb (tap *t)
{
if (! t -> pre16) {
tty_suspend_callback (t -> sp, True);
free_resp (t);
}
}
/*}}}*/
/*{{{ response handling */
static int
show_response (tap *t)
{
rmsg *r;
int nr, typ;
char *line, *ptr;
for (r = t -> r, nr = -1; r; r = r -> next) {
nr = r -> rnr;
if (line = sextract (r -> str)) {
for (ptr = line; isdigit (*ptr); ++ptr)
;
while (isspace (*ptr))
++ptr;
} else
ptr = "(none)";
switch (nr) {
case 110:
V (1, ("TAP Version: %s\n", ptr));
break;
case 111:
V (1, ("processing input\n"));
break;
case 112:
V (1, ("maximum pages entered\n"));
break;
case 113:
V (1, ("maximum time reached\n"));
break;
case 114:
V (1, ("Welcome: %s\n", ptr));
break;
case 115:
V (1, ("Byebye: %s\n", ptr));
break;
case 211:
V (1, ("Page(s) sent successful\n"));
break;
case 212:
V (1, ("Long message truncated and sent\n"));
break;
case 213:
V (1, ("Message accepted - held for deferred delivery\n"));
break;
case 214:
V (1, ("%d character maximum, message has been truncated and sent\n", atoi (ptr)));
break;
case 501:
V (1, ("Timeout during input\n"));
break;
case 502:
V (1, ("Unexpected character received before transaction\n"));
break;
case 503:
V (1, ("Excessive attempts to send/re-send a transaction with checksum errors\n"));
break;
case 504:
V (1, ("Message have to be empty for tone-only pager\n"));
break;
case 505:
V (1, ("Message must not contain characters for a numeric pager\n"));
break;
case 506:
V (1, ("Excessive invalid pages received\n"));
break;
case 507:
V (1, ("Invalid logon attempt: Incorrectly formed logon sequence\n"));
break;
case 508:
V (1, ("Invalid Logon attempt: Service type and category given is not supported\n"));
break;
case 509:
V (1, ("Invalid Logon attempt: Invalid password supplied\n"));
break;
case 510:
V (1, ("Illegal Pager ID\n"));
break;
case 511:
V (1, ("Invalid Pager ID\n"));
break;
case 512:
V (1, ("Temporarily cannot deliver to Pager ID\n"));
break;
case 513:
V (1, ("Long message rejected for exceeding maximum character length\n"));
break;
case 514:
V (1, ("Checksum error\n"));
break;
case 515:
V (1, ("Message format error\n"));
break;
case 516:
V (1, ("Message quota temporarily exceeded\n"));
break;
case 517:
V (1, ("%d character maximum, message rejected\n", atoi (ptr)));
break;
default:
typ = nr / 100;
switch (typ) {
default:
V (1, ("Response"));
break;
case 1:
V (1, ("Informal"));
break;
case 2:
V (1, ("Success"));
break;
case 5:
V (1, ("Fail"));
break;
}
V (1, (" %03d: %s\n", r -> rnr, ptr));
break;
}
if (line)
free (line);
}
return nr;
}
/*}}}*/
/*{{{ login/logout */
int
tap_login (void *tp, char *stype, char ttype, char *passwd, string_t *callid)
{
tap *t = (tap *) tp;
int n, ep;
char *cbuf;
int clen;
int err;
MCHK (t);
if ((! t) || (! t -> sp))
return ERR_ABORT;
if (! stype)
stype = DEF_SERVICE_TYPE;
else if (strlen (stype) != 2) {
V (1, ("Invalid service type %s\n", stype));
return ERR_ABORT;
}
if (! ttype)
ttype = DEF_TERMINAL_TYPE;
switch (CHKTYPE (stype, ttype)) {
case CHKSTYPE ('P', 'G', '1'):
t -> typ = PG1;
break;
}
if (t -> typ == None) {
V (1, ("Invalid service/terminal type combination\n"));
return ERR_ABORT;
}
t -> callid = sfree (t -> callid);
if (callid && (! (t -> callid = snew (callid -> str, callid -> len))))
return ERR_ABORT;
for (n = 0; n < t -> n1; ++n)
if (tty_send (t -> sp, "\r", 1) != 1)
V (1, ("Unable to send initial CR\n"));
else if (tty_expect (t -> sp, t -> t1, "ID=", 3, NULL) == 1) {
V (1, ("Send initial CR\n"));
break;
}
if (n == t -> n1) {
V (1, ("Didn't got initial response\n"));
return ERR_ABORT;
}
if (cbuf = malloc ((passwd ? strlen (passwd) : 0) + strlen (stype) + 16)) {
if (passwd)
sprintf (cbuf, "\x1b%s%c%s\r", stype, ttype, passwd);
else
sprintf (cbuf, "\x1b%s%c\r", stype, ttype);
clen = strlen (cbuf);
} else {
V (1, ("Out of memory!\n"));
return ERR_ABORT;
}
err = NO_ERR;
for (n = 0; n < t -> licnt; ++n)
if (tty_send (t -> sp, cbuf, clen) != clen)
V (1, ("Unable to send Logon request\n"));
else {
setcb (t);
ep = tty_expect (t -> sp, t -> t3, "\x06\r", 2, "ID=", 3, "\x15\r", 2, "\x1b\x04\r", 3, NULL);
if ((! t -> pre16) && t -> r)
show_response (t);
if (ep == 1) {
V (1, ("Login request accepted\n"));
break;
} else if (ep == 2)
V (1, ("Oops, got ID= again\n"));
else if (ep == 3)
V (1, ("Login request not accepted\n"));
else if (ep == 4) {
V (1, ("Logout forced\n"));
n = t -> licnt;
err = ERR_ABORT;
break;
}
}
free (cbuf);
clrcb (t);
if (n == t -> licnt) {
V (1, ("Could not login\n"));
return (err == NO_ERR) ? ERR_FATAL : err;
}
if (tty_expect (t -> sp, t -> t3, "\x1b[p\r", 4, NULL) != 1) {
V (1, ("Didn't got Go Ahead message\n"));
return ERR_FATAL;
} else
V (1, ("Successful login\n"));
return NO_ERR;
}
int
tap_logout (void *tp)
{
tap *t = (tap *) tp;
int err;
int n, ep;
MCHK (t);
if ((! t) || (! t -> sp))
return ERR_FATAL;
err = NO_ERR;
for (n = 0; n < t -> locnt; ++n)
if (tty_send (t -> sp, "\x04\r", 2) != 2)
V (1, ("Unable to send logout request\n"));
else {
setcb (t);
ep = tty_expect (t -> sp, t -> t3, "\x1b\x04\r", 3, "\x1e\r", 2, NULL);
if ((! t -> pre16) && t -> r)
show_response (t);
if (ep == 1) {
V (1, ("Message sending completed\n"));
break;
} else if (ep == 2) {
V (1, ("Message sending failed (%d)\n", ep));
err = ERR_FATAL;
n = t -> locnt;
break;
}
}
clrcb (t);
if (n == t -> locnt) {
if (err == NO_ERR)
err = ERR_FAIL;
V (1, ("Unable to logout\n"));
return err;
} else
V (1, ("Logout successful\n"));
return NO_ERR;
}
/*}}}*/
/*{{{ transmit */
int
tap_transmit (void *tp, string_t **field, Bool last)
{
tap *t = (tap *) tp;
int err;
string_t **snd;
char *ptr;
int len;
int n, m, ep;
MCHK (t);
if ((! t) || (! t -> sp))
return ERR_FATAL;
switch (t -> typ) {
default:
case None:
V (1, ("Invalid service/terminal type\n"));
return ERR_FAIL;
case PG1:
for (n = 0; field[n]; ++n)
;
if (n != 2) {
V (1, ("PG1 service/terminal type needs exactly two fields\n"));
return ERR_FAIL;
}
break;
}
err = ERR_FATAL;
if (snd = convert_tap (t, field)) {
err = NO_ERR;
for (m = 0; snd[m]; ++m) {
ptr = (char *) snd[m] -> str;
len = snd[m] -> len;
for (n = 0; n < t -> n2; ++n)
if (tty_send (t -> sp, ptr, len) != len)
V (1, ("Unable to transmit part\n"));
else {
setcb (t);
ep = tty_expect (t -> sp, t -> t3, "\x06\r", 2, "\x15\r", 2, "\x1e\r", 2, "\x1b\x04\r", 3, NULL);
if ((! t -> pre16) && t -> r)
show_response (t);
if (ep == 1) {
V (1, ("Transmited part\n"));
break;
} else if (ep == 2)
V (1, ("Can't transmit part\n"));
else if (ep == 3) {
V (1, ("Can't transmit this message\n"));
err = ERR_FAIL;
n = t -> n2;
break;
} else if (ep == 4) {
V (1, ("Logout forced\n"));
err = ERR_ABORT;
n = t -> n2;
break;
}
}
sfree (snd[m]);
clrcb (t);
if (n == t -> n2) {
V (1, ("Unable to send part %d\n", m));
for (n = m + 1; snd[n]; ++n)
sfree (snd[n]);
break;
}
}
if (! snd[m])
V (1, ("Sent message\n"));
else if (err == NO_ERR)
err = ERR_FAIL;
free (snd);
} else
V (1, ("Unable to convert message\n"));
return err;
}
/*}}}*/
/*{{{ configuration */
void
tap_config (void *tp, void (*logger) (char, char *, ...), Bool pre16)
{
tap *t = (tap *) tp;
MCHK (t);
if (t) {
t -> logger = logger;
if (t -> pre16 = pre16)
tty_suspend_callback (t -> sp, True);
}
}
void
tap_timeouts (void *tp, int t1, int t2, int t3, int t4, int t5)
{
tap *t = (tap *) tp;
MCHK (t);
if (t) {
if (t1 != -1)
t -> t1 = t1;
if (t2 != -1)
t -> t2 = t2;
if (t3 != -1)
t -> t3 = t3;
if (t4 != -1)
t -> t4 = t4;
if (t5 != -1)
t -> t5 = t5;
}
}
void
tap_retries (void *tp, int n1, int n2, int n3, int licnt, int locnt)
{
tap *t = (tap *) tp;
MCHK (t);
if (t) {
if (n1 != -1)
t -> n1 = n1;
if (n2 != -1)
t -> n2 = n2;
if (n3 != -1)
t -> n3 = n3;
if (licnt != -1)
t -> licnt = licnt;
if (locnt != -1)
t -> locnt = locnt;
}
}
void
tap_set_convtable (void *tp, void *ctab)
{
tap *t = (tap *) tp;
MCHK (t);
if (t) {
if (t -> ctab)
cv_free (t -> ctab);
t -> ctab = ctab;
}
}
static void
new_convtab (tap *t)
{
int n;
if (t -> ctab = cv_new ())
for (n = 128; n < 256; ++n)
cv_invalid (t -> ctab, (char_t) n);
}
void
tap_add_convtable (void *tp, void *ctab)
{
tap *t = (tap *) tp;
MCHK (t);
if (t) {
if (! t -> ctab)
new_convtab (t);
if (t -> ctab)
cv_merge (t -> ctab, ctab, True);
}
}
/*}}}*/
/*{{{ new/free/etc */
void *
tap_new (void *sp)
{
tap *t;
if (t = (tap *) malloc (sizeof (tap))) {
# ifndef NDEBUG
t -> magic = MAGIC;
# endif /* NDEBUG */
t -> sp = sp;
new_convtab (t);
t -> logger = NULL;
t -> callid = NULL;
t -> typ = None;
t -> pre16 = False;
t -> t1 = 2;
t -> t2 = 1;
t -> t3 = 10;
t -> t4 = 4;
t -> t5 = 8;
t -> n1 = 3;
t -> n2 = 3;
t -> n3 = 3;
t -> licnt = 3;
t -> locnt = 3;
t -> r = NULL;
t -> prv = NULL;
tty_set_line_callback (t -> sp, getresponse, "\r", (void *) t);
tty_suspend_callback (t -> sp, True);
}
return (void *) t;
}
void *
tap_free (void *tp)
{
tap *t = (tap *) tp;
MCHK (t);
if (t) {
if (t -> ctab)
cv_free (t -> ctab);
if (t -> sp)
tty_set_line_callback (t -> sp, NULL, NULL, NULL);
if (t -> callid)
sfree (t -> callid);
if (t -> r)
free_resp (t);
free (t);
}
return NULL;
}
int
tap_preinit (void)
{
return 0;
}
void
tap_postdeinit (void)
{
}
/*}}}*/

1132
tty.c Normal file

File diff suppressed because it is too large Load Diff

1801
ucp.c Normal file

File diff suppressed because it is too large Load Diff

596
util.c Normal file
View File

@ -0,0 +1,596 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <ctype.h>
# include <string.h>
# include <time.h>
# include "pager.h"
/*{{{ utility functions */
char *
skip (char *str)
{
while (*str && (! isspace (*str)))
++str;
if (*str) {
*str++ = '\0';
while (isspace (*str))
++str;
}
return str;
}
char *
skipch (char *str, char ch)
{
while (*str && (*str != ch))
++str;
if (*str) {
*str++ = '\0';
while (isspace (*str))
++str;
}
return str;
}
char *
getline (FILE *fp, Bool cont)
{
char *buf;
int size;
char *ret;
int len;
char *ptr;
size = 256;
if (! (buf = malloc (size + 2)))
return NULL;
len = 0;
while (ret = fgets (buf + len, size - len - 2, fp)) {
if (ptr = strchr (buf + len, '\n')) {
*ptr = '\0';
len += strlen (buf + len);
if (! cont)
break;
if (len && (buf[len - 1] == '\\')) {
--len;
buf[len] = '\0';
} else
break;
} else
len += strlen (buf + len);
if (len + 64 >= size) {
size += size;
if (! (buf = Realloc (buf, size + 2)))
break;
}
}
if ((! ret) && buf) {
free (buf);
buf = NULL;
}
return len || ret ? buf : NULL;
}
int
verbose_out (char *fmt, ...)
{
va_list par;
va_start (par, fmt);
vfprintf (stdout, fmt, par);
va_end (par);
return 0;
}
/*}}}*/
/*{{{ string_t handling */
string_t *
snewc (char *str)
{
string_t *s;
if (s = (string_t *) malloc (sizeof (string_t))) {
s -> str = NULL;
if (str) {
s -> len = strlen (str);
s -> size = s -> len + 1;
if (s -> str = (char_t *) malloc (sizeof (char_t) * s -> size))
memcpy (s -> str, str, s -> len);
else {
free (s);
s = NULL;
}
} else {
s -> len = 0;
s -> size = 0;
}
}
return s;
}
string_t *
snew (char_t *str, int len)
{
string_t *s;
if (s = (string_t *) malloc (sizeof (string_t))) {
s -> str = NULL;
s -> len = 0;
s -> size = 0;
if (len > 0)
if (s -> str = (char_t *) malloc (sizeof (char_t) * (len + 1))) {
s -> size = len + 1;
if (str) {
s -> len = len;
memcpy (s -> str, str, len);
} else
s -> len = 0;
} else {
free (s);
s = NULL;
}
}
return s;
}
Bool
sexpand (string_t *s, int nsize)
{
if (s && (nsize + 2 > s -> size)) {
s -> size = nsize + 2;
if (! (s -> str = (char_t *) Realloc (s -> str, sizeof (char_t) * s -> size))) {
s -> size = 0;
s -> len = 0;
return False;
}
}
return True;
}
Bool
scopy (string_t *dst, string_t *src)
{
if (dst && src && sexpand (dst, src -> len + 1)) {
if (src -> str) {
memcpy (dst -> str, src -> str, src -> len);
dst -> len = src -> len;
} else
dst -> len = 0;
return True;
}
return False;
}
Bool
scat (string_t *dst, string_t *src)
{
if (dst && src && sexpand (dst, dst -> len + src -> len + 1)) {
if (src -> str) {
memcpy (dst -> str + dst -> len, src -> str, src -> len);
dst -> len += src -> len;
}
return True;
}
return False;
}
static Bool
dostr (string_t *dst, char *src, Bool (*func) (string_t *, string_t *))
{
Bool ret;
string_t *rsrc;
ret = False;
if (dst)
if (src) {
if (rsrc = snewc (src)) {
ret = (*func) (dst, rsrc);
sfree (rsrc);
}
} else
ret = True;
return ret;
}
Bool
scopyc (string_t *dst, char *src)
{
return dostr (dst, src, scopy);
}
Bool
scatc (string_t *dst, char *src)
{
return dostr (dst, src, scat);
}
string_t *
scut (string_t *str, int start, int len)
{
string_t *res;
if (len < 0)
len = str ? str -> len - start : 0;
if (res = snew (NULL, len + 1)) {
if (str -> len > start) {
if (str -> len - start < len)
len = str -> len - start;
} else
len = 0;
if (len > 0)
memcpy (res -> str, str -> str + start, len);
res -> len = len;
}
return res;
}
void
sdel (string_t *str, int start, int len)
{
int size;
if (str -> len > start) {
if (str -> len - start < len)
len = str -> len - start;
} else
len = 0;
if (len > 0) {
size = str -> len - (start + len);
if (size > 0)
memcpy (str -> str + start, str -> str + start + len, str -> len - (start + len));
str -> len -= len;
}
}
Bool
sput (string_t *str, string_t *ins, int pos, int len)
{
if ((len < 0) || (len > ins -> len))
len = ins -> len;
if (len + pos >= str -> size)
if (! sexpand (str, len + pos + 1))
return False;
memcpy (str -> str + pos, ins -> str, len);
if (str -> len < len + pos)
str -> len = len + pos;
return True;
}
Bool
sputc (string_t *str, char *ins, int pos, int len)
{
Bool ret;
string_t *rins;
ret = False;
if (str && ins && (rins = snewc (ins))) {
ret = sput (str, rins, pos, len);
sfree (rins);
}
return ret;
}
char *
sextract (string_t *s)
{
char *ret;
ret = NULL;
if (s)
if (ret = malloc (s -> len + 1))
if (s -> str) {
memcpy (ret, s -> str, s -> len);
ret[s -> len] = '\0';
} else
ret[0] = '\0';
return ret;
}
char *
schar (string_t *s)
{
if (s) {
if (s -> len + 1>= s -> size)
sexpand (s, s -> len + 2);
if (s -> len + 1 < s -> size) {
s -> str[s -> len] = '\0';
return (char *) s -> str;
}
}
return NULL;
}
void *
sfree (string_t *s)
{
if (s) {
if (s -> str)
free (s -> str);
free (s);
}
return NULL;
}
void
srelease (string_t *s)
{
if (s -> size + 1 > s -> len) {
s -> size = s -> len + 1;
if (! (s -> str = (char_t *) Realloc (s -> str, sizeof (char_t) * (s -> size + 2)))) {
s -> size = 0;
s -> len = 0;
}
}
}
Bool
siscntrl (string_t *s, int pos)
{
return (s && (pos >= 0) && (pos < s -> len) && iscntrl (s -> str[pos])) ? True : False;
}
Bool
sisspace (string_t *s, int pos)
{
return (s && (pos >= 0) && (pos < s -> len) && isspace (s -> str[pos])) ? True : False;
}
Bool
sisdigit (string_t *s, int pos)
{
return (s && (pos >= 0) && (pos < s -> len) && isdigit (s -> str[pos])) ? True : False;
}
int
stoi (string_t *s)
{
int ret;
ret = 0;
if (s && s -> str) {
s -> str[s -> len] = '\0';
ret = atoi ((char *) s -> str);
}
return ret;
}
/*}}}*/
/*{{{ date_t handling */
# if ! HAVE_MEMSET && ! HAVE_BZERO
static void
dozero (void *p, int len)
{
unsigned char *ptr = (char *) p;
while (len-- > 0)
*ptr++ = 0;
}
# endif /* ! HAVE_MEMSET && ! HAVE_BZERO */
date_t *
dat_free (date_t *d)
{
if (d)
free (d);
return NULL;
}
date_t *
dat_parse (char *str)
{
date_t *d;
time_t tim;
struct tm *tt;
struct tm tm;
Bool add;
char *ptr, *sav;
char *p1, *p2;
int mode;
int n, val;
char sep;
date_t tmp;
d = NULL;
if ((! str) || (str = strdup (str))) {
if (d = (date_t *) malloc (sizeof (date_t))) {
time (& tim);
if (tt = localtime (& tim)) {
d -> day = tt -> tm_mday;
d -> mon = tt -> tm_mon + 1;
d -> year = tt -> tm_year + 1900;
d -> hour = tt -> tm_hour;
d -> min = tt -> tm_min;
d -> sec = tt -> tm_sec;
} else {
d -> day = 1;
d -> mon = 1;
d -> year = 1970;
d -> hour = 0;
d -> min = 0;
d -> sec = 0;
}
if (str && strcmp (str, "now")) {
if (*str == '+') {
add = True;
ptr = str + 1;
} else {
add = False;
ptr = str;
}
tmp.day = -1;
tmp.mon = -1;
tmp.year = -1;
tmp.hour = -1;
tmp.min = -1;
tmp.sec = -1;
while (*ptr) {
sav = ptr;
ptr = skip (ptr);
if (strchr (sav, '.')) {
sep = '.';
mode = 1;
} else if (strchr (sav, '/')) {
sep = '/';
mode = 2;
} else if (strchr (sav, ':')) {
sep = ':';
mode = 3;
} else {
sep = '\0';
mode = 0;
}
for (p1 = sav, n = 0; *p1; ++n) {
p2 = p1;
p1 = skipch (p1, sep);
val = atoi (p2);
switch (mode) {
case 0:
tmp.sec = 0;
if (val < 30) {
tmp.hour = val;
tmp.min = 0;
} else {
tmp.hour = val / 60;
tmp.min = val % 60;
}
break;
case 1:
if (n == 0)
tmp.day = val;
else if (n == 1)
tmp.mon = val;
else if (n == 2) {
if ((! add) && (val < 1900))
val += 1900;
tmp.year = val;
}
break;
case 2:
if (n == 0)
tmp.mon = val;
else if (n == 1)
tmp.day = val;
else if (n == 2) {
if ((! add) && (val < 1900))
val += 1900;
tmp.year = val;
}
break;
case 3:
if (n == 0) {
tmp.hour = val;
tmp.min = 0;
tmp.sec = 0;
} else if (n == 1)
tmp.min = val;
else if (n == 2)
tmp.sec = val;
break;
}
}
}
if (add) {
if (tmp.day != -1)
d -> day += tmp.day;
if (tmp.mon != -1)
d -> mon += tmp.mon;
if (tmp.year != -1)
d -> year += tmp.year;
if (tmp.hour != -1)
d -> hour += tmp.hour;
if (tmp.min != -1)
d -> min += tmp.min;
if (tmp.sec != -1)
d -> sec += tmp.sec;
} else {
if (tmp.day != -1)
d -> day = tmp.day;
if (tmp.mon != -1)
d -> mon = tmp.mon;
if (tmp.year != -1)
d -> year = tmp.year;
if (tmp.hour != -1)
d -> hour = tmp.hour;
if (tmp.min != -1)
d -> min = tmp.min;
if (tmp.sec != -1)
d -> sec = tmp.sec;
}
# if HAVE_MEMSET
memset (& tm, 0, sizeof (tm));
# elif HAVE_BZERO
bzero (& tm, sizeof (tm));
# else
dozero (& tm, sizeof (tm));
# endif /* ! HAVE_MEMSET && ! HAVE_BZERO */
tm.tm_mday = d -> day;
tm.tm_mon = d -> mon - 1;
tm.tm_year = d -> year - 1900;
tm.tm_hour = d -> hour;
tm.tm_min = d -> min;
tm.tm_sec = d -> sec;
tm.tm_isdst = tt -> tm_isdst;
if (mktime (& tm) == (time_t) -1)
d = dat_free (d);
else {
d -> day = tm.tm_mday;
d -> mon = tm.tm_mon + 1;
d -> year = tm.tm_year + 1900;
d -> hour = tm.tm_hour;
d -> min = tm.tm_min;
d -> sec = tm.tm_sec;
}
}
}
if (str)
free (str);
}
return d;
}
int
dat_diff (date_t *d1, date_t *d2)
{
int v1, v2;
if (d1)
v1 = (((((d1 -> year * 12 + d1 -> mon) * 31 + d1 -> day) * 24 + d1 -> hour) * 60 + d1 -> min) * 60 + d1 -> sec);
else
v1 = 0;
if (d2)
v2 = (((((d2 -> year * 12 + d2 -> mon) * 31 + d2 -> day) * 24 + d2 -> hour) * 60 + d2 -> min) * 60 + d2 -> sec);
else
v2 = 0;
return v2 - v1;
}
void
dat_clear (date_t *d)
{
d -> day = 0;
d -> mon = 0;
d -> year = 0;
d -> hour = 0;
d -> min = 0;
d -> sec = 0;
}
void
dat_localtime (date_t *d)
{
time_t tim;
struct tm *tt;
time (& tim);
if (tt = localtime (& tim)) {
d -> day = tt -> tm_mday;
d -> mon = tt -> tm_mon + 1;
d -> year = tt -> tm_year + 1900;
d -> hour = tt -> tm_hour;
d -> min = tt -> tm_min;
d -> sec = tt -> tm_sec;
} else
dat_clear (d);
}
/*}}}*/

126
valid.c Normal file
View File

@ -0,0 +1,126 @@
/* -*- mode: c; mode: fold -*- */
# include "config.h"
/*# undef HAVE_REGEX_H*/
# include <stdlib.h>
# include <string.h>
# include "pager.h"
# include "valid.h"
valid_t *
v_new (char *pattern)
{
valid_t *v;
# if ! HAVE_REGEX_H
int cnt, siz;
char *ptr, *sav;
int n;
# endif /* ! HAVE_REGEX_H */
if (v = (valid_t *) malloc (sizeof (valid_t))) {
# if HAVE_REGEX_H
if (regcomp (& v -> r, pattern, REG_EXTENDED)) {
free (v);
v = NULL;
}
# else /* HAVE_REGEX_H */
v -> pats = NULL;
v -> lens = NULL;
v -> malways = 0;
if (! strcmp (pattern, "-"))
v -> malways = 1;
else if (pattern = strdup (pattern)) {
cnt = 0;
siz = 0;
for (ptr = pattern; ptr; ) {
sav = ptr;
if (ptr = strchr (ptr, '|'))
*ptr++ = '\0';
if (cnt >= siz) {
siz += 4;
if (! (v -> pats = Realloc (v -> pats, (siz + 1) * sizeof (char *))))
break;
}
if (! (v -> pats[cnt] = strdup (sav))) {
while (--cnt >= 0)
free (v -> pats[cnt]);
free (v -> pats);
v -> pats = NULL;
break;
}
++cnt;
}
free (pattern);
if (v -> pats) {
v -> pats[cnt] = NULL;
if (! (v -> lens = (int *) malloc ((cnt + 1) * sizeof (int)))) {
for (n = 0; n < cnt; ++n)
free (v -> pats[n]);
free (v -> pats);
v -> pats = NULL;
} else
for (n = 0; n < cnt; ++n)
v -> lens[n] = strlen (v -> pats[n]);
}
if (! v -> pats) {
free (v);
v = NULL;
}
}
# endif /* HAVE_REGEX_H */
}
return v;
}
Bool
v_alidate (valid_t *v, char *str, int *start, int *end)
{
Bool ret = False;
# if HAVE_REGEX_H
regmatch_t mt;
if (! regexec (& v -> r, str, 1, & mt, 0)) {
*start = mt.rm_so;
*end = mt.rm_eo;
ret = True;
}
# else /* HAVE_REGEX_H */
int n;
if (v -> pats) {
for (n = 0; v -> pats[n]; ++n)
if (! strncmp (v -> pats[n], str, v -> lens[n]))
break;
if (v -> pats[n]) {
*start = 0;
*end = v -> lens[n];
ret = True;
}
} else if (v -> malways) {
*start = 0;
*end = 0;
ret = True;
}
# endif /* HAVE_REGEX_H */
return ret;
}
void
v_free (valid_t *v)
{
# if HAVE_REGEX_H
regfree (& v -> r);
# else /* HAVE_REGEX_H */
int n;
if (v -> pats) {
for (n = 0; v -> pats[n]; ++n)
free (v -> pats[n]);
free (v -> pats);
}
if (v -> lens) {
free (v -> lens);
v -> lens = NULL;
}
# endif /* HAVE_REGEX_H */
free (v);
}

21
valid.h Normal file
View File

@ -0,0 +1,21 @@
/* -*- mode: c; mode: fold -*- */
# ifndef __VALID_H
# define __VALID_H 1
# if HAVE_REGEX_H
# include <regex.h>
# endif /* HAVE_REGEX_H */
typedef struct {
# if HAVE_REGEX_H
regex_t r;
# else /* HAVE_REGEX_H */
char **pats;
int *lens;
int malways;
# endif /* HAVE_REGEX_H */
} valid_t;
extern valid_t *v_new (char *pattern);
extern Bool v_alidate (valid_t *v, char *str, int *start, int *end);
extern void v_free (valid_t *v);
# endif /* __VALID_H */

19
yaps.1 Normal file
View File

@ -0,0 +1,19 @@
.TH YAPS 1 "V 0.92 21. May 1997"
.SH NAME
yaps \- Yet Another Pager Software
.SH SYNOPSIS
yaps [opts] [parameter]
.SH DESCRIPTION
Sorry, this manual page is currently more or less empty. See the user
documentation
.B yaps.html
or
.BR yaps.doc .
.SH AUTHOR
Written and copyrighted by Ulrich Dessauer, Germering, Germany. See file
.B COPYRIGHT
and
.B COPYING.GPL
for details on usage and warrenty.
.SH BUGS
Perhaps a lot as this is considered as alpha software.

2489
yaps.c Normal file

File diff suppressed because it is too large Load Diff

910
yaps.doc Normal file
View File

@ -0,0 +1,910 @@
Table of Contents
1. Introduction
2. Installation
3. Configuration
4. Command Line
5. Sending/Expecting Syntax
6. Scripting
7. Examples
8. Changelog
Introduction
Welcome to Yaps, Yet Another Paging Package. The program is used to
send textual messages to a remote paging device using a modem gateway.
Many pager companies offer such modem gateways and are using specific
protocols. The most often used one, TAP is implemented beside others
(more or less complete.) This command line program uses a global and a
private configuration file to get information about each paging
service, installed modems and possibly other.
As the main part is implemented as a library it is not very
complicated to write a client/server solution. For the legal status
see the File Copying.
Installation
The software is written, tested and designed on and for Unix(tm) like
operating systems and requires the so called Posix system calls and
function library. Gnumake and GCC are required, too (or some changes
to the Makefile and the code may be neccessary.) It is known to run at
least on following operating systems:
* Linux (native system)
* Solaris 2.5.1 (Frank Käfer)
* SunOS 4.1.3 aka Solaris 1.1 (Frank Käfer)
(more may follow.)
Typically these steps should be enough to install the package:
Edit Config
For GCC the settings of CC and CFLAGS should be okay. Define
SLANG=True, if you like to use the SLang scripting language,
which can be found on space.mit.edu. Install it somewhere the
compiler can find it. Define LUA=True for using the lua
scripting language, which is located on ftp.icad.puc-rio.br.
READ THE COPYRIGHT RELATED FILES OF EACH PACKAGE BEFORE
INSTALLING IT!
Edit config.h
This is used to adapt the software to various variants of
Unix(tm). If you do not have a regex.h file, either set
HAVE_REGEX_T to zero or install the GNU regular expression
library. Be sure the library and includefile can be found by
the compiler and the name of the header file is regex.h,
otherwise make a (symbolic) link to this file. Add the libary
to EXLIB = in Config.
make depend
This create the dependency file which will be included during
make.
make (or make all)
This compiles the library, the program driver and links the
program. The documentation is created using lynx. As lynx is
not on every system the already formated result is included as
well.
make install
This copies the program and the global configuration file to
the final location. This step requires a working install
program. If this is missing, you have to install it by hand
(well, two files should not be too much.)
Edit the global configuration file
With your favorite editor you should edit the global
configuration file (which will be installed as /etc/yaps.rc on
default) and change everything as required. See the
Configuration section for a detailed description of the
contents of the file.
Done!
You may play around with your configuration until you are
satisfied, but this fine tuning is up to you.
If you have problems during compilation, feel free to send me a mail.
Configuration
The program reads first the global configuration file /etc/yaps.rc
(when not overwritten by command line switch), then the local one in
~/.yapsrc to get its configuration. Command line options may overwrite
some settings in these files. Both configuration files have the same
layout where the local one can overwrite settings of the global one.
Each file is seperated in sections, where a section is started with
[<name>] or [] for the global section. When a file is opened all
entries are stored in the global section until a section name appears.
If a section expression [..] is followed by a comma seperate list of
names, then these are the fallback sections, i.e. variables not found
int his section are taken from the fallback sections before trying the
global one.
If the first character is a bar (|) then the rest is taken as a
filename to be included at this point. The current section is NOT
affected by this call. Each line may have exactly one entry (or a
comment starting with a hash sign in the first column) where the
variable name is seperated by whitespaces from its value. If the first
character of the value is a backslash (\), then this is removed. This
allowes creating values starting with whitespaces. But if a value
should start with a backslash itself, be sure to escape it with
another backslash. A line can split over several physical line, if
each line (expect the last one) ends with a backslash. If the value
starts with an opening curly bracket ({) then all lines up to the
closing curly bracket (}) in the first column are taken as the value
for that variable. The brackets (and the lines where they appear) are
not part of the value.
The value may either be textual, numeric, boolean or a check
expression. Textual values are starting with the first non whitespace
character and continue to the end of the line. Numeric values are a
sequence of digits which are parsed by the C-function atoi(3). Boolean
may either be T, Y, 1 or + for true and F, N, 0 or - for false (or in
greater detail, everything that is not true is false.) Case is here
not significant. The check is a sequence of special characters which
must match the given string. If a > is found, then the rest is
optional, but must still match, if a < is found and the string is not
at its end, it is considered as too long. These characters are
supported:
* 1 numeric
* h hexadecimal
* l lowercase
* u uppercase
* a alpha
* n alphanumeric
* p printable
* x ascii
* every other character matches every character
Some simple examples:
* >1 A string with unlimited length, but made only out of numeric
values.
* aaa A string of exact three alpha characters.
* >xxxx< A string of length zero up to four made of ASCII
characters.
* ....>1111< A string starting with exact four characters, followed
by zero to four numeric characters.
Alternative one can specify the check by a description, if the
checkstring is prefixed by a plus sign. This is then a comma seperated
list of checks, which are seperated by an equal sign into variable and
value. These variables are supported:
* type=<type> Each character in the string must match the type,
which may be one of the following:
+ numeric only digits are allowed.
+ sedecimal only hexdigits are allowed.
+ lower only lowercase characters are allowed.
+ upper only uppercase characters are allowed.
+ alpha only alpha characters are allowed.
+ alphanumeric only digits and alpha characters are allowed.
+ print only printable characters are allowed.
+ ascii only ASCII characters are allowed.
* length=<length> The string must have exact this length.
* minimum=<length> The string must at least this length.
* maximum=<length> The string must not be longer than this length.
The global section defines global values or default values for other
sections. Some section may not inherit these values, but currently
there is only one and is marked as such.
Global section
These are typical found in the global section and can be overwritten
in other sections, if required.
services <text>
This is the comma seperated list of available services.
call-id <text>
If the pager allows to send the source caller id this id is
used, if not overwritten by a command line argument.
signature <text>
If this is present, then the text is appended to each message
sent to the pager (and if use-signature is True).
verbose <num>
Sets the debugging/verbosity level. The bigger the number, the
more output is generated.
logfile <text>
If the given text is a valid filename the status of a sending
request is loged there.
logstring <text>
If this is present, then only these parts are logged, which
match the given string. Currently these elements are supported:
+ message had been trasmitted successfully
- message had not been transmitted
* part had been transmitted successfully
/ part had not been transmitted
i informal logfile entry
c cost relevant informations
s session start
e session end
p protocol specific
modems <text>
This is a list of modem entries, seperated by commas.
final-report <text>
If this is set, a final report is written to the given
filename. If filename is -, then it is written to stdout. This
feature is intended for use in shell scripts, so the script
could proof which message has actual send and which one has
been rejected instead of simple rely on the return code of
yaps.
Service section
The names of these section are free to the user, but their contents
describe a paging service (or a paging company.) Following variables
are allowed for service sections:
speed <num>
The speed of the serial device.
bits-per-byte <num>
The number of bits per byte, supported are 5 to 8.
parity <text>
The used parity, this may either be none, even or odd.
stopbits <num>
The number of stopbits, supported are 1 or 2.
phone <text>
The phone number of the modem gateway for this service. If the
number contains %P and insert-pager-id is set, then the pagerid
is inserted into the phonenumber.
protocol <text>
This is the communication protocol, that this service requires.
Currently are ascii, script, tap and ucp allowed.
max-size <num>
The maximal length of a message for this service.
may-split <bool>
If this is true, then a message, which is too long will be
split into several messages.
max-messages <num>
The maximum number of messages per message, that can be send.
If this is zero, then an unlimited number of messages can be
send.
truncate <bool>
If this is set a message is not split, but truncated to the
length allowed by the provider.
use-call-id <bool>
If this is true, then the caller-id is inserted. Where it is
insert is protocol specific.
use-signature <bool>
If this is true and a signature is given, this is appended to
each message.
insert-pager-id <bool>
If this is true, then the pagerid is inserted as part of the
phone number. This implies, that only messages to the same
receipiant can be send at one call.
rm-invalids-cid <text>
Remove every character in text, that appears in the caller id.
This is designed to make a caller id more readable, but still
useable by the desired service.
rm-invalids-pid <text>
Dito for pager ids.
valid-pid <text>
This is a regular expression to check wether a pager-id is
valid for this service. If your system does not support Posix
regular expression, you can use a simple replacement. This is
just a list of strings, seperated by a bar which must match the
beginning of the pager-id.
change-pid <text>
If the pager-id matches the regular expression of valid-pid,
then this matching part is replaced with this string. If the
string is just a minus (-), then the match is removed from the
resulting pager-id.
valid-cid <text>
The same like valid-pid for the caller id.
change-cid <text>
The same like change-pid for the caller id.
conv-table <text>
The value is a filename to a character conversion table. This
affects only the message (and depending on the protocol the
pagerid) and allows transforming illegal characters to valid
ones.
convert <text>
This is comma seperated list of direct change entries of the
convertion table. If you want to include more than one pair,
the block construct using curly brackets ({..}) must be used.
Each line contains a source and a destination character, i.e.
if the source character is encountered in a message, the
destination character is used for it. There are also some
predefined convertion rules, which all starts with an asterisk:
+ *no-control control characters are suppressed
+ *control control characters are inserted literal
+ *no-8bit no characters with 8'th bit set are included
+ *8bit use also characters with 8'th bit set.
+ *numeric only numeric characters are allowed.
cost <text>
This string is used to calculate the costs for each call. The
description is a comma seperated list of variables with equal
sign seperated optional value. These variables are currently
implemented:
fixed
This tells the software, that the cost are fixed per call,
i.e. no real calculation takes place according to the used
entities.
entity-length=<entity>
This is the length of one entity. This is interpreted as a
floating point number.
max-entities=<count>
Some providers only charge until a maximum of entites had
been used and stop then charging.
dial-overhead=<seconds>
The counter starts before dialing. Typically it takes some
time from dialing to the first billed entity. This time
can be specified using this variable.
cost=<cost>
This is the cost per entity (or the whole cost on fixed
charging services). This is a floating point number.
unit=<string>
This string is appended in the logfile for the currency.
This is only of cosmetic value.
remainder=<digits>
This is the number of digits after the point in the cost
display. This value is typical two.
timetable=<description>
If a timetable entry is given, then the cost are
calculated depending on weekday and time. On fixed
charging services the value describes the complete costs
for the call, in the other case the value is the
entity-length for this day/time. The description is a
semi-colon seperated list of single entries of the form:
<Weekday(s)><from>-<to>=<value>
Each weekday is a two letter sequence (So, Mo, Tu, We, Th,
Fr, Sa) and there are three special "weekdays": Wk for
working days (monday to friday), Ss for weekend (saturday
and sunday) and al for all days. A typical example may
look like: Wk0800-1800=12;Wk1800-0800=24;Ss=24, but this
could be written shorter as: =24;Wk0800-1800=12 because
the first entry is taken as the default, if no match is
found. And the construct =24 does not contain any weekday,
so it is invalid for any regular check.
force <bool>
If a feature is requested, but this service do not support it,
the message will still be delivered, if this variable is set to
True.
can-delay <bool>
Set this to True, if the service provider accepts a delay for
sending the message.
can-expire <bool>
Set this to True, if the service provider allowes the setting
of an expiration timestamp.
can-rds <bool>
Set this to True, if the service provider allowes the request
for a delivery status.
rds <bool>
Set this to True, if can-rds is True and you always want to get
a delivery status.
check-call-id <check>
The caller id must match the check expression.
check-pager-id <check>
Each pager id must match the check expression.
Modem section
Each modem should have its own section. Following entries are
currently supported:
device <text>
The filename for the device where the modem is attached to.
lock-prefix <text>
This is the pathname to prefix the basename of the modemdevice
to create lockfiles. This can be used to enable more than one
application to use the modem.
lock-method <text>
This is a comma seperated list of locking mechanism. Currently
these flags are supported:
+ ascii PID is stored as ASCII text in lockfile.
+ binary PID is stored in machine representation in lockfile.
+ lower converts device part of lockfile to lower case.
+ upper converts device part of lockfile to upper case.
+ sysv4 append SysV4 style infos to lockfile instead of the
basename of the device.
+ timeout=<secs> tries to lock the device secs seconds.
init <text>
This is the init sequence to initialize the modem.
dial <text>
This is the dial sequence to dial a phone number with the
modem. An \L in the string will be replaced by the phone
number.
timeout <num>
This is the default timeout to wait for responses of the modem.
reset <text>
This is the sequence to reset the modem.
local-init <text>
This is used to customize an existing modem entry for different
purpose (e.g. force a specific connect rate, etc.)
Beside this the section may contain protocol specific entries to adapt
the protocol for this service.
ASCII based protocol
A \C is replaced with the caller id, if available. If request a
delivery report is switched on, a \R is replaced with 1, else with 0.
asc-timeout <num>
This is the default timeout for sequences when communicating
with the remote side.
asc-login <text>
This is the sequence to login to the remote service.
asc-logout <text>
This is the sequence to logout from the remote service.
asc-pagerid <text>
This is the sequence to embedded the pager id to be sent. \P is
replaced with the pager id.
asc-message <text>
Dito for the message, \M is replaced with the message.
asc-next <text>
This is the sequence to start the next transmission.
asc-sync <text>
If we get out of sync, then this sequence should bring us back
to a stage as if we had just loged in.
Script specific
script-type <text>
This is the scripting language to choose. Currently these are
supported: SLang, Lua.
script-name <text>
This is the name (e.g. the name of the variable containing) the
script. If the name starts with a slash or a plus sign, then
the value is treated as a filename from where the script should
be read. The plus sign is stripped off before opening the file.
scr-login <text>
This is the function/label where to start at login. If the
caller id is available (and the language supports it) the
caller id is passed as an argument.
scr-logout <text>
Dito for logout.
scr-pagerid <text>
Dito for sending the pagerid. The pagerid is passed as an
argument.
scr-message <text>
Dito for sending the message. The message is passed as an
argument.
scr-next <text>
Dito to go to the next message.
scr-sync <text>
Dito to sync to a definite state (i.e. as if we had just loged
in.)
TAP specific
tap-t1, tap-t2, tap-t3, tap-t4, tap-t5 <num>
This is the timeout for each stage defined in the TAP
specification. See there for details.
tap-n1, tap-n2, tap-n3 <num>
This is the retry count for each stage defined int the TAP
specification. See there for details.
tap-login-count <num>
This is the number of tries to login to the remote service.
tap-logout-count <num>
This is the number of tries to logout from the remote service.
UCP specific
ucp-timeout <num>
This is the time to wait for an answer from the remote system.
The documentation says that this could be about 40 to 60
seconds. This depends on the provider.
ucp-retry <num>
This specifies how often a message should be sent, until the
program gives up.
ucp-extend <bool>
If this is True then the extend UCP implementation is used,
i.e. the more complex, but more flexibel protocol (currently
only possible on german cellular phone provider Mannesmann D2.)
ucp-ds-timeout <num>
Wait a maximum of this value seconds for receiving of the
delivery status.
Alias section
The entries in this section are not able to access the global entries.
Each entry contains an alias name with its real number.
Command Line
Yaps support several command line parameter which can overwrite the
possibly used default values in the configuration files. Following
options are understood by this program (on some systems, there are is
also support for long options):
-C <configfile>, --config=<configfile>
Use cfgfile instead of the default global configuration file
/etc/yaps.rc.
-s <service>, --service=<service>
Use paging service service instead of the default of the
configuration file.
-t, --truncate
If this is set, then a message is truncated, if it is longer
than the allowed limit of the choosen service.
-c <callid>, --call-id=<callid>
Use callid as the caller id.
-S <signature>, --signature=<signature>
If signature appending is enabled by the service, use this
string as the signature.
-l <logfile>, --logfile=<logfile>
Write status of transmission to logfile.
-L <logstr>, --logstring=<logstr>
This is used to select the messages written to the logfile. See
above unter the configuration entry logstring for a detailed
description.
-f, --force
Force sending of messages, even if -d/-e/-r is not supported by
the service.
-d <date>, --delay=<date>
If the service supports it, the message is delayed and sent at
date.
-e <date>, --expire=<date>
If the service supports it, the message is deleted, if this
date is reached and the message had not been transmitted until
then.
-r, --request-delivery-status
If the service supports it, a delivery status is requested.
-R <fname>, --final-report=<fname>
A final report is written to fname (or stdout, if fname is -.)
This feature is useful to check which message had been
delivered successfully or not.
-z <fname>, --message-file=<fname>
Reads pager-ids and messages form fname. Each line contains one
pair, seperated by whitespace(s).
-v, --verbose
Increase the verbosity of yaps, more -v's give more debug
output.
-p, --print-config
This is used to printout configuration values for testing
purpose. The remaining paramters are variables to print out
with their value.
Following the options the user has to give receiver/message pairs, all
using the same service. A receiver is either the pager id itself or an
alias. If the first character is a colon, then the colon is cut off
and the remaining part is taken as an alias, if the first character is
a slash, it is cut off as well and the remaining is taken as the pager
id. If the first character is a digit, it is taken as a pager id,
otherwise as an alias. It is possible to specify multiple receiver, if
the receiver is a comma seperate list of individual receivers. If the
first character of the message is a plus sign, then the remaining
message is treated as a filename and the real message is read from
this file. If the message is just a minus (-), then the message is
read from stdin, if it is just a dot (.), then the message is empty.
The options -d and -e accept a date representation which must be
(according to option parsing) one argument, e.g. if it contains spaces
it must be quoted. If the first character of date is a plus (+) sign,
then the date is taken as an offset to the current time. All further
definitions are seperated by spaces:
* <hour>:<min>:<sec>
* <day>.<month>.<year>
* <month>/<day>/<year>
* <numeric> if less than 30 is taken as the hour
* <numeric> if greater or equal than 30 is taken as minutes
Sending/Expecting Syntax
Whenever communication over the serial line takes place the
send/expect functions are comming into play. There are three important
functions, which are called from several parts: sending of data,
expecting data and a send/expect function. Each is explained in detail
here (including the supported syntax):
Sending
Sending itself is nothing fancy, just all data will be written to the
serial line.
Expecting
Expecting means to wait for some pattern to arrive. It is possible to
expect more than one sequence and the function returns the matching
entry, a timeout or an error condition.
Send/Expect
Most communication parts call this function (which then calls the
functions above.) This function requires a string with tokens
seperated by whitespaces. A token may contain whitespaces, if the
token is enclosed in single or double quotes. These quotes (as any
other quotes) are removed during the preparse. The first character of
the token is relevant for the method to be executed. Each token is
preparsed to remove/interpret special characters. Following special
characters are interpreted:
* Backslash \
The backslash is used to escape any other special character
(inclusive quotes and the backslash itself) or to insert typical
control characters. These are supported:
+ \a -> Bel
+ \b -> Bs
+ \f -> Ff
+ \l -> Lf
+ \n -> Nl (system depended)
+ \r -> CR
+ \s -> Space
+ \t -> Tab
* Up arrow ^
This is used to insert control characters, e.g. ^M means CR.
* Percent %<nr>
This inserts optional paramter nr, if supplied.
These character initiate the behaviour of the token:
< Expect
The rest of the token is for expecting. If the token contains -
then the token is split again and each subtoken is treated as
expect/send, if the expect failed. The expect token may be
seperated by | to indicate alternatives. The expect is failed,
if an error occurs, a timeout arised or not the first
alternatives matches. The < may be appended by a numeric value,
which is used as the timeout in seconds.
! Command
To insert dynamic commands into the sequence use this
construct. Following is an optional numeric value n and a
command character. If n is not set, its default value is one.
Following characters are supported:
+ d - sleep n seconds
+ D - sleep n miliseconds
+ b - send break (length depends on n and the implementation)
+ h - hangup the line (lowering DTR by n * 0,5 seconds.)
+ o - waits for output to drain
+ < - flushes the input queue
+ > - flushes the output queue
+ f - forces the sequence to fail
+ s - forces the sequence to succeed
Any other character
This string is just send to the remote side.
Scripting
Scripting has the advantage (compared to the ASCII protocol) that one
is more flexible. As there are a lot of scripting languages around,
there will be no specific one for this package. As long as such a
language is embeddable into C programs, it should not be too
complicate to integrate it into this package.
This section explains the additional function (or simular) for the
available scripting languages. The syntax itself is explained in the
distribution of each scripting package.
SLang
Beside the new functions there is an extension to the string class, so
you can use (beside others) the plus sign to concaternate strings. One
time this part should make its way into the main SLang distribution.
Variable index
int NO_ERR;
This is the return value for a function, that ended successful.
int ERR_FAIL;
This is the return value for a function, that encountered an
error, but which allowes the script to continue.
int ERR_FATAL;
Dito, but the script should not continue any more.
int ERR_ABORT;
Dito, but no further action should take place.
int rds;
Is set to True, if a delivery status should be requested.
int delay_day, delay_mon, delay_year, delay_hour, delay_min,
delay_sec;
This is the time/date to delay the delivery of the message.
int expire_day, expire_mon, expire_year, expire_hour, expire_min,
expire_sec;
This is the time/date to expire a buffered message.
int False;
The numeric value for False.
int True;
Dito for True.
Function index
void setcb (string func, string sep);
This enable the line callback facility and stores each line
into a local variable, which will be overwritten after each new
encountered line. A line is considered as complete, if one
character in sep is received. If func is the name of a defined
function, then this function is called on every completed new
line. The line is passed as the paramter to this function.
void clrcb (void);
Clears the line callback facility.
string line (void);
Returns the last complete read in line, if the line callback
facility is enabled.
void hangup (void);
Tries to hangup, if the modem is currently off-hook. This is
done by lowering the DTR line.
int send (string str);
Sends the string to the remote side. Returns True on success,
False otherwise.
int csend (string str);
Dito, but the string is converted before it is sended to the
remote side.
int expect (int tout, string str1, ..., string strn, int cnt);
The function waits tout seconds until one of the strings is
received. If no string is received, 0 is returned, -1 on error.
Otherwise the number of the string is returned (1 for str1, 2
for str2, etc). cnt is the number of strings to wait for.
int send_expect (int tout, string expr);
This function executes the expr with its internal send/expect
evaluater and returns True, when the sequence had been executed
completely, otherwies False.
void drain (int secs);
This function reads and discards any character for secs
seconds.
void cvdef (int src, int dst);
Defines a converion rule. Every character src will be replaced
by dst. The conversion is used in csend().
void cvundef (int ch);
Undefines the conversion rule for ch.
void cvinval (int ch);
Marks the character ch as invalid.
string conv (string str);
Converts the string str using the defined conversion rules and
returns the converted string.
Lua
Examples
Here are some examples that may help you to understand the software a
bit better. First you should read the example configuration file
yaps.rc. This could be used as a base for your own global
configuration file.
Calling
Typically the program is called yaps <pagerid> <message>. pagerid is
either the exact pagerid of the receiver or an alias found in the
alias section. message is the message to send by itself. If a pager-id
leads to more than one provider, then the first is used. To force a
special service use the -s <service> switch.
Script protocol
In the contrib directory, you can find tap.sl, an example on how to
use the scripting facility to emulate a protocol. This is a minimal,
but working reimplemetation of TAP.
Changelog
This is a list of changes:
9. May 1997: V 0.90 released
+ Minor cleanup on calling sending routines
+ Added optional multiple receiver per message
+ Changing UCP to prepare the real implementation
+ Preparing the creation of a client/server solution
+ Compile configuration moved to seperate file
13. May 1997: V 0.91 released
+ Converted `char *' to `string_t *' in several places
+ Added max-messages configuration option
+ Moved some configuration stuff to config.h
+ Got UCP docu! Implemented it partial (as much as it makes
sense)
+ Added option -d/-e as UCP (in extended mode) can support it
+ Added special date handling functions for this purpose
+ Changed copyright to the GPL
+ Use transparent data in extended UCP, if characters with set
8th bit are found
+ Better message splitting
+ Added some sanity checks
22. May 1997: V 0.92 released
+ Added handling of configuration variants
+ Added include option in configuration files
+ First bugs encountered by tester fixed
+ Message can now be read from stdin, if message == '-' (idea
by <markus@mail.yezz.de>)
+ Message can now be empty, if message == '.'
+ Minor bugfixing/Makefilehandling (reported by Frank Käfer)
+ Enhanced lockfile handling, including SysV4 lockfiles
(inspirated by Frank Käfer)
+ Total rewrite of UCP sending
26. May 1997: V 0.93 released
+ UCP works again including delivery report
+ Added checking of pager id for a service
+ Added signature in configuration file
+ Added value start escaping with backslash
+ Changed checking of pager id for service
+ Automatic assign of a pager id to a service
+ Could now handle more than one service at one call
30. May 1997: V 0.94 released
+ Workaround for serial bug in sunos/solaris (by Frank Käfer)
+ If the system does not support Posix regular expression, a
simple replacement is added
+ More comments in yaps.rc (as wished by Frank Käfer ;-)
+ Change handling of control chars in TAP/pre V1.6 (hint by
<markus@mail.yezz.de>)
+ Added default conversion rules
+ Added force/-f
+ Added long options support
+ Added getopt() for systems without this function
+ Added valid-cid/change-cid/rm-invalids-cid/rm-invalids-pid
3. June 1997: V 0.95 released
+ Added final status report
+ Added a 2nd checking scheme
+ Added support for lua (another scripting language)
+ Removed porting approach, should be done by someone who has
access to such an OS.
+ Added reading of pager-id/message pairs from file
+ Added cost calculation
+ Enhanced logfile handling
14. June 1997: V 0.96 released

883
yaps.html Normal file
View File

@ -0,0 +1,883 @@
<HTML><Head><Title>
yaps
</Title></Head><Body>
<H1>Table of Contents</H1>
<Ol Compact>
<Li> <a href="#intro">Introduction</a>
<Li> <a href="#install">Installation</a>
<Li> <a href="#config">Configuration</a>
<Li> <a href="#cmdline">Command Line</a>
<Li> <a href="#syntax">Sending/Expecting Syntax</a>
<Li> <a href="#script">Scripting</a>
<Li> <a href="#sample">Examples</a>
<Li> <a href="#chlog">Changelog</a>
</Ol>
<H1 ID="intro">Introduction</H1>
Welcome to <em>Yaps</em>, Yet Another Paging Package. The program is used
to send textual messages to a remote paging device using a modem gateway.
Many pager companies offer such modem gateways and are using specific
protocols. The most often used one, TAP is implemented beside others (more
or less complete.) This command line program uses a global and a private
configuration file to get information about each paging service, installed
modems and possibly other.<P>
As the main part is implemented as a library it is not very complicated to
write a client/server solution. For the legal status see the File
<a href="COPYING.GPL">Copying</a>.
<H1 ID="install">Installation</H1>
The software is written, tested and designed on and for Unix(tm) like
operating systems and requires the so called Posix system calls and function
library. Gnumake and GCC are required, too (or some changes to the Makefile
and the code may be neccessary.) It is known to run at least on following
operating systems:
<Ul Compact>
<Li> <a href="http://www.linux.org/">Linux</a> (native system)
<Li> <a href="http://www.sun.com/">Solaris 2.5.1</a> (Frank K&auml;fer)
<Li> <a href="http://www.sun.com/">SunOS 4.1.3 aka Solaris 1.1</a> (Frank
K&auml;fer)
</Ul>
(more may follow.)<P>
Typically these steps should be enough to install the package:
<Dl>
<Dt> Edit Config
<Dd> For GCC the settings of CC and CFLAGS should be okay. Define
<strong>SLANG=True</strong>, if you like to use the SLang scripting
language, which can be found on
<a href="ftp://space.mit.edu/pub/davis/slang/">space.mit.edu</a>. Install it
somewhere the compiler can find it. Define <strong>LUA=True</strong> for
using the lua scripting language, which is located on
<a href="ftp://ftp.icad.puc-rio.br/pub/lua">ftp.icad.puc-rio.br</a>. READ
THE COPYRIGHT RELATED FILES OF EACH PACKAGE BEFORE INSTALLING IT!
<Dt> Edit config.h
<Dd> This is used to adapt the software to various variants of Unix(tm). If
you do not have a regex.h file, either set HAVE_REGEX_T to zero or install
the GNU regular expression library. Be sure the library and includefile can
be found by the compiler and the name of the header file is
<em>regex.h</em>, otherwise make a (symbolic) link to this file. Add the
libary to <em>EXLIB =</em> in Config.
<Dt> make depend
<Dd> This create the dependency file which will be included during make.
<Dt> make (or make all)
<Dd> This compiles the library, the program driver and links the program.
The documentation is created using lynx. As lynx is not on every system the
already formated result is included as well.
<Dt> make install
<Dd> This copies the program and the global configuration file to the final
location. This step requires a working <em>install</em> program. If this is
missing, you have to install it by hand (well, two files should not be too
much.)
<Dt> Edit the global configuration file
<Dd> With your favorite editor you should edit the global configuration file
(which will be installed as <em>/etc/yaps.rc</em> on default) and change
everything as required. See the <a href="#config">Configuration</a> section
for a detailed description of the contents of the file.
<Dt> Done!
<Dd> You may play around with your configuration until you are satisfied,
but this fine tuning is up to you.
</Dl><P>
If you have problems during compilation, feel free to send me a
<a href="mailto:yaps@nitmar.tnet.de">mail</a>.
<H1 ID="config">Configuration</H1>
The program reads first the global configuration file <em>/etc/yaps.rc</em>
(when not overwritten by command line switch), then the local one in
<em>~/.yapsrc</em> to get its configuration. Command line options may
overwrite some settings in these files. Both configuration files have the
same layout where the local one can overwrite settings of the global one.
Each file is seperated in sections, where a section is started with
<strong>[&lt;name&gt;]</strong> or <strong>[]</strong> for the global
section. When a file is opened all entries are stored in the global section
until a section name appears. If a section expression [..] is followed by a
comma seperate list of names, then these are the fallback sections, i.e.
variables not found int his section are taken from the fallback sections
before trying the global one.<P>
If the first character is a bar (<strong>|</strong>) then the rest is taken
as a filename to be included at this point. The current section is
<strong>NOT</strong> affected by this call.
Each line may have exactly one entry (or a comment starting with a hash sign
in the first column) where the variable name is seperated by whitespaces
from its value. If the first character of the value is a backslash
(<strong>\</strong>), then this is removed. This allowes creating values
starting with whitespaces. But if a value should start with a backslash
itself, be sure to escape it with another backslash. A line can split over
several physical line, if each line (expect the last one) ends with a
backslash. If the value starts with an opening curly bracket (<em>{</em>)
then all lines up to the closing curly bracket (<em>}</em>) in the first
column are taken as the value for that variable. The brackets (and the lines
where they appear) are not part of the value.<P>
The value may either be textual, numeric, boolean or a check expression.
Textual values are starting with the first non whitespace character and
continue to the end of the line. Numeric values are a sequence of digits
which are parsed by the C-function <em>atoi(3)</em>. Boolean may either be
<em>T</em>, <em>Y</em>, <em>1</em> or <em>+</em> for true and <em>F</em>,
<em>N</em>, <em>0</em> or <em>-</em> for false (or in greater detail,
everything that is not true is false.) Case is here not significant. The
check is a sequence of special characters which must match the given string.
If a <em>&gt;</em> is found, then the rest is optional, but must still
match, if a <em>&lt;</em> is found and the string is not at its end, it is
considered as too long. These characters are supported:
<Ul Compact>
<Li> <em>1</em> numeric
<Li> <em>h</em> hexadecimal
<Li> <em>l</em> lowercase
<Li> <em>u</em> uppercase
<Li> <em>a</em> alpha
<Li> <em>n</em> alphanumeric
<Li> <em>p</em> printable
<Li> <em>x</em> ascii
<Li> every other character matches every character
</Ul>
Some simple examples:
<Ul Compact>
<Li> <strong>&gt;1</strong> A string with unlimited length, but made only
out of numeric values.
<Li> <strong>aaa</strong> A string of exact three alpha characters.
<Li> <strong>&gt;xxxx&lt;</strong> A string of length zero up to four made
of ASCII characters.
<Li> <strong>....&gt;1111&lt;</strong> A string starting with exact four
characters, followed by zero to four numeric characters.
</Ul>
Alternative one can specify the check by a description, if the checkstring
is prefixed by a plus sign. This is then a comma seperated list of checks,
which are seperated by an equal sign into variable and value. These
variables are supported:
<Ul>
<Li> <strong>type=&lt;type&gt;</strong> Each character in the string must
match the type, which may be one of the following:
<Ul Compact>
<Li> <strong>numeric</strong> only digits are allowed.
<Li> <strong>sedecimal</strong> only hexdigits are allowed.
<Li> <strong>lower</strong> only lowercase characters are allowed.
<Li> <strong>upper</strong> only uppercase characters are allowed.
<Li> <strong>alpha</strong> only alpha characters are allowed.
<Li> <strong>alphanumeric</strong> only digits and alpha characters are
allowed.
<Li> <strong>print</strong> only printable characters are allowed.
<Li> <strong>ascii</strong> only ASCII characters are allowed.
</Ul>
<Li> <strong>length=&lt;length&gt;</strong> The string must have exact this
length.
<Li> <strong>minimum=&lt;length&gt;</strong> The string must at least this
length.
<Li> <strong>maximum=&lt;length&gt;</strong> The string must not be longer
than this length.
</Ul>
<P>
The global section defines global values or default values for other
sections. Some section may not inherit these values, but currently there is
only one and is marked as such.<P>
<H2>Global section</H2>
These are typical found in the global section and can be overwritten in
other sections, if required.
<Dl>
<Dt> services &lt;text&gt;
<Dd> This is the comma seperated list of available services.
<Dt> call-id &lt;text&gt;
<Dd> If the pager allows to send the source caller id this id is used, if
not overwritten by a command line argument.
<Dt> signature &lt;text&gt;
<Dd> If this is present, then the text is appended to each message sent to
the pager (and if use-signature is True).
<Dt> verbose &lt;num&gt;
<Dd> Sets the debugging/verbosity level. The bigger the number, the more
output is generated.
<Dt> logfile &lt;text&gt;
<Dd> If the given text is a valid filename the status of a sending request
is loged there.
<Dt> <a ID="logstr"></a>logstring &lt;text&gt;
<Dd> If this is present, then only these parts are logged, which match the
given string. Currently these elements are supported:
<Ul Plain Compact>
<Li> <strong>+</strong> message had been trasmitted successfully
<Li> <strong>-</strong> message had not been transmitted
<Li> <strong>*</strong> part had been transmitted successfully
<Li> <strong>/</strong> part had not been transmitted
<Li> <strong>i</strong> informal logfile entry
<Li> <strong>c</strong> cost relevant informations
<Li> <strong>s</strong> session start
<Li> <strong>e</strong> session end
<Li> <strong>p</strong> protocol specific
</Ul>
<Dt> modems &lt;text&gt;
<Dd> This is a list of modem entries, seperated by commas.
<Dt> final-report &lt;text&gt;
<Dd> If this is set, a final report is written to the given filename. If
filename is <strong>-</strong>, then it is written to stdout. This feature
is intended for use in shell scripts, so the script could proof which
message has actual send and which one has been rejected instead of simple
rely on the return code of yaps.
</Dl>
<H2>Service section</H2>
The names of these section are free to the user, but their contents describe
a paging service (or a paging company.) Following variables are allowed for
service sections:
<Dl>
<Dt> speed &lt;num&gt;
<Dd> The speed of the serial device.
<Dt> bits-per-byte &lt;num&gt;
<Dd> The number of bits per byte, supported are 5 to 8.
<Dt> parity &lt;text&gt;
<Dd> The used parity, this may either be <em>n</em>one, <em>e</em>ven or
<em>o</em>dd.
<Dt> stopbits &lt;num&gt;
<Dd> The number of stopbits, supported are 1 or 2.
<Dt> phone &lt;text&gt;
<Dd> The phone number of the modem gateway for this service. If the number
contains <strong>%P</strong> and <em>insert-pager-id</em> is set, then the
pagerid is inserted into the phonenumber.
<Dt> protocol &lt;text&gt;
<Dd> This is the communication protocol, that this service requires.
Currently are <em>ascii</em>, <em>script</em>, <em>tap</em> and <em>ucp</em>
allowed.
<Dt> max-size &lt;num&gt;
<Dd> The maximal length of a message for this service.
<Dt> may-split &lt;bool&gt;
<Dd> If this is true, then a message, which is too long will be split into
several messages.
<Dt> max-messages &lt;num&gt;
<Dd> The maximum number of messages per message, that can be send. If this
is zero, then an unlimited number of messages can be send.
<Dt> truncate &lt;bool&gt;
<Dd> If this is set a message is not split, but truncated to the length
allowed by the provider.
<Dt> use-call-id &lt;bool&gt;
<Dd> If this is true, then the caller-id is inserted. Where it is insert is
protocol specific.
<Dt> use-signature &lt;bool&gt;
<Dd> If this is true and a signature is given, this is appended to each
message.
<Dt> insert-pager-id &lt;bool&gt;
<Dd> If this is true, then the pagerid is inserted as part of the phone
number. This implies, that only messages to the same receipiant can be send
at one call.
<Dt> rm-invalids-cid &lt;text&gt;
<Dd> Remove every character in <em>text</em>, that appears in the caller id.
This is designed to make a caller id more readable, but still useable by the
desired service.
<Dt> rm-invalids-pid &lt;text&gt;
<Dd> Dito for pager ids.
<Dt> valid-pid &lt;text&gt;
<Dd> This is a regular expression to check wether a pager-id is valid for
this service. If your system does not support Posix regular expression, you
can use a simple replacement. This is just a list of strings, seperated by a
bar which must match the beginning of the pager-id.
<Dt> change-pid &lt;text&gt;
<Dd> If the pager-id matches the regular expression of <em>valid-pid</em>,
then this matching part is replaced with this string. If the string is just
a minus (<em>-</em>), then the match is removed from the resulting pager-id.
<Dt> valid-cid &lt;text&gt;
<Dd> The same like <em>valid-pid</em> for the caller id.
<Dt> change-cid &lt;text&gt;
<Dd> The same like <em>change-pid</em> for the caller id.
<Dt> conv-table &lt;text&gt;
<Dd> The value is a filename to a character conversion table. This affects
only the message (and depending on the protocol the pagerid) and allows
transforming illegal characters to valid ones.
<Dt> convert &lt;text&gt;
<Dd> This is comma seperated list of direct change entries of the convertion
table. If you want to include more than one pair, the block construct using
curly brackets (<em>{..}</em>) must be used. Each line contains a source and
a destination character, i.e. if the source character is encountered in a
message, the destination character is used for it. There are also some
predefined convertion rules, which all starts with an asterisk:
<Ul Compact>
<Li> <strong>*no-control</strong> control characters are suppressed
<Li> <strong>*control</strong> control characters are inserted literal
<Li> <strong>*no-8bit</strong> no characters with 8'th bit set are
included
<Li> <strong>*8bit</strong> use also characters with 8'th bit set.
<Li> <strong>*numeric</strong> only numeric characters are allowed.
</Ul>
<Dt> cost &lt;text&gt;
<Dd> This string is used to calculate the costs for each call. The
description is a comma seperated list of variables with equal sign seperated
optional value. These variables are currently implemented:
<Dl Compact>
<Dt> fixed
<Dd> This tells the software, that the cost are fixed per call, i.e.
no real calculation takes place according to the used entities.
<Dt> entity-length=&lt;entity&gt;
<Dd> This is the length of one entity. This is interpreted as a
floating point number.
<Dt> max-entities=&lt;count&gt;
<Dd> Some providers only charge until a maximum of entites had
been used and stop then charging.
<Dt> dial-overhead=&lt;seconds&gt;
<Dd> The counter starts before dialing. Typically it takes some
time from dialing to the first billed entity. This time can
be specified using this variable.
<Dt> cost=&lt;cost&gt;
<Dd> This is the cost per entity (or the whole cost on fixed charging
services). This is a floating point number.
<Dt> unit=&lt;string&gt;
<Dd> This string is appended in the logfile for the currency. This is
only of cosmetic value.
<Dt> remainder=&lt;digits&gt;
<Dd> This is the number of digits after the point in the cost display.
This value is typical two.
<Dt> timetable=&lt;description&gt;
<Dd> If a timetable entry is given, then the cost are calculated
depending on weekday and time. On fixed charging services the
value describes the complete costs for the call, in the other
case the value is the entity-length for this day/time. The
description is a semi-colon seperated list of single entries of
the form:<BR>
<strong>&lt;Weekday(s)&gt;&lt;from&gt;-&lt;to&gt;=&lt;value&gt;</strong><BR>
Each weekday is a two letter sequence (So, Mo, Tu, We, Th, Fr, Sa)
and there are three special &quot;weekdays&quot;: <em>Wk</em> for
working days (monday to friday), <em>Ss</em> for weekend
(saturday and sunday) and <em>al</em> for all days. A typical
example may look like:
<strong>Wk0800-1800=12;Wk1800-0800=24;Ss=24</strong>, but this
could be written shorter as:
<strong>=24;Wk0800-1800=12</strong> because the first entry is
taken as the default, if no match is found. And the construct
<em>=24</em> does not contain any weekday, so it is invalid for
any regular check.
</Dl>
<Dt> force &lt;bool&gt;
<Dd> If a feature is requested, but this service do not support it, the
message will still be delivered, if this variable is set to True.
<Dt> can-delay &lt;bool&gt;
<Dd> Set this to True, if the service provider accepts a delay for sending
the message.
<Dt> can-expire &lt;bool&gt;
<Dd> Set this to True, if the service provider allowes the setting of an
expiration timestamp.
<Dt> can-rds &lt;bool&gt;
<Dd> Set this to True, if the service provider allowes the request for a
delivery status.
<Dt> rds &lt;bool&gt;
<Dd> Set this to True, if <em>can-rds</em> is True and you always want to
get a delivery status.
<Dt> check-call-id &lt;check&gt;
<Dd> The caller id must match the <strong>check</strong> expression.
<Dt> check-pager-id &lt;check&gt;
<Dd> Each pager id must match the <strong>check</strong> expression.
</Dl>
<H2>Modem section</H2>
Each modem should have its own section. Following entries are currently
supported:
<Dl>
<Dt> device &lt;text&gt;
<Dd> The filename for the device where the modem is attached to.
<Dt> lock-prefix &lt;text&gt;
<Dd> This is the pathname to prefix the basename of the modemdevice to
create lockfiles. This can be used to enable more than one application to
use the modem.
<Dt> lock-method &lt;text&gt;
<Dd> This is a comma seperated list of locking mechanism. Currently these
flags are supported:
<Ul Compact>
<Li> <em>ascii</em> PID is stored as ASCII text in lockfile.
<Li> <em>binary</em> PID is stored in machine representation in
lockfile.
<Li> <em>lower</em> converts device part of lockfile to lower case.
<Li> <em>upper</em> converts device part of lockfile to upper case.
<Li> <em>sysv4</em> append SysV4 style infos to lockfile instead of the
basename of the device.
<Li> <em>timeout=&lt;secs&gt;</em> tries to lock the device
<strong>secs</strong> seconds.
</Ul>
<Dt> init &lt;text&gt;
<Dd> This is the init sequence to initialize the modem.
<Dt> dial &lt;text&gt;
<Dd> This is the dial sequence to dial a phone number with the modem. An
<strong>\L</strong> in the string will be replaced by the phone number.
<Dt> timeout &lt;num&gt;
<Dd> This is the default timeout to wait for responses of the modem.
<Dt> reset &lt;text&gt;
<Dd> This is the sequence to reset the modem.
<Dt> local-init &lt;text&gt;
<Dd> This is used to customize an existing modem entry for different purpose
(e.g. force a specific connect rate, etc.)
</Dl>
Beside this the section may contain protocol specific entries to adapt the
protocol for this service.
<H2>ASCII based protocol</H2>
A <strong>\C</strong> is replaced with the caller id, if available. If
request a delivery report is switched on, a <strong>\R</strong> is replaced
with <em>1</em>, else with <em>0</em>.
<Dl>
<Dt> asc-timeout &lt;num&gt;
<Dd> This is the default timeout for sequences when communicating with the
remote side.
<Dt> asc-login &lt;text&gt;
<Dd> This is the sequence to login to the remote service.
<Dt> asc-logout &lt;text&gt;
<Dd> This is the sequence to logout from the remote service.
<Dt> asc-pagerid &lt;text&gt;
<Dd> This is the sequence to embedded the pager id to be sent.
<strong>\P</strong> is replaced with the pager id.
<Dt> asc-message &lt;text&gt;
<Dd> Dito for the message, <strong>\M</strong> is replaced with the message.
<Dt> asc-next &lt;text&gt;
<Dd> This is the sequence to start the next transmission.
<Dt> asc-sync &lt;text&gt;
<Dd> If we get out of sync, then this sequence should bring us back to a
stage as if we had just loged in.
</Dl>
<H2>Script specific</H2>
<Dl>
<Dt> script-type &lt;text&gt;
<Dd> This is the scripting language to choose. Currently these are
supported: <strong>SLang</strong>, <strong>Lua</strong>.
<Dt> script-name &lt;text&gt;
<Dd> This is the name (e.g. the name of the variable containing) the script.
If the name starts with a slash or a plus sign, then the value is treated as
a filename from where the script should be read. The plus sign is stripped
off before opening the file.
<Dt> scr-login &lt;text&gt;
<Dd> This is the function/label where to start at login. If the caller id is
available (and the language supports it) the caller id is passed as an
argument.
<Dt> scr-logout &lt;text&gt;
<Dd> Dito for logout.
<Dt> scr-pagerid &lt;text&gt;
<Dd> Dito for sending the pagerid. The pagerid is passed as an argument.
<Dt> scr-message &lt;text&gt;
<Dd> Dito for sending the message. The message is passed as an argument.
<Dt> scr-next &lt;text&gt;
<Dd> Dito to go to the next message.
<Dt> scr-sync &lt;text&gt;
<Dd> Dito to sync to a definite state (i.e. as if we had just loged in.)
</Dl>
<H2>TAP specific</H2>
<Dl>
<Dt> tap-t1, tap-t2, tap-t3, tap-t4, tap-t5 &lt;num&gt;
<Dd> This is the timeout for each stage defined in the TAP specification.
See
<a href="http://www.mot.com/MIMS/MSPG/pcia_protocols/tap_v1p8/timing_retry_parameters.html#params">
there</a>
for details.
<Dt> tap-n1, tap-n2, tap-n3 &lt;num&gt;
<Dd> This is the retry count for each stage defined int the TAP
specification. See
<a href="http://www.mot.com/MIMS/MSPG/pcia_protocols/tap_v1p8/timing_retry_parameters.html#params">
there</a>
for details.
<Dt> tap-login-count &lt;num&gt;
<Dd> This is the number of tries to login to the remote service.
<Dt> tap-logout-count &lt;num&gt;
<Dd> This is the number of tries to logout from the remote service.
</Dl>
<H2>UCP specific</H2>
<Dl>
<Dt> ucp-timeout &lt;num&gt;
<Dd> This is the time to wait for an answer from the remote system. The
documentation says that this could be about 40 to 60 seconds. This depends
on the provider.
<Dt> ucp-retry &lt;num&gt;
<Dd> This specifies how often a message should be sent, until the program
gives up.
<Dt> ucp-extend &lt;bool&gt;
<Dd> If this is True then the extend UCP implementation is used, i.e. the
more complex, but more flexibel protocol (currently only possible on german
cellular phone provider Mannesmann D2.)
<Dt> ucp-ds-timeout &lt;num&gt;
<Dd> Wait a maximum of this value seconds for receiving of the delivery
status.
</Dl>
<H2>Alias section</H2>
The entries in this section are not able to access the global entries. Each
entry contains an alias name with its real number.
<H1 ID="cmdline">Command Line</H1>
Yaps support several command line parameter which can overwrite the possibly
used default values in the configuration files. Following options are
understood by this program (on some systems, there are is also support for
long options):
<Dl>
<Dt> -C &lt;configfile&gt;, --config=&lt;configfile&gt;
<Dd> Use <strong>cfgfile</strong> instead of the default global
configuration file <em>/etc/yaps.rc</em>.
<Dt> -s &lt;service&gt;, --service=&lt;service&gt;
<Dd> Use paging service <strong>service</strong> instead of the default of
the configuration file.
<Dt> -t, --truncate
<Dd> If this is set, then a message is truncated, if it is longer than the
allowed limit of the choosen service.
<Dt> -c &lt;callid&gt;, --call-id=&lt;callid&gt;
<Dd> Use <strong>callid</strong> as the caller id.
<Dt> -S &lt;signature&gt;, --signature=&lt;signature&gt;
<Dd> If signature appending is enabled by the service, use this string as
the signature.
<Dt> -l &lt;logfile&gt;, --logfile=&lt;logfile&gt;
<Dd> Write status of transmission to <strong>logfile</strong>.
<Dt> -L &lt;logstr&gt;, --logstring=&lt;logstr&gt;
<Dd> This is used to select the messages written to the logfile. See
<a href="#logstr">above</a> unter the configuration entry
<em>logstring</em> for a detailed description.
<Dt> -f, --force
<Dd> Force sending of messages, even if -d/-e/-r is not supported by the
service.
<Dt> -d &lt;date&gt;, --delay=&lt;date&gt;
<Dd> If the service supports it, the message is delayed and sent at
<strong>date</strong>.
<Dt> -e &lt;date&gt;, --expire=&lt;date&gt;
<Dd> If the service supports it, the message is deleted, if this date is
reached and the message had not been transmitted until then.
<Dt> -r, --request-delivery-status
<Dd> If the service supports it, a delivery status is requested.
<Dt> -R &lt;fname&gt;, --final-report=&lt;fname&gt;
<Dd> A final report is written to <em>fname</em> (or stdout, if fname is
<strong>-</strong>.) This feature is useful to check which message had been
delivered successfully or not.
<Dt> -z &lt;fname&gt;, --message-file=&lt;fname&gt;
<Dd> Reads pager-ids and messages form <em>fname</em>. Each line contains
one pair, seperated by whitespace(s).
<Dt> -v, --verbose
<Dd> Increase the verbosity of yaps, more -v's give more debug output.
<Dt> -p, --print-config
<Dd> This is used to printout configuration values for testing purpose. The
remaining paramters are variables to print out with their value.
</Dl>
Following the options the user has to give receiver/message pairs, all using
the same service. A receiver is either the pager id itself or an alias. If
the first character is a colon, then the colon is cut off and the remaining
part is taken as an alias, if the first character is a slash, it is cut off
as well and the remaining is taken as the pager id. If the first character
is a digit, it is taken as a pager id, otherwise as an alias. It is possible
to specify multiple receiver, if the receiver is a comma seperate list of
individual receivers. If the first character of the message is a plus sign,
then the remaining message is treated as a filename and the real message is
read from this file. If the message is just a minus (<strong>-</strong>),
then the message is read from stdin, if it is just a dot
(<strong>.</strong>), then the message is empty.<P>
The options <em>-d</em> and <em>-e</em> accept a date representation which
must be (according to option parsing) one argument, e.g. if it contains
spaces it must be quoted. If the first character of date is a plus
(<strong>+</strong>) sign, then the date is taken as an offset to the
current time. All further definitions are seperated by spaces:
<Ul>
<Li> &lt;hour&gt;<strong>:</strong>&lt;min&gt;<strong>:</strong>&lt;sec&gt;
<Li> &lt;day&gt;<strong>.</strong>&lt;month&gt;<strong>.</strong>&lt;year&gt;
<Li> &lt;month&gt;<strong>/</strong>&lt;day&gt;<strong>/</strong>&lt;year&gt;
<Li> &lt;numeric&gt; if less than 30 is taken as the hour
<Li> &lt;numeric&gt; if greater or equal than 30 is taken as minutes
</Ul>
<H1 ID="syntax">Sending/Expecting Syntax</H1>
Whenever communication over the serial line takes place the send/expect
functions are comming into play. There are three important functions, which
are called from several parts: sending of data, expecting data and a
send/expect function. Each is explained in detail here (including the
supported syntax):
<H2>Sending</H2>
Sending itself is nothing fancy, just all data will be written to the serial
line.
<H2>Expecting</H2>
Expecting means to wait for some pattern to arrive. It is possible to expect
more than one sequence and the function returns the matching entry, a
timeout or an error condition.
<H2>Send/Expect</H2>
Most communication parts call this function (which then calls the functions
above.) This function requires a string with tokens seperated by
whitespaces. A token may contain whitespaces, if the token is enclosed in
single or double quotes. These quotes (as any other quotes) are removed
during the preparse. The first character of the token is relevant for the
method to be executed. Each token is preparsed to remove/interpret special
characters. Following special characters are interpreted:
<Ul Compact>
<Li> Backslash <strong>\</strong><BR>
The backslash is used to escape any other special character (inclusive
quotes and the backslash itself) or to insert typical control characters.
These are supported:
<Ul>
<Li> \a -&gt; Bel
<Li> \b -&gt; Bs
<Li> \f -&gt; Ff
<Li> \l -&gt; Lf
<Li> \n -&gt; Nl (system depended)
<Li> \r -&gt; CR
<Li> \s -&gt; Space
<Li> \t -&gt; Tab
</Ul>
<Li> Up arrow <strong>^</strong><BR>
This is used to insert control characters, e.g. ^M means CR.
<Li> Percent <strong>%&lt;nr&gt;</strong><BR>
This inserts optional paramter <strong>nr</strong>, if supplied.
</Ul><P>
These character initiate the behaviour of the token:
<Dl>
<Dt> <strong>&lt;</strong> Expect
<Dd> The rest of the token is for expecting. If the token contains
<strong>-</strong> then the token is split again and each subtoken is
treated as expect/send, if the expect failed. The expect token may be
seperated by <strong>|</strong> to indicate alternatives. The expect is
failed, if an error occurs, a timeout arised or not the first alternatives
matches. The <strong>&lt;</strong> may be appended by a numeric value, which
is used as the timeout in seconds.
<Dt> <strong>!</strong> Command
<Dd> To insert dynamic commands into the sequence use this construct.
Following is an optional numeric value <strong>n</strong> and a command
character. If <strong>n</strong> is not set, its default value is one.
Following characters are supported:
<Ul>
<Li> d - sleep <strong>n</strong> seconds
<Li> D - sleep <strong>n</strong> miliseconds
<Li> b - send break (length depends on <strong>n</strong> and the
implementation)
<Li> h - hangup the line (lowering DTR by <strong>n</strong> * 0,5
seconds.)
<Li> o - waits for output to drain
<Li> &lt; - flushes the input queue
<Li> &gt; - flushes the output queue
<Li> f - forces the sequence to fail
<Li> s - forces the sequence to succeed
</Ul>
<Dt> Any other character
<Dd> This string is just send to the remote side.
</Dl>
<H1 ID="script">Scripting</H1>
Scripting has the advantage (compared to the ASCII protocol) that one is
more flexible. As there are a lot of scripting languages around, there will
be no specific one for this package. As long as such a language is
embeddable into C programs, it should not be too complicate to integrate it
into this package.<P>
This section explains the additional function (or simular) for the available
scripting languages. The syntax itself is explained in the distribution of
each scripting package.
<H2>SLang</H2>
Beside the new functions there is an extension to the string class, so you
can use (beside others) the plus sign to concaternate strings. One time this
part should make its way into the main SLang distribution.
<H3>Variable index</H3>
<Dl>
<Dt> int NO_ERR;
<Dd> This is the return value for a function, that ended successful.
<Dt> int ERR_FAIL;
<Dd> This is the return value for a function, that encountered an error, but
which allowes the script to continue.
<Dt> int ERR_FATAL;
<Dd> Dito, but the script should not continue any more.
<Dt> int ERR_ABORT;
<Dd> Dito, but no further action should take place.
<Dt> int rds;
<Dd> Is set to <em>True</em>, if a delivery status should be requested.
<Dt> int delay_day, delay_mon, delay_year, delay_hour, delay_min, delay_sec;
<Dd> This is the time/date to delay the delivery of the message.
<Dt> int expire_day, expire_mon, expire_year, expire_hour, expire_min, expire_sec;
<Dd> This is the time/date to expire a buffered message.
<Dt> int False;
<Dd> The numeric value for False.
<Dt> int True;
<Dd> Dito for True.
</Dl>
<H3>Function index</H3>
<Dl>
<Dt> void setcb (string func, string sep);
<Dd> This enable the line callback facility and stores each line into a
local variable, which will be overwritten after each new encountered line. A
line is considered as complete, if one character in <strong>sep</strong> is
received. If <strong>func</strong> is the name of a defined function, then
this function is called on every completed new line. The line is passed as
the paramter to this function.
<Dt> void clrcb (void);
<Dd> Clears the line callback facility.
<Dt> string line (void);
<Dd> Returns the last complete read in line, if the line callback facility
is enabled.
<Dt> void hangup (void);
<Dd> Tries to hangup, if the modem is currently off-hook. This is done by
lowering the DTR line.
<Dt> int send (string str);
<Dd> Sends the string to the remote side. Returns <strong>True</strong> on
success, <strong>False</strong> otherwise.
<Dt> int csend (string str);
<Dd> Dito, but the string is converted before it is sended to the remote
side.
<Dt> int expect (int tout, string str1, ..., string strn, int cnt);
<Dd> The function waits <strong>tout</strong> seconds until one of the
strings is received. If no string is received, <strong>0</strong> is
returned, <strong>-1</strong> on error. Otherwise the number of the string
is returned (<strong>1</strong> for <strong>str1</strong>,
<strong>2</strong> for <strong>str2</strong>, etc). <strong>cnt</strong> is
the number of strings to wait for.
<Dt> int send_expect (int tout, string expr);
<Dd> This function executes the <strong>expr</strong> with its internal
send/expect evaluater and returns <strong>True</strong>, when the sequence
had been executed completely, otherwies <strong>False</strong>.
<Dt> void drain (int secs);
<Dd> This function reads and discards any character for
<strong>secs</strong> seconds.
<Dt> void cvdef (int src, int dst);
<Dd> Defines a converion rule. Every character <strong>src</strong> will be
replaced by <strong>dst</strong>. The conversion is used in <em>csend()</em>.
<Dt> void cvundef (int ch);
<Dd> Undefines the conversion rule for <strong>ch</strong>.
<Dt> void cvinval (int ch);
<Dd> Marks the character <strong>ch</strong> as invalid.
<Dt> string conv (string str);
<Dd> Converts the string <strong>str</strong> using the defined conversion
rules and returns the converted string.
</Dl>
<H2>Lua</H2>
<!-- TODO! -->
<H1 ID="sample">Examples</H1>
Here are some examples that may help you to understand the software a bit
better. First you should read the example configuration file
<a href="yaps.rc">yaps.rc</a>. This could be used as a base for your own
global configuration file.
<H2>Calling</H2>
Typically the program is called <strong>yaps &lt;pagerid&gt;
&lt;message&gt;</strong>. <em>pagerid</em> is either the exact pagerid of
the receiver or an alias found in the alias section. <em>message</em> is the
message to send by itself. If a pager-id leads to more than one provider,
then the first is used. To force a special service use the <strong>-s
&lt;service&gt;</strong> switch.
<H2>Script protocol</H2>
In the contrib directory, you can find <a href="contrib/tap.sl">tap.sl</a>,
an example on how to use the scripting facility to emulate a protocol. This
is a minimal, but working reimplemetation of TAP.
<H1 ID="chlog">Changelog</H1>
This is a list of changes:
<Ul Plain>
<Li> 9. May 1997: V 0.90 released
<Ul Compact>
<Li> Minor cleanup on calling sending routines
<Li> Added optional multiple receiver per message
<Li> Changing UCP to prepare the real implementation
<Li> Preparing the creation of a client/server solution
<Li> Compile configuration moved to seperate file
</Ul>
<Li> 13. May 1997: V 0.91 released
<Ul Compact>
<Li> Converted `char *' to `string_t *' in several places
<Li> Added max-messages configuration option
<Li> Moved some configuration stuff to config.h
<Li> Got UCP docu! Implemented it partial (as much as it makes sense)
<Li> Added option -d/-e as UCP (in extended mode) can support it
<Li> Added special date handling functions for this purpose
<Li> Changed copyright to the GPL
<Li> Use transparent data in extended UCP, if characters with
set 8th bit are found
<Li> Better message splitting
<Li> Added some sanity checks
</Ul>
<Li> 22. May 1997: V 0.92 released
<Ul Compact>
<Li> Added handling of configuration variants
<Li> Added include option in configuration files
<Li> First bugs encountered by tester fixed
<Li> Message can now be read from stdin, if message == '-'
(idea by &lt;markus@mail.yezz.de&gt;)
<Li> Message can now be empty, if message == '.'
<Li> Minor bugfixing/Makefilehandling (reported by Frank K&auml;fer)
<Li> Enhanced lockfile handling, including SysV4 lockfiles (inspirated
by Frank K&auml;fer)
<Li> Total rewrite of UCP sending
</Ul>
<Li> 26. May 1997: V 0.93 released
<Ul Compact>
<Li> UCP works again including delivery report
<Li> Added checking of pager id for a service
<Li> Added signature in configuration file
<Li> Added value start escaping with backslash
<Li> Changed checking of pager id for service
<Li> Automatic assign of a pager id to a service
<Li> Could now handle more than one service at one call
</Ul>
<Li> 30. May 1997: V 0.94 released
<Ul Compact>
<Li> Workaround for serial bug in sunos/solaris (by Frank K&auml;fer)
<Li> If the system does not support Posix regular expression, a simple
replacement is added
<Li> More comments in yaps.rc (as wished by Frank K&auml;fer ;-)
<Li> Change handling of control chars in TAP/pre V1.6 (hint by
&lt;markus@mail.yezz.de&gt;)
<Li> Added default conversion rules
<Li> Added force/-f
<Li> Added long options support
<Li> Added getopt() for systems without this function
<Li> Added valid-cid/change-cid/rm-invalids-cid/rm-invalids-pid
</Ul>
<Li> 3. June 1997: V 0.95 released
<Ul Compact>
<Li> Added final status report
<Li> Added a 2nd checking scheme
<Li> Added support for lua (another scripting language)
<Li> Removed porting approach, should be done by someone who
has access to such an OS.
<Li> Added reading of pager-id/message pairs from file
<Li> Added cost calculation
<Li> Enhanced logfile handling
</Ul>
<Li> 14. June 1997: V 0.96 released
</Ul>
</Body></HTML>

19
yaps.lsm Normal file
View File

@ -0,0 +1,19 @@
Begin3
Title: yaps
Version: 0.96
Entered-date: 14JUN97
Description: This is a standalone program to send messages to paging
devices over a modem gateway using well defined protocols.
Keywords: pager sms tap ucp
Author: ud@nitmar.tnet.de (Ulrich Dessauer)
Maintained-by: ud@nitmar.tnet.de (Ulrich Dessauer)
Primary-site: ftp.sta.com /pub/fk/yaps
91k yaps-0.96.tar.gz
725 yaps.lsm
Alternate-site: sunsite.unc.edu /pub/Linux/apps/serialcomm/machines/
91k yaps-0.96.tar.gz
725 yaps.lsm
Platforms: Linux, Solaris, SunOS and modem (or modem like device,
e.g. ISDN) optional SLang V99.38, Lua-2.5
Copying-policy: GPL
End

370
yaps.rc Normal file
View File

@ -0,0 +1,370 @@
# -*- sh -*-
#
# General yaps example configuration file
#
#########################################
# global section #
#########################################
#
# This is a comma seperated list of available services. This
# is required for autodetect the matching service for a
# pager-id
services D1,D2,E+
+services Telmi,Telmi-Fun,Telmi-Family,Telmi-Top,Telmi-Pro
+services Skyper,Quix
#
# This is the default caller-id. If the protocol/service allowes
# it, this is inserted in the message (and the receiver gets this
# as the sender's number)
call-id +1-(555)-1234
#
# If you forget to sign your message, you can automatically append
# this string to each message.
signature (It's me!)
#
# You can either switch the use of the signature here on for all
# services or in each service section for that particular service.
use-signature True
#
# To get more verbose output when running yaps increase this value.
# Currently 4 is the highest supported value.
verbose 0
#
# If you'd like to log every sending session define this. It should
# point to a writeable file. If you install the software setgid, then
# change the group of this file to the same yaps uses and make it
# group writeable.
logfile /var/log/yaps.log
#
# A comma seperated list of modem sections. You can also define this
# in each service section.
modems standard
#
# some global defaults for the serial interface (even if the most
# protocols are assuming 7e1, these settings seem to work well)
speed 38400
bits-per-byte 8
parity none
stopbits 1
#
# To calculate the cost for each call, you can define some globales
# here and do the fine tuning in each protocol
cost cost=0.12,unit=DM,remainder=2,dial-overhead=13
#
# These are two example of internal conversion tables. The can be
# used using the `convert' entry (see below).
cv-default {
Ä [
Ö \
Ü ]
ä {
ö |
ü }
ß ~
}
cv-extend {
\l \s
\n \s
\r \s
\f \s
\t \s
}
#
# These values are normally only found in each service section,
# but are listen here with an explaination for completeness.
#
# This is the phone number of the modem gateway for this service
#phone 0015559876
#
# This is the protocol the service uses. Currently this can be
# either ascii, script, ucp or tap. Each protocol has a set of
# special configuration parameters, see below.
#protocol tap
#
# Most services limit the length of a message to a specific length.
# Enter the value here to check valid messages
#max-size 160
#
# If a message is longer than max-size, you can set this to split
# it off into several single messages of allowed length
#may-split True
#
# If a message is longer than max-size, you can set this to truncate
# the message to the allowed length. The remaining part is discarded.
#truncate True
#
# Some services allow to send more than one message per session. If
# it is limited, set it using this parameter
#max-messages 1
#
# If the service allows using your caller-id set this to True.
#use-call-id True
#
# If the service is reachable over a phonenumber where the pager-id
# is part of the phone number, define this and add a `%P' anywehere
# in the `phone' number.
#insert-pager-id True
#
# Remove these characters from the pager-id, as they are not valid
rm-invalids-pid + (-)
#
# Dito for caller id
rm-invalids-cid + (-)
#
# Check for valid call id (see below for more details) While
# valid-pid is required, this is optional
#valid-cid ^(001|1)
#change-cid 001
#
# Depending on your system the value for this parameter is either a
# regular expression or a simple list of strings (seperated by bars)
# which must match the prefix of the pager-id.
#valid-pid ^(0171|0049171)
#valid-pid 0171|0049171
# Use these paramters in the global section if you want do not want
# to check pager-ids (and do not set change-pid):
#valid-pid .
#valid-pid -
#
# If a pagerid has matched the expression above, then the matching part
# may be replaced by this string
#change-pid 0171
#
# As the services do not use (in general) the ISO 8859/1 character set,
# one can define convertion tables. you can either specify a file which
# contains the convertion rules:
#conv-table /usr/local/lib/yaps/iso2din.tab
# or use predefined convertion rules
#convert *no-control,*no-8bit,cv-default,cv-extended
#
# If this is set, send a message even if a requested feature is
# not available
#force True
#
# If the provider supportes to set a delay for sending the message,
# set this
#can-delay True
#
# If the provider can delete a buffered message after a period of time,
# set this
#can-expire True
#
# If the provider can report a delivery status, set this.
#can-rds True
#
# To check wether a call-id/pager-id is valid use these paramters.
# For the exact syntax see the documentation
#check-call-id >1111111111111111<
#check-pager-id >1111111111111111<
#check-call-id +minimum=0,maximum=16,type=numeric
#
# These values are typically found in a modem section, but can also
# appear in the global section to set some defaults
#
# Set this to the modem device you wish to use
#device /dev/modem
#device /dev/cua1
#device /dev/cua/a
#
# Set this to the prefix of the lockfile use for the device. There
# are several places, and two common formats:
#lock-prefix /usr/spool/uucp/LCK..
#lock-prefix /var/spool/lock/LCK..
#lock-prefix /var/spool/locks/LK.
#
# The different format of the part which is appended to the lockfile
# and the contents can be specified here. See documentation for a
# full list inclusive explaination
#lock-method sysv4
#lock-method binary
#lock-method timeout=10
#
# These are send/expect sequences to talk to the modem. For an exact
# definition see (again) the documentation. Following entries are
# supported:
# init: to initialize the modem
# local-init: a second initialization string, used to customize
# already defined modems for different handling
# dial: to dial a phone number %L is replaced with the
# phone number itself
# timeout: the default timeout in seconds to wait for answers
# reset: to reset the modem
#########################################
# service section #
#########################################
#
# D1 (by Deutsche Telekom)
#
[D1]
protocol tap
valid-pid 0171|0049171|49171
change-pid 0171
convert *no-8bit,cv-d1
cv-d1 {
Ä [
Ö \
Ü ~
ä {
ö |
ü ~
ß ^]
}
+cost timetable=Wk0800-1800=5.7;Wk1800-0800=11.4;Ss=11.4
phone 01712092522
max-size 160
may-split True
use-call-id False
tap-old True
#
# D2 (by Mannesmann Mobilfunk)
#
[D2]
modem standard-d2
protocol ucp
valid-pid 0172|0049172|49172
change-pid 0172
convert *no-8bit,cv-default
+cost timetable=Wk0800-1800=5.7;Wk1800-0800=11.4;Ss=11.4
phone 01722278020
max-size 160
may-split True
use-call-id True
can-delay True
can-expire True
can-rds True
check-call-id >1111111111111111<
check-pager-id >1111111111111111<
ucp-extend True
#
# E+ (by ???)
# !! UNTESTED !!
#
[E+]
protocol tap
valid-pid 0177|0049177|49177
change-pid 0177
convert *no-8bit,cv-default
+cost timetable=Wk0800-1800=5.7;Wk1800-0800=11.4;Ss=11.4
phone 01771167
max-size 160
may-split True
use-call-id False
#
# Telmi, Telmi-* (by Deutsche Funkruf)
# !! ONLY TESTED FOR TELMI-FUN !!
#
[Telmi]
protocol tap
valid-pid 01661|01665|00491661|00491665|491661|491665
change-pid -
convert *no-control,*no-8bit,cv-default,cv-extend
+cost entity-length=5.2
phone 016601010101
max-size 114
may-split True
max-messages 1
use-call-id False
check-pager-id 1111111
tap-old True
[Telmi-Fun] Telmi
[Telmi-Family] Telmi
[Telmi-Top] Telmi
max-size 240
[Telmi-Pro] Telmi-Top
#
# Skyper (by Deutsche Telekom)
# !! UNTESTED !!
#
[Skyper]
protocol tap
valid-pid 01692|00491692|491692
change-pid -
convert *no-8bit,cv-default,cv-extend
+cost fixed,cost=0.96
phone 01692%P
max-size 80
use-call-id False
insert-pager-id True
#
# Quix (by Miniruf)
# !! UNTESTED !!
#
[Quix]
protocol ucp
valid-pid 01653|00491653|491653
change-pid -
+cost fixed,timetable=Wk0800-1800=1.20;Al=0.96
convert *no-8bit,cv-default,cv-extend
phone 016593
max-size 80
use-call-id True
#########################################
# modem section #
#########################################
[standard]
#
# Locking
#
# Older Unix versions
lock-prefix /usr/spool/uucp/LCK..
# Newer Unix versions
#lock-prefix /var/spool/uucp/LCK..
#lock-prefix /var/lock/LCK..
# SysV4
#lock-prefix /var/spool/locks/LK.
#lock-method sysv4
#
# Device
#
# Typical a symbolic link to the real device
device /dev/modem
# "normal" call-out device
#device /dev/cua1
# Solaris convention
#device /dev/cua/a
#
# Modem talk
#
init \\r !200D ATZ\r <OK ATE0Q0V1\r <OK
dial ATD%L\r <60CONNECT|OK|BUSY|NO\sDIALTONE|NO\sCARRIER
reset ATZ\r <OK
timeout 10
# Customizing an existing modem entry
[standard-d2] standard
local-init AT\%C2\r <OK
#
# alias section
#
[alias]
#foo 001 555 1221
#bar +1-(555)-2112