UAS API - Inbound Receive Fax Sample Application

  • Filename:

    samples/inbound_receive_fax.py

    Description:

    A sample application that will answer an inbound call and receive a fax. The sample first creates a FaxToReceive object which is the wrapper for the fax document. This object is used to set the name of the file to which the fax will be received. It is assumed that the name of the fax file will be read from the application_parameters variable which is configured on the Inbound Services page (Manage -> Inbound Services). To this is added the application_instance_id to make it unique.

    After creating the fax document object, the call is answered and the function channel.FaxReceiver.start() is called to start receiving the fax. The start function is passed a reference to the fax document object.

    The sample then waits for the fax settings to be negotiated, channel.FaxReceiver.wait_for_negotiated_settings(), and prints them to the screen. It then uses channel.FaxReceiver.wait_for_next_page() to wait for each page to be received, it does this until the last page has been indicated, and prints out the quality of the page. The page quality, along with several other things, is available on the fax document object.

    Finally, the function channel.FaxReceiver.wait_until_finished() is used to wait until the fax session has completed. After that, the call is hung up.

    Code:

    """
    A simple example that will answer an inbound call, 
    and receive a fax.
    
        Actions:
            - check the channel state
            - answer
            - receive a fax
            - hang up
    
    It is assumed that the name of the fax file is given in 
    application_parameters. To this is added the application_instance_id
    to make it unique.
    
    """
    
    from prosody.uas import Hangup, Error, FaxToSend, FaxToReceive
    
    __uas_identify__ = "application"
    __uas_version__  = "0.01b"
    
    def main(channel, application_instance_id, file_man, my_log, application_parameters):
        try:
            return_code = 0
    
            # This outbound application is going to receive a fax, so we create
            # a FaxToReceive object, known as a fax document object
            my_fax = FaxToReceive()
    
            # Now set the name of the file to which the fax will be saved.
            cause = my_fax.set_file_name('{0}_{1}.tif'.format(application_parameters, application_instance_id))
    
            # The cause will be of type FileCause and should be checked.
            if cause != my_fax.FileCause.NORMAL:
                raise Error("failed to set the file name, cause is {0}".format(cause))
    
            # Answer the inbound call in the normal way
            if channel.state() == channel.State.CALL_INCOMING:
                channel.answer() # this can raise a Hangup exception
            else:
                raise Hangup('No inbound call')
    
            # Now we can start to receive the fax.
            if channel.FaxReceiver.start(fax_to_receive=my_fax) != True:
                cause = channel.FaxReceiver.cause()
                raise Error("fax receiver failed to start receiving the fax, cause is {0}.".format(cause))
    
            # The fax endpoints will negotiate the parameters for the fax session - which modem
            # and the modem speed, among other things. We can wait until these have been published
            # and then have a look. Note that the dictionary will be empty if fax negotiation fails.
            negotiated_settings = channel.FaxReceiver.wait_for_negotiated_settings()
            if negotiated_settings == {}:
                cause = channel.FaxReceiver.cause()
                if cause == channel.FaxReceiver.Cause.NOTFAX:
                    raise Hangup("The transmitter was not a fax machine.")
                else:
                    raise Error("Fax negotiation failed with cause {0}".format(cause))
    
            my_log.debug("Negotiated Settings")
            for setting, value in negotiated_settings.items():
                my_log.debug("{0:>15.15} : {1}".format(setting, value))
    
            # Now we can wait for each page to be received, we do this until we've been told
            # that no more pages will be received. For each page we log the page quality.
            # This, and more, detail is available on the fax document object.
            # It is important to note that the last_page flag does not indicate success, it simply 
            # means that no more pages will be processed.
            while channel.FaxReceiver.Details.last_page is not True:
                pages = channel.FaxReceiver.wait_for_next_page()
                my_log.debug("Received {0} pages so far".format(pages))
                my_log.debug("Last received page quality: {0}".format(my_fax.PageDetails[-1].receive_quality))
    
            # Now we need to wait until the fax session has finished. We need to do this even though
            # the last page flag has been set. Remember to check the cause, the last_page indicator
            # may have been set, but this does not mean that every page was received.
            cause = channel.FaxReceiver.wait_until_finished()
            if cause != channel.FaxReceiver.Cause.NORMAL:
                raise Error("Fax receiver failed with cause {0}".format(cause))
    
        except Hangup as exc:
            my_log.info("Hangup exception reports {0}".format(exc))
            return_code = -101
    
        except Error as exc:
            my_log.error("Error exception reports {0}".format(exc))
            return_code = -100
    
        except Exception as exc:
            my_log.exception("Got unexpected exception {0}".format(exc))
            return_code = -102
    
        finally:
            if channel.state() != channel.State.IDLE:
                channel.hang_up()
        return return_code
  • Filename:

    Samples\C#\InboundReceiveFax\InboundReceiveFax.cs

    Description:

    For this sample application, the 'Enable fax receive' option needs to be ticked in the fax tab of your inbound service that will invoke it. Typically the default fax options provided will result in a fax being received successfully.

    The filename for the fax to be received is formed by extracting the user part of the CallFrom property of the incoming call and adding the current date.

    Having called Ring and Answer the sample sets the fax document's filename. The UASApplication object exposes the single fax document that can be received on the incoming call. It then calls the channel.FaxReceiver.Receive() method to perform the fax reception. If successful this will return FaxCause.Normal and the received fax will have been saved under the specified filename. The sample then waits for the remote end to be hung up.

    Code:

    using System;
    using System.Threading;
    using AMSClassLibrary;
    using UASAppAPI;
    
    // An inbound application that answers a call and receives a fax from that call.
    //
    // The received fax is saved to a .tif file name constructed from the user part of the
    // callFrom field and the current date.
    //
    // Fax receiving can be enabled for a particular service by editing the service entry
    // from the platform Inbound Services page.
    //
    // Requires:
    // [Fax Receive to be enabled in the service invoking this application]
    namespace InboundReceiveFax
    {
        // The application class.
        // This must have the same name as the assembly and must inherit from either 
        // UASInboundApplication or UASOutboundApplication.
        // It must override the Run method.
        public class InboundReceiveFax : UASInboundApplication
        {
            // Possible return codes
            enum ReturnCode
            {
                // Success Codes:
                Success = 0,
    
                // Fail Codes:
                // -1 to -99 reserved
                ExceptionThrown = -100,
                FaxReceiveNotEnabled = -101,
                FaxReceiveFailed = -102,
                FaxReceiveTimedOut = -103
            }
    
            // This is the entry point for the application
            public override int Run(UASCallChannel channel,
                                    string applicationParameters)
            {
                this.Trace.TraceInfo("Start - appParms [{0}]", applicationParameters);
                ReturnCode reply = ReturnCode.Success;
    
                // Check that fax receiving has been enabled in the calling service.
                if (this.FaxDocumentToReceive == null)
                {
                    this.Trace.TraceError("This app requires that fax receiving is enabled in the calling service");
                    return (int)ReturnCode.FaxReceiveNotEnabled;
                }
    
                // Get the user from CallFrom
                string callFromUser = channel.CallDetails.CallFrom;
                callFromUser = callFromUser.Remove(callFromUser.LastIndexOf('@'));
                callFromUser = callFromUser.Substring(callFromUser.IndexOf(':') + 1);
    
                // Construct the file name of the fax to be received
                DateTime now = DateTime.Now;
                string receivedFaxFileName = String.Format("/faxs/received/{0}_{1}:{2}:{3}.tif", 
                    callFromUser, 
                    now.Year,
                    now.Month,
                    now.Day);
    
                try
                {
                    // Ring for 2 seconds
                    channel.Ring(2);
    
                    // Answer the call
                    CallState state = channel.Answer();
                    if (state == CallState.Answered)
                    {
                        this.Trace.TraceInfo("Answered");
    
                        // Set the file name target for the received fax
                        this.FaxDocumentToReceive.SetFileName(receivedFaxFileName);
    
                        // Set fax options:
                        // Just set this end's subscriber id.
                        // (this overrides any set in the service registration)
                        FaxOptions options = new FaxOptions("SubscriberId", "1234");
    
                        // Now receive the fax
                        this.Trace.TraceInfo("Receiving fax to {0}", receivedFaxFileName);
                        FaxCause cause = channel.FaxReceiver.Receive(this.FaxDocumentToReceive, options);
                        if (cause != FaxCause.Normal)
                        {
                            this.Trace.TraceInfo("Failed to receive fax: cause {0}", channel.FaxSender.Cause.ToString());
                            reply = ReturnCode.FaxReceiveFailed;
                        }
                        else
                        {
                            // Received ok, now retrieve some of the negotiated fax options
                            // used to send/receive the fax.
                            FaxOptions negotiatedOptions = this.FaxDocumentToReceive.Details.NegotiatedOptions;
                            String sendingSubscriberId = negotiatedOptions["remotesubscriberid"];
                            this.Trace.TraceInfo("Received fax from subscriber Id: {0}", sendingSubscriberId);
                        }
                    }
    
                    // Wait for the call to be hung up by the far end
                    channel.WaitForIdle(Timeout.Infinite);
                }
                catch (Exception e)
                {
                    this.Trace.TraceError("Exception thrown {0}", e.Message);
                    reply = ReturnCode.ExceptionThrown;
                }
    
                this.Trace.TraceInfo("Completed");
                return (int)reply;
            }
        }
    }
  • Filename:

    Samples\VB\InboundReceiveFax\InboundReceiveFax.vb

    Description:

    For this sample application, the 'Enable fax receive' option needs to be ticked in the fax tab of your inbound service that will invoke it. Typically the default fax options provided will result in a fax being received successfully.

    The filename for the fax to be received is formed by extracting the user part of the CallFrom property of the incoming call and adding the current date.

    Having called Ring and Answer the sample sets the fax document's filename. The UASApplication object exposes the single fax document that can be received on the incoming call. It then calls the channel.FaxReceiver.Receive() method to perform the fax reception. If successful this will return FaxCause.Normal and the received fax will have been saved under the specified filename. The sample then waits for the remote end to be hung up.

    Code:

    Imports System
    Imports AMSClassLibrary
    Imports UASAppAPI
    
    ' An inbound application that answers a call and receives a fax from that call.
    '
    ' The received fax is saved to a .tif file name constructed from the user part of the
    ' callFrom field and the current date and time.
    '
    ' Requires:
    ' [Fax Receive to be enabled in the service invoking this application]
    Namespace InboundReceiveFax
    
        ' The application class.
        ' This must have the same name as the assembly and must inherit from either 
        ' UASInboundApplication or UASOutboundApplication.
        ' It must override the Run method.
        Public Class InboundReceiveFax
            Inherits UASInboundApplication
    
            ' Possible return codes
            Enum ReturnCode
                ' Success Codes:
                Success = 0
                ' ... any positive integer
    
                ' Fail Codes:
                ' -1 to -99 reserved
                ExceptionThrown = -100
                FaxReceiveFailed = -101
                FaxReceiveTimedOut = -102
            End Enum
    
            ' This is the entry point for the application
            Overrides Function Run(ByVal channel As UASCallChannel, _
                                   ByVal applicationParameters As String) _
                                   As Integer
    
                Me.Trace.TraceInfo("Start - appParms [{0}]", applicationParameters)
                Dim reply As ReturnCode = ReturnCode.Success
    
                ' Get the user from CallFrom
                Dim callFromUser = channel.CallDetails.CallFrom
                callFromUser = callFromUser.Remove(callFromUser.LastIndexOf("@"))
                callFromUser = callFromUser.Substring(callFromUser.IndexOf(":") + 1)
    
                ' Construct the file name of the fax to be received
                Dim now As DateTime = DateTime.Now
                Dim receivedFaxFileName = String.Format("/faxs/received/{0}_{1}:{2}:{3}_{4}.tif", _
                    callFromUser, _
                    now.Year, _
                    now.Month, _
                    now.Day, _
                    now.ToShortTimeString())
    
                Try
                    ' Ring for 2 seconds
                    channel.Ring(2)
    
                    ' Answer the call
                    Dim state As CallState
                    state = channel.Answer()
    
                    If state = CallState.Answered Then
                        Me.Trace.TraceInfo("Call answered")
    
                        ' Set the file name target for the received fax
                        Me.FaxDocumentToReceive.SetFileName(receivedFaxFileName)
    
                        ' Now receive the fax
                        Me.Trace.TraceInfo("Receiving fax to {0}", receivedFaxFileName)
                        Dim cause As FaxCause = channel.FaxReceiver.Receive(Me.FaxDocumentToReceive)
                        If Not cause = FaxCause.Normal Then
                            Me.Trace.TraceInfo("Failed to receive fax: cause {0}", channel.FaxSender.Cause.ToString())
                            reply = ReturnCode.FaxReceiveFailed
                        End If
                    End If
    
                    ' Wait for the call to be hung up by the far end
                    channel.WaitForIdle(Timeout.Infinite)
    
                Catch ex As Exception
                    Me.Trace.TraceError("Exception thrown {0}", ex.Message)
                    reply = ReturnCode.ExceptionThrown
                End Try
    
                Me.Trace.TraceInfo("Completed")
                Return reply
    
            End Function
    
        End Class
    
    End Namespace