capisuite/docs/manual.docbook

2838 lines
152 KiB
XML

<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[
<!ENTITY cs "<application>CapiSuite</application>">
]>
<book lang="en">
<title>CapiSuite 0.5.git</title>
<subtitle><ulink url="http://www.capisuite.de"/></subtitle>
<bookinfo>
<author>
<firstname>Gernot</firstname><surname>Hillier</surname>
<affiliation><address><email>gernot@hillier.de</email></address></affiliation>
</author>
</bookinfo>
<preface id="intro"><title>Introduction</title>
<sect1 id="welcome"><title>Welcome to &cs;</title>
<para>Welcome to &cs;, a Python-scriptable ISDN telecommunication suite.</para>
<para>
This manual should help you to be able to use &cs; as quick as possible.
As I hate reading long documentation just as much as you do, let's jump
right in.
</para>
<refentry id="capisuite">
<refmeta>
<refentrytitle>capisuite</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>capisuite</refname>
<refpurpose>Python-scriptable ISDN telecommunication suite</refpurpose>
</refnamediv>
<refsect1><title>Description</title>
<para>&cs; is a Python-scriptable ISDN telecommunication suite.
It uses the new CAPI interface for accessing
your ISDN-hardware - so you'll need a card for which a CAPI compatible
driver is available. Currently these are all cards manufactured by AVM
and some Eicon cards.
</para>
<para condition="man">This man page only gives a short introduction, for
the real documentation please see the HTML or PDF manual distributed
with &cs;.</para>
<para>&cs; tries to give the user the ability to code his own ISDN applications
without having to fiddle around with all the dirty programming details like callback
functions, data buffers, protocol settings and so on.</para>
<para>I took a scripting language which is (in my opinion) very easy to understand,
to use and to learn - especially for beginners: Python. I extended it with some
functions providing the basic ISDN "building blocks" for the users application.
Behind these functions the heart of &cs; implements all the dirty details
a user isn't interested in. My goal was to make script-coding as
simple as possible but to also give you the flexibility to realize what you
want.</para>
<para>To give you an impression, coding a simple answering machine is as easy as:
<informalexample>
<programlisting>def callIncoming (call, service, call_from, call_to):
connect_voice (call, 10) # answer call after 10 secs
audio_send (call, "announcemnt.la") # play announcement
audio_send (call, "beep.la") # play beep
audio_receive (call, "call.la", 10) # record call</programlisting>
</informalexample>
</para>
<para>Of course some details are missing like creating a unique filename or storing
the additional information (called and calling party numbers, time, ...) - but I assume
you got my idea.</para>
<para>And - don't be afraid - if you just want to have a normal answering machine or send and
receive some fax documents, you can use the default scripts distributed with &cs;.
They give you already some nice features - e.g. the answering machine is multi-user
ready, supports automatic fax detection and remote inquiry functions. You'll only
need to tell &cs; some details like your own number, record an own announcement
and that's it.</para>
<para>So &cs; is already equipped for your daily telecommunication needs - but if you don't
like to do the things the way I do - just change it or completely do it on your
own. And if you write nice scripts or have changes to my default scripts, I would
love to get and perhaps make them available for all users if you don't mind.</para>
</refsect1>
<refsect1 condition="man"><title>See Also</title>
<para><simplelist type="inline">
<member><xref linkend="capisuite.conf"/></member>
<member><xref linkend="fax.conf"/></member>
<member><xref linkend="answering_machine.conf"/></member>
<member><xref linkend="capisuitefax"/></member>
</simplelist></para>
</refsect1>
</refentry>
</sect1>
<sect1 id="manual"><title>Structure of the manual</title>
<para>This manual is split into three big parts.</para>
<para>The first part (<xref linkend="gettingstarted"/>) explains how to install &cs;, what
you can do with the default scripts you have after installing it and how
to configure them. No line of code will be presented here. If you just want
to use the default scripts that should be all the reading you need.</para>
<para>The second part (<xref linkend="userguide"/>) will tell you how to write your own scripts. It will
give you a very, very small introduction into Python and a complete reference
of the commands &cs; adds to it. Last, an overview over the default
scripts is given which will tell you how they work so you can easily take them
as starting points and/or examples for your own application.</para>
<para>The last part is intended for programmers who want to help in developing the &cs; core.
It provides an overview of the system and a detailled description for each single class, method
and attribute. As it's autocreated from the sources of &cs;, it's not included in this document.
You'll find it locally in <ulink url="../reference/index.html"/> or online at
<ulink url="http://www.capisuite.de/reference/index.html"/>.</para>
<para>There are also some additional parts containing "what I also wanted to mention":</para>
<para>As &cs; started as a diploma thesis, I want to thank all who helped me so far in <xref linkend="acknowledgements"/></para>
<para>When you want to code your own scripts or want to help in developing the &cs; core,
you'll soon stumble upon some special ISDN and CAPI error codes, which are explained in
<xref linkend="capicodes"/>.
</para>
<para>If you need further information or support, please have a look at the &cs; home page on
<ulink url="http://www.capisuite.de"/>. You'll find links to a bug tracker, up-to-date documentation,
downloads and other ressources there. If you have questions, need support or want to tell us your
ideas concerning &cs; or your opinion, you're more than welcome on the &cs; mailing lists. Please don't
write me personal mails with such questions as this won't help other users and I can't answer the same
question ten times a day, sorry. For informations on how to subscribe to the lists and where to find the
archives, please also refer to the home page.</para>
<para>Hope I managed to whet your appetite - so let's now really start over to get you ready to
use it.</para>
</sect1>
</preface>
<chapter id="gettingstarted"><title>Getting Started</title>
<sect1 id="install"><title>Requirements and installation of &cs;</title>
<sect2 id="requirements"><title>Requirements</title>
<sect3 id="require_hard"><title>Hardware and drivers</title>
<para>As &cs; uses the CAPI (Common ISDN Application Programming Interface)
for accessing your ISDN-hardware, you'll need a card for which a CAPI compatible
driver is available.</para>
<para>Currently these are all cards manufactured by AVM and some Eicon cards.
If you have one of the passive cards of AVM, you'll have to download and
install their CAPI drivers.</para>
<para>With the upcoming Linux 2.6 and the new mISDN project included therein,
also most cards which are supported by the HiSax driver today will soon have
a CAPI-compliant driver. Unfortunately, mISDN also won't include a fax protocol
implementation and therefore passive cards still won't be able to fax in &cs;
(or in any other program under Linux); fax support for passive cards is only
available in the binary drivers from AVM currently.</para>
<para>There's no way to get &cs; to work with the old ISDN4Linux interface
and drivers. Presumable there also never will be one because of the mISDN project
which will replace HiSax/ISDN4Linux soon.</para>
<para>There are some distributions (e.g. current versions of SUSE) which
include the Capi4Linux drivers from AVM already - you'll only have to
activate them (use YaST2 in SUSE Linux). If you own an active card of AVM
(e.g. the B1, C2 or C4), then you'll have everything you need already installed.
SuSE also provides a small frontend to configure &cs; in YaST.</para>
<para>&cs; has mainly been tested on AVM ISDN cards, esp. the Fritz!PCI, the Fritz!USB and
the B1 on the i386 platform but there should be no problem with other
CAPI-compatible drivers for other cards or on other platforms. Nevertheless,
some features aren't mandatory for all CAPI-compatible cards, so perhaps
you may not be able to fax or to switch from voice to fax mode with all
cards.</para>
</sect3>
<sect3 id="require_soft"><title>Software</title>
<para>&cs; depends on some packages which must be installed before &cs; can be used.</para>
<para>I will list them here with a short information why these packages are needed and where to
find further information on how to install them. It may be always a good idea to check the
installation tool of your favourite distribution first and see if they're included with it before
trying to download and install them from the net. Don't be afraid, because there are so many -
most of them are included in nearly every distribution and perhaps are already installed on your system.</para>
<variablelist>
<varlistentry>
<term>Python >= 2.2</term>
<listitem><para>&cs; uses an embedded Python interpreter to interpret the given scripts -
so you'll need an installed and working version of Python. This should be included
in mostly every up-to-date Linux distribution. For further infos on Python, a nice
tutorial and much more, please go to <ulink url="http://www.python.org"/></para>
</listitem>
</varlistentry>
<varlistentry>
<term>sox >= 12.17.3</term>
<listitem><para>This is the swiss-knife for converting audio formats. It's not required
by the &cs; core, but will be very helpful if you want to hear or record the
voice files used for calls on your machine. It's also required if you want to
use the default scripts of &cs;. I'll bet this is included in your distribution
and most likely already installed on your system. Just try to start <command>sox</command>
to get sure. As Helmut Gruber pointed out, you need at least version 12.17.3, as this
version started to handle inverse A-Law files. You'll find more details on
<ulink url="http://sox.sourceforge.net"/>
</para></listitem>
</varlistentry>
<varlistentry>
<term>sfftobmp</term>
<listitem><para>&cs; will save fax files in the CAPI specific format Structured Fax File (SFF).
sfftobmp is a small but useful converter to convert this files to more
common formats like JPEG, TIFF or BMP. Get it on <ulink url="http://sfftools.sourceforge.net/sfftobmp.html"/>.
It's again not needed by the &cs; core, but by the default scripts.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>sffview</term>
<listitem><para>This tool is a simple but useful SFF viewer. It's not needed by any
&cs; component, but very useful if you just want to see a fax file without
the need to convert it first. You can get it from <ulink url="http://sfftools.sourceforge.net/sffview.html"/>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>tiff2pdf</term>
<listitem><para>A small utility to losslessly convert TIFF files to the PDF format. It's needed by
the default script to convert faxes to PDF files (SFF->TIFF->PDF :-} ).
It's often included in a package called <literal>tiff</literal> or
<literal>tifftools</literal>. Details on <ulink url="http://www.libtiff.org"/>
</para></listitem>
</varlistentry>
<varlistentry>
<term>current Ghostscript with cfax patch</term>
<listitem><para>Current Ghostscript versions will include a device to create the above mentioned
SFF files. If you have an older version, you'll need the patch from
<ulink url="http://sfftools.sourceforge.net/ghostscript.html"/>. To see if your GhostScript
version already has this patch, please call <command>gs --help</command> and see if you can
find the device <literal>cfax</literal> in the long list of supported devices.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>jpeg2ps</term>
<listitem><para>The <command>jpeg2ps</command> command is used to convert color fax files to the
PostScript format for mail delivery. It's not so important, unless you want to be able to receive
color faxes. Unfortunately, there's currently no way to disable the reception of color faxes with
AVM cards due to a bug in the AVM CAPI driver. So if someone sends you a color fax (which seems to
be a very rare case), you'll need this package - unless you'll get a mail stating this error.
If your distribution doesn't have this packages, you can download it from
<ulink url="http://www.pdflib.com/products/more/jpeg2ps.html"/>.</para>
<para>As the color fax protocol uses concatenated JPEG files for transferring multiple pages, you
should also download and apply my multipleJPEG patch from
<ulink url="http://www.hillier.de/linux/jpeg2ps-multi.php3"/></para>
</listitem>
</varlistentry>
<varlistentry>
<term>glibc locales</term>
<listitem><para>If you want to use an AVM card (which most of you will do ;-) ) to send or receive
faxes, you'll need installed glibc locales because &cs; needs to convert your fax
headline to the historic CP437 encoding which AVM drivers expect. The glibc locales are
a part of the default C library glibc which you definitely already have installed, but some
distributors make the locales installable separately. SuSE e.g. puts them in a package
called glibc-locale which you probably have to install. To see if you already have them,
look for a file called "IBM437.so" in your library paths (in SuSE it's located in
/usr/lib/gconv). If you don't find it, look for sub-packages of glibc which could include
them.</para>
</listitem>
</varlistentry>
</variablelist>
</sect3>
</sect2>
<sect2 id="install_install"><title>Installation</title>
<para>First of all, I would suggest to check if your CAPI-driver is setup correctly.
To do this, simply run <command>capiinfo</command> on a root shell.</para>
<para>If you get many lines of output, your CAPI driver works. If you just get
an error message, you'll have to install CAPI-compatible drivers. Refer
to the documentation of your ISDN card vendor, your Linux distribution
and/or some ISDN mailing lists for this, please.</para>
<para>The rest of the installation depends on wether you use binary or source
packages for installing &cs;. If you don't want to change the
&cs; sources, I would recommend you to use the binary packages
when available for your distribution and platform.</para>
<para>You can download both binary packages and sources from the download section on
<ulink url="http://www.capisuite.de"/>. If you built packages for other
distributions not yet available, please send me your link and I'll happily include it
there...</para>
<sect3 id="install_bin"><title>Installation from binary packages</title>
<para>If you can get binary packages for your distribution and platform,
I would advise to use them. There are many binary packages of
CapiSuite available for different distributions maintained by different
people. It's also part of current versions of SUSE, Debian and Gentoo.</para>
<para>If you managed to install &cs; on a system not mentioned below,
please tell me and I'll include the instructions here. If you have created
binary packages for other distributions, I'll be also happy to point
to your download section or make them available on my page.</para>
<para>Now everything should be setup ready to run. So please read on in
<xref linkend="csglobal"/>.</para>
<sect4 id="install_bin_rpm"><title>Installation from RPM packages (SUSE, Fedora, Mandrake &amp; Co.)</title>
<para>To install the &cs; RPM packages you can either use your favorite setup tool -
either provided by your distributor or the community - or you can do manually
(as root):</para>
<screen>rpm -Uvh capisuite-version.rpm</screen>
</sect4>
<sect4 id="install_bin_other"><title>Installation from other packages</title>
<para>Please refer to the documentation of your distribution and the
information given in the packages or on the homepage of the
maintainers. If someone wants to write a section about these packages,
please contact me.</para>
</sect4>
</sect3>
<sect3 id="install_source"><title>Installation from the source packages</title>
<para>If there are no binary packages you can use or if you like to do
everything on your own, you can get the sources from the download section.</para>
<para>Download the newest source tarball (capisuite-X.Y.tar.gz) from the
&cs; homepage and copy it to some location. Go there and issue the following
commands:</para>
<screen
>./configure
make
su # get root now
make install</screen>
<para>This will install &cs; completely in the <filename>/usr/local</filename>-tree. If you
want it to stay in other directories, please see the commandline-help
printed by
<screen
>./configure --help</screen>
for options to customize the installation directories.</para>
</sect3>
<sect3 id="install_GIT"><title>Installation from Git</title>
<para>If you want to live on the bleeding edge and always test the newest features,
you may also checkout the current sources of &cs; from the repository.</para>
<para>If you want to live on the bleeding edge and always test the
newest features, you can also checkout the current sources of &cs;
from github:</para>
<para><screen>git clone https://github.com/larsimmisch/capisuite.git</screen></para>
<para><emphasis>This is not recommended unless you want to test the newest features or
want to help in developing &cs;! The development sources may do anything,
may not work or not even compile. Do this on your own risk!</emphasis></para>
<para>You'll need installed and working versions of the usual development tools like
GNU make, gcc/g++ and also the components described above (esp. development packages
of Python).</para>
<para>If you want to build the documentation out of the sources, you'll also need
Doxygen and correctly installed Docbook/XML tools.</para>
<para>Now, you can continue with the normal installation process as described in
<xref linkend="install_source"/>.</para>
</sect3>
</sect2>
<sect2 id="install_update"><title>Updating from previous versions</title>
<para>This section will give you an overview of how to update
CapiSuite from earlier versions.</para>
<para>In general, the usual update mechanism depending on your
installation method should be used - that means the update features
of your package managers if you installed from binary packages.
If you installed from sources, you should save your configuration
files before doing <command>make install</command>. As this is
done like for any other software package you use, we won't go into
further detail about that here.</para>
<para>What this section should mainly cover are the changes in the
configuration files and requirements to other tools between different
versions, so that you'll be able to update your configuration quickly.
For a more complete list of new features and important changes, please
refer to the file <filename>NEWS</filename> distributed with the
CapiSuite packages. In addition, all single changes in the different
source code files can be found in the <filename>ChangeLog</filename>,
which, however, will only be interesting for developers, I suppose.</para>
<sect3 id="install_update_0_4_5"><title>From 0.4.4 to 0.4.5</title>
<para>The <emphasis>default scripts</emphasis> now use
an SMTP connection to localhost instead of calling the
<command>sendmail</command> command manually as previous
versions did. This was changed because the other mechanism
had many stability problems in the past. This means, you now
have to have a running SMTP daemon listening on your localhost.
As this is the default configuration of most distributions,
this should be no problem.</para>
<para>In <filename>answering_machine.conf</filename> and
<filename>fax.conf</filename>, two new options have been added:
<option>fax_email_from</option> and <option>voice_email_from</option>
allow the configuration of the from address CapiSuite uses
when sending mails to the user. These new entries are optional -
if you don't set them, the user name is used as from address
as in previous versions.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="csglobal"><title>How &cs; works, how it is configured and started</title>
<para>First, let's start with a short introduction what &cs; actually
is and how it works. After that, the configuration and startup of &cs;
will be explained in short.</para>
<sect2 id="howwork"><title>How does &cs; work?</title>
<para>&cs; is a daemon (program which runs in the background) whos
main task is to sit around and wait until a call is incoming.
If this happens it will start a special Python script - the
<emphasis>incoming script</emphasis> - and do what this script tells it, for example
record a voice call to implement an answering machine.</para>
<para>To also be able to issue outgoing calls, another script is called
at regular intervals - the <emphasis>idle script</emphasis>. It can check any resource
to get instructions for placing a call - one can for example imagine
to check a special mail account or watch a special directory where
tasks are placed by the user.</para>
<para>So all user-visible actions and the behaviour of &cs; are defined
in these two scripts.</para>
<para>You'll need to do two things now:</para>
<itemizedlist>
<listitem><para>provide scripts by either</para>
<itemizedlist>
<listitem><para>using and configuring the default scripts distributed with &cs; or</para></listitem>
<listitem><para>writing your own scripts (perhaps by using the default ones as templates)</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>configure &cs; itself and tell it where to find the two scripts</para></listitem>
</itemizedlist>
<para>This page concentrates on the general configuration of &cs; - that consists mainly of
options telling it which scripts to use and where and how to log its activities. After
that, some details about starting &cs; are described.</para>
<para>The next pages will then introduce the standard scripts you already installed along with
&cs; and tell you how to use the answering maching and fax functions provided
by them.</para>
<para>The details on how to write your own scripts are covered in another part of the
documentation (<xref linkend="userguide"/>).</para>
</sect2>
<sect2 id="configcs"><title>Configuration of &cs;</title>
<para>&cs; uses a general configuration file for the core functions. This file should
be located in <filename>/etc/capisuite/capisuite.conf</filename> or <filename>/usr/local/etc/capisuite/capisuite.conf</filename>
depending on how you installed &cs;. It's described in detail in <xref linkend="capisuite.conf"/>.
Most options are set to reasonable defaults already for using the standard scripts -
so if you want you can also skip this section.</para>
<refentry id="capisuite.conf">
<refmeta>
<refentrytitle>capisuite.conf</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>capisuite.conf</refname>
<refpurpose>configuration of the &cs; daemon</refpurpose>
</refnamediv>
<refsect1><title>Description</title>
<para>The options for the &cs; daemon are configured here. They will be
presented in brief here - for further details please
refer to the comments in the configuration file itself.</para>
</refsect1>
<refsect1><title>Options</title>
<variablelist>
<varlistentry>
<term><option>incoming_script="/path/to/incoming.py"</option></term>
<listitem><para>This option tells &cs; which script should be executed at incoming
calls. Only change this if you want to use your own script.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>idle_script="/path/to/idle.py"</option></term>
<listitem><para>This option reflects the path and name of the idle script.
This script is called in regular intervalls to check if any outgoing
call should be done. As above, the default should be ok if you don't
use your own script.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>idle_script_interval="30"</option></term>
<listitem><para>Here you can define how often the idle script should be executed. The
number given is the interval between subsequent invocations in seconds.
Lesser numbers give you quicker response to queued jobs but also a higher
system load. The default should be ok in most cases.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>log_file="/path/to/capisuite.log"</option></term>
<listitem><para>This file will be used for all "normal" messages printed by
&cs; telling you what it does. Error messages are written to a
special log (see below).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>log_level="1"</option></term>
<listitem><para>You can define how detailled the log output of &cs; will be.
The default will give you some informational messages for each
incoming and outgoing call and should be enough for normal use. I would
recommend to only increase it if you encounter some problems.
Logs of higher level are mainly intended for developers, so just use
them if you want to report a problem or have some know-how of the CAPI
interface and the internals of &cs;.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>log_error="/path/to/capisuite.error"</option></term>
<listitem><para>All errors which &cs; detects internally and in your scripts
will end up here. They are written to an extra file so that they don't
get lost in the normal log. Please check this log regularly for any
messages - especially when you encounter problems. Please report all
messages you don't understand and which aren't caused by your
own script-modifications to the &cs; team.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>DDI_length="0"</option></term>
<listitem><para>When your ISDN card is connected to an ISDN interface in PtP mode,
i.e. if you use DDI which, in understandable words mean you have only one
ISDN phone number and can define your own extensions as you like, you have
to set the length of your extension numbers here. In Germany, PtP mode is
called "Anlagenanschluss". Let's say you use 1234-000 till 1234-999, then your
DDI_length would be 3. If you set this to 0, DDI/PtP is disabled.</para>
<para>If you're not sure what all this should mean, then chances
are high you don't use DDI and can leave this option as it is.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>DDI_base_length="0"</option></term>
<listitem><para>This option is only used when DDI_length is not 0. This is the length
of your base number - in the example above it would be 4.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>DDI_stop_numbers=""</option></term>
<listitem><para>If you usually use extension numbers of a specified length, but also
want to use some shorter ones (e.g. the "-0" extension for you switchboard), then
you can list these shorter extensions here, separated by commas.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 condition="man"><title>See Also</title>
<para><simplelist type="inline">
<member><xref linkend="capisuite"/></member>
<member><xref linkend="fax.conf"/></member>
<member><xref linkend="answering_machine.conf"/></member>
<member><xref linkend="capisuitefax"/></member>
</simplelist></para>
</refsect1>
</refentry>
</sect2>
<sect2 id="startcs"><title>Startup of CapiSuite</title>
<para>As &cs; is a daemon, it is normally activated during the system
startup process. Just add a call to
<screen><command>/path/to/capisuite -d</command></screen>
in your startup scripts. In LSB conforming Linux distributions, you'll
find the startup scripts in <filename>/etc/init.d</filename>. For detailled documentation
how to add a service there please refer to the documentation of your
distribution. There's an example startup script written for SUSE Linux included
in the source distribution (see <filename>rc.capisuite</filename>) which should (hopefully)
work with other LSB compliant distributions, too. If you need to modify it, I'll
welcome your feedback and happily add instructions for other distributions here.</para>
<para>If you use the right RPM packages of &cs;, the necessary scripts
should already be included. For activating them, please use your
distributors config tool. If you use the RPM distributed with SUSE Linux
and want to stay with the default scripts, everything should work "out of the box".
As soon as you have configured the default scripts, simply run
<command>rccapisuite restart</command>.</para>
<para>For debug purposes, you can also start &cs; manually at any time
by just calling
<screen><command>/path/to/capisuite</command></screen></para>
<para>There are also some other commandline options available:</para>
<variablelist>
<title>commandline options of &cs;</title>
<varlistentry>
<term><option>--help, -h</option></term>
<listitem><para>show a short summary of commandline options</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--config=file, -c file</option></term>
<listitem><para>use a custom configuration file instead
of <filename>/etc/capisuite/capisuite.conf</filename> or
<filename>/usr/local/etc/capisuite/capisuite.conf</filename>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--daemon, -d</option></term>
<listitem><para>run as daemon (used in your startup script, see above)</para></listitem>
</varlistentry>
</variablelist>
<para>&cs; can run as any user you want theoretically. It only needs read/write permissions to <filename>/dev/capi20</filename>.
If you use the default scripts, however, &cs; <emphasis>must</emphasis> run as <literal>root</literal>.</para>
</sect2>
</sect1>
<sect1 id="scripts"><title>Features and configuration of the default scripts</title>
<para>As already written above, &cs; comes with default scripts
giving you the most used communication functions of an answering machine
and a fax device.</para>
<para>This section should help you to use them for your daily needs.</para>
<sect2 id="script_features"><title>Script features</title>
<para>The scripts distributed with &cs; give you the following main
functions:</para>
<itemizedlist>
<listitem>
<para>multi-user answering machine</para>
<itemizedlist>
<listitem><para>different users using different numbers and different announcements are supported</para></listitem>
<listitem><para>incoming calls are saved and sent to the user by email</para></listitem>
<listitem><para>the delay until a call is accepted and the maximum record length are freely adjustable</para></listitem>
<listitem><para>silence is detected and the call terminated after an adjustable silence period</para></listitem>
<listitem><para>incoming fax calls are automatically detected and received</para></listitem>
<listitem><para>comfortable, menu-controlled remote inquiry functions are supported telling you
the date/time when the call was received and the called and calling numbers.</para></listitem>
<listitem><para>record your own announcement via the remote inquiry menu</para></listitem>
<listitem><para>nearly each setting is configurable globally but can be overwritten for each user</para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para>fax machine</para>
<itemizedlist>
<listitem><para>different users using different numbers are supported</para></listitem>
<listitem><para>incoming faxes are stored and sent to the user by email</para></listitem>
<listitem><para>command line tool for faxing PostScript documents included</para></listitem>
<listitem><para>number of tries and delays for sending faxes freely configurable</para></listitem>
<listitem><para>currently supports only one ISDN controller for outgoing faxes</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>As my native language is german, all waves distributed with &cs; are in german only. If someone wants to
provide waves in english (or any other language), please contact me. Thx!</para>
</sect2>
<sect2 id="howscriptswork"><title>How the scripts work</title>
<para>Here follows a rough overview of how the scripts work in general. I will only explain
the behaviour which is important for the user here. If you want to understand the internals,
please refer to <xref linkend="default_script_overview"/>.</para>
<para>When an incoming call is received, several lists for the different users are
searched for the called number. The different users can define their own numbers in
the configuration (see below). So the scripts decide by looking on the called number
to which user the call destinates. If they find the number in the voice- or fax-number
list of any user, they'll answer the call with this service and give the caller the possibility to
leave his message or send his fax.</para>
<para>The received document is then saved to a local directory in some native format
and also converted to a well-known format and mailed to the user along with some
details of the call. Voice calls are sent as a WAV attachment, while fax calls
are sent as PDF documents attached to the mail.</para>
<para>So you'll normally get your incoming calls as a mail to a specified address -
but they're also saved in the local filesystem to be on the safe side.
It's your task to delete old files you don't need any more. For further instructions,
please see <xref linkend="deleteoldfiles"/>.</para>
<para>There's also the possibility to do a remote inquiry on the answering machine.
The caller is presented a menu where he can choose to record
his announcement or to hear the saved voice calls. He will be told how many calls
are available, from whom and when they were received and so on. He'll also be
able to delete recorded calls he doesn't need any more.</para>
<para>Another script will check special queue directories for fax send jobs
regularly. To put jobs in this directory, the commandline tool <command>capisuitefax</command> is
provided. See <xref linkend="usingscripts"/> for further details on this.</para>
</sect2>
<sect2 id="script_config"><title>Script configuration</title>
<para>There are some important options which the scripts need to know before you can use them -
things like the users' numbers and some details of how to handle the calls.</para>
<para>These options are read from two configuration files. All options for the two
files are described in short below. For all details, please see the comments
in the sample configuration files installed with &cs;.</para>
<refentry id="fax.conf">
<refmeta>
<refentrytitle>fax.conf</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>fax.conf</refname>
<refpurpose>configuration of the &cs; fax services</refpurpose>
</refnamediv>
<refsect1><title>Description</title>
<para>This file holds all available config options for the fax
services provided by the default scripts distributed with &cs;.
It is read from <filename>/etc/capisuite/fax.conf</filename> or
<filename>/usr/local/etc/capisuite/fax.conf</filename> (depending on the installation).</para>
<para>It is divided into one or more sections. A section begins with the section
name in square brackets like <literal>[section]</literal> while the options are <literal>key="value"</literal> lines.</para>
<para>A special section called <literal>[GLOBAL]</literal> and one section
for each user called <literal>[&lt;username&gt;]</literal> are required.
<emphasis>The <literal>&lt;username&gt;</literal> must be a valid system user</emphasis>.</para>
<para>The <literal>[GLOBAL]</literal>-section defines some global options like
pathnames and default settings for options that can be overridden in the user-sections.
The user-sections hold all the options which belong to a particular user.</para>
</refsect1>
<refsect1><title>The [GLOBAL] section</title>
<variablelist>
<varlistentry id="fax_spool_dir">
<term><option>spool_dir="/path/to/spooldir/"</option></term>
<listitem><para>This directory is used to archive sent (or failed) jobs. It must exist and
the user &cs; runs as must have write permission to its subdirectories.
Two subdirectories are used:</para>
<variablelist>
<varlistentry>
<term><filename>spooldir/done/</filename></term>
<listitem><para>Jobs finished successfully are moved to this directory.</para></listitem>
</varlistentry>
<varlistentry>
<term><filename>spooldir/failed/</filename></term>
<listitem><para>Job which have failed finally end up here.</para></listitem>
</varlistentry>
</variablelist>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_user_dir">
<term><option>fax_user_dir="/path/to/userdir/"</option></term>
<listitem><para>This directory is used to store fax jobs and received documents
to. It must exist and
the user &cs; runs as must have write permission to it. It will contain
one subdirectory for each configured user (named like his userid). The
following subdirectories are used below the user-specific dir:</para>
<variablelist>
<varlistentry>
<term><filename>user_dir/username/received/</filename></term>
<listitem><para>Received faxes are saved here.</para></listitem>
</varlistentry>
<varlistentry>
<term><filename>user_dir/username/sendq/</filename></term>
<listitem><para>Fax files to be sent are queued here by <command>capisuitefax</command>.</para></listitem>
</varlistentry>
</variablelist>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_send_tries">
<term><option>send_tries="10"</option></term>
<listitem>
<para>When a fax can't be sent to the destination for any reason, it's tried for several times.
This setting limits the number of tries. If all tries failed, the job will be moved to the failed dir
(see <option>fax_spool_dir</option>) and the user will get a mail.
</para>
<para>This option is optional. If not given, it defaults to 10 tries.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_send_delays">
<term><option>send_delays="60,60,60,300,300,3600,3600,18000,36000"</option></term>
<listitem><para>When a fax can't be sent to the destination for any reason, it's tried again.
This setting specifies the delays in seconds between subsequent tries. The different values are
separated with commas and <emphasis>no blanks</emphasis>. The list should have send_tries-1
(see <option>fax_send_tries</option>) values - if not, surplus entries are ignored and missing
entries are filled up with the last value. The default should just be ok giving you increasing
delays for up to 10 tries.</para>
<para>This option is optional. If not given, it defaults to the list shown above.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_send_controller">
<term><option>send_controller="1"</option></term>
<listitem><para>If you have more than one ISDN controller installed (some active cards for more than
one basic rate interface like the AVM C2 or C4 are also represented as multiple controllers for
CAPI applications like &cs;), you can decide which controller (and therefore which basic rate
interface) should be used for sending your faxes. All controllers are numbered starting with 1.
If you're not sure which controller has which number, increase the log level to at least 2
in &cs; (see <xref linkend="configcs"/>), restart it and have a look in the log file where all
controllers will be listed then. Unfortunately, &cs; isn't able to use more than one controller
for sending faxes at the moment, so no list is allowed here. If you have only one controller,
just leave it at <literal>1</literal></para>
<para>This option is optional. If not given, it defaults controller 1.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_outgoing_MSN">
<term><option>outgoing_MSN="&lt;your MSN&gt;"</option></term>
<listitem><para>This number is used as our own number for outgoing calls. If it's not given,
the first number of fax_numbers is used (see user sections). If
this one is also empty, the user can't send faxes. Please
replace with one valid MSN of your ISDN interface or leave empty. This value can be
overwritten in the user sections individually.</para>
<para>This option is optional. If not given, it defaults to empty.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_outgoing_timeout">
<term><option>outgoing_timeout="60"</option></term>
<listitem><para>Default setting which defines how many seconds we will wait for a successful connection after
dialing the number. This value can be overwritten in the user sections individually.</para>
<para>This option is optional. If not given, it defaults to 60 seconds.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_dial_prefix">
<term><option>dial_prefix=""</option></term>
<listitem>
<para>If anything is entered here, it will be used as a prefix which is added to any
number given to <command>capisuitefax</command> as prefix. This is e.g. very helpful if your
ISDN adapter is connected to a PBX which needs "0" for external calls. It's also possible to
disable its usage later for a certain fax document, so setting this will certainly not prevent
you from placing internal calls without prefix.
</para>
<para>This option is optional. If not given, it defaults to an empty prefix.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_stationID">
<term><option>fax_stationID="&lt;your faxID&gt;"</option></term>
<listitem><para>Default fax station ID to use when sending a fax document. The station ID is
usually the number of your fax station in international format, so an example would be
"+49 89 123456" for a number in Munich, Germany. Station IDs may only consist of the "+"-sign,
spaces and the digits 0-9. The maximal length is 20. This value can be overwritten in the user
sections individually.</para>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_headline">
<term><option>fax_headline="&lt;your faxheadline&gt;"</option></term>
<listitem><para>Default fax headline to use when sending a fax document. Where and if this
headline will be presented depends on the implementation of your CAPI driver. The headline
should have a reasonable length to fit on the top of a page, but there's no definite limit
given.</para>
<para>This option is optional. If not given, it defaults to an empty headline.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_email_from">
<term><option>fax_email_from="&lt;mailaddress&gt;"</option></term>
<listitem><para>You can set a default originator ("From"-address) for the e-mails &cs; sends
here.</para>
<para>This option is optional. If you set this to an empty string, the destinator is used as
originator (i.e. if "gernot" receives a fax, the mail comes from "gernot" to "gernot").</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1><title>The user sections</title>
<variablelist>
<varlistentry>
<term><option>outgoing_MSN</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>outgoing_timeout</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>fax_stationID</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>fax_headline</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>fax_email_from</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry id="fax_numbers">
<term><option>fax_numbers="&lt;number1&gt;,&lt;number2&gt;,..."</option></term>
<listitem><para>A list containing the numbers on which this user wants to receive incoming fax calls.
These numbers are used to differ between users - so the same number must not appear in more
than one user section! The numbers are separated with commas and <emphasis>no blanks</emphasis>
are allowed. The first number of the list also serves as our own number for
sending a fax if outgoing_MSN is not set (see <option>outgoing_MSN</option>).</para>
<para>If you want to use the same number for receiving fax and voice calls, please
<emphasis>do not</emphasis> enter it here. Use the voice_numbers option instead
(see <xref linkend="answering_machine.conf"/>) - the answering machine has a built in fax detection
and can also receive faxes.</para>
<para>When this list is set to <literal>*</literal>,
<emphasis>all</emphasis> incoming calls will be accepted for this user (use with care!).
This is only useful for a setup with only one user which wants to receive any call as fax.
</para>
<para>If for any reason <emphasis>no destination</emphasis> number is signalled for special
MSNs (austrian telecom seems to do this for the main MSN, where it is called "Global Call"),
you can use the special sign <literal>-</literal> which means "no destination number available".</para>
<para>This option is optional. If not given, the user can't receive fax documents.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_email">
<term><option>fax_email=""</option></term>
<listitem><para>If given, this string indicates email-addresses where the received faxes will
be sent to. More addresses are separated by commas. If it is empty, they will be sent
to the user account on the system &cs; is running on. The address is also used to send
status reports for sent fax jobs to. If you don't want emails to be sent at all, use the
action option (see option <option>fax_action</option>) below.</para>
<para>This option is optional. If not given, the mail is sent to the system account.</para>
</listitem>
</varlistentry>
<varlistentry id="fax_action">
<term><option>fax_action="MailAndSave"</option></term>
<listitem><para>Here you can define what action will be taken when a call is received.
Currently, two possible actions are supported:
<variablelist>
<varlistentry>
<term><option>MailAndSave</option></term>
<listitem><para>The received call will be mailed to the given address (see
<option>fax_email</option> above) and saved to the <option>fax_user_dir</option> (see global options)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>SaveOnly</option></term>
<listitem><para>The call will be only saved to the fax_user_dir (see global options)</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 condition="man"><title>See Also</title>
<para><simplelist type="inline">
<member><xref linkend="capisuite"/></member>
<member><xref linkend="capisuite.conf"/></member>
<member><xref linkend="answering_machine.conf"/></member>
<member><xref linkend="capisuitefax"/></member>
</simplelist></para>
</refsect1>
</refentry>
<refentry id="answering_machine.conf">
<refmeta>
<refentrytitle>answering_machine.conf</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>answering_machine.conf</refname>
<refpurpose>configuration of &cs; answering machine</refpurpose>
</refnamediv>
<refsect1><title>Description</title>
<para>This file holds all available config options for the answering
machine provided by the default scripts distributed with &cs;. It is read
from <filename>/etc/capisuite/answering_machine.conf</filename>
or <filename>/usr/local/etc/capisuite/answering_machine.conf</filename> (depending on the installation).</para>
<para>It is divided into one or more sections. A section begins with the section
name in square brackets like <literal>[section]</literal> while the options are <literal>key="value"</literal> lines.</para>
<para>A special section called <literal>[GLOBAL]</literal> and one section
for each user called <literal>[&lt;username&gt;]</literal> are required.
<emphasis>The <literal>&lt;username&gt;</literal> must be a valid system user</emphasis>.</para>
<para>The <literal>[GLOBAL]</literal>-section defines some global options like
pathnames and default settings for options that can be overridden in the user-sections.
The user-sections hold all the options which belong to a particular user.</para>
</refsect1>
<refsect1><title>The [GLOBAL] section</title>
<variablelist>
<varlistentry id="voice_audio_dir">
<term><option>audio_dir="/path/to/audiodir/"</option></term>
<listitem><para>The answering machine script uses several wave files, for example
a global announcement if the user hasn't set his own and some spoken word fragments
for the remote inquiry and the menu presented there. These audio files are searched
in this directory. If user_audio_files is enabled (see <option>user_audio_files</option>), each user can also
provide his own audio snippets in his user_dir (see <option>voice_user_dir</option>).</para>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_user_dir">
<term><option>voice_user_dir="/path/to/userdir/"</option></term>
<listitem><para>This directory is used to save user specific data to. It must exist and
the user &cs; runs as must have write permission to it. It will contain
one subdirectory for each configured user (named like his userid). The
following subdirectories are used below the user-specific dir:</para>
<variablelist>
<varlistentry>
<term><filename>user_dir/username/</filename></term>
<listitem><para>Here the user may provide his own audio_files
(see also option <option>user_audio_files</option> below).
The user defined announcement is also saved here.</para></listitem>
</varlistentry>
<varlistentry>
<term><filename>user_dir/username/received/</filename></term>
<listitem><para>Received voice calls are saved here.</para></listitem>
</varlistentry>
</variablelist>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_user_audio_files">
<term><option>user_audio_files="0"</option></term>
<listitem>
<para>If set to <literal>1</literal>, each user may provide his own audio files
in his user directory (see <option>voice_user_dir</option>). If set to <literal>0</literal>,
only the audio_dir (see <option>voice_audio_dir</option>) will be searched.
</para>
<para>This option is optional. If not set, it defaults to not reading own user audio files (0).</para>
</listitem>
</varlistentry>
<varlistentry id="voice_delay">
<term><option>voice_delay="15"</option></term>
<listitem><para>Sets the default value for the delay for accepting an incoming
call in (in seconds). A value of <literal>10</literal> means that the answering
machine accepts incoming calls 10 seconds after the incoming connection request.
This value can be overwritten in the user sections individually.</para>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_announcement">
<term><option>announcement="announcement.la"</option></term>
<listitem><para>Sets the default name to use for user announcements.
The announcements are searched in <filename>user_dir/username/announcement</filename>
then. If not found, a global announcement containing the called MSN will be played.
This value can be overwritten in the user sections individually.</para>
<para>This option is optional. If not set, it defaults to "announcement.la".</para>
</listitem>
</varlistentry>
<varlistentry id="voice_record_length">
<term><option>record_length="60"</option></term>
<listitem><para>Default setting for the maximum record length in seconds. This value can
be overwritten in the user sections individually.</para>
<para>This option is optional. If not set, it defaults to 60 seconds.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_record_silence_timeout">
<term><option>record_silence_timeout="5"</option></term>
<listitem><para>Default setting for the record silence timeout in seconds. When set to a value
greater than 0, the recording will be aborted if silence is detected for the given
amount of seconds. Set this to 0 to disable it. This value can
be overwritten in the user sections individually.</para>
<para>This option is optional. If not set, it defaults to 5 seconds.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_email_from">
<term><option>voice_email_from="&lt;mailaddress&gt;"</option></term>
<listitem><para>You can set a default originator ("From"-address) for the e-mails &cs; sends
here.</para>
<para>This option is optional. If you set this to an empty string, the destinator is used
as originator (i.e. if "gernot" receives a voice call, the mail comes from "gernot" to
"gernot").</para>
</listitem>
</varlistentry>
</variablelist></refsect1>
<refsect1><title>The user sections</title>
<variablelist>
<varlistentry>
<term><option>voice_delay</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>announcement</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>record_length</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>record_silence_timeout</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry>
<term><option>voice_email_from</option></term>
<listitem><para>User specific value for the corresponding global option</para></listitem>
</varlistentry>
<varlistentry id="voice_numbers">
<term><option>voice_numbers="&lt;number1&gt;,&lt;number2&gt;,..."</option></term>
<listitem><para>A list containing the numbers on which this user wants to receive incoming voice calls.
These numbers are used to differ between users - so the same number must not appear in more
than one user section! The numbers are separated with commas and <emphasis>no blanks</emphasis>
are allowed. The answering machine script does also automatic fax detection, so a fax can
be sent to this number. When this list is set to <literal>*</literal>,
<emphasis>all</emphasis> incoming calls will be accepted for this user (use with care!).
This is only useful for a setup with only one user which wants to receive any call.</para>
<para>If for any reason <emphasis>no destination</emphasis> number is signalled for special MSNs
(austrian telecom seems to do this for the main MSN, where it is called "Global Call"), you can
use the special sign <literal>-</literal> which means "no destination number available".</para>
<para>This option is optional. If not set, the user won't receive voice calls.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_email">
<term><option>voice_email=""</option></term>
<listitem><para>If given, this string indicates email-addresses where the received faxes and
voice calls will be sent to. If it is empty, they will be sent to the user account on the
system &cs; is running on. More addresses are separated by commas. If you don't want emails
to be sent at all, use the action option (see <option>voice_action</option>).</para>
<para>This option is optional. If not set, the calls are mailed to the system account.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_pin">
<term><option>pin="&lt;your PIN&gt;"</option></term>
<listitem><para>The answering machine also supports a remote inquiry function.
This function is used by entering a PIN (Personal Identification Number)
while the announcement is played. This PIN can be setup here.
If you don't want to use the remote inquiry function, just use an empty
PIN setting. The PIN doesn't have a maximal length - but perhaps you should
not use 200 digits or you perhaps won't be able to remember them (I won't at least). ;-)</para>
<para>This option is optional. If not set, remote inquiry is disabled.</para>
</listitem>
</varlistentry>
<varlistentry id="voice_action">
<term><option>voice_action="MailAndSave"</option></term>
<listitem><para>Here you can define what action will be taken when a call is received.
Currently, three possible actions are supported:
<variablelist>
<varlistentry>
<term><option>MailAndSave</option></term>
<listitem><para>The received call will be mailed to the given address (see
<option>voice_email</option> above) and saved to the <filename>voice_user_dir</filename>
(see global options)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>SaveOnly</option></term>
<listitem><para>The call will be only saved to the <filename>voice_user_dir</filename>
(see global options)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>None</option></term>
<listitem><para>Only the announcement will be played - no recording is done.</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>This option is mandatory.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 condition="man"><title>See Also</title>
<para><simplelist type="inline">
<member><xref linkend="capisuite"/></member>
<member><xref linkend="capisuite.conf"/></member>
<member><xref linkend="fax.conf"/></member>
<member><xref linkend="capisuitefax"/></member>
</simplelist></para>
</refsect1>
</refentry>
</sect2>
<sect2 id="deleteoldfiles"><title>Deleting old files</title>
<para>As written above, all incoming and outgoing calls will be saved on
the local file system to assure nothing gets lost. There's no cleaning
up done by &cs;, so these files will stay forever on your system
if you don't clean them up from time to time.</para>
<para>As it's not very convenient to do this manually, I would advise to
automate this process. <application>cron</application> is predestinated for
such a task. On most modern GNU/Linux distributions, you can simply place
scripts in <filename>/etc/cron.daily</filename> and they will be called
automatically once a day.</para>
<para>An example for a bash script you can use is included in the &cs; distribution.
Just copy <filename>capisuite.cron</filename> to <filename>/etc/cron.daily/capisuite</filename>
and assure it has correct permissions (owner root, executable bit set).</para>
<para>Now edit the file <filename>cronjob.conf</filename> and copy it to
your &cs; configuration directory (usually <filename>/etc/capisuite</filename>
or <filename>/usr/local/etc/capisuite</filename>). It tells the cron job how
long the files should be stored in the different dirs.</para>
<para>The following options are available:</para>
<variablelist>
<varlistentry>
<term><option>MAX_DAYS_RCVD="&lt;value&gt;"</option></term>
<listitem><para>Files stored in the user receive directories
which weren't accessed in the last <option>&lt;value&gt;</option>
days are deleted. Set to <option>0</option> to disable this
automatic deletion.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>MAX_DAYS_DONE="&lt;value&gt;"</option></term>
<listitem><para>Files stored in the global done directory
which weren't accessed in the last <option>&lt;value&gt;</option>
days are deleted. Set to <option>0</option> to disable this
automatic deletion.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>MAX_DAYS_FAILED="&lt;value&gt;"</option></term>
<listitem><para>Files stored in the global failed directory
which weren't accessed in the last <option>&lt;value&gt;</option>
days are deleted. Set to <option>0</option> to disable this
automatic deletion.</para></listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
<sect1 id="usingscripts"><title>Using &cs; together with the default scripts</title>
<sect2 id="usingscripts_receive"><title>Receiving calls</title>
<para>Now this is a nice, short section. Once you have configured
&cs;, the scripts and started &cs; successfully, there's nothing
more you have to do. You'll get your mails as described in
<xref linkend="howscriptswork"/> and that's it. You only have
to setup your mail program to receive local mails. Enjoy! :-)</para>
</sect2>
<sect2 id="usingscripts_remoteinquiry"><title>Doing a remote inquiry</title>
<para>To do a remote inquiry, please enter your PIN (see <xref linkend="answering_machine.conf"/>)
while the announcement of the answering machine is played. After some seconds
you will get a "voice menu" telling you how to record your own announcement
for your answering machine or how to playback the received calls.</para>
</sect2>
<sect2 id="usingscripts_send"><title>Sending fax jobs</title>
<para>The default scripts for &cs; also include a commandline
tool for sending faxes called <command>capisuitefax</command>. It's
described in the next section.</para>
<refentry id="capisuitefax">
<refmeta>
<refentrytitle>capisuitefax</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>capisuitefax</refname>
<refpurpose>sending faxes with the &cs; default scripts</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>capisuitefax</command>
<arg>-q</arg>
<arg>-n</arg>
<arg>-u <replaceable>user</replaceable></arg>
<arg>-A <replaceable>adr</replaceable></arg>
<arg>-S <replaceable>subj</replaceable></arg>
<arg choice="plain">-d <replaceable>number</replaceable></arg>
<arg choice="plain" rep="repeat">file</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>capisuitefax</command>
<arg>-q</arg>
<arg choice="plain">-a <replaceable>id</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>capisuitefax</command>
<arg choice="plain">-h</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>capisuitefax</command>
<arg choice="plain">-l</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1><title>Description</title>
<para>The default scripts for &cs; come with the tool <command>capisuitefax</command>
for sending faxes.</para>
<para>It will be called with some parameters
telling it which file to send (it currently only supports PostScript and PDF files)
and to which number. It will then enqueue the job converted to the
right format into the send queue
from which it's collected by another &cs; script and sent to the
destination. If the sending was completed successfully or failed finally
after trying for some time, the according user will get an email
telling him/her what has happened.</para>
</refsect1>
<refsect1><title>Options</title>
<variablelist>
<varlistentry>
<term><option>-a id</option></term>
<listitem><para>Abort the job with the given id. To get a job id, use the <option>-l</option>
option.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-A adr</option></term>
<listitem><para>The addressee of the fax. This option is (currently) only
for informational purposes and will be quoted in the sent status mail.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-d number</option></term>
<listitem><para>The number which should be called (destination of the fax)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option></term>
<listitem><para>Show a short commandline help</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-l</option></term>
<listitem><para>Shows the jobs which are currently in the send queue.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-n</option></term>
<listitem><para>Don't use the configured dial prefix for this job. Useful for internal jobs.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-q</option></term>
<listitem><para>Be quiet, don't output informational messages</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-S subj</option></term>
<listitem><para>A subject for the fax. This option is (currently) only
for informational purposes and will be quoted in the sent status mail.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-u user</option></term>
<listitem><para>
Send fax as another user. Only allowed if <command>capisuitefax</command>
is called as user <literal>root</literal>. This is mainly helpful for realizing
extensions to e.g. do network faxing.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>file...</option></term>
<listitem><para>One or more PostScript/PDF files to send to this destination. More than
one PostScript file will produce several separate fax jobs.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 condition="man"><title>See Also</title>
<para><simplelist type="inline">
<member><xref linkend="capisuite"/></member>
<member><xref linkend="capisuite.conf"/></member>
<member><xref linkend="fax.conf"/></member>
<member><xref linkend="answering_machine.conf"/></member>
</simplelist></para>
</refsect1>
</refentry>
</sect2>
</sect1>
</chapter>
<chapter id="userguide"><title>Users Guide</title>
<para>In the last chapter you've seen how to use the default scripts distributed with &cs;.
But the main goal in developing &cs; was not to provide a perfect ready-to-use
application. I intended to develop a tool where you can write your <emphasis>own</emphasis>
applications very easyly. I'll show you how to do this in the next sections.</para>
<sect1 id="ug_python"><title>Introduction to Python</title>
<para>As I thought about the scripting language I wanted to integrate into &cs;,
my first idea was to develop an own, simple one. But as more as I looked into it, the
more I found that a general purpose language will be much
more helpful than re-inventing every wheel that I would need. So I looked for some
easy to integrate (and to learn) language. The one I liked most was Python - and it
also had a nice documentation about embedding, so I chose it and I'm still happy about
that decision. :-)</para>
<para>So the first thing you'll have to do is to learn Python. Don't be afraid -
it was developed as a beginners language and Guido (Guido van Rossum, the inventor of Python)
has done very well in my opinion.</para>
<para>In the next few sections, I'll give you a short introduction to the features of Python
you most probably will need for &cs;. As this shouldn't be a manual about Python or a tutorial
in computer programming, I assume you're already familiar with the basic concepts of todays
wide-spread procedural and object-oriented languages.</para>
<para>If not, I would advise you to get and read a book for learning Python - there are many
available in different languages. The Python home page on <ulink url="http://www.python.org"/>
has also nice and comprehensive manuals and tutorials available for free.</para>
<sect2 id="python_basics"><title>Python Basics</title>
<para>Python supports most features you know from other common languages. Here's the
syntax of the basic operations shown in a Python session. A Python session is another
fine feature of its interpreter: just start it by typing <command>python</command>
in a shell and you'll get a prompt:</para>
<screen
>gernot@linux:~> python
Python 2.2.1 (#1, Sep 10 2002, 17:49:17)
[GCC 3.2] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
&gt;&gt;&gt;</screen>
<para>As you can see, the Python prompt is <literal>&gt;&gt;&gt;</literal>.
If you enter commands that span multiple lines, Python shows a second
prompt: <literal>...</literal></para>
<screen>&gt;&gt;&gt; if (1==2):
... print "Now THAT's interesting!"
...</screen>
<para>Ok, now let's go on:</para>
<screen>&gt;&gt;&gt; # comments start with # at the begin of a line
&gt;&gt;&gt; # now the usual first steps
&gt;&gt;&gt; print "hello world"
hello world
&gt;&gt;&gt; # variables
&gt;&gt;&gt; a=5 # no separate declarations necessary
&gt;&gt;&gt; b=a*2
&gt;&gt;&gt; print b
10
&gt;&gt;&gt; b='hello'
&gt;&gt;&gt; print b,'world'
hello world
&gt;&gt;&gt; # python is very powerful in handling sequences
&gt;&gt;&gt; a=(1,2,3) # defines a tuple (not changeable!)
&gt;&gt;&gt; print a
(1, 2, 3)
&gt;&gt;&gt; a[1]=2 # this must fail
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in ?
TypeError: object doesn't support item assignment
&gt;&gt;&gt; a=[1,2,3] # defines a list (changeable)
&gt;&gt;&gt; a[1]=7
&gt;&gt;&gt; print a
[1, 7, 3]
&gt;&gt;&gt; # control structures
&gt;&gt;&gt; if (b=='hello'):
... print "b is hello"
... else:
... print "????"
...
b is hello
&gt;&gt;&gt; # the for statement can iterate over sequences
&gt;&gt;&gt; for i in a:
... print i
...
1
7
3
&gt;&gt;&gt; # replace positions 1 to 3 (without 3) with 0
&gt;&gt;&gt; a[1:3]=[0]
&gt;&gt;&gt; a
[1, 0]
&gt;&gt;&gt; # a[-i] is the i-the element counted from the back
&gt;&gt;&gt; a[-1]=7; a[-2]=8
&gt;&gt;&gt; a
[8, 7]</screen>
</sect2>
<sect2 id="py_blocks"><title>Blocks, Functions and Exceptions</title>
<para>Blocks are grouped only by identation. No <literal>begin</literal>,
<literal>end</literal>, braces (<literal>{</literal>, <literal>}</literal>)
or the like are needed. This sounds very uncomfortable at the first sight, but it's
really nice - you must always structure your code exactly how you
<emphasis>mean</emphasis> it:</para>
<screen>&gt;&gt;&gt; for i in [1,2,3]:
... print 2*i
...
2
4
6
&gt;&gt;&gt; i=0
&gt;&gt;&gt; while (i!=3):
... print i
... i+=1
...
0
1
2</screen>
<para>Now let's see how to define functions and how to work with
exceptions:</para>
<screen>&gt;&gt;&gt; def double_it(a):
... return (2*a)
...
&gt;&gt;&gt; print double_it(9)
18
&gt;&gt;&gt; print double_it("hello")
hellohello
&gt;&gt;&gt;
&gt;&gt;&gt; # let's trigger a exception
&gt;&gt;&gt; a=1/0
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
&gt;&gt;&gt;
&gt;&gt;&gt; # now let's catch it
&gt;&gt;&gt; try:
... a=1/0
... except ZeroDivisionError,e:
... print "You divided by zero, message was:",e
...
You divided by zero, message was: integer division or modulo by zero</screen>
</sect2>
<sect2 id="py_modules"><title>Working with modules</title>
<para>Modules are a way to group functions together. They must be
imported before you can use them and they give you a new object
containing all functions. Let's play around with some of them:
</para>
<screen>&gt;&gt;&gt; import time
&gt;&gt;&gt; # what is in time?
&gt;&gt;&gt; dir(time)
['__doc__', '__file__', '__name__', 'accept2dyear', ...]
&gt;&gt;&gt; # So - what do all these functions do? Python can tell...
&gt;&gt;&gt; print time.__doc__
This module provides various functions to manipulate time values.
[...]
Variables:
[...]
Functions:
time() -- return current time in seconds since the Epoch as a float
ctime() -- convert time in seconds to string
[...]
&gt;&gt;&gt; # Could you please explain ctime in more detail?
&gt;&gt;&gt; print time.ctime.__doc__
ctime(seconds) -> string
Convert a time in seconds since the Epoch to a string in local time.
This is equivalent to asctime(localtime(seconds)). When the time tuple
is not present, current time as returned by localtime() is used.
&gt;&gt;&gt; time.time()
1044380131.186987
&gt;&gt;&gt; time.ctime()
'Tue Feb 4 18:35:36 2003'
&gt;&gt;&gt; import os
&gt;&gt;&gt; os.getuid()
500
&gt;&gt;&gt; import pwd
&gt;&gt;&gt; pwd.getpwuid(500)
('hans', 'x', 500, 100, 'Hans Meier', '/home/hans', '/bin/bash')</screen>
<para>Ok, now I hope you got a small idea of Python. Have fun with
it. I had... :-)</para>
<para>If you have further questions, I would <emphasis>really</emphasis> advise you
to continue with a good book or the documentation on
<ulink url="http://www.python.org"/>. Please don't ask general Python
questions on the &cs; lists...</para>
</sect2>
</sect1>
<sect1 id="ug_writing_scripts"><title>A first look on the incoming and idle scripts</title>
<para>In <xref linkend="howwork"/> I already told you that there are two kinds
of scripts used in &cs;. Now let's have a closer look on them.</para>
<sect2 id="ug_scripts_incoming"><title>The incoming script</title>
<para>Every time a call is received by &cs;, it will call the incoming script -
to be precise it will call a function named <literal>callIncoming</literal> in
a python script located somewhere on your disk. This "somewhere" was defined in
<xref linkend="configcs"/>, remember?</para>
<para>So the given script must always define a function with the following signature:</para>
<programlisting>def callIncoming(call,service,call_from,call_to):
# function body
...</programlisting>
<para>The parameters given by &cs; are:</para>
<variablelist>
<varlistentry>
<term>call</term>
<listitem><para>reference to the incoming call. This will be used
later in all &cs;-functions you call to tell the system which call
you mean. You'll only pass this parameter on to other functions - the
script can't do anything other with it (it's
<emphasis>opaque</emphasis>).</para></listitem>
</varlistentry>
<varlistentry>
<term>service (integer)</term>
<listitem><para>Service of the incoming call as signalled by the ISDN,
set to one of the following values:
<itemizedlist>
<listitem><para><literal>SERVICE_VOICE</literal>: voice call</para></listitem>
<listitem><para><literal>SERVICE_FAXG3</literal>: analog fax call</para></listitem>
<listitem><para><literal>SERVICE_OTHER</literal>: other service not listed above</para></listitem>
</itemizedlist>
</para></listitem>
</varlistentry>
<varlistentry>
<term>call_from (string)</term>
<listitem><para>the number of the calling party (source of the call) as Python string</para></listitem>
</varlistentry>
<varlistentry>
<term>call_to (string)</term>
<listitem><para>the number of the called party (destination of the call) as Python string</para></listitem>
</varlistentry>
</variablelist>
<para>The first task of the function should be to decide if it wants to accept or reject
the call. If it accepts it, it will normally do something with it (receive a fax, record
a voice call, play nice announcements, ...) and then disconnect. After it has done
all necessary work, it should finish immidiately. In a later chapter, I'll present
you some examples which should make things clearer.</para>
<para>Naturally, you can break down your application in more functions and perhaps more
scripts, which will be called and/or imported recursively - but the starting point is always
the <emphasis>incoming script</emphasis> containing <literal>callIncoming</literal>.
If Python and &cs; are correctly installed, you should also be able to import and use
any Python module.</para>
</sect2>
<sect2 id="ug_scripts_idle"><title>The idle script</title>
<para>As the incoming script will only be started when a call comes in, we need
another mechanism to initiate an outgoing call. As &cs; can't know when you plan
to do so, it will just call a function named <literal>idle</literal> in the
so called "idle script" in regular intervals. For configuring the intervals and where
this script is located, please refer to <xref linkend="configcs"/>.</para>
<para>The called function must have the following signature:</para>
<programlisting>def idle(capi):
# function body
...</programlisting>
<para>The only parameter given by &cs; is:</para>
<variablelist>
<varlistentry>
<term>capi</term>
<listitem><para>This is a reference to an internal class of &cs;
which handles the communication with the CAPI interface. You'll
have to pass on this parameter to some &cs; functions. Nothing
else useful you can do with it in your script. This
parameter has internal reasons and will possibly (hopefully)
go away some day in the future. Just pass it on when told
to do so for now.</para></listitem>
</varlistentry>
</variablelist>
<para>Now you can do what you want in this function. Most likely, you'll check
for a job in an email account, look for a file to send in a special directory
or so and place a call to send the job to the right destination.</para>
<para>Theoretically, you could also accomplish every other periodical task on your
system in the idle script - but perhaps we should leave such general things to
applications which were designed for this like <application>cron</application>. ;-)</para>
<para>As above, <literal>idle</literal> can call other functions or scripts if
you like to and all Python modules are available for import.</para>
</sect2>
</sect1>
<sect1 id="fileformats"><title>Used file formats</title>
<para>Before we'll continue with writing scripts, please let me tell you some words
about the file formats the &cs; core uses.</para>
<para>&cs; always reads and saves files in the native format as they are be expected and given
by the CAPI ISDN drivers. This preserves it from having to convert everything from and to other
formats thus reducing unnecessary overhead.</para>
<para>As these formats aren't that well-known and you will need special tools to convert or
view/play them, I'll give you a short overview of how you can do this.</para>
<para>Most likely, your scripts will convert the special ISDN file formats to well-known
ones for sending them to you via e-mail for example. Nevertheless, I'd advice you to store
the received and sent files in the native &cs; formats somewhere. This will protect you from
losing data in the case the conversion fails and will help you in debugging problems which may
arise with your scripts.</para>
<para>All tools which I refer to here are described in <xref linkend="require_soft"/>. See
there for informations how to get them.</para>
<sect2 id="voice_fileformat"><title>Format of voice files (inversed A-Law, 8kHz, mono)</title>
<para>ISDN transmits voice data as waves with a sample-rate of 8kHz in mono. To
save bandwith, a compression called A-Law is used (at least in Europe, other countries
like the USA use u-Law which is quite similar to A-Law). For any reason
beyond my understanding, they use a bit-reversed form of A-Law called
"inversed A-Law".</para>
<sect3 id="creating_alaw"><title>Creating A-Law files</title>
<para>There are two possible ways to create A-Law files.</para>
<para>The first one is to call your computer with your phone (either use the default answering
machine script and configure it as described in <xref linkend="answering_machine.conf"/>
or write a simple script yourself). Now, record whatever you want and take the created
output file (when you use the default scripts please take the file from the
user_dir, not the attachment of the mail as this is already converted) and use it.</para>
<para>You eventually want to trim the recorded file and remove unwanted
noise and silence at the beginning and the end. This can easily be done
by <command>sox</command> and <command>play</command> (both come together
with the <command>sox</command> package).</para>
<para><command>sox</command> is used to convert a file while <command>play</command>
is used to just play it. Both support the same effects including the trim option.
Both also detect what type of file you are using by looking at the suffix of
your file name. So all your inversed A-Law files should be named like
<filename>something.la</filename> (<filename>.la</filename> is the inversed
form of <filename>.al</filename> which stands for A-Law).</para>
<para>So let's first try to find the optimal values for the trim effect by calling
<command>play:</command></para>
<screen><command>play myfile.la trim &lt;start-offset&gt; &lt;duration&gt;</command></screen>
<para>Now play around with start-offset and duration (both given in seconds) until
you know the right values. If you found them, you can use <command>sox</command>
to actually produce the needed file:</para>
<screen><command>sox myfile.la outfile.la trim &lt;start-offset&gt; &lt;duration&gt;</command></screen>
<para>You'll now get a file named <filename>outfile.la</filename> which should
contain what you want.</para>
<para>The second way to create an inversed A-Law file is to record a normal WAV-file
with your favourite sound-tools and convert it to the destination format using
<command>sox</command>. You'll get the best results when your WAV file already
is in 8kHz, mono, 16 bit format. <command>sox</command> is able to convert
other waves if necessary but this usually will result in worse quality. You should
also normalize your sound file to about 50% of the maximum amplitude.</para>
<para>You can convert WAV to inversed A-Law by calling (thx to Carsten Heesch for the tip):</para>
<screen><command>sox myfile.wav -r 8000 -c 1 -b outfile.la resample -ql</command></screen>
<para>If you used vbox in the past and want to convert your old message files, you can
use the following command:</para>
<screen><command>vboxtoau &lt; infile.msg | sox -tau - outfile.la</command></screen>
</sect3>
<sect3 id="playing_alaw"><title>Playing A-Law files</title>
<para>Again, there are two possibilities. The <command>play</command> command
of <command>sox</command> is able to just play the inversed A-Law format without
any conversion. Just call <command>play</command> with the filename as parameter:</para>
<screen><command>play myfile.la</command></screen>
<para>But you can also use sox to convert the A-Law files to the more common
WAV format by just invoking:</para>
<screen><command>sox myfile.la -w outfile.wav</command></screen>
<para>The created <filename>outfile.wav</filename> can be played
by nearly any audio player without problems.</para>
</sect3>
</sect2>
<sect2 id="fax_fileformat"><title>Format of fax files (Structured Fax Files)</title>
<para>CAPI-compliant drivers will expect and provide fax files in a so called
Structured Fax File (SFF). As this seems to be a CAPI-specific format, there
are not much tools out there for GNU/Linux which are capable of handling it.
Finally I found some small tools written by Peter Sch&auml;fer, which we can
use here.</para>
<para>&cs; is also able to receive color fax files which will be stored in
a special file format I called CFF.</para>
<sect3 id="create_sff"><title>Creating a SFF</title>
<para>In current Ghostscript releases, a patch from Peter has been
included to produce SF files. To see if your Ghostscript already
supports it, enter <command>gs --help</command> and look for
the so-called <command>cfax</command>-device in the long device list
presented to you. If it's not listed, you have to take a newer Ghostscript
or recompile it, sorry. I don't know any other way to produce SFF currently.</para>
<para>You need a PostScript file (as produced by nearly every Linux program
when you choose "print to file") first. Now you can call GhostScript to
convert it to a SFF:</para>
<screen><command>gs -dNOPAUSE -dBATCH -sDEVICE=cfax -sOutputFile=outfile.sff file.ps</command></screen>
<para>If you're not sure if it worked you can use <command>sffview</command>
as described below.</para>
</sect3>
<sect3 id="view_sff"><title>Viewing / converting from SFF</title>
<para>To simply view a received SFF, you can use the <command>sffview</command>
program. It's a simple but useful tool for viewing SF files without the need
to convert them. Just start it and you will get a GUI where you can open the
desired file.</para>
<para>If you want to convert a fax file to a more common format, I recommend
using <command>sfftobmp</command>. It supports quite some output formats
like JPEG, TIFF, PBM or BMP. I prefer multipage TIFF files as this is the only
format being able to store several pages in one file. To convert
SFF to multipage TIFF, call:</para>
<screen><command>sfftobmp -tif myfile.sff outfile.tiff</command></screen>
<para>This will give you a TIFF file which you can convert now to nearly
any other useful format with the TIFF tools, for example <command>tiff2pdf</command>.
</para>
</sect3>
<sect3 id="cff"><title>Color faxes - the CFF format</title>
<para>There exists an enhancement to the fax standard which allows to transfer
documents in color. It's not very widely used, but as some people wanted it for &cs;,
I added support for receiving these faxes with &cs;.</para>
<para>The CFF format (I don't know if this is an official name for the format) basically
consists of concatenated JPEG images. Most programs who can handle JPEG files
should be able to open it and display at least the first page. Together with my patch
described in <xref linkend="require_soft"/>, the jpeg2ps tool can convert it to
the PostScript format so you can open it with any usual viewer.</para>
<para>Currently, I don't know a nice way to create this format manually. Therefore,
&cs; currently only supports the reception of these files. If someone knows
such a tool or is willing to implement one, please contact me!</para>
</sect3>
</sect2>
</sect1>
<sect1 id="incoming_tutorial"><title>Tutorial: writing an incoming script</title>
<para>In this section, I'll show you how to code your own incoming script step by step.
We begin with simply accepting every incoming call, playing a beep. The last example
is a very simple but useful answering machine with fax recognition and receiving.</para>
<sect2 id="incoming_tut_basics"><title>Basics and a really dumb answering machine.</title>
<para>Let's start with a very simple case: accept all incoming calls, beep and record
something so we have an audio file to play with later. First of all, create a new directory
somewhere which must be writable to <literal>root</literal>. We also need some test audio
file for sending. Let's take the beep which is distributed with &cs;.</para>
<screen>mkdir capisuite-examples
chmod 777 capisuite-examples # make it world-writeable
cd capisuite-examples
cp /usr/local/share/capisuite/beep.la .</screen>
<para>Perhaps you must change the path in the last line to reflect your installation.</para>
<para>Now copy and paste the example shown here to a file called <filename>example.py</filename>
in this directory. Don't forget to change the <literal>my_path</literal>-setting.</para>
<example><title>example.py</title>
<programlisting>import capisuite<co id="incoming_ex1_1"/>
my_path="/path/to/the/just/created/capisuite-examples/"<co id="incoming_ex1_2"/>
def callIncoming(call,service,call_from,call_to):<co id="incoming_ex1_3"/>
capisuite.connect_voice(call,10)<co id="incoming_ex1_4"/>
capisuite.audio_send(call,my_path+"beep.la")<co id="incoming_ex1_5"/>
capisuite.audio_receive(call,my_path+"recorded.la",20,3)<co id="incoming_ex1_6"/>
capisuite.disconnect(call)<co id="incoming_ex1_7"/></programlisting></example>
<para>Let's walk through the script line by line:</para>
<calloutlist>
<callout arearefs="incoming_ex1_1">
<para>Import the capisuite module which holds all &cs; specific functions.
All &cs; objects (functions, constants) in this module can be referenced by
<literal>capisuite.objectname</literal> now. You could also do a
"<literal>from capisuite import *</literal>", which will insert all objects in the
current namespace - but this isn't recommended as they may collide with other
global objects.</para>
<note><para>The imported module <literal>capisuite</literal> isn't available
as extra module, so you can't do this in an interactive Python session.
It's included in the &cs; binary and only available in scripts interpreted
by &cs;.</para></note>
</callout>
<callout arearefs="incoming_ex1_2">
<para>Please change this to the real path you use for running these examples.</para>
</callout>
<callout arearefs="incoming_ex1_3">
<para>Define the necessary function as explained in
<xref linkend="ug_scripts_incoming"/></para>
</callout>
<callout arearefs="incoming_ex1_4">
<para>That's the first &cs; function we use: it accepts the pending call. The
first parameter tells &cs; which call you mean. This parameter is necessary
for nearly all &cs; functions. Ok, we only have one call now - but please
think about an incoming script which also wants to place an outgoing call at
the same time (for example to transfer a call). In this case &cs; wouldn't know
which call you mean - so you must pass the reference you got to all connection
related functions.</para>
<para>You can also tell &cs; to wait for an arbitrary time before accepting a
call - that's what the second parameter is used for. So this script will wait
10 seconds before connecting with the caller. Don't think this parameter is
useless and you could call a Python function (like <literal>time.sleep()</literal>)
to wait instead. This won't work for any delay longer than 4 (or 8, depending
on your ISDN setup) seconds as the call will timeout if an ISDN device doesn't
"pre-accept" it by telling your network provider that it's ringing. &cs; will
do so if necessary - so please just use this parameter.</para>
</callout>
<callout arearefs="incoming_ex1_5">
<para>This call should be fairly self-explainig. Send the audio file stored in
<filename>beep.la</filename>.</para>
</callout>
<callout arearefs="incoming_ex1_6">
<para>Record an audio file for maximal 20 seconds - stopping earlier if more than
3 seconds of silence are recognized.</para>
</callout>
<callout arearefs="incoming_ex1_7">
<para>Last, but not least - disconnect. Hang up. Finish. It's over.</para>
</callout>
</calloutlist>
<para>&cs; configuration must be changed to use the just created script.
Do this by editing your <filename>capisuite.conf</filename> and replacing the
<literal>incoming_script</literal> value by the path to the file you just
created (see <xref linkend="configcs"/>) and restart &cs;.</para>
<para>Now test it: call any number which ends up at your ISDN card - if you have
connected it to your ISDN interface, than any number (MSN) will do - if it's connected
to a PBX, then you must call a number which was configured for the card in your PBX.</para>
<para>You should hear a beep and then you can speak something into this primitive answering
machine. Please don't hangup before the script does as this case isn't handled yet. Just
wait 3 seconds after saying something - it should disconnect after this period of silence.</para>
<para>If it doesn't work, you perhaps made an error when copying the script. In this case,
please have a look at the &cs; log and error log, which you'll find in
<filename>/var/log/capisuite</filename> or <filename>/usr/local/var/log/capisuite</filename>
if you haven't changed the path.</para>
<para>A good trick to check for syntax errors is also to run your script through
the normal Python interpreter. Do this by calling <command>python /path/to/your/example.py</command>.
Naturally, it will complain about the <literal>import capisuite</literal> as this is no standard
Python module. But before it does this, it will check the syntax of your script - so if you get
any <emphasis>other</emphasis> error, please fix it and try again. If you only get
<screen>Traceback (most recent call last):
File "../scripts/incoming.py", line 16, in ?
import capisuite,cs_helpers
ImportError: No module named capisuite</screen>
then your script has a correct syntax.</para>
<para>I hope you got your script working by now - if not, don't hesitate to ask on the
&cs; mailing lists <emphasis>if</emphasis> you have read a Python tutorial before.</para>
<para>In the next section we want to use an announcement, so please record some words
with this simple script and move the created file <filename>recorded.la</filename> to
<filename>announce.la</filename>.</para>
</sect2>
<sect2 id="incoming_tut_improving"><title>Improving it to a useful (?) state</title>
<para>Well, it's really not nice that the caller mustn't hangup - and it's even worse
that we do accept all incoming calls - perhaps by taking away your mothers important
calls?</para>
<para>Let's quickly improve this.</para>
<example><title>example.py, improved</title>
<programlisting>import capisuite
my_path="/path/to/the/just/created/capisuite-examples/"
def callIncoming(call,service,call_from,call_to):
try:<co id="incoming_ex2_1"/>
if (call_to=="123"):<co id="incoming_ex2_2"/>
capisuite.connect_voice(call,10)
capisuite.audio_send(call,my_path+"announce.la")<co id="incoming_ex2_2a"/>
capisuite.audio_send(call,my_path+"beep.la")
capisuite.audio_receive(call,my_path+"recorded.la",20,3)
capisuite.disconnect(call)
else:
capisuite.reject(call,1)<co id="incoming_ex2_3"/>
capisuite.disconnect(call)<co id="incoming_ex2_3a"/>
except capisuite.CallGoneError:
capisuite.disconnect(call)<co id="incoming_ex2_4"/></programlisting></example>
<calloutlist>
<callout arearefs="incoming_ex2_1">
<para>If the other party hangs up unexpectedly, &cs; will raise an
exception named <literal>CallGoneError</literal>. Therefore, you should
always put your code in a <literal>try</literal> statement and catch
the raised exception at the end of your script (or perhaps
earlier if needed). This exception can be raised by any call to a &cs;
command which expects a connection like audio_send(). Since &cs; 0.5, it's
not raised at once on normal disconnects; for example if the caller hangs up
<emphasis>during</emphasis> audio_receive() the function will just finish.
An exception will not be raised until you call the <emphasis>next</emphasis>
command which expects a connection. The reason for this change was to only
raise an exception on real errors and to make it possible to handle disconnects
in the normal flow of your scripts. On most scripts, this change shouldn't
have an effect.
</para>
</callout>
<callout arearefs="incoming_ex2_2">
<para>Have a look at the called number (please replace <literal>123</literal>
with the number &cs; should accept)...</para>
</callout>
<callout arearefs="incoming_ex2_2a">
<para>Play the announcement we recorded in the last section. If you don't
like it, simply record a new one and move the <filename>recorded.la</filename>
again to <filename>announce.la</filename>.</para>
</callout>
<callout arearefs="incoming_ex2_3">
<para>Ignore the call.
The second parameter tells the exact reason for the reject - you can
ignore a call (any other ISDN device or phone will still be ringing for
that number) by using <literal>1</literal>, actively disconnect by
using <literal>2</literal> or any error condition which is
available in the ISDN specification (see <xref linkend="capicodes_isdn"/>
for available codes).</para>
</callout>
<callout arearefs="incoming_ex2_3a">
<para>You always have to call <literal>disconnect</literal> at the end of your script,
as this will wait for the end of the call, while <literal>reject</literal> only initiates
the call reject. Otherwise you'll get a warning in the error log.</para>
</callout>
<callout arearefs="incoming_ex2_4">
<para>This is the exception handler for <literal>CallGoneError</literal> - the
exception &cs; raises when the call is disconnected by the other party
unexpectedly. You should also call <literal>disconnect</literal> here to
wait until the call is completely disconnected.</para>
</callout>
</calloutlist>
<para>Save this to <filename>example.py</filename> again and test it.
It's not necessary to restart &cs; as all scripts will be read at
each time they're executed. Now you're allowed to hang up, too ;-).
</para>
</sect2>
<sect2 id="incoming_tut_unique_names"><title>Using sensible file names</title>
<para>We always used the same name to save the recorded message to which clearly isn't
reasonable. We should really choose a new name for every new call. This isn't as simple as
it may sound - you must assure that the used algorithm will also work for multiple calls
arriving at the same time. Fortunately, the helpful programmer of &cs; had the same problem
and so we can use the code he (hmmm... I?) has written.</para>
<para>The Python module <filename>cs_helpers.py</filename> contains some useful functions
which are needed by the default scripts provided with &cs; but may be also helpful
for the use in your own scripts. It contains the function <literal>uniqueName</literal>
which does exactly what we need here. The syntax is:</para>
<screen>filename=cs_helpers.uniqueName(directory,prefix,sufix)</screen>
<para>The function will find a new unique filename in the given <literal>directory</literal>.
The created filename will be "<filename>prefix-XXX.suffix</filename>" where <literal>XXX</literal>
is the next free number started at 0. The next free number is remembered in a file
<filename>prefix-nextnr</filename> and the created name is returned.</para>
<para>We can simply add this call to our script:</para>
<example><title>using unique filenames</title>
<programlisting>import capisuite<emphasis>,cs_helpers</emphasis>
my_path="/path/to/the/just/created/capisuite-examples/"
def callIncoming(call,service,call_from,call_to):
try:
if (call_to=="123"):
<emphasis>filename=cs_helpers.uniqueName(my_path,"voice","la")</emphasis>
capisuite.connect_voice(call,10)
capisuite.audio_send(call,my_path+"announce.la")
capisuite.audio_send(call,my_path+"beep.la")
capisuite.audio_receive(call,<emphasis>filename</emphasis>,20,3)
capisuite.disconnect(call)
else:
capisuite.reject(call,1)
except capisuite.CallGoneError:
capisuite.disconnect(call)</programlisting></example>
<para>If you're interested in other functions which <literal>cs_helpers.py</literal>
defines, just have a look at the reference at <xref linkend="default_helpers"/>.</para>
</sect2>
<sect2 id="incoming_tut_fax_recognition"><title>Automatic fax recognition and receiving</title>
<para>As last step, I want to show you how fax recognition and receiving works and
how to switch from voice to fax mode.</para>
<para>Here's the last and most complicated example of this section. It'll introduce
four new &cs; functions and shows how to split up the functionality in another
function which is used by <literal>callIncoming</literal>. There are much changes
which are described below - but most of them should be nearly self-explanatory.
So I don't think this last step is too big. And you don't want to read 10 more steps
here, do you? ;-)</para>
<example><title>Adding fax functions</title>
<programlisting>import capisuite,cs_helpers,os<co id="incoming_ex4_0"/>
my_path="/path/to/the/just/created/capisuite-examples/"
def callIncoming(call,service,call_from,call_to):
try:
if (call_to=="123"):
filename=cs_helpers.uniqueName(my_path,"voice","la")
capisuite.connect_voice(call,10)
capisuite.enable_DTMF(call)<co id="incoming_ex4_1"/>
capisuite.audio_send(call,my_path+"announce.la",1)<co id="incoming_ex4_2"/>
capisuite.audio_send(call,my_path+"beep.la",1)
capisuite.audio_receive(call,filename,20,3,1)
dtmf=capisuite.read_DTMF(call,0)<co id="incoming_ex4_3"/>
if (dtmf=="X"):<co id="incoming_ex4_4"/>
if (os.access(filename,os.R_OK)):<co id="incoming_ex4_5"/>
os.unlink(filename)
faxIncoming(call)<co id="incoming_ex4_6"/>
capisuite.disconnect(call)
else:
capisuite.reject(call,1)
except capisuite.CallGoneError:
capisuite.disconnect(call)
def faxIncoming(call):
capisuite.switch_to_faxG3(call,"+49 123 45678","Test headline")<co id="incoming_ex4_7"/>
filename=cs_helpers.uniqueName(my_path,"fax","sff")
capisuite.fax_receive(call,filename)<co id="incoming_ex4_8"/></programlisting></example>
<calloutlist>
<callout arearefs="incoming_ex4_0">
<para>In this example, we need a normal Python module for the first time.
The <literal>os</literal> module holds functions for all kinds of operation
system services and is needed for deleting a file here.</para>
</callout>
<callout arearefs="incoming_ex4_1">
<para>DTMF is the abbreviation for Dual Tone Multi Frequency. These
are the tones which are generated when you press the digits on your
phone and are usually used for dialling. They're also sent by modern
fax machines before the transmission starts. Therefore, the same
functions can be used for recognizing pressed digits and fax machines.
</para>
<para>Before any DTMF is recognized by &cs;, the according function must
be enabled by <literal>enable_DTMF</literal>.</para>
</callout>
<callout arearefs="incoming_ex4_2">
<para>All audio send and receive functions support abortion when a DTMF
tone is recognized. This is enabled by passing "<literal>1</literal>"
as last parameter. It will also prevent the function from starting
if a DTMF char was recognized <emphasis>before</emphasis> but not yet
read by the script.</para>
</callout>
<callout arearefs="incoming_ex4_3">
<para>&cs; stores all received DTMF signals in a buffer from where they
can be read at any time. Reading is done by <literal>read_DTMF</literal>
which also clears the buffer. It will return all received characters in
a string, so if the caller presses "3","5","*", you'll get "35*".</para>
<para>The <literal>0</literal> tells &cs; not to wait for DTMF signals -
if none are available, it will simply return an empty string.
It's also possible to specify that it should wait for a certain amount of
time or until a certain number of signals have been received.</para>
<note><para>Please note that it's not necessary to check for received DTMF
after each audio send or receive function. Simply enable the DTMF abortion
in all commands in a block and check for received tones after the whole block.
</para></note>
</callout>
<callout arearefs="incoming_ex4_4">
<para>Fax machines send a special tone which is represented as
"<literal>X</literal>" by the CAPI. So if you receive the string
"X", a fax machine is calling and we should start our fax handling routines.</para>
</callout>
<callout arearefs="incoming_ex4_5">
<para>Possibly, the announcement was so short that the recording has started
already before the fax is recognized. We won't save a file containing
only the fax beep and so we test if it was created (<function>os.access</function>
checks for the existence of a file) and delete it if needed by calling
<literal>os.unlink</literal>.</para>
</callout>
<callout arearefs="incoming_ex4_6">
<para>Fax handling was realized in a separate function which is called here.</para>
</callout>
<callout arearefs="incoming_ex4_7">
<para>So far, this connection is in voice mode (which was set by using
<literal>connect_voice</literal>). If we want to receive a fax now, the
mode must be changed to fax. This is done by <literal>switch_to_faxG3</literal>.
As the fax protocol needs some additional parameters, they must be given
here. The first string is the so called <emphasis>fax station ID</emphasis>
which is sent to the calling fax and shown in it's protocol, while the
second one is a <emphasis>fax headline</emphasis>. This headline is mainly
used for sending faxes. To be honest, I personally don't know if it has any
sense to specify this if you only want to receive a fax. But it surely won't
harm ;-). If someone knows this for sure, please tell me.</para>
<note><para>If you want to use an own number solely for fax purposes, you
should <emphasis>not</emphasis> use <literal>switch_to_faxG3</literal>.
Use <literal>connect_faxG3</literal> instead.</para></note>
</callout>
<callout arearefs="incoming_ex4_8">
<para>After the connection has been set to fax mode succesfully, we can
receive the fax document finally. The used function
<literal>fax_receive</literal> gets a new name which is again created by
calling <literal>cs_helpers.uniqueName</literal> as above.</para>
</callout>
</calloutlist>
<para>Congrats. You've finished my small tutorial. Now it's up to you - you can
play with the created script and try to make it more complete. Many of the
commands used above also return useful informations which we didn't use here.
There's still much to do - sending received calls to a user via e-mail, log
connections, ... If you want to complete this script,
<xref linkend="command_reference"/> will be helpful. You can also read on here
to have a short look on the idle scripts, followed by a quick overview of the
structure of the default scripts shipped with &cs;.</para>
</sect2>
</sect1>
<sect1 id="idle_examples"><title>Example for an idle script</title>
<para>After we've seen how to handle incoming calls, a very short introduction to
initiate outgoing calls by using the idle script will follow.</para>
<para>As written before, the idle script will be called by &cs; in regular intervals
allowing you to look for stored jobs somewhere and sending them to the destinations.</para>
<para>The example shown here will look for a file <filename>job-XXXX.sff</filename> in
the example directory we created in the last section. This file will be faxed to the
destination indicated by <literal>XXXX</literal>. If you have no valid destination
where you can send test faxes to, how about using &cs; as source and destination at
the same time? In this case, replace <literal>XXXX</literal> by the number your
incoming script handles. This won't work if your ISDN card can't handle two fax
transfers in parallel (some old AVM B1 cards have this limitation, for example).</para>
<para>We now need one or more fax files in the SFF format for our tests, so please
create some with a name like the one shown above. If you don't know how to do this,
please refer to <xref linkend="create_sff"/>.</para>
<para>If I want to develop a &cs; script but am not really sure how to do it, I often
start by coding a normal script which I can test without &cs;. So let's create a script
which searches the files and extracts the destination numbers first. If this works,
we can continue by adding the &cs; specific calls later.</para>
<example><title>idle_example.py</title>
<programlisting>import os,re<co id="idle_ex1_1"/>
my_path="/path/to/your/capisuite-examples/"
files=os.listdir(my_path)<co id="idle_ex1_2"/>
files=filter (lambda s: re.match("job-.*\.sff",s),files)<co id="idle_ex1_3"/>
for job in files:<co id="idle_ex1_4"/>
destination=job[4:-3]<co id="idle_ex1_5"/> # Hmmm.. Is this right?
print "found",job,"to destination",destination</programlisting>
</example>
<calloutlist>
<callout arearefs="idle_ex1_1">
<para>We know the <literal>os</literal> module already.
<literal>re</literal> provides functions for searching for regular
expressions. If you don't know what regular expressions are, please
read for example the Python documentation for the
<literal>re</literal>-module or some other documentation about them.
It's too complicated to explain it here.</para>
</callout>
<callout arearefs="idle_ex1_2">
<para><literal>os.listdir</literal> returns the files in a given
directory as list.</para>
</callout>
<callout arearefs="incoming_ex1_3">
<para>This line is a little bit more tricky. It filters out all filenames
which doesn't follow the rule <emphasis>starting with "job-", then any
number of chars, ending with ".sff"</emphasis> from the list. This is
done by the <literal>filter</literal> function. The function expects the name
of a function which checks the rule as first parameter and the list to filter
(<literal>files</literal>) as second one.</para>
<para>We could now define a new function and use its name here, but the
<literal>lambda</literal> keyword allows a much more elegant solution: it
defines a "nameless function" with the parameter <literal>s</literal>. The
function body follows directly behind and consists of a call to
<literal>re.match</literal> which checks if the given string
<literal>s</literal> matches the expression.
</para>
</callout>
<callout arearefs="incoming_ex1_4">
<para>Iterate over all found filenames.</para>
</callout>
<callout arearefs="incoming_ex1_5">
<para>The destination is extracted from the given filename by using string
indexes.</para>
</callout>
</calloutlist>
<para>Now, save the script as <filename>idle_example.py</filename> in our example dir and run
it by calling <command>python idle_example.py</command>.</para>
<para>If you have provided SFF files with the right names they should be shown line by line
now. But... Obviously something doesn't work right here. The destination includes the
"<literal>.</literal>". Indeed, I've made a mistake when indexing the string. It should be
<literal>destination=job[4:-4]</literal> instead of <literal>[4:-3]</literal>. So let's change
that and test again. It should work now. That's the reason why I prefer to code such scripts
outside of &cs; first. Debugging is much faster this way...</para>
<para>As we know now that the basic parts work, we can add the real communication functions.</para>
<para>Please save this example to <filename>idle_example.py</filename> in your example directory, again.</para>
<example><title>idle_example.py, version for &cs;</title>
<programlisting>import os,re<emphasis>,capisuite</emphasis>
my_path="/path/to/your/capisuite-examples/"
my_number="678"<co id="idle_ex2_1"/>
my_stationID="+49 123 45678"
my_headline="example headline"
def idle(capi):<co id="idle_ex2_4"/>
files=os.listdir(my_path)
files=filter (lambda s: re.match("job-.*\.sff",s),files)
for job in files:
destination=job[4:-4]
capisuite.log("sending "+job+" to destination "+destination,1)<co id="idle_ex2_5"/>
try:
(call,result)=capisuite.call_faxG3(capi,1,my_number,destination,
60,my_stationID,my_headline)<co id="idle_ex2_6"/>
if (result!=0):<co id="idle_ex2_7"/>
capisuite.log("job "+job+" failed at call setup with reason "
+str(hex(result)),1)
os.rename(my_path+job,my_path+"failed-"+job)<co id="idle_ex2_9"/>
return<co id="idle_ex2_10"/>
capisuite.fax_send(call,my_path+job)<co id="idle_ex2_11"/>
(result,resultB3)=capisuite.disconnect(call)<co id="idle_ex2_12"/>
except capisuite.CallGoneError:
(result,resultB3)=capisuite.disconnect(call)
if (result in (0,0x3400,0x3480,0x3490,0x349f) and resultB3==0):<co id="idle_ex2_13"/>
capisuite.log("job "+job+" was successful",1)
os.rename(my_path+job,my_path+"done-"+job)
return
else:
capisuite.log("job "+job+" failed during send with reasons "
+str(hex(result))+","+str(hex(resultB3)),1)
os.rename(my_path+job,my_path+"failed-"+job)</programlisting>
</example>
<calloutlist>
<callout arearefs="idle_ex2_1">
<para>Some parameters for sending the fax are set here. <literal>my_number</literal> is your own number
which is used for sending the fax. <literal>my_stationID</literal> is the fax station ID, which will
be transmitted to the other fax machine and shown on the sent fax page. Only digits and "+" are allowed.
You can also define a short text which will show up in the fax headline in <literal>fax_headline</literal>.
</para>
</callout>
<callout arearefs="idle_ex2_4">
<para>As explained in <xref linkend="ug_scripts_idle"/>, you have to define a function called
<literal>idle</literal> which will be executed in regular intervals by &cs; then. So all code
has been moved to this function.</para>
</callout>
<callout arearefs="idle_ex2_5">
<para>We can't print messages to stdout as the script will run in the context of a daemon. So &cs;
provides functions for creating entries in the &cs; log file. <function>log</function> expects at
least two parameters: the message and a log level. This level corresponds to the log level setting
in the global &cs; configuration (see <xref linkend="configcs"/>). If the level of the message is
<emphasis>less or equal</emphasis> the level set in the configuration, it is printed to the logs.
So you can insert messages for debug purposes which aren't printed to the logs in normal operation
by using levels higher than 1.</para>
</callout>
<callout arearefs="idle_ex2_6">
<para>This function initiates an outgoing call using the fax service. The parameters are:</para>
<itemizedlist>
<listitem><para>reference to the Capi object you got from &cs; (parameter to <function>idle</function>).</para></listitem>
<listitem><para>the (number of the) controller to use for outgoing calls. The first controller has always number "1".</para></listitem>
<listitem><para>own number to use for the outgoing call</para></listitem>
<listitem><para>destination number to call</para></listitem>
<listitem><para>maximum time to wait for a successful connection in seconds</para></listitem>
<listitem><para>the fax station ID</para></listitem>
<listitem><para>fax headline</para></listitem>
</itemizedlist>
<para>The function returns a tuple containing a reference to the created call and an error value.</para>
</callout>
<callout arearefs="idle_ex2_7">
<para>This block checks if the connection was successful. For a detailled description of possible error values,
please see the <xref linkend="command_reference"/>. 0 means "everything was ok, call is established".</para>
</callout>
<callout arearefs="idle_ex2_9">
<para>If the call wasn't successful, rename the fax file to prevent the script from sending the same file
over and over.</para>
</callout>
<callout arearefs="idle_ex2_10">
<para>Don't forget to exit the <function>idle</function> function if the call couldn't be established!</para>
</callout>
<callout arearefs="idle_ex2_11">
<para>Another very simple &cs; command: send the given file as fax document.</para>
</callout>
<callout arearefs="idle_ex2_12">
<para>We previously ignored the reasons <emphasis>why</emphasis> a call was disconnected. Now we have to
analyze them because we need to know if the file was transferred succesful. Therefore,
<function>disconnect</function> returns a tuple containing of the physical and logical error value. Every
ISDN connection contains one physical and (at least) one logical connection. One could imagine the physical
connection as "the wire" connecting us to our destination, while the logical connection refers to
the fax protocol which uses this "wire". You have to look on both values to see if everything was ok.</para>
</callout>
<callout arearefs="idle_ex2_13">
<para>Allowed values for the physical disconnection are 0,0x3400,0x3480, 0x3490 and 0x349f. These all mean "no error
occured, call was disconnected normally". The logical value may only be 0 if everything went ok. For further
information on error values, please refer to <xref linkend="command_reference"/>.</para>
</callout>
</calloutlist>
<para>After you've saved the file and changed the default values to your own configuration, please alter the value of
<literal>idle_script</literal> in the &cs; configuration to point to this script as described in <xref linkend="configcs"/>.
</para>
<para>Restart &cs; and watch the logs. Some minutes later, the <filename>job-XXX.sff</filename> files should've been sent
and renamed to either <filename>done-job-XXX.sff</filename> or <filename>failed-job-XXX.sff</filename>. If the job failed,
please consult the error log and the error values explained in
<xref linkend="command_reference"/> and <xref linkend="capicodes"/>.</para>
<para>Hopefully, this tutorial helped you in understanding how to code your own scripts. Please continue with changing the
examples or the files distributed with &cs; (read <xref linkend="default_script_overview"/> before). You will find a
complete reference of the available commands in <xref linkend="command_reference"/>.</para>
<para>If you have any trouble in getting your scripts up and running, please use the &cs; mailing lists. And don't forget to have
fun. ;-)</para>
</sect1>
<sect1 id="default_script_overview"><title>Structural overview of the default scripts</title>
<sect2 id="default_incoming"><title>incoming.py</title>
<para>The incoming script handles all incoming connections. It reads two configuration files containing all necessary
data which were described in detail in <xref linkend="script_config"/>. The overall structure will be described here
giving you an overview of how it is implemented.</para>
<para>First (after importing some necessary modules), it defines the necessary function <function>callIncoming</function>
which will call all other functions if needed.</para>
<sect3 id="default_incoming_1"><title>function <function>callIncoming</function></title>
<para>This function starts with a call to <function>cs_helpers.readConfig</function>
to read the configuration. It then iterates through all sections representing the configured users (except
<literal>GLOBAL</literal>) to see if the called number belongs to any user. If a match is found, the user and
the defined service are saved to <literal>curr_user</literal> and <literal>curr_service</literal>.</para>
<para>If no match was found (<literal>curr_user</literal> is empty), the call is
rejected and the function returns. Otherwise the call is accepted and - depending
on the service used - <function>faxIncoming</function> or
<function>voiceIncoming</function> is called.</para>
<para>The function also defines an exeception handler for <literal>capisuite.CallGoneError</literal>.</para>
</sect3>
<sect3 id="default_incoming_2"><title>function <function>faxIncoming</function></title>
<para>First of all, the directory to use for incoming fax data is determined and created
if not existing yet, the existence of the given user is checked and a log entry is written.</para>
<para>It then switches to fax mode if necessary, creates a uniqe filename, calls
<function>capisuite.fax_receive</function>, disconnects and logs the disconnection reasons.
Then it checks if a fax has been really received succesfully (i.e. if the file exists). If yes, it creates a description file for it,
<command>chown</command>'s the file to the right user and sends the file as mail.</para>
</sect3>
<sect3 id="default_incoming_3"><title>function <function>voiceIncoming</function></title>
<para><function>voiceIncoming</function> has much more features to accomplish like fax recognition
and switching to fax mode, starting a remote inquiry etc.</para>
<para>It starts by determining the directory to use and creating a unique filename. Also, the PIN for remote inquiry
is saved to a private variable. There are two possibilites now: the user has already an own announcement - in this case
it's played now. Otherwise, a predefined announcement containing of a general announcement and the number which was called
is played. If recording a message wasn't disabled (by setting <literal>voice_action</literal> to <literal>None</literal>),
it starts now after a beep.</para>
<para>All <function>audio_send</function> and <literal>audio_receive</literal> calls used so far had DTMF abortion enabled
and so the script "falls through" all these calls after a DTMF signal was recognized. After them,
<function>read_DTMF</function> is used to see if any such signal have been found. "<literal>X</literal>" represents the fax
tone and triggers a switch to fax protocols and a call to <function>faxIncoming</function>. Any other received signals
are interpreted to be a part of the PIN for remote inquiry and so a loop which waits 3 seconds after each tone for the next
one is entered. If a valid PIN is entered, it starts the <function>remoteInquiry</function>. After three wrong attempts,
it will disconnect.</para>
<para>After disconnecting and logging, a description file is written (if the recorded file exists), both files will be
<command>chown</command>'ed to the right user and the recorded message will be mailed to him/her.</para>
</sect3>
<sect3 id="default_incoming_4"><title>function <function>remoteInquiry</function></title>
<para>The <function>remoteInquiry</function> starts by creating a lock file and acquiring an
exclusive lock on it to prevent two parallel remote inquiries for the same user. If the lock
can't be acquired, an error message is played and the function returns. If locking has succeeded,
a list of the recorded voice calls is compiled by listing the user directory, filtering and
sorting it. Now, a file called <filename>last_inquiry</filename> is read when it exists.
It contains the number of the last heard message. With this information, the old messages can
be filtered out to a separate list and thus the caller can listen to messages he doesn't know
already first.</para>
<para>The number of new messages is said, followed by a small menu where the caller can choose
to either record an announcment or hear the recorded messages. If he chooses announcement
recording, the function <function>newAnnouncement</function> is called, otherwise
<function>remoteInquiry</function> will continue.</para>
<para>Now, a loop will first iterate over the new and then the all old messages. It starts by
telling the caller how much messages have been found. Then all messages will be played, repeating
the following steps for each one:</para>
<itemizedlist>
<listitem><para>read the description file of the current message</para></listitem>
<listitem><para>play an information block containing the current message number, source, destination, date and time of the
call.</para>
</listitem>
<listitem><para>play the message</para></listitem>
<listitem><para>provide a menu where the caller can go on to the next or last message, repeat the current message or delete
it</para>
</listitem>
</itemizedlist>
<para>At the end, the caller will be informed that no more messages are available and the connection will be finished, followed
by releasing the lock file and deleting it.</para>
</sect3>
<sect3 id="default_incoming_5"><title>function <function>newAnnouncement</function></title>
<para><function>newAnnouncement</function> presents some instructions to the caller first. Then, the new announcement will be
recorded to a temporary file. To give the user the ability to check it, it will be played, followed by a menu allowing him/her to
save it or to repeat the recording. If the user has chosen to save it, it will be moved from the temporary file to
<filename>announcement.la</filename> in the users voice directory and <command>chown</command>'ed to him/her. The call will be
finished with an approval to the caller that it has been saved succesfully.</para>
</sect3>
</sect2>
<sect2 id="default_idle"><title>idle.py</title>
<para>The idle script is responsible for collecting jobs from the send queues (where they're stored by <command>capisuitefax</command>)
and sending them to the given destinations. It reads its configuration from the files presented in <xref linkend="script_config"/>, too.
</para>
<sect3 id="default_idle_1"><title>function <function>idle</function></title>
<para>After reading the configuration by calling <function>cs_helpers.readConfig</function> and testing for the existence
of the archive directories needed, the userlist is compiled from the list of available sections.</para>
<para>For each user who has a valid fax setup (otherwise this user will be skipped), the send queue will be looked at. If the
necessary queue directories don't exist, they'll be created. After that, a list called <literal>files</literal> with the names of
all files in the send queue is created and filtered to only contain fax jobs.</para>
<para>For each found job, a security check is done to see if it was created by the right user. If this check was successful, a
lock file is created and a lock on it is acquired. This prevents the <command>capisuitefax</command> command to abort a job while
it is in transfer. After that, the existence of the file is checked (perhaps the job has been cancelled before we could acquire
the lock?).</para>
<para>Now, the description file for this job is read and the starttime is checked. If it's not reached, the script will go on with
the next job. Otherwise, some parameters are taken from the configuration and a log message is created. The file is transferred by
calling <function>sendfax</function>. The results are stored and logged. If the job was successful, it is moved to the done dir and
an approval is mailed to the user. If it wasn't succesful, the delay interval will be determined from the configuration and the new
starttime is calculated by increasing the old starttime by this interval. A counter for the used tries is increased and the description
file is rewritten with the new values. If the number of tries exceeds a given maximum, the job is moved to the failed dir and the
error is reported to the user by mail.</para>
<para>Finally, the lock file will be unlocked and deleted.</para>
</sect3>
<sect3 id="default_idle_2"><title>function <function>sendfax</function></title>
<para>This function handles the send process. After determining the MSN to use from either the <literal>outgoing_MSN</literal>
setting or from the <literal>fax_numbers</literal> list, a call to the destination is initiated. If it fails, the function returns;
otherwise the file will be sent and the connection finished.</para>
</sect3>
<sect3 id="default_idle_3"><title>function <function>movejob</function></title>
<para>This is a small helper function used for moving a job and its accompanying description file to another directory.</para>
</sect3>
</sect2>
<sect2 id="default_capisuitefax"><title>capisuitefax</title>
<para><command>capisuitefax</command> allows to enqueue fax jobs, list the current queue and abort jobs. It's not used directly by the
&cs; system - it's a frontend for the users send queue directory. It has several commandline options - for an explanation
of its usage, please refer to <xref linkend="usingscripts_send"/>.</para>
<para>There are three helper functions defined first. <emphasis><function>usage</function></emphasis> prints out a small help if
"<option>--help</option>" or "<option>-h</option>" was given as parameter or if a parameter isn't understood. <emphasis><function
>showlist</function></emphasis> gets a listing from the users send queue directory and prints it nicely formatted as table. <emphasis>
<function>abortjob</function></emphasis> removes a job from the queue. It does this safely by using a lock file to not interfere with
the sending process.</para>
<para>The main code of this script checks the given commandline options first. It sets several variables to the given values.
After some checks of the validity of the options, the rights of the user to send faxes and the existence of the necessary
directories, it will fulfill the requested task. Either, <function>listqueue</function> will be called to show a listing of
active jobs, <function>abortjob</function> to abort a job or the given files are processed and put to the queue.</para>
<para>To process a job, the existence of it and its format will be checked. Currently, only PostScript is allowed. The &cs; core
itself only supports the SF format. Therefore, the files are converted from PostScript to it by calling
<command>ghostscript</command>. Finally, the description file for this job is created containing the given parameters like the
destination number.</para>
</sect2>
<sect2 id="default_helpers"><title>cs_helpers.py</title>
<para>The <filename>cs_helpers.py</filename> script contains many small helper functions used in the other scripts. These are:</para>
<variablelist>
<varlistentry>
<term><function>readConfig</function></term>
<listitem><para>Reads either the configuration files described in <xref linkend="script_config"/> or an arbitrary
config file like the description files accompanying each received file or job to send.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>escape</function></term>
<listitem><para>"Escapes" a file name - this means puts it into quotation marks to be able to
call external tools with it as parameter savely and correctly even if the name contains
special characters or whitespaces.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>getOption</function></term>
<listitem><para>Get an option from the given user section and fall back to the global section if it's not found.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>getAudio</function></term>
<listitem><para>Get an audio file from the users directory or fall back to the global &cs; directory.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>uniqueName</function></term>
<listitem><para>Construct a new file name in a given directory by using a given prefix &amp; suffix and adding a counter. See
also <xref linkend="incoming_tut_unique_names"/>.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>sendMIMEMail</function></term>
<listitem><para>Send an e-mail with attachment to a given user. Supports also automatic format conversion SFF -> PDF and
inversed A-Law -> WAV.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>sendSimpleMail</function></term>
<listitem><para>Send a normal e-mail without attachment to a given user.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>writeDescription</function></term>
<listitem><para>Create a description file which can be read by <function>readConfig</function> later.</para></listitem>
</varlistentry>
<varlistentry>
<term><function>sayNumber</function></term>
<listitem><para>Supports saying a number using various wave fragments. Works only for german output currently.</para></listitem>
</varlistentry>
</variablelist>
<para>For a detailled description of each function and its usage, please have a look at the script file itself. There are
comments describing each function in detail.</para>
</sect2>
</sect1>
<sect1 id="command_reference"><title>&cs; command reference</title>
<para>&cs; provides an internal Python module called <literal>capisuite</literal> which can be imported as usual by <literal>import capisuite</literal>.
Internal means, it's compiled in the &cs; binary and will only be found if &cs; interpretes the script.</para>
<para>A complete reference of all functions of this module is auto-generated from the &cs; sources and so you'll find it in the reference
manual available locally on <ulink url="../reference/group__python.html"/> or online on
<ulink url="http://www.capisuite.de/reference/group__python.html"/>.</para>
<para>As it doesn't make sense to duplicate the information here, please refer to it.</para>
<note><para>These functions are implemented in C internally and so the reference document shows the C function header instead
of the header how it would be defined in Python. So please ignore the function header shown there and only have a look at the
description and the parameters given under <emphasis>args</emphasis>. If this is too confusing, please tell me and perhaps I'll
find a better way to auto-create this document someday then...</para></note>
</sect1>
</chapter>
<appendix id="acknowledgements"><title>Acknowledgements</title>
<para>&cs; started as diploma thesis in winter semester 2002/03. I want to thank the following people for helping me with it:</para>
<itemizedlist>
<listitem><para>Karsten Keil from SUSE Linux AG (my tutor for the thesis) for his invaluable support and patience when answering me
many ISDN questions, doing tests and for his suggestions concerning the architecture of &cs;</para></listitem>
<listitem><para>Prof. Dr. Wolfgang J&uuml;rgensen from the UAS Landshut (my tutor from the UAS) for his help in ISDN
questions during the thesis and for teaching me the ISDN basics in his lecture before</para></listitem>
<listitem><para>Prof. Dr. Peter Scholz from the UAS Landshut (second tutor from the UAS) for his support and his suggestions</para></listitem>
<listitem><para>my girl friend Claudia and her sister Bethina for proof-reading my thesis</para></listitem>
<listitem><para>Peter Reinhart from SUSE for proof-reading my thesis</para></listitem>
<listitem><para>many colleagues from SUSE for helping me with technical problems, esp. Andreas Jaeger, Andreas Schwab, Thorsten Kukuk and Andi Kleen</para></listitem>
<listitem><para>Achim Bohnet for being the first one from the community trying to compile the CVS version and making me quite some suggestions
how to improve it</para></listitem>
<listitem><para>Achim Bohnet and Herbert H&uuml;bner for providing binary RPMs for
RedHat and Debian</para></listitem>
</itemizedlist>
<para>Since I published &cs;, many other people tested it, reported errors and sent me bug
fixes or new code to include. I won't mention them all here, but I'm including all names in the
ChangeLog and NEWS files distributed with &cs;. A general THANK YOU to all of my users and
especially those named there!</para>
</appendix>
<appendix id="capicodes"><title>CAPI 2.0 Error Codes</title>
<para>The CAPI interface used here has its own coding of standard ISDN
error codes. Most of the errors described in <xref linkend="capicodes_general"/>
are only important for developers of the &cs; core. As user, you only need
to know the codes shown in <xref linkend="capicodes_connection"/>
as they'll be used in the &cs; Python functions like <function>capisuite.disconnect</function>.</para>
<para>You'll find a list of all the codes and a short description below. A detailled description of
the CAPI codes can be found in the CAPI specification available at
<ulink url="http://www.capi.org"/>.</para>
<para>All numbers are given <emphasis>hexadecimal</emphasis>!</para>
<section id="capicodes_connection"><title>CAPI errors describing connection problems</title>
<para>All errors described here indicate some problem with the connection. These errors
are also important for script writers as they're returned by some &cs; Python functions.
See <xref linkend="command_reference"/> for further details.</para>
<section id="capicodes_protocol"><title>Protocol errors</title>
<para>Protocol errors indicate some problem during data transfer. Only messages for
the transparent (voice) and fax protocols spoken by &cs; are shown here.</para>
<itemizedlist>
<listitem><para><literal>0</literal> - Normal call clearing, no error</para></listitem>
<listitem><para><literal>3301</literal> - Protocol error layer 1 (broken line or B-channel removed by signalling protocol)</para></listitem>
<listitem><para><literal>3302</literal> - Protocol error layer 2</para></listitem>
<listitem><para><literal>3303</literal> - Protocol error layer 3</para></listitem>
<listitem><para><literal>3304</literal> - Another application got that call</para></listitem>
<listitem><para><literal>3311</literal> - T.30 (fax) error: Connection not successful (remote station is not a G3 fax device)</para></listitem>
<listitem><para><literal>3312</literal> - T.30 (fax) error: Connection not successful (training error)</para></listitem>
<listitem><para><literal>3313</literal> - T.30 (fax) error: Disconnect before transfer (remote station doesn't support transfer mode, e.g. wrong resolution)</para></listitem>
<listitem><para><literal>3314</literal> - T.30 (fax) error: Disconnect during transfer (remote abort)</para></listitem>
<listitem><para><literal>3315</literal> - T.30 (fax) error: Disconnect during transfer (remote procedure error)</para></listitem>
<listitem><para><literal>3316</literal> - T.30 (fax) error: Disconnect during transfer (local transmit data underflow)</para></listitem>
<listitem><para><literal>3317</literal> - T.30 (fax) error: Disconnect during transfer (local receive data overflow)</para></listitem>
<listitem><para><literal>3318</literal> - T.30 (fax) error: Disconnect during transfer (local abort)</para></listitem>
<listitem><para><literal>3319</literal> - T.30 (fax) error: Illegal parameter coding (e.g. defective SFF file)</para></listitem>
</itemizedlist>
</section>
<section id="capicodes_isdn"><title>ISDN error codes</title>
<para>These codes are ISDN error codes which are described by the
ETS 300 102-01 standard in more detail. It's currently available for private use at
<ulink url="http://www.etsi.org"/> without fee. For details how the ISDN codes
are mapped to the CAPI numbers see the CAPI specification, parameter "Info".</para>
<itemizedlist>
<listitem><para><literal>3400</literal> - Normal termination, no reason available</para></listitem>
<listitem><para><literal>3480</literal> - Normal termination</para></listitem>
<listitem><para><literal>3481</literal> - Unallocated (unassigned) number</para></listitem>
<listitem><para><literal>3482</literal> - No route to specified transit network</para></listitem>
<listitem><para><literal>3483</literal> - No route to destination</para></listitem>
<listitem><para><literal>3486</literal> - Channel unacceptable</para></listitem>
<listitem><para><literal>3487</literal> - Call awarded and being delivered in an established channel</para></listitem>
<listitem><para><literal>3490</literal> - Normal call clearing</para></listitem>
<listitem><para><literal>3491</literal> - User busy</para></listitem>
<listitem><para><literal>3492</literal> - No user responding</para></listitem>
<listitem><para><literal>3493</literal> - No answer from user (user alerted)</para></listitem>
<listitem><para><literal>3495</literal> - Call rejected</para></listitem>
<listitem><para><literal>3496</literal> - Number changed</para></listitem>
<listitem><para><literal>349A</literal> - Non-selected user clearing</para></listitem>
<listitem><para><literal>349B</literal> - Destination out of order</para></listitem>
<listitem><para><literal>349C</literal> - Invalid number format</para></listitem>
<listitem><para><literal>349D</literal> - Facility rejected</para></listitem>
<listitem><para><literal>349E</literal> - Response to STATUS ENQUIRY</para></listitem>
<listitem><para><literal>349F</literal> - Normal, unspecified</para></listitem>
<listitem><para><literal>34A2</literal> - No circuit / channel available</para></listitem>
<listitem><para><literal>34A6</literal> - Network out of order</para></listitem>
<listitem><para><literal>34A9</literal> - Temporary failure</para></listitem>
<listitem><para><literal>34AA</literal> - Switching equipment congestion</para></listitem>
<listitem><para><literal>34AB</literal> - Access information discarded</para></listitem>
<listitem><para><literal>34AC</literal> - Requested circuit / channel not available</para></listitem>
<listitem><para><literal>34AF</literal> - Resources unavailable, unspecified</para></listitem>
<listitem><para><literal>34B1</literal> - Quality of service unavailable</para></listitem>
<listitem><para><literal>34B2</literal> - Requested facility not subscribed</para></listitem>
<listitem><para><literal>34B9</literal> - Bearer capability not authorized</para></listitem>
<listitem><para><literal>34BA</literal> - Bearer capability not presently available</para></listitem>
<listitem><para><literal>34BF</literal> - Service or option not available, unspecified</para></listitem>
<listitem><para><literal>34C1</literal> - Bearer capability not implemented</para></listitem>
<listitem><para><literal>34C2</literal> - Channel type not implemented</para></listitem>
<listitem><para><literal>34C5</literal> - Requested facility not implemented</para></listitem>
<listitem><para><literal>34C6</literal> - Only restricted digital information bearer capability is available</para></listitem>
<listitem><para><literal>34CF</literal> - Service or option not implemented, unspecified</para></listitem>
<listitem><para><literal>34D1</literal> - Invalid call reference value</para></listitem>
<listitem><para><literal>34D2</literal> - Identified channel does not exist</para></listitem>
<listitem><para><literal>34D3</literal> - A suspended call exists, but this call identity does not</para></listitem>
<listitem><para><literal>34D4</literal> - Call identity in use</para></listitem>
<listitem><para><literal>34D5</literal> - No call suspended</para></listitem>
<listitem><para><literal>34D6</literal> - Call having the requested call identity has been cleared</para></listitem>
<listitem><para><literal>34D8</literal> - Incompatible destination</para></listitem>
<listitem><para><literal>34DB</literal> - Invalid transit network selection</para></listitem>
<listitem><para><literal>34DF</literal> - Invalid message, unspecified</para></listitem>
<listitem><para><literal>34E0</literal> - Mandatory information element is missing</para></listitem>
<listitem><para><literal>34E1</literal> - Message type non-existent or not implemented</para></listitem>
<listitem><para><literal>34E2</literal> - Message not compatible with call state or message type non-existent or not implemented</para></listitem>
<listitem><para><literal>34E3</literal> - Information element non-existent or not implemented</para></listitem>
<listitem><para><literal>34E4</literal> - Invalid information element contents</para></listitem>
<listitem><para><literal>34E5</literal> - Message not compatible with call state</para></listitem>
<listitem><para><literal>34E6</literal> - Recovery on timer expiry</para></listitem>
<listitem><para><literal>34EF</literal> - Protocol error, unspecified</para></listitem>
<listitem><para><literal>34FF</literal> - Interworking, unspecified</para></listitem>
</itemizedlist>
</section>
</section>
<section id="capicodes_general"><title>Internal CAPI errors</title>
<para>These errors are mainly of interest for developers of the &cs; core. If you're a user, you normally
won't need them.</para>
<section id="capicodes_info"><title>Informative values (no error)</title>
<para>These values are only warnings and may appear in the extensive &cs; log in messages from the CAPI.</para>
<itemizedlist>
<listitem><para><literal>0000</literal> - No error, request accepted</para></listitem>
<listitem><para><literal>0001</literal> - NCPI not supported by current protocol, NCPI ignored</para></listitem>
<listitem><para><literal>0002</literal> - Flags not supported by current protocol, flags ignored</para></listitem>
<listitem><para><literal>0003</literal> - Alert already sent by another application</para></listitem>
</itemizedlist>
</section>
<section id="capicodes_register"><title>Errors concerning CAPI_REGISTER</title>
<para>These errors may appear when the application starts and mostly indicate problems with your driver installation.</para>
<itemizedlist>
<listitem><para><literal>1001</literal> - Too many applications.</para></listitem>
<listitem><para><literal>1002</literal> - Logical Block size too small; must be at least 128 bytes.</para></listitem>
<listitem><para><literal>1003</literal> - Buffer exceeds 64 kbytes.</para></listitem>
<listitem><para><literal>1004</literal> - Message buffer size too small, must be at least 1024 bytes.</para></listitem>
<listitem><para><literal>1005</literal> - Max. number of logical connections not supported.</para></listitem>
<listitem><para><literal>1006</literal> - reserved (unknown error).</para></listitem>
<listitem><para><literal>1007</literal> - The message could not be accepted because of an internal busy condition.</para></listitem>
<listitem><para><literal>1008</literal> - OS Resource error (out of memory?).</para></listitem>
<listitem><para><literal>1009</literal> - CAPI not installed.</para></listitem>
<listitem><para><literal>100A</literal> - Controller does not support external equipment.</para></listitem>
<listitem><para><literal>100B</literal> - Controller does only support external equipment.</para></listitem>
</itemizedlist>
</section>
<section id="capicodes_messages"><title>Message exchange errors</title>
<para>These errors are really internal: they're raised if the application calls
CAPI in a wrong way. If they occur, it's usually a bug which you should tell
the &cs; developers.</para>
<itemizedlist>
<listitem><para><literal>1101</literal> - Illegal application number.</para></listitem>
<listitem><para><literal>1102</literal> - Illegal command or subcommand, or message length less than 12 octets.</para></listitem>
<listitem><para><literal>1103</literal> - The message could not be accepted because of a queue full condition.</para></listitem>
<listitem><para><literal>1104</literal> - Queue is empty.</para></listitem>
<listitem><para><literal>1105</literal> - Queue overflow: a message was lost!!</para></listitem>
<listitem><para><literal>1106</literal> - Unknown notification parameter.</para></listitem>
<listitem><para><literal>1107</literal> - The message could not be accepted because on an internal busy condition.</para></listitem>
<listitem><para><literal>1108</literal> - OS resource error (out of memory?).</para></listitem>
<listitem><para><literal>1109</literal> - CAPI not installed.</para></listitem>
<listitem><para><literal>110A</literal> - Controller does not support external equipment.</para></listitem>
<listitem><para><literal>110B</literal> - Controller does only support external equipment.</para></listitem>
</itemizedlist>
</section>
<section id="capicodes_resource"><title>Resource/Coding Errors</title>
<para>The errors described here are issued when the application tries to use a ressource which isn't available.
These are mostly also bugs in the application. Please tell us.</para>
<itemizedlist>
<listitem><para><literal>2001</literal> - Message not supported in current state</para></listitem>
<listitem><para><literal>2002</literal> - Illegal Controller / PLCI / NCCI</para></listitem>
<listitem><para><literal>2003</literal> - Out of PLCI</para></listitem>
<listitem><para><literal>2004</literal> - Out of NCCI</para></listitem>
<listitem><para><literal>2005</literal> - Out of LISTEN</para></listitem>
<listitem><para><literal>2007</literal> - llegal message parameter coding</para></listitem>
</itemizedlist>
</section>
<section id="capicodes_service"><title>Errors concerning requested services</title>
<para>The errors described here are issued when the application tries to request a service in a wrong way.
Again, these are mostly bugs you should tell us.</para>
<itemizedlist>
<listitem><para><literal>3001</literal> - B1 protocol not supported</para></listitem>
<listitem><para><literal>3002</literal> - B2 protocol not supported</para></listitem>
<listitem><para><literal>3003</literal> - B3 protocol not supported</para></listitem>
<listitem><para><literal>3004</literal> - B1 protocol parameter not supported</para></listitem>
<listitem><para><literal>3005</literal> - B2 protocol parameter not supported</para></listitem>
<listitem><para><literal>3006</literal> - B3 protocol parameter not supported</para></listitem>
<listitem><para><literal>3007</literal> - B protocol combination not supported</para></listitem>
<listitem><para><literal>3008</literal> - NCPI not supported</para></listitem>
<listitem><para><literal>3009</literal> - CIP Value unknown</para></listitem>
<listitem><para><literal>300A</literal> - Flags not supported (reserved bits)</para></listitem>
<listitem><para><literal>300B</literal> - Facility not supported</para></listitem>
<listitem><para><literal>300C</literal> - Data length not supported by current protocol</para></listitem>
<listitem><para><literal>300D</literal> - Reset procedure not supported by current protocol</para></listitem>
</itemizedlist>
</section>
</section>
</appendix>
</book>