Structural overview of the default scripts

incoming.py

The incoming script handles all incoming connections. It reads two configuration files containing all necessary data which were described in detail in the section called “Script configuration”. The overall structure will be described here giving you an overview of how it is implemented.

Firstly (after importing some necessary modules), it defines the necessary function callIncoming which will call all other functions if needed.

function callIncoming

This function starts with a call to cs_helpers.readConfig to read the configuration. It then iterates through all sections representing the configured users (except GLOBAL) to see if the called number belongs to any user. If a match is found, the user and the defined service are saved to curr_user and curr_service.

If no match was found (curr_user is empty), the call is rejected and the function returns. Otherwise the directory to use for incoming fax or voice data is determined and created if not existing yet.

The last thing the function does, is to produce a log entry, accept the call with the right service (fax or voice) and call either faxIncoming or voiceIncoming. It also defines an exeception handler for capisuite.CallGoneError.

function faxIncoming

faxIncoming is quite straight forward: it creates a uniqe filename, calls capisuite.fax_receive, disconnects and logs the disconnection reasons. Then it checks if a fax have been really received succesfully (i.e. if the file exists). If yes, it creates a description file for it, chown's the file to the right user and sends the file as mail.

function voiceIncoming

voiceIncoming has much more features to accomplish like fax recognition and switching to fax mode, starting a remote inquiry etc.

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 voice_action to None), it starts now after a beep.

All audio_send and audio_receive 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, read_DTMF is used to see if any such signal have been found. "X" represents the fax tone and triggers a switch to fax protocols and a call to faxIncoming. 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 remoteInquiry. After three wrong attempts, it will disconnect.

After disconnecting and logging, a description file is written (if the recorded file exists), both files will be chown'ed to the right user and the recorded message will be mailed to him/her.

function remoteInquiry

The remoteInquiry 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 last_inquiry 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.

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 newAnnouncement is called, otherwise remoteInquiry will continue.

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:

  • read the description file of the current message

  • play an information block containing the current message number, source, destination, date and time of the call.

  • play the message

  • provide a menu where the caller can go on to the next or last message, repeat the current message or delete it

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.

function newAnnouncement

newAnnouncement 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 announcement.la in the users voice directory and chown'ed to him/her. The call will be finished with an approval to the caller that it has been saved succesfully.

idle.py

The idle script is responsible for collecting jobs from the send queues (where they're stored by capisuitefax) and sending them to the given destinations. It reads its configuration from the files presented in the section called “Script configuration”, too.

function idle

After reading the configuration by calling cs_helpers.readConfig and testing for the existence of the archive directories needed, the userlist is compiled from the list of available sections.

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 files with the names of all files in the send queue is created and filtered to only contain fax jobs.

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 capisuitefax 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?).

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 sendfax. 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.

Finally, the lock file will be unlocked and deleted.

function sendfax

This function handles the send process. After determining the MSN to use from either the outgoing_MSN setting or from the fax_numbers list, a call to the destination is initiated. If it fails, the function returns; otherwise the file will be sent and the connection finished.

function movejob

This is a small helper function used for moving a job and its accompanying description file to another directory.

capisuitefax

capisuitefax allows to enqueue fax jobs, list the current queue and abort jobs. It's not used directly by the CapiSuite 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 the section called “Sending fax jobs”.

There are three helper functions defined first. usage prints out a small help if "--help" or "-h" was given as parameter or if a parameter isn't understood. showlist gets a listing from the users send queue directory and prints it nicely formatted as table. abortjob removes a job from the queue. It does this safely by using a lock file to not interfere with the sending process.

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, listqueue will be called to show a listing of active jobs, abortjob to abort a job or the given files are processed and put to the queue.

To process a job, the existence of it and its format will be checked. Currently, only PostScript is allowed. The CapiSuite core itself only supports the SF format. Therefore, the files are coverted from PostScript to it by calling ghostscript. Finally, the description file for this job is created containing the given parameters like the destination number.

cs_helpers.py

The cs_helpers.py script contains many small helper functions used in the other scripts. These are:

readConfig

Reads either the configuration files described in the section called “Script configuration” or an arbitrary config file like the description files accompanying each received file or job to send.

getOption

Get an option from the given user section and fall back to the global section if it's not found.

getAudio

Get an audio file from the users directory or fall back to the global CapiSuite directory.

uniqueName

Construct a new file name in a given directory by using a given prefix & suffix and adding a counter. See also the section called “Using sensible file names”.

sendMIMEMail

Send an e-mail with attachment to a given user. Supports also automatic format conversion SFF -> PDF and inversed A-Law -> WAV.

sendSimpleMail

Send a normal e-mail without attachment to a given user.

writeDescription

Create a description file which can be read by readConfig later.

sayNumber

Supports saying a number using various wave fragments. Works only for german output currently.

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.