Example for an idle script

After we've seen how to handle incoming calls, a very short introduction to initiate outgoing calls by using the idle script will follow.

As written before, the idle script will be called by CapiSuite in regular intervals allowing you to look for stored jobs somewhere and sending them to the destinations.

The example shown here will look for a file job-XXXX.sff in the example directory we created in the last section. This file will be faxed to the destination indicated by XXXX. If you have no valid destination where you can send test faxes to, how about using CapiSuite as source and destination at the same time? In this case, replace XXXX 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).

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 the section called “Creating a SFF”.

If I want to develop a CapiSuite script but am not really sure how to do it, I often start by coding a normal script which I can test without CapiSuite. 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 CapiSuite specific calls later.

Example 2.5. idle_example.py

import os,re1

my_path="/path/to/your/capisuite-examples/"

files=os.listdir(my_path)2
files=filter (lambda s: re.match("job-.*\.sff",s),files)3

for job in files:4
	destination=job[4:-3]5 # Hmmm.. Is this right?
	print "found",job,"to destination",destination
1

We know the os module already. re 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 re-module or some other documentation about them. It's too complicated to explain it here.

2

os.listdir returns the files in a given directory as list.

3

This line is a little bit more tricky. It filters out all filenames which doesn't follow the rule starting with "job-", then any number of chars, ending with ".sff" from the list. This is done by the filter function. The function expects the name of a function which checks the rule as first parameter and the list to filter (files) as second one.

We could now define a new function and use its name here, but the lambda keyword allows a much more elegant solution: it defines a "nameless function" with the parameter s. The function body follows directly behind and consists of a call to re.match which checks if the given string s matches the expression.

4

Iterate over all found filenames.

5

The destination is extracted from the given filename by using string indexes.

Now, save the script as idle_example.py in our example dir and run it by calling python idle_example.py.

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 ".". Indeed, I've made a mistake when indexing the string. It should be destination=job[4:-4] instead of [4:-3]. 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 CapiSuite first. Debugging is much faster this way...

As we know now that the basic parts work, we can add the real communication functions.

Please save this example to idle_example.py in your example directory, again.

Example 2.6. idle_example.py, version for CapiSuite

import os,re,capisuite

my_path="/path/to/your/capisuite-examples/"
my_number="678"1
my_stationID="+49 123 45678"
my_headline="example headline"

def idle(capi):2
	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)3
		try:
			(call,result)=capisuite.call_faxG3(capi,1,my_number,destination,
			              60,my_stationID,my_headline)4
			if (result!=0):5
				capisuite.log("job "+job+" failed at call setup with reason "
				              +str(hex(result)),1)
				os.rename(my_path+job,my_path+"failed-"+job)6
				return7
			capisuite.fax_send(call,my_path+job)8
			(result,resultB3)=capisuite.disconnect(call)9
		except capisuite.CallGoneError:
			(result,resultB3)=capisuite.disconnect(call)

		if (result in (0,0x3400,0x3480,0x3490) and resultB3==0):10
			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)
1

Some parameters for sending the fax are set here. my_number is your own number which is used for sending the fax. my_stationID 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 fax_headline.

2

As explained in the section called “The idle script”, you have to define a function called idle which will be executed in regular intervals by CapiSuite then. So all code has been moved to this function.

3

We can't print messages to stdout as the script will run in the context of a daemon. So CapiSuite provides functions for creating entries in the CapiSuite log file. log expects at least two parameters: the message and a log level. This level corresponds to the log level setting in the global CapiSuite configuration (see the section called “Configuration of CapiSuite”). If the level of the message is less or equal 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.

4

This function initiates an outgoing call using the fax service. The parameters are:

  • reference to the Capi object you got from CapiSuite (parameter to idle).

  • the (number of the) controller to use for outgoing calls. The first controller has always number "1".

  • own number to use for the outgoing call

  • destination number to call

  • maximum time to wait for a successful connection in seconds

  • the fax station ID

  • fax headline

The function returns a tuple containing a reference to the created call and an error value.

5

This block checks if the connection was successful. For a detailled description of possible error values, please see the the section called “CapiSuite command reference”. 0 means "everything was ok, call is established".

6

If the call wasn't successful, rename the fax file to prevent the script from sending the same file over and over.

7

Don't forget to exit the idle function if the call couldn't be established!

8

Another very simple CapiSuite command: send the given file as fax document.

9

We previously ignored the reasons why a call was disconnected. Now we have to analyze them because we need to know if the file was transferred succesful. Therefore, disconnect 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.

10

Allowed values for the physical disconnection are 0,0x3400,0x3480 and 0x3490. 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 the section called “CapiSuite command reference”.

After you've saved the file and changed the default values to your own configuration, please alter the value of idle_script in the CapiSuite configuration to point to this script as described in the section called “Configuration of CapiSuite”.

Restart CapiSuite and watch the logs. Some minutes later, the job-XXX.sff files should've been sent and renamed to either done-job-XXX.sff or failed-job-XXX.sff. If the job failed, please consult the error log and the error values explained in the section called “CapiSuite command reference” and Appendix B, CAPI 2.0 Error Codes.

Hopefully, this tutorial helped you in understanding how to code your own scripts. Please continue with changing the examples or the files distributed with CapiSuite (read the section called “Structural overview of the default scripts” before). You will find a complete reference of the available commands in the section called “CapiSuite command reference”.

If you have any trouble in getting your scripts up and running, please use the CapiSuite mailing lists. And don't forget to have fun. ;-)