#!/usr/bin/perl
############################################################################
#
#   Copyright 1999-2000 Phone.com, Inc.  All rights reserved.
#
#   Subject to the terms and conditions of the SDK License Agreement, 
#   Phone.com, Inc. hereby grants you the right to use the UP.SDK 
#   software and its related documentation.
#
#   The Phone.com name and logo and the family of terms carrying the "UP."
#   prefix are trademarks of Phone.com, Inc. All other brands and product 
#   names may be trademarks of the respective companies with which they 
#   are associated.
#
############################################################################

######################################################################
#
# Employee Directory Application
#
# The application allows a user to lookup employees in a file-based
# database and then call, email or fax that employee.
#
# Key concepts illustrated include:
#	- Calling and returning from contexts
#	- Passing in and receiving values from contexts
#	- Sending an email using UP.Mail
#	- Sending a fax using the UP.Link Fax Manager
#
# Application Flow:
#
# A user's navigation through the application is represented as state
# machine transitions.  Each URL encodes the state to transition to in
# the "NEXT" (Next State) argument.  The main routine of the application
# examines the NEXT argument and either returns the appropriate static
# WML deck, or invokes the appropriate routine to generate the dynamic
# WML deck.
#
# The NEXT state could be one of the following:
# HOME or blank - To start the application and display the Welcome msg
# EMPINFO - To display information about the selected employee
# DOCLIST - To display the list of documents available for faxing
# NOEMP   - To display an error message if no employee is selected
# SENDFAX - To fax the selected document to the selected employee
#
# The application has 4 contexts:
#  - A main context that displays employee info and launches the others
#  - An employee_picker context to select an employee
#  - The UP.Mail context to send email
#  - A fax context
#
######################################################################

######################################################################
#
# SDK SAMPLE APPLICATION CONFIGURATION
#
# To configure this application to run on your system:
#
# 1. On Unix, change the first line of the file to use the
#    path for the Perl interpreter on your system
#
# 2. On NT, verify that the .cgi file extension is mapped to
#    the Perl interpreter on your system or rename the file
#    extension to the default extension that is mapped to the
#    Perl interpreter on your system (e.g. .pl)
#
######################################################################

######################################################################
# AppUtils Loading and Configuration
######################################################################
# Include the apputils directory which contains all the SDK utilities
BEGIN { push (@INC, "../apputils");	} # Path to SDK apputils

# Load required application utilities
require 'FileUtils.pl';
require Digest;
require Fax;

######################################################################
# Constants
######################################################################
# Employees records file
$EMPDATA_FILE = './employees.data';

# The Decks

# Home page for the ACME Sample Application
# This card demonstrates calling the employee picker context by 
# utilizing the <spawn>, <onexit> and <recieve> elements.  
# If the user selects a valid employee, the URL listed href 
# attribute is called.  The <receive> elements specifies the 
# variables that will hold the return values returned by the 
# employee picker context.  If the user cancels from the context, 
# <catch> is used as a default exception handler so user returns 
# to this deck.  

# HOME Deck 
# ACME Employee Directory home deck. 
$HOME = 
'<wml>
   <card id="AcmeEmpDir">
      <do type="accept">
         <spawn href="acme_picker.cgi"
	    onexit="acme_emp.cgi?NEXT=EMPINFO">
               <receive name="ln"/>
               <receive name="fn"/>
               <receive name="ph"/>
               <receive name="em"/>
               <receive name="fax"/>
            <catch/>
	 </spawn>
      </do>

      <do type="option" label="Info">
         <go href="#AcmeInfo"/>
      </do>

      <p align="center">
         <img src="../images/acme.bmp" alt="ACME"/>
      </p>

      <p align="center">
         Employee Directory
      </p>
   </card>

   <card id="AcmeInfo">
      <p mode="wrap"> 
         The ACME Employee Directory is a sample WML application that 
         demonstrates searching for an employee in a file-based database, 
         then provides the ability to call, email or fax that employee.
      </p>
   </card>
</wml>';


# Utility Deck 
# Used to display data 

$DISPINFO =
'<wml>
   <card>
      <p>
         %s
      </p>
   </card>
</wml>';


# Employee Info Deck 
# Displays information about the employee selected in the
# employee picker context

$EMPINFO =
'<wml>
   <card>

<!--  call employee picker, to retrieve employee specific info -->         

      <do type="options" label="Find">
           <spawn href="acme_picker.cgi" 
                onexit="acme_emp.cgi?NEXT=EMPINFO">
            <receive name="ln"/>
            <receive name="fn"/>
            <receive name="ph"/>
            <receive name="em"/>
            <receive name="fax"/> 
            <catch/>
	 </spawn>
      </do>
            
<!--  center and highlight the selected name -->         

      <p align="center">
         <strong>
            $ln, $fn 
            <br/>
         </strong>
      </p>

<!--  display select options Call, Email and Fax w/images -->         

      <p mode="nowrap">

         <select name="ListOps" title="Make Call">

<!--  Call via wtai (Wireless Telephoney Application Interface) -->         

            <option title="Call">
               <onevent type="onpick">
                  <go href="wtai://wp/mc;$ph"/>
               </onevent>
               <img localsrc="phone3" src="" alt="Call"/> $ph
            </option>

<!--  Email via UP.Mail -->         

            <option title="Email" >
               <onevent type="onpick">
                  <spawn href="device:home/goto?svc=Email&amp;SUB=sendMsg">
                     <setvar name="TO" value="$em"/>
                     <setvar name="SUBJ" value="Mail from ACME"/>
                     <setvar name="MT" value="Mail from ACME Example Application"/>                  <catch/>
                  </spawn> 
               </onevent>
               <img localsrc="envelope1" src="" alt="Email"/>$em 
            </option>

<!--  Fax via UP.Link Fax Manager -->         

            <option title="Fax">
               <onevent type="onpick">
                  <spawn href="?NEXT=DOCLIST" onexit="$next_url">
                     <setvar name="fax" value="$fax"/>
                     <setvar name="ln" value="$ln"/>
                     <setvar name="fn" value="$fn"/>
                     <setvar name="next_url" value=""/>
                     <receive name="next_url"/>
                  </spawn>
               </onevent>
               <img localsrc="fax" src="" alt="Fax"/>$fax
            </option>
         </select>
      </p>
   </card>
</wml>';


# FaxDoc Deck 
# Calls the UP.Link Fax Manager for faxing text or postscript document.

$FAXDOC =
'<wml>
   <card>
      <do type="accept" label="Fax">
         <go method="get" href="?">
	    <postfield name="NEXT" value="SENDFAX"/>
            <postfield name="DOC" value="$doc"/>
            <postfield name="FAX" value="$fax"/>
            <postfield name="LAST" value="$ln"/>
            <postfield name="FIRST" value="$fn"/>
	 </go>
      </do>
      <p>
         $ln, $fn
         <select name="doc">
            <option value="1">Text doc</option>
	    <option value="2">PostScript Doc</option>
         </select>
      </p>
   </card>
</wml>';

# FAXDONE Deck 
# Confirms fax was sent
$FAXDONE =
'<wml>
   <card>
      <p>
         %s was faxed to: $fax
      </p>
   </card>
</wml>';

######################################################################
# State definitions
#
# main uses these definitions to determine next state
######################################################################
# Static states {state, deck}
%StaticStateArray = ( "EMPINFO", $EMPINFO, 
                      "DOCLIST", $FAXDOC
                    );

# Dynamic states {state, routine}
%DynamicStateArray = ( "HOME", "splashScreen",
                       "SENDFAX", "faxDocument"
                     );

#Call the main function to begin execution
&main;

######################################################################
#
# main Function
#
# When a URL request is received, the application checks the value of
# NEXT to determine the next action. The next action may be to display
# a static WML deck or to execute a function to generate dynamic WML.
# This function implements this logic.
#
# This function also reads the CGI variables into %cgiVars for the
# rest of the application to use.
#
######################################################################
sub main
{
    # Parse the HTTP CGI variables into the associative array %cgiVars
    %cgiVars = &AppUtils::ParseCGIVars();

    # Get the next state, if undefined, use HOME as the state
    $nextState = $cgiVars{"NEXT"};
    if( !defined($nextState) )	{
        $nextState = "HOME";
    }

    # Transition to the next state
    $deck = $StaticStateArray{$nextState};
    if( $deck ne "" ) {
        # Found a static deck to return for the NEXT state, just return it
        &AppUtils::OutputDeck($deck);
    }
    else {
        #Retrieve dynamic function state 
        $subRoutine = $DynamicStateArray{$nextState};

        # Check for valid function
	if ($subRoutine ne undef) {

	    # Function found to generate NEXT state dynamic WML
            &$subRoutine();
        }
        else {
            #Invalid NEXT state, return Error deck
	    &AppUtils::ErrorExit("Invalid Dynamic State", "");
        }
    }
}

######################################################################
# splashScreen
#
# This function builds a digest containing the splash screen image
# and the ACME application's home WML deck.
#
######################################################################
sub splashScreen
{
   # Before adding a splash screen first check to see
   # if the browser supports images
   my $supportsImages = 0;
   foreach (split(/\,/, $ENV{'HTTP_ACCEPT'})) {
      if (m/image\/bmp/) {
         $supportsImages = 1;
      }
   }

   # Read in the image. In production code, you should
   # check for and handle, errors when reading images.
   if ($supportsImages == 1) {
       open(FD, "<../images/acme.bmp");
       seek(FD, 0, 2);
       $fdsize = tell(FD);
       seek(FD, 0, 0);
       read(FD, $image, $fdsize);
       close FD;
   }
	
   # Declare, create and build digest containg deck and if images 
   # are supported, include image.  Then return digest. 
   my $digest;
   $digest = new Digest;
   $digest->addDeck("?", $HOME);
   if ($supportsImages == 1) {
     $digest->addImage("image/bmp", "../images/acme.bmp", $image);
   }
   &AppUtils::OutputDigest($digest->asString());
}

######################################################################
# faxDocument
#
# This function shows the creation of a multi-part MIME message using
# the SDK libraries to create a Fax message and to send a response deck
# to the phone
#
######################################################################
sub faxDocument
{
    my $faxNum = $cgiVars{'FAX'};
    my $doc = $cgiVars{'DOC'};
    my $last = $cgiVars{'LAST'};
    my $first = $cgiVars{'FIRST'};

    # NOTE: A well-behaved application should check the value
    # of the FAX_ACCEPTS variable to verify that the fax manager
    # can accept the types of fax documents it wants to send.
    # 
    # The FAX_LIMIT variable should also be checked if the app
    # is prepared to send a document which may exceed the maximum
    # fax byte limit.  
    #
    # Finally, the app should check FAX_ENCODINGS
    # to confirm if the fax manager accepts any encoding types
    # besides the default (7bit).
    #
    # For simplicity, this app only checks for the existence of
    # the FAX_ACCEPTS variable to confirm that the fax manager
    # is available.
     
    my $upFaxLimit = $ENV{'HTTP_X_UP_FAX_LIMIT'};
    my $upFaxEncodings = $ENV{'HTTP_X_UP_FAX_ENCODINGS'};
    my $upFaxAccepts = $ENV{'HTTP_X_UP_FAX_ACCEPTS'};
    
    if ($upFaxAccepts eq '' || $upFaxAccepts eq 'none') {
        &AppUtils::OutputDeck(sprintf($DISPINFO,
                                      "Fax manager not available"));
        return;
    }

    #Find the content source depending on the user's document selection
    my $docName, $docType;
    if ($doc == 1) {
        $docName = "fax.txt";
        $docType = "text/plain";
    }
    elsif ($doc == 2) {
        $docName = "fax.ps";
	$docType = "application/postscript";
    }
    else {
            &AppUtils::OutputDeck(sprintf($DISPINFO,
                                          "No document selected for faxing"));
            return;
    }

    #Verify valid fax number, if not return
    if (length($faxNum) != 12) {
        &AppUtils::OutputDeck(sprintf($DISPINFO,
                                      "Invalid fax number"));
	return;
    }

    #Update the fax number format
    $faxNum =~ s/\-/ /g;

    # Prefix fax number with dialing prefix, "1"
    $faxNum = "1 ".$faxNum;

    #Read the fax content in from a file.
    my $faxData;
    open (FAX_FILE, $docName);
    $faxData = join ('', <FAX_FILE>);
    close (FAX_FILE);
    
    #Create a fax object
    my($fax) = new Fax($faxNum, $faxData, $docType);
    $fax->setComment("Comment line that appears on the cover page");
    $fax->setRecipientName("$first $last");
    $fax->setSenderName("ACME Employees Directory Application");

    # Create a digest with an WML deck
    my $digest;
    $digest = new Digest;
    $digest->addDeck("", sprintf($FAXDONE,$docName));

    $digest->addFax($fax);
	
    # The service ID is optional, and is only used to facilitate
    # transaction logging by the UP.Link operator (network carrier).
    $digest->addHeader("x-up-service", "UP.SDK ACME Example Application");

    &AppUtils::OutputDigest($digest->asString());
}
