Location: PHPKode > scripts > PHP PrintIPP > php-printipp/php_classes/BasicIPP.php
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
 /* @(#) $Header: /sources/phpprintipp/phpprintipp/php_classes/BasicIPP.php,v 1.1 2008/06/21 00:30:56 harding Exp $
 *
 * Class BasicIPP - Send Basic IPP requests, Get and parses IPP Responses.
 *
 *   Copyright (C) 2005-2006  Thomas HARDING
 *   Parts Copyright (C) 2005-2006 Manuel Lemos
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *   mailto:hide@address.com
 *   Thomas Harding, 56 rue de la bourie rouge, 45 000 ORLEANS -- FRANCE
 *   
 */
    
/*

    This class is intended to implement Internet Printing Protocol on client side.

    References needed to debug / add functionnalities:
        - RFC 2910
        - RFC 2911
        - RFC 3380
        - RFC 3382
*/
/*
    TODO: beta tests on other servers than Cups
*/


    // {{{ required and included files
            
            require_once("http_class.php");
            
            // If you want http backend from http://www.phpclasses.org/browse/package/3.html
            /*
            require_once("HTTP/http.php");
            include_once("SASL/sasl.php");
            include_once("SASL/basic_sasl_client.php");
            include_once("SASL/digest_sasl_client.php");
            include_once("SASL/ntlm_sasl_client.php");
            */
    // }}}


/***********************
*
* ippException class
*
************************/

    // {{{ class ippException
class ippException extends Exception {
    
    protected $errno;

    public function __construct($msg,$errno=null) {
        parent :: __construct($msg);
        $this->errno = $errno;
    }

    public function getErrorFormatted() {
    
        $return = sprintf("[ipp]: %s -- "._(" file %s, line %s"),
                $this->getMessage(),
                $this->getFile(),
                $this->getLine());

    return $return;
    }

    public function getErrno() {
    
    return $this->errno ;
    }

}
    // }}}



class BasicIPP {

    // {{{ variables declaration
    // setup variables
    public $paths = array("root" => "/", 
                          "admin" => "/admin/", 
                          "printers" => "/printers/", 
                          "jobs" => "/jobs/"); 
    public $http_timeout = 0; // timeout at http connection (seconds) 0 => default => 30.
    public $http_data_timeout = 0; // data reading timeout (milliseconds) 0 => default => 30.
    public $ssl = false;
    public $debug_level = 3; // max 3: almost silent
    public $alert_on_end_tag;// debugging purpose: echo "END tag OK" if (1 and  reads while end tag)
    public $with_exceptions = 0; // compatibility mode for old scripts
    public $handle_http_exceptions = 1;
    // readables variables
    public $jobs = array();
    public $jobs_uri = array();
    public $status = array();
    public $response_completed = array();
    public $last_job = "";
    public $attributes; // object you can read: attributes after validateJob()
    public $printer_attributes; // object you can read: printer's attributes after getPrinterAttributes()
    public $job_attributes; // object you can read: last job attributes
    public $jobs_attributes; // object you can read: jobs attributes after getJobs()
    public $available_printers = array();
    public $printers_uri = array();
    public $debug = array();
    public $response;
   
    // {{{ protected variables;
    
    protected $log_level = 2; // max 3: very verbose
    protected $log_type = 3; // 3: file | 1: e-mail | 0: logger
    protected $log_destination; // e-mail or file
    protected $serveroutput;
    protected $setup;
    protected $stringjob;
    protected $data;    
    protected $debug_count = 0;
    protected $username;
    protected $charset;
    protected $password;
    protected $requesring_user;
    protected $client_hostname = "localhost";
    protected $stream;    
    protected $host = "localhost";
    protected $port = "631";
    protected $printer_uri;
    protected $timeout = "20"; //20 secs
    protected $errNo;
    protected $errStr;
    protected $datatype;
    protected $datahead;
    protected $datatail;
    public $meta;
    protected $operation_id;
    protected $delay;
    protected $error_generation; //devel feature
    protected $debug_http = 0;
    protected $no_disconnect;
    protected $job_tags;
    protected $operation_tags;
    protected $index;
    protected $collection ; //RFC3382
    protected $collection_index; //RFC3382
    protected $collection_key = array(); //RFC3382
    protected $collection_depth = -1; //RFC3382
    protected $end_collection = false; //RFC3382
    protected $collection_nbr = array(); //RFC3382
    protected $unix = false; // true -> use unix sockets instead of http
    // }}}
    // }}}
    
    // {{{ constructor
    public function __construct() {
        $tz = getenv("date.timezone");
        if (!$tz)
            $tz = date_default_timezone_get();
        date_default_timezone_set($tz);

        $this->meta = new stdClass();
        $this->setup = new stdClass();
        $this->values = new stdClass();
        $this->serveroutput = new stdClass();
        $this->error_generation = new stdClass();
        $this->_parsing = new stdClass();

        self::_initTags ();
    }
    // }}}

/*****************
*
* PUBLIC FUNCTIONS
*
*******************/


// SETUP

    // {{{ setPort($port='631')
    public function setPort($port='631'){
        $this->port = $port;
	self::_putDebug("Port is ".$this->port,2);
    }
    // }}}

    // {{{ setUnix($socket='/var/run/cups/cups.sock')
    public function setUnix($socket='/var/run/cups/cups.sock') {
        $this->host = $socket;
        $this->unix = true;
	self::_putDebug("Host is ".$this->host,2);
    }
    // }}}

     // {{{ setHost($host='localhost')
    public function setHost($host='localhost'){
        $this->host = $host;
        $this->unix = false;
	self::_putDebug("Host is ".$this->host,2);
    }
    // }}}
    
    // {{{ setTimeout($timeout)
    public function setTimeout($timeout){
        $this->timeout = $timeout;
    }
    // }}}

    // {{{ setPrinterURI ($uri)
    public function setPrinterURI ($uri) {
        

        $length = strlen ($uri);
        $length = chr($length);
        
        while (strlen($length) < 2)
            $length = chr(0x00) . $length;
        
        $this->meta->printer_uri = chr(0x45) // uri type | value-tag
                         .  chr(0x00) . chr(0x0B) // name-length
                         .  "printer-uri" // printer-uri | name
                         . $length
                         . $uri;

        $this->printer_uri = $uri;
        
        self::_putDebug(sprintf(_("Printer URI: %s"),$uri),2);
        
        $this->setup->uri = 1;

    }
    // }}}

    // {{{ setData($data)
    public function setData($data){ 
        // 
        $this->data = $data;
        self::_putDebug("Data set",2);
    }
    // }}}
    
    // {{{ setRawText ()
    public function setRawText () {
        $this->setup->datatype = 'TEXT';
        $this->meta->mime_media_type = "";
        $this->setup->mime_media_type = 1;
        $this->datahead = chr(0x16);
                       
        if (is_readable($this->data)){
            //It's a filename.  Open and stream.
            $data = fopen($this->data, "rb");
            while(!feof($data))
                $output = fread($data, 8192);
        } else {
            $output = $this->data;
            }

        if (substr($output,-1,1) != chr(0x0c))
            if (!isset($this->setup->noFormFeed))
                $this->datatail = chr(0x0c);
        
        self::_putDebug(_("Forcing data to be interpreted as RAW TEXT"),2);
    }
    // }}}

    // {{{ unsetRawText ()
    public function unsetRawText () {
        
        $this->setup->datatype = 'BINARY';
        $this->datahead = '';
        $this->datatail = '';
        self::_putDebug(_("Unset forcing data to be interpreted as RAW TEXT"),2);

    }
    // }}}

    // {{{ setBinary()
    public function setBinary () {
        self::unsetRawText();
    }
    // }}}

    // {{{ setFormFeed ()
    public function setFormFeed () {
        $this->datatail = "\r\n".chr(0x0c);
        unset($this->setup->noFormFeed);
    }
    // }}}

    // {{{ unsetFormFeed ()
    public function unsetFormFeed () {
        $this->datatail = '';
        $this->setup->noFormFeed = 1;
    }
    // }}}

    // {{{ setCharset ($charset)
    public function setCharset ($charset='us-ascii') {

        $charset = strtolower($charset);
        $this->charset = $charset;

        $this->meta->charset = chr(0x47) // charset type | value-tag
                         . chr(0x00) . chr(0x12) // name-length
                         . "attributes-charset" // attributes-charset | name
                         . self::_giveMeStringLength($charset) // value-length
                         . $charset; // value
        
        self::_putDebug(sprintf(_("Charset: %s"),$charset),2);

        $this->setup->charset = 1;
    }
    // }}}
 
    // {{{ setLanguage($language)
    public function setLanguage($language='en_us') {

        $language = strtolower($language);
        
        $this->meta->language = chr(0x48)    // natural-language type | value-tag
                         .  chr(0x00) . chr(0x1B) //  name-length
                         .  "attributes-natural-language" //attributes-natural-language
                         .  self::_giveMeStringLength($language) // value-length
                         .  $language; // value
 
        self::_putDebug(sprintf(_("Language: %s"),$language),2);
        
        $this->setup->language = 1;
    }
    // }}}

    // {{{ setMimeMediaType ($mime_media_type='application/octet-stream')
    public function setMimeMediaType ($mime_media_type='') {
        
        self::setBinary();
                                     
        $length = strlen ($mime_media_type);
        if ($length == 0)
        {
          $this->meta->mime_media_type = "";
        }
        else
        {
        $length = chr($length);
        
        while (strlen($length) < 2)
            $length = chr(0x00) . $length;
        
        
        self::_putDebug( sprintf(_("mime type: %s"),$mime_media_type),2);
 
        $this->meta->mime_media_type = chr(0x49) // document-format tag
                                . self::_giveMeStringLength('document-format')
                                . 'document-format' // 
                                . self::_giveMeStringLength($mime_media_type)
                                . $mime_media_type; // value
        }                            
        $this->setup->mime_media_type = 1;
    }
    // }}}

    // {{{ setDocumentFormat ($mime_media_type="application/octet-stream") // setMimeMediaType alias
    public function setDocumentFormat ($mime_media_type="application/octet-stream") {
        self::setMimeMediaType ($mime_media_type);
    }
    // }}}
    
    // {{{ setCopies ($nbrcopies=1)
    public function setCopies ($nbrcopies=1) {
        
        $this->meta->copies = "";
        if ($nbrcopies == 1 || !$nbrcopies)
            return true;
        
        $copies = self::_integerBuild($nbrcopies);
        
        $this->meta->copies = chr(0x21) // integer type | value-tag
                    . chr(0x00) .chr(0x06) //             name-length
                    . "copies" // copies    |             name
                    . self::_giveMeStringLength($copies) // value-length 
                    . $copies;
        
        self::_putDebug( sprintf(_("Copies: %s"),$nbrcopies),2);

        $this->setup->copies = 1;

    }
    // }}}
    
    // {{{ setDocumentName ($document_name)
    public function setDocumentName ($document_name="") {
        
        $this->meta->document_name = "";
        if (!$document_name)
            return true;
        
        $document_name = substr($document_name,0,1023);
        
        $length = strlen ($document_name);
        $length = chr($length);
        
        while (strlen($length) < 2)
            $length = chr(0x00) . $length;
        
        
        self::_putDebug( sprintf(_("document name: %s"),$document_name),2);
 
        $this->meta->document_name = chr(0x41) // textWithoutLanguage tag
                                . chr(0x00) . chr(0x0d) // name-length 
                                . "document-name" // mimeMediaType
                                . self::_giveMeStringLength($document_name)
                                . $document_name; // value
                                    
    }
    // }}}

    // {{{ setJobName ($jobname='(PHP)',$absolute=false)
    public function setJobName ($jobname='',$absolute=false) {
        
        $this->meta->jobname = '';
        if ($jobname=='')
        {
            $this->meta->jobname = '';
            return true;
        }
        $postpend = date('-H:i:s-') . $this->_setJobId();
        
        if ($absolute)
            $postpend = '';
        
        if (isset($this->values->jobname) && $jobname == '(PHP)')
            $jobname = $this->values->jobname;
        
        $this->values->jobname = $jobname;
        
        $jobname .= $postpend;
        
        $this->meta->jobname = chr(0x42)  // nameWithoutLanguage type || value-tag
                    . chr(0x00) . chr(0x08) //                           name-length
                    . "job-name" //        job-name   ||                 name
                    . self::_giveMeStringLength($jobname)  //           value-length
                    . $jobname ; //                                      value
        
        self::_putDebug( sprintf(_("Job name: %s"),$jobname),2); 
        $this->setup->jobname = 1;
    }
    // }}}

    // {{{ setUserName ($username='PHP-SERVER')
    public function setUserName ($username='PHP-SERVER') {
        
        $this->requesting_user = $username;
        $this->meta->username = '';
        if (!$username)
            return true;

        if ($username == 'PHP-SERVER' && isset($this->meta->username))
            return TRUE;
        
        $value_length = 0x00;
        for ($i = 0 ; $i < strlen($username)  ; $i ++) {
            $value_length += 0x01;
            }
        $value_length = chr($value_length);

        while (strlen($value_length) < 2)
            $value_length = chr(0x00) . $value_length;
                       
        $this->meta->username = chr(0x42) // keyword type || value-tag
                            . chr(0x00). chr(0x14) // name-length
                            . "requesting-user-name"
                            . $value_length
                            . $username;
                            
        self::_putDebug( sprintf(_("Username: %s"),$username),2);
        $this->setup->username = 1;
    }
    // }}}

    // {{{ setAuthentification ($username,$password)
    public function setAuthentification ($username,$password) {
        self::setAuthentication ($username,$password);
    }
    // }}}

    // {{{ setAuthentication ($username,$password)
    public function setAuthentication ($username,$password) {
        $this->password = $password;
        $this->username = $username;
        
        self::_putDebug( _("Setting password"),2);
        $this->setup->password = 1;
    }
    // }}}

    // {{{ setSides ($sides=2)
    public function setSides ($sides=2) {
        
        $this->meta->sides = '';
        if (!$sides)
            return true;
        
        switch ($sides) {
            case 1:
                $sides = "one-sided";
                break;
            case 2:
                $sides = "two-sided-long-edge";
                break;
            case "2CE":
                $sides = "two-sided-short-edge";
                break;
            default:
                $sides = $sides; // yeah, what ?
                break;
            }
        
                   
        $this->meta->sides = chr(0x44) // keyword type | value-tag
                        . chr(0x00). chr(0x05) //        name-length
                        . "sides" // sides |             name
                        . self::_giveMeStringLength($sides) //               value-length
                        . $sides ; // one-sided |          value
                        
        self::_putDebug( sprintf(_("Sides value set to %s"), $sides),2);
    }
    // }}}
   
    // {{{ setFidelity ()
    public function setFidelity () {
    
    // whether the server can't replace any attributes (eg, 2 sided print is not possible,
    // so print one sided) and DO NOT THE JOB.
        $this->meta->fidelity = chr(0x22) // boolean type  |  value-tag
                    . chr(0x00). chr(0x16) //                  name-length
                    . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name
                    . chr(0x00) . chr(0x01) //  value-length
                    . chr(0x01); //  true | value
        
        self::_putDebug( _("Fidelity attribute is set (paranoid mode)"),3);
 
    }
    // }}}
    
    // {{{ unsetFidelity ()
    public function unsetFidelity () {
    
    // whether the server can replace any attributes (eg, 2 sided print is not possible,
    // so print one sided) and DO THE JOB.
    
        $this->meta->fidelity = chr(0x22) //  boolean type | value-tag
                            . chr(0x00). chr(0x16) //        name-length
                    . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name
                    . chr(0x00) . chr(0x01) //               value-length
                    . chr(0x00); // false |                   value
        
        self::_putDebug( _("Fidelity attribute is unset"),2);
    }
    // }}}
    
    // {{{ setMessage()
    public function setMessage ($message='') {
        
        $this->meta->message = '';
        if (!$message)
            return true;
    
        $this->meta->message = chr(0x41) // attribute type = textWithoutLanguage
                            . chr(0x00) . chr(0x07)
                            . "message"
                            . self::_giveMeStringLength(substr($message,0,127))
                            . substr($message,0,127);
        
        self::_putDebug( sprintf(_('Setting message to "%s"'),$message),2);
    }
    // }}}

    // {{{ setPageRanges($page_ranges)
    public function setPageRanges($page_ranges) {
    
        // $pages_ranges = string:  "1:5 10:25 40:52 ..."
        // to unset, specify an empty string.
        
        $this->meta->page_range = '';
        
        if (!$page_ranges)
            return true;

        $page_ranges = trim(str_replace("-",":",$page_ranges));

        $first = true;
        $page_ranges = split(' ',$page_ranges);
        foreach ($page_ranges as $page_range) {
            $value = self::_rangeOfIntegerBuild($page_range);
            
            if ($first)
                $this->meta->page_ranges .= $this->tags_types['rangeOfInteger']['tag']
                                         .  self::_giveMeStringLength('page-ranges')
                                         .  'page-ranges'
                                         .  self::_giveMeStringLength($value)
                                         .  $value;
            else
                $this->meta->page_ranges .= $this->tags_types['rangeOfInteger']['tag']
                                         .  self::_giveMeStringLength('')
                                         .  self::_giveMeStringLength($value)
                                         .  $value;
            $first = false;                        
            }
            
    }
    // }}}
    
    // {{{ setAttribute($attribute,$value)
    public function setAttribute($attribute,$values) {

        $operation_attributes_tags = array_keys($this->operation_tags);
        $job_attributes_tags = array_keys($this->job_tags);
        $printer_attributes_tags = array_keys($this->printer_tags);
        self::unsetAttribute($attribute);
        
        if (in_array($attribute,$operation_attributes_tags)) {
            if (!is_array($values))
                self::_setOperationAttribute ($attribute,$values);
            else
                foreach ($values as $value)
                    self::_setOperationAttribute ($attribute,$value);
                    
        } elseif (in_array($attribute,$job_attributes_tags)) {
            if (!is_array($values))
                self::_setJobAttribute ($attribute,$values);
            else
                foreach ($values as $value) 
                    self::_setJobAttribute ($attribute,$value);
        } elseif (in_array($attribute,$printer_attributes_tags)) {
             if (!is_array($values))
                self::_setPrinterAttribute ($attribute,$values);
            else
                foreach ($values as $value)
                    self::_setPrinterAttribute ($attribute,$value);

        } else {
            trigger_error(sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),E_USER_NOTICE);
            self::_putDebug(sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),3);
            self::_errorLog(sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),2);
            return FALSE;
            }

    }
    // }}}
    
    // {{{ unsetAttribute($attribute)
    public function unsetAttribute($attribute) {

        $operation_attributes_tags = array_keys($this->operation_tags);
        $job_attributes_tags = array_keys($this->job_tags);
        $printer_attributes_tags = array_keys($this->printer_tags);

        if (in_array($attribute,$operation_attributes_tags)) 
            unset  ($this->operation_tags[$attribute]['value'], $this->operation_tags[$attribute]['systag']);
        elseif (in_array($attribute,$job_attributes_tags))
            unset ($this->job_tags[$attribute]['value'], $this->job_tags[$attribute]['systag']);
        elseif (in_array($attribute,$printer_attributes_tags))
            unset ($this->printer_tags[$attribute]['value'], $this->printer_tags[$attribute]['systag']);
        else {
            trigger_error(sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),E_USER_NOTICE);
            self::_putDebug(sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),3);
            self::_errorLog(sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),2);
            return FALSE;
            }

    return true;
    }
    // }}}

// LOGGING / DEBUGGING

    // {{{ setLog ($log_destination,$destination_type='file',$level=2)
    public function setLog ($log_destination,$destination_type='file',$level=2) {
        
        if (is_string($log_destination) && !empty($log_destination))
            $this->log_destination = $log_destination;
        
        switch ($destination_type) {
            case 'file':
            case 3:
                $this->log_destination = $log_destination;
                $this->log_type = 3;
                break;
            case 'logger':
            case 0:
                $this->log_destination = '';
                $this->log_type = 0;
                break;
            case 'e-mail':
            case 1:
                $this->log_destination = $log_destination;
                $this->log_type = 1;
                break;
            }
            $this->log_level = $level;
    
    }
    // }}}

    // {{{ printDebug()
    public function printDebug() {
        for ($i = 0 ; $i < $this->debug_count ; $i++)
            echo $this->debug[$i], "\n";
        $this->debug = array();
        $this->debug_count = 0;
    }
    // }}}
    
    // {{{ getDebug()
    public function getDebug() {
        $debug = '';
        for ($i = 0 ; $i < $this->debug_count ; $i++)
            $debug .= $this->debug[$i];
        $this->debug = array();
        $this->debug_count = 0;
        return $debug;
    }
    // }}}

// OPERATIONS

    // {{{ printJob()
    public function printJob(){
        // this version of printJob do not parse server output for job's attributes
        
        self::_putDebug( sprintf("************** Date: %s ***********",
                date('Y-m-d H:i:s')));

        if (!$this->_stringJob())
            return FALSE;
                       
        if (is_readable($this->data)){
            self::_putDebug( _("Printing a FILE")); 
                
            $this->output = $this->stringjob;
           
            if ($this->setup->datatype == "TEXT")
                $this->output .= chr(0x16);
            
             
            $post_values = array( "Content-Type" => "application/ipp",
                                  "Data" => $this->output,
                                  "File" => $this->data);
            
            if ($this->setup->datatype == "TEXT" && !isset($this->setup->noFormFeed))
                $post_values = array_merge($post_values,array("Filetype"=>"TEXT"));
            
        } else {                      
            self::_putDebug( _("Printing DATA")); 
            
            $this->output = $this->stringjob;
            $this->output .= $this->datahead;    
            $this->output .= $this->data;
            $this->output .= $this->datatail;
            
            $post_values = array( "Content-Type" => "application/ipp",
                                  "Data" => $this->output);
             
            
            }
            
        if (self::_sendHttp ($post_values,$this->paths["printers"]))
            self::_parseServerOutput();
        
        if (isset($this->serveroutput) && isset($this->serveroutput->status)) {
            
            $this->status = array_merge($this->status,array($this->serveroutput->status));

            if ($this->serveroutput->status == "successfull-ok")
                self::_errorLog(sprintf("printing job %s: ",$this->last_job) .$this->serveroutput->status,3);
            else 
                self::_errorLog(sprintf("printing job: ",$this->last_job) .$this->serveroutput->status,1);

            return $this->serveroutput->status; 
            
            }

        $this->status = array_merge($this->status,array("OPERATION FAILED"));
        $this->jobs = array_merge($this->jobs,array(""));
        $this->jobs_uri = array_merge($this->jobs_uri,array(""));
        self::_errorLog("printing job : OPERATION FAILED",1);
    
    return false;
    }
    // }}}
    

/******************
*
* PROTECTED FUNCTIONS
*
*******************/

// HTTP OUTPUT

    // {{{ _sendHttp ($post_values,$uri)
    protected function _sendHttp ($post_values,$uri) {
    /*
        This function Copyright (C) 2005-2006 Thomas Harding, Manuel Lemos  
    */
            
            $this->response_completed[] = "no";       
            unset($this->serverouptut);

            self::_putDebug( _("Processing HTTP request"),2);
            
            $this->serveroutput->headers = array();
            $this->serveroutput->body = "";
            
            $http = new http_class;
            if (!$this->unix)
                $http->host = $this->host;
            else
                $http->host = "localhost";
            $http->with_exceptions = $this->with_exceptions;
            
            
            if ($this->debug_http) {
                $http->debug = 1;
                $http->html_debug=0;
            } else {
                $http->debug=0;
                $http->html_debug=0;
            }
            
            $url="http://".$this->host;
            if ($this->ssl)
                $url="https://".$this->host;
            if ($this->unix)
                $url="unix://".$this->host;
            
            $http->port = $this->port;
            $http->timeout = $this->http_timeout;
            $http->data_timeout= $this->http_data_timeout;
            
            $http->force_multipart_form_post = false;
            
            $http->user = $this->username;
            $http->password = $this->password;
            
            $error=$http->GetRequestArguments($url,$arguments);
            $arguments["RequestMethod"]="POST";
            $arguments["Headers"] = array("Content-Type" => "application/ipp");
            $arguments["BodyStream"] = array( array("Data" => $post_values["Data"]) );

            if (isset($post_values["File"]))
                $arguments["BodyStream"][]=array("File"=>$post_values["File"]);
            if (isset($post_values["FileType"])
             && !strcmp($post_values["FileType"],"TEXT"))
                 $arguments["BodyStream"][]=array("Data"=>Chr(12));
            
            $arguments["RequestURI"] = $uri;
            
            if ($this->with_exceptions && $this->handle_http_exceptions)
            {
              try
              {
                $error=$http->Open($arguments);
              }
              catch (httpException $e)
              {
                throw new ippException(sprintf("http error: %s", $e->getMessage()),$e->getErrno());
              }
            } 
            else
            {
              $error=$http->Open($arguments);
            }

            if($error=="") {
                $error=$http->SendRequest($arguments);
                
                if($error=="") {
                
                    self::_putDebug( "H T T P    R E Q U E S T :");
                    self::_putDebug("Request headers:");
                    
                    for(Reset($http->request_headers),$header=0;$header<count($http->request_headers);Next($http->request_headers),$header++) {
                    
                        $header_name=Key($http->request_headers);
                        if(GetType($http->request_headers[$header_name])=="array") {
                             for($header_value=0;$header_value<count($http->request_headers[$header_name]);$header_value++)
                                self::_putDebug( $header_name.": ".$http->request_headers[$header_name][$header_value]);
                        } else
                              self::_putDebug( $header_name.": ".$http->request_headers[$header_name]);
                         
                        }
                    self::_putDebug( "Request body:");
                    self::_putDebug( htmlspecialchars($http->request_body)
                                 ."*********** END REQUEST BODY *********");

                         
                    $i = 0;
                    $headers=array();
                    unset($this->serveroutput->headers);
                    $error=$http->ReadReplyHeaders($headers);
                    
                    self::_putDebug( "H T T P    R E S P O N S E :");
                    if($error=="") {
                    
                        self::_putDebug("Response headers:");
                        for(Reset($headers),$header=0;$header<count($headers);Next($headers),$header++) {
                            $header_name=Key($headers);
                            if(GetType($headers[$header_name])=="array") {
                                for($header_value=0;$header_value<count($headers[$header_name]);$header_value++) {
                                    self::_putDebug( $header_name.": ".$headers[$header_name][$header_value]);
                                    $this->serveroutput->headers[$i] = $header_name.": ".$headers[$header_name][$header_value];
                                    $i++;
                                    }
                            } else {
                                self::_putDebug( $header_name.": ".$headers[$header_name]);
                                $this->serveroutput->headers[$i] = $header_name.": ".$headers[$header_name];
                                $i++;
                                }
                            }
                             
                        self::_putDebug( "\n\nResponse body:\n");
                        $this->serveroutput->body = "";
                        for(;;) {
                            $error=$http->ReadReplyBody($body,1024);
                            if($error!="" || strlen($body)==0)
                            break;
                            self::_putDebug(htmlentities($body));
                            $this->serveroutput->body .= $body;
                            }
                        }
                        self::_putDebug( "********* END RESPONSE BODY ********");
                    }
                }
            $http->Close();
            if(strlen($error)) {
                self::_putDebug($error,4);
                if ($this->with_exceptions) {
                    $this->serveroutput->status = $error;
                    throw new ippException($error);
                }
                trigger_error($error,E_USER_WARNING);
                $this->serveroutput->status = $error;
                return FALSE;
                }
    return true;
    }
    // }}}

// INIT
    
    // {{{ _initTags ()
    protected function _initTags () {
        
        $this->tags_types = array ( "unsupported" => array ("tag" => chr(0x10),
                                                        "build" => ""),
                              "reserved"    => array ("tag" => chr(0x11),
                                                        "build" => ""),
                              "unknown"     => array ("tag" => chr(0x12),
                                                        "build" => ""),
                              "no-value"    => array ("tag" => chr(0x13),
                                                        "build" => "no_value"),
                              "integer"     => array ("tag" => chr(0x21),
                                                        "build" => "integer"),
                              "boolean"     => array ("tag" => chr(0x22),
                                                        "build" => "boolean"),
                              "enum"        => array ("tag" => chr(0x23),
                                                        "build" => "enum"),
                              "octetString" => array ("tag" => chr(0x30),
                                                        "build" => "octet_string"),
                              "datetime"    => array ("tag" => chr(0x31),
                                                        "build" => "datetime"),
                              "resolution"  => array ("tag" => chr(0x32),
                                                        "build" => "resolution"),
                              "rangeOfInteger" => array ("tag" => chr(0x33),
                                                        "build" => "range_of_integers"),
                              "textWithLanguage" => array ("tag" => chr(0x35),
                                                        "build" => "string"),
                              "nameWithLanguage" => array ("tag" => chr(0x36),
                                                        "build" => "string"),
                              /*
                              "text" => array ("tag" => chr(0x40),
                                                        "build" => "string"),
                              "text string" => array ("tag" => chr(0x40),
                                                        "build" => "string"),
                              */
                              "textWithoutLanguage" => array ("tag" => chr(0x41),
                                                        "build" => "string"),
                              "nameWithoutLanguage" => array ("tag" => chr(0x42),
                                                        "buid" => "string"),
                              "keyword"     => array ("tag" => chr(0x44),
                                                        "build" => "string"),
                              "uri"         => array ("tag" => chr(0x45),
                                                        "build" => "string"),
                              "uriScheme"   => array ("tag" => chr(0x46),
                                                        "build" => "string"),
                              "charset"     => array ("tag" => chr(0x47),
                                                        "build" => "string"),
                              "naturalLanguage" => array ("tag" => chr(0x48),
                                                        "build" => "string"),
                              "mimeMediaType" => array ("tag" => chr(0x49),
                                                        "build" => "string"),
                              "extendedAttributes" => array ("tag" => chr(0x7F),
                                                        "build" => "extended"),
                              );
                                                        
 
        $this->operation_tags = array ("compression" => array("tag" => "keyword"),
                                     "document-natural-language" => array("tag" => "naturalLanguage"),
                                     "job-k-octets" => array("tag" => "integer"),
                                     "job-impressions" => array("tag" => "integer"),
                                     "job-media-sheets" => array("tag" => "integer"),
                                     ); 

        $this->job_tags = array (   "job-priority" => array("tag" => "integer"),
                                    "job-hold-until" => array("tag" => "keyword"),
                                    "job-sheets" => array("tag" => "keyword"), //banner page
                                    "multiple-document-handling" => array("tag" => "keyword"),
                                    //"copies" => array("tag" => "integer"),
                                    "finishings" => array("tag" => "enum"),
                                    //"page-ranges" => array("tag" => "rangeOfInteger"), // has its own function
                                    //"sides" => array("tag" => "keyword"), // has its own function
                                    "number-up" => array("tag" => "integer"),
                                    "orientation-requested" => array("tag" => "enum"),
                                    "media" => array("tag" => "keyword"),
                                    "printer-resolution" => array("tag" => "resolution"),
                                    "print-quality" => array("tag" => "enum"),
                                    "job-message-from-operator" => array("tag" => "textWithoutLanguage"),
                                    );

    $this->printer_tags = array ( "requested-attributes" => array("tag" => "keyword"));
    }
    // }}}

// SETUP

    // {{{ _setOperationId ()
    protected function _setOperationId () {
            $prepend = '';
            $this->operation_id += 1;
            $this->meta->operation_id = self::_integerBuild($this->operation_id);
            self::_putDebug( "operation id is: ".$this->operation_id,2);
    }
    // }}}
    
    // {{{ _setJobId()
    protected function _setJobId() {

        $this->meta->jobid +=1;
        $prepend = '';
        $prepend_length = 4 - strlen($this->meta->jobid);
        for ($i = 0; $i < $prepend_length ; $i++ )
            $prepend .= '0';

    return $prepend.$this->meta->jobid;
    }
    // }}}
    
    // {{{ _setJobUri ($job_uri) 
    protected function _setJobUri ($job_uri) {
       
        $this->meta->job_uri = chr(0x45) // type uri
                             . chr(0x00).chr(0x07) // name-length
                             . "job-uri"
                             //. chr(0x00).chr(strlen($job_uri))
                             . self::_giveMeStringLength($job_uri)
                             . $job_uri;
        
        self::_putDebug( "job-uri is: ".$job_uri,2);
    }
    // }}}
    
// RESPONSE PARSING

    // {{{ _parseServerOutput ()
    protected function _parseServerOutput () {

        $this->serveroutput->response = array();
        
        if (!self::_parseHttpHeaders ()) return FALSE;
        
        $this->_parsing->offset = 0;
        
        self::_parseIppVersion ();
        self::_parseStatusCode ();
        self::_parseRequestID  ();
        $this->_parseResponse ();
        
        //devel
        self::_putDebug( sprintf("***** IPP STATUS: %s ******",$this->serveroutput->status),4);
        self::_putDebug( "****** END OF OPERATION ****");
       
   return true;
   }
   // }}}
   
    // {{{ _parseHttpHeaders
    protected function _parseHttpHeaders () {
        
        $response = "";
        
        switch ($this->serveroutput->headers[0]) {
            
            case "http/1.1 200 ok: ":
                $this->serveroutput->httpstatus = "HTTP/1.1 200 OK";
                $response = "OK";
                break;
            case "http/1.1 100 continue: ":
                $this->serveroutput->httpstatus = "HTTP/1.1 100 CONTINUE";
                $response = "OK";
                break;
            case "":
                $this->serveroutput->httpstatus = "HTTP/1.1 000 No Response From Server";
                $this->serveroutput->status = "HTTP-ERROR-000_NO_RESPONSE_FROM_SERVER";
                trigger_error("No Response From Server",E_USER_WARNING);
                self::_errorLog("No Response From Server",1);
                $this->disconnected = 1;
                return FALSE;
                break;
            default:
                $server_response = preg_replace("/: $/",'',$this->serveroutput->headers[0]);
                $strings = split(' ',$server_response,3);
                $errno = $strings[1];
                $string = strtoupper(str_replace(' ','_',$strings[2]));
                trigger_error(sprintf(_("server responds %s"),$server_response),E_USER_WARNING);
                self::_errorLog("server responds ".$server_response,1);
                $this->serveroutput->httpstatus = strtoupper($strings[0])." ".$errno." ".ucfirst($strings[2]);
                $this->serveroutput->status = "HTTP-ERROR-".$errno."-".$string;
                $this->disconnected = 1;
                return FALSE;
                break;
            }
        
        unset ($this->serveroutput->headers);
        
    return TRUE;
    }
    // }}}
     
    // {{{ _parseIppVersion ()
    protected function _parseIppVersion () {

        $ippversion = (ord($this->serveroutput->body[ $this->_parsing->offset]) *  256) 
                    +  ord($this->serveroutput->body[$this->_parsing->offset + 1]);
        
        switch($ippversion) {
            case 0x0101:
                $this->serveroutput->ipp_version = "1.1";
                break;
            default:
                $this->serveroutput->ipp_version = sprintf("%u.%u (Unknown)",ord($this->serveroutput->body[ $this->_parsing->offset]) *  256,ord($this->serveroutput->body[$this->_parsing->offset + 1]));
                break;
        }
        
   self::_putDebug( "I P P    R E S P O N S E :\n\n"); 
   self::_putDebug( sprintf("IPP version %s%s: %s",
        ord($this->serveroutput->body[ $this->_parsing->offset]),
        ord($this->serveroutput->body[$this->_parsing->offset + 1]),
        $this->serveroutput->ipp_version));
    
        $this->_parsing->offset += 2;
    return;
    }
    // }}}

    // {{{ _parseStatusCode ()
    protected function _parseStatusCode () {
        $status_code = (ord($this->serveroutput->body[$this->_parsing->offset]) * 256)
                     +  ord($this->serveroutput->body[$this->_parsing->offset + 1]);
        

        $this->serveroutput->status ="NOT PARSED";
        
        $this->_parsing->offset += 2;
        
        if (strlen($this->serveroutput->body) < $this->_parsing->offset) 
        return false;

        
        if ($status_code < 0x00FF) {
            $this->serveroutput->status = "successfull";
        } elseif ($status_code < 0x01FF) {
            $this->serveroutput->status = "informational";
        } elseif ($status_code < 0x02FF) {
            $this->serveroutput->status = "redirection";
        } elseif ($status_code < 0x04FF) {
            $this->serveroutput->status = "client-error";
        } elseif ($status_code < 0x05FF) {
            $this->serveroutput->status = "server-error";
            }  

        switch ($status_code) {
            case 0x0000:
                $this->serveroutput->status = "successfull-ok";
                break;
            case 0x0001:
                $this->serveroutput->status = "successful-ok-ignored-or-substituted-attributes";
                break;
            case 0x002:
                $this->serveroutput->status = "successful-ok-conflicting-attributes";
                break;
            case 0x0400:
                $this->serveroutput->status = "client-error-bad-request";
                break;
            case 0x0401:
                $this->serveroutput->status = "client-error-forbidden";
                break;
            case 0x0402:
                $this->serveroutput->status = "client-error-not-authenticated";
                break;
            case 0x0403:
                $this->serveroutput->status = "client-error-not-authorized";
                break;
            case 0x0404:
                $this->serveroutput->status = "client-error-not-possible";
                break;
            case 0x0405:
                $this->serveroutput->status = "client-error-timeout";
                break;
            case 0x0406:
                $this->serveroutput->status = "client-error-not-found";
                break;       
            case 0x0407:
                $this->serveroutput->status = "client-error-gone";
                break;      
            case 0x0408:
                $this->serveroutput->status = "client-error-request-entity-too-large";
                break;      
            case 0x0409:
                $this->serveroutput->status = "client-error-request-value-too-long";
                break;      
            case 0x040A:
                $this->serveroutput->status = "client-error-document-format-not-supported";
                break;      
            case 0x040B:
                $this->serveroutput->status = "client-error-attributes-or-values-not-supported";
                break;      
            case 0x040C:
                $this->serveroutput->status = "client-error-uri-scheme-not-supported";
                break;      
            case 0x040D:
                $this->serveroutput->status = "client-error-charset-not-supported";
                break;      
            case 0x040E:
                $this->serveroutput->status = "client-error-conflicting-attributes";
                break;      
            case 0x040F:
                $this->serveroutput->status = "client-error-compression-not-supported";
                break;      
            case 0x0410:
                $this->serveroutput->status = "client-error-compression-error";
                break;      
            case 0x0411:
                $this->serveroutput->status = "client-error-document-format-error";
                break;      
            case 0x0412:
                $this->serveroutput->status = "client-error-document-access-error";
                break;      
            case 0x0413: // RFC3380
                $this->serveroutput->status = "client-error-attributes-not-settable";
                break;
            case 0x0500:
                $this->serveroutput->status = "server-error-internal-error";
                break;      
            case 0x0501:
                $this->serveroutput->status = "server-error-operation-not-supported";
                break;      
            case 0x0502:
                $this->serveroutput->status = "server-error-service-unavailable";
                break;      
            case 0x0503:
                $this->serveroutput->status = "server-error-version-not-supported";
                break;      
            case 0x0504:
                $this->serveroutput->status = "server-error-device-error";
                break;      
            case 0x0505:
                $this->serveroutput->status = "server-error-temporary-error";
                break;      
            case 0x0506:
                $this->serveroutput->status = "server-error-not-accepting-jobs";
                break;      
            case 0x0507:
                $this->serveroutput->status = "server-error-busy";
                break;      
            case 0x0508:
                $this->serveroutput->status = "server-error-job-canceled";
                break;      
            case 0x0509:
                $this->serveroutput->status = "server-error-multiple-document-jobs-not-supported";
                break;      
            default:
                break;
        }
        
    
    self::_putDebug( sprintf("status-code: %s%s: %s ",$this->serveroutput->body[$this->_parsing->offset],
                                  $this->serveroutput->body[$this->_parsing->offset + 1],
                                  $this->serveroutput->status),4);
        
    return;
    }
    // }}}

    // {{{ _parseRequestID ()
    protected function _parseRequestID () {
        
        $this->serveroutput->request_id = self::_interpretInteger(substr($this->serveroutput->body,$this->_parsing->offset,4));
        self::_putDebug( "request-id ". $this->serveroutput->request_id,2);
        $this->_parsing->offset += 4;

    return;    
    }
    // }}}

    // {{{ _interpretInteger($value)
    protected function _interpretInteger($value) {

        // they are _signed_ integers
        $value_parsed = 0;
        
        for ($i = strlen($value) ; $i > 0 ; $i --) 
            $value_parsed += (1 << (($i - 1)*8)) * ord($value[strlen($value) - $i]);
       if ($value_parsed >= 2147483648)
        $value_parsed -= 4294967296;
    return $value_parsed;
    }
    // }}}

    // {{{ _parseResponse () {}
    protected function _parseResponse () {}
    // }}}
// REQUEST BUILDING
    
    // {{{ _stringJob ()
    protected function _stringJob () {
    
        if (!isset($this->setup->charset))
            self::setCharset('us-ascii');
        if (!isset($this->setup->datatype))
            self::setBinary();

        if (!isset($this->setup->uri)) {
            $this->getPrinters();
            unset($this->jobs[count($this->jobs) - 1]);
            unset($this->jobs_uri[count($this->jobs_uri) - 1]);
            unset($this->status[count($this->status) - 1]);
            
            if (array_key_exists(0,$this->available_printers))
               self::setPrinterURI($this->available_printers[0]);
            else {
                trigger_error(_("_stringJob: Printer URI is not set: die"),E_USER_WARNING);
                self::_putDebug( _("_stringJob: Printer URI is not set: die"),4);
                self::_errorLog(" Printer URI is not set, die",2);
                return FALSE;
                }
            }
            
        if (!isset($this->setup->copies)) 
            self::setCopies(1);
        if (!isset($this->setup->language))
            self::setLanguage('en_us');

        if (!isset($this->setup->mime_media_type))
            self::setMimeMediaType();
        if ($this->setup->datatype != "TEXT")
        unset ($this->setup->mime_media_type);
            
        if (!isset($this->setup->jobname))
            self::setJobName();
        unset($this->setup->jobname);

        if (!isset($this->meta->username))
            self::setUserName();

        if (!isset($this->meta->fidelity))
            $this->meta->fidelity = '';
        
        if (!isset($this->meta->document_name))
            $this->meta->document_name = '';

        if (!isset($this->meta->sides))
            $this->meta->sides = '';
        
        if (!isset($this->meta->page_ranges))
            $this->meta->page_ranges = '';
       
        $jobattributes = '';
        $operationattributes = '';
        $printerattributes = '';
        $this->_buildValues($operationattributes,$jobattributes,$printerattributes);
        self::_setOperationId();

        if (!isset($this->error_generation->request_body_malformed))
            $this->error_generation->request_body_malformed = "";
       
        $this->stringjob = chr(0x01) . chr(0x01) // 1.1  | version-number
                         . chr(0x00) . chr (0x02) // Print-Job | operation-id
                         . $this->meta->operation_id //           request-id
                         . chr(0x01) // start operation-attributes | operation-attributes-tag
                         . $this->meta->charset
                         . $this->meta->language
                         . $this->meta->printer_uri
                         . $this->meta->username
                         . $this->meta->jobname
                         . $this->meta->fidelity
                         . $this->meta->document_name
                         . $this->meta->mime_media_type
                         . $operationattributes;
                         if ($this->meta->copies 
                            ||  $this->meta->sides
                            ||  $this->meta->page_ranges
                            ||  !empty($jobattributes))
                         {
                         $this->stringjob .= chr(0x02) // start job-attributes | job-attributes-tag
                         . $this->meta->copies
                         . $this->meta->sides
                         . $this->meta->page_ranges
                         . $jobattributes;
                         }
                         $this->stringjob .= chr(0x03); // end-of-attributes | end-of-attributes-tag
        
        self::_putDebug( sprintf(_("String sent to the server is: %s"), $this->stringjob));
        return TRUE;
    }
    // }}}

    // {{{ _buildValues (&$operationattributes,&$jobattributes);
    protected function _buildValues (&$operationattributes,&$jobattributes,&$printerattributes) {

        $operationattributes = '';
        foreach ($this->operation_tags as $key => $values) {
            $item = 0;
            if (array_key_exists('value',$values)) 
                    foreach ($values['value'] as $item_value) {
                        if ($item == 0)
                            $operationattributes .= $values['systag']
                                        . self::_giveMeStringLength($key)
                                        . $key
                                        . self::_giveMeStringLength($item_value)
                                        . $item_value;
                        else
                            $operationattributes .= $values['systag']
                                        . self::_giveMeStringLength('')
                                        . self::_giveMeStringLength($item_value)
                                        . $item_value;
                    
                        $item++;
                    }
            }
        
        $jobattributes = '';
        foreach ($this->job_tags as $key => $values)
        {
            $item = 0;
            if (array_key_exists('value',$values))
            {
                    foreach ($values['value'] as $item_value) {
                    if ($item == 0)
                            $jobattributes .= $values['systag']
                                        . self::_giveMeStringLength($key)
                                        . $key
                                        . self::_giveMeStringLength($item_value)
                                        . $item_value;
                        else
                            $jobattributes .= $values['systag']
                                        . self::_giveMeStringLength('')
                                        . self::_giveMeStringLength($item_value)
                                        . $item_value;
                    
                        $item++;
                    }
            }
        }

        $printerattributes = '';
        foreach ($this->printer_tags as $key => $values) {
            $item = 0;
            if (array_key_exists('value',$values)) 
                    foreach ($values['value'] as $item_value) {
                        if ($item == 0)
                            $printerattributes .= $values['systag']
                                        . self::_giveMeStringLength($key)
                                        . $key
                                        . self::_giveMeStringLength($item_value)
                                        . $item_value;
                        else
                            $printerattributes .= $values['systag']
                                        . self::_giveMeStringLength('')
                                        . self::_giveMeStringLength($item_value)
                                        . $item_value;
                    
                        $item++;
                    }
            }
 
        reset ($this->job_tags);
        reset ($this->operation_tags);
        reset ($this->printer_tags);
    return true;
    }
    // }}}

    // {{{ _giveMeStringLength ($string)   
    protected function _giveMeStringLength ($string) {
        
        $prepend = '';
        $length = strlen($string);
        $lengthlength = strlen(chr($length));
        while ($lengthlength < 2) {
            $prepend .= chr(0x00);
            $lengthlength += 1;
            }
        $length = $prepend . chr($length);
 
    return $length;
    }
    // }}}

    // {{{ _enumBuild ($tag,$value)
    protected function _enumBuild ($tag,$value) {
        
        switch ($tag) {
            case "orientation-requested":
                switch ($value) {
                    case 'portrait':
                        $value = chr(3);
                        break;
                    case 'landscape':
                        $value = chr(4);
                        break;
                    case 'reverse-landscape':
                        $value = chr(5);
                        break;
                    case 'reverse-portrait':
                        $value = chr(6);
                        break;
                }
            break;
            case "print-quality":
                switch($value) {
                    case 'draft':
                        $value = chr(3);
                        break;
                    case 'normal':
                        $value = chr(4);
                        break;
                    case 'high':
                        $value = chr(5);
                        break;
                }
            break;
            case "finishing":
                switch ($value) {
                        case 'none':
                            $value = chr(3);
                            break;
                        case 'staple':
                            $value = chr(4);
                            break;
                        case 'punch':
                            $value = chr(5);
                            break;
                        case 'cover':
                            $value = chr(6);
                            break;
                        case 'bind':
                            $value = chr(7);
                            break;
                        case 'saddle-stitch':
                            $value = chr(8);
                            break;
                        case 'edge-stitch':
                            $value = chr(9);
                            break;
                        case 'staple-top-left':
                            $value = chr(20);
                            break;
                        case 'staple-bottom-left':
                            $value = chr(21);
                            break;
                        case 'staple-top-right':
                            $value = chr(22);
                            break;
                        case 'staple-bottom-right':
                            $value = chr(23);
                            break;
                        case 'edge-stitch-left':
                            $value = chr(24);
                            break;
                        case 'edge-stitch-top':
                            $value = chr(25);
                            break;
                        case 'edge-stitch-right':
                            $value = chr(26);
                            break;
                        case 'edge-stitch-bottom':
                            $value = chr(27);
                            break;
                        case 'staple-dual-left':
                            $value = chr(28);
                            break;
                        case 'staple-dual-top':
                            $value = chr(29);
                            break;
                        case 'staple-dual-right':
                            $value = chr(30);
                            break;
                        case 'staple-dual-bottom':
                            $value = chr(31);
                            break;
                    }
                break;
            }

        $prepend = '';
        while ((strlen($value) + strlen($prepend)) < 4)
            $prepend .= chr(0);
        
    return $prepend.$value;
    }
    // }}}

    // {{{ _integerBuild ($integer)
    protected function _integerBuild ($value) {
        
        if ($value >= 2147483647 || $value < -2147483648) {
            trigger_error(_("Values must be between -2147483648 and 2147483647: assuming '0'"),E_USER_WARNING);
            return chr(0x00).chr(0x00).chr(0x00).chr(0x00);
            }
        
        $initial_value = $value;
            
            $int1 = $value & 0xFF;
            $value -= $int1;
            $value = $value >> 8;
            $int2 = $value & 0xFF;
            $value -= $int2;
            $value = $value >> 8;
            $int3 = $value & 0xFF;
            $value -= $int3;
            $value = $value >> 8;
            $int4 = $value & 0xFF; //64bits

    if ($initial_value < 0)
        $int4 = chr($int4) | chr(0x80);
    else
        $int4 = chr($int4);

    $value = $int4.chr($int3).chr($int2).chr($int1);
    
    return $value;
    }
    // }}}

    // {{{ _rangeOfIntegerBuild ($integers)
    protected function _rangeOfIntegerBuild ($integers) {
        
        $integers = split(":",$integers);
        
        for ($i = 0 ; $i < 2 ; $i++) 
            $outvalue[$i] = self::_integerBuild($integers[$i]);
            
        return $outvalue[0].$outvalue[1];
    }
    // }}}

    // {{{ _setJobAttribute ($attribute,$value)
    protected function _setJobAttribute ($attribute,$value) {
    //used by setAttribute
             
             $tag_type = $this->job_tags[$attribute]['tag'];
             switch ($tag_type) {
                case 'integer':
                    $this->job_tags[$attribute]['value'][] = self::_integerBuild($value);
                    break;
                case 'nameWithoutLanguage':
                case 'nameWithLanguage':
                case 'textWithoutLanguage':
                case 'textWithLanguage':
                case 'keyword':
                case 'naturalLanguage':
                    $this->job_tags[$attribute]['value'][] = $value;
                break;
                case 'enum':
                    $value = $this->_enumBuild($attribute,$value); // may be overwritten by children
                    $this->job_tags[$attribute]['value'][] = $value;
                    break;
                case 'rangeOfInteger':
                    // $value have to be: INT1:INT2 , eg 100:1000
                    $this->job_tags[$attribute]['value'][] = self::_rangeOfIntegerBuild($value);
                break;
                case 'resolution':
                    if (preg_match("#dpi#",$value)) $unit = chr(0x3);
                    if (preg_match("#dpc#",$value)) $unit = chr(0x4);
                    $search = array("#(dpi|dpc)#",'#(x|-)#');
                    $replace = array("",":");
                    $value = self::_rangeOfIntegerBuild(preg_replace($search,$replace,$value)).$unit;
                    $this->job_tags[$attribute]['value'][] = $value;
                    break;
                default:
                    trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),E_USER_NOTICE);
                    self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2);
                    self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2);
                    return FALSE;
                    break;
                }
            $this->job_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag'];
    
    }
    // }}}

    // {{{ _setOperationAttribute ($attribute,$value)
    protected function _setOperationAttribute ($attribute,$value) {
    //used by setAttribute
            $tag_type = $this->operation_tags[$attribute]['tag'];
            switch ($tag_type) {
                case 'integer':
                    $this->operation_tags[$attribute]['value'][] = self::_integerBuild($value);
                    break;
                case 'keyword':
                case 'naturalLanguage':
                    $this->operation_tags[$attribute]['value'][] = $value;
                    break;
                default:
                    trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),E_USER_NOTICE);
                    self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2);
                    self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2);
                    return FALSE;
                    break;
                }
            $this->operation_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag'];
                
    }
    // }}}

    // {{{ _setPrinterAttribute ($attribute,$value)
    protected function _setPrinterAttribute ($attribute,$value) {
    //used by setAttribute
            $tag_type = $this->printer_tags[$attribute]['tag'];
            switch ($tag_type) {
                case 'integer':
                    $this->printer_tags[$attribute]['value'][] = self::_integerBuild($value);
                    break;
                case 'keyword':
                case 'naturalLanguage':
                    $this->printer_tags[$attribute]['value'][] = $value;
                    break;
                default:
                    trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),E_USER_NOTICE);
                    self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2);
                    self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2);
                    return FALSE;
                    break;
                }
            $this->printer_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag'];
                
    }
    // }}}
// DEBUGGING

    // {{{ _putDebug($string,$level)
    protected function _putDebug($string,$level=1) {
        if ($level === false)
            return;
        if ($level < $this->debug_level)
            return;
        $this->debug[$this->debug_count] = substr($string,0,1024);
        $this->debug_count ++;
        //$this->debug .= substr($string,0,1024);
    }
    // }}}

// LOGGING

    // {{{ _errorLog($log,$level)
    protected function _errorLog($string_to_log,$level) {
        
        if ($level < $this->log_level)
            return;
    
        $string = sprintf('%s : %s:%s user %s : %s',
                            basename($_SERVER['PHP_SELF']),
                            $this->host,
                            $this->port,
                            $this->requesting_user,
                            $string_to_log);
            
        if ($this->log_type == 0) {
            error_log($string);
            return;
            }
        
        $string = sprintf("%s %s Host %s:%s user %s : %s\n",
                            date('M d H:i:s'),
                            basename($_SERVER['PHP_SELF']),
                            $this->host,
                            $this->port,
                            $this->requesting_user,
                            $string_to_log);
        error_log($string,$this->log_type,$this->log_destination);

    return;
    }
    // }}}
   
};

/*
 * Local variables:
 * mode: php
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 */
?>
Return current item: PHP PrintIPP