PageRenderTime 66ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/root/usr/share/nethesis/NethServer/Tool/phpprintipp/BasicIPP.php

https://github.com/nethesis/nethserver-cups
PHP | 2000 lines | 1622 code | 161 blank | 217 comment | 136 complexity | e3b6d792eb5616a8af992b3866b570e6 MD5 | raw file
Possible License(s): GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=2 shiftwidth=2 foldmethod=marker: */
  3. /* @(#) $Header: /sources/phpprintipp/phpprintipp/php_classes/BasicIPP.php,v 1.6 2010/08/22 15:45:17 harding Exp $
  4. *
  5. * Class BasicIPP - Send Basic IPP requests, Get and parses IPP Responses.
  6. *
  7. * Copyright (C) 2005-2009 Thomas HARDING
  8. * Parts Copyright (C) 2005-2006 Manuel Lemos
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Library General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Library General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Library General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. *
  24. * mailto:thomas.harding@laposte.net
  25. * Thomas Harding, 56 rue de la bourie rouge, 45 000 ORLEANS -- FRANCE
  26. *
  27. */
  28. /*
  29. This class is intended to implement Internet Printing Protocol on client side.
  30. References needed to debug / add functionnalities:
  31. - RFC 2910
  32. - RFC 2911
  33. - RFC 3380
  34. - RFC 3382
  35. */
  36. /*
  37. TODO: beta tests on other servers than Cups
  38. */
  39. // required and included files
  40. require_once ("http_class.php");
  41. /*
  42. // If you want http backend from http://www.phpclasses.org/browse/package/3.html
  43. require_once("HTTP/http.php");
  44. include_once("SASL/sasl.php");
  45. include_once("SASL/basic_sasl_client.php");
  46. include_once("SASL/digest_sasl_client.php");
  47. include_once("SASL/ntlm_sasl_client.php");
  48. */
  49. /**
  50. * Class and Function List:
  51. * Function list:
  52. * - __construct()
  53. * - getErrorFormatted()
  54. * - getErrno()
  55. * - setPort()
  56. * - setUnix()
  57. * - setHost()
  58. * - setTimeout()
  59. * - setPrinterURI()
  60. * - setData()
  61. * - setRawText()
  62. * - unsetRawText()
  63. * - setBinary()
  64. * - setFormFeed()
  65. * - unsetFormFeed()
  66. * - setCharset()
  67. * - setLanguage()
  68. * - setDocumentFormat()
  69. * - setMimeMediaType()
  70. * - setCopies()
  71. * - setDocumentName()
  72. * - setJobName()
  73. * - setUserName()
  74. * - setAuthentification()
  75. * - setAuthentication()
  76. * - setSides()
  77. * - setFidelity()
  78. * - unsetFidelity()
  79. * - setMessage()
  80. * - setPageRanges()
  81. * - setAttribute()
  82. * - unsetAttribute()
  83. * - setLog()
  84. * - printDebug()
  85. * - getDebug()
  86. * - printJob()
  87. * - _sendHttp()
  88. * - _initTags()
  89. * - _setOperationId()
  90. * - _setJobId()
  91. * - _setJobUri()
  92. * - _parseServerOutput()
  93. * - _parseHttpHeaders()
  94. * - _parseIppVersion()
  95. * - _parseStatusCode()
  96. * - _parseRequestID()
  97. * - _interpretInteger()
  98. * - _parseResponse()
  99. * - _stringJob()
  100. * - _buildValues()
  101. * - _giveMeStringLength()
  102. * - _enumBuild()
  103. * - _integerBuild()
  104. * - _rangeOfIntegerBuild()
  105. * - _setJobAttribute()
  106. * - _setOperationAttribute()
  107. * - _setPrinterAttribute()
  108. * - _putDebug()
  109. * - _errorLog()
  110. * Classes list:
  111. * - ippException extends Exception
  112. * - BasicIPP
  113. */
  114. /***********************
  115. *
  116. * ippException class
  117. *
  118. ************************/
  119. class ippException extends Exception
  120. {
  121. protected $errno;
  122. public function __construct($msg, $errno = null)
  123. {
  124. parent::__construct($msg);
  125. $this->errno = $errno;
  126. }
  127. public function getErrorFormatted()
  128. {
  129. $return = sprintf("[ipp]: %s -- " . _(" file %s, line %s"),
  130. $this->getMessage() , $this->getFile() , $this->getLine());
  131. return $return;
  132. }
  133. public function getErrno()
  134. {
  135. return $this->errno;
  136. }
  137. }
  138. class BasicIPP
  139. {
  140. //
  141. // variables declaration
  142. //
  143. // setup variables
  144. public $paths = array(
  145. "root" => "/",
  146. "admin" => "/admin/",
  147. "printers" => "/printers/",
  148. "jobs" => "/jobs/"
  149. );
  150. public $http_timeout = 30; // timeout at http connection (seconds) 0 => default => 30.
  151. public $http_data_timeout = 30; // data reading timeout (milliseconds) 0 => default => 30.
  152. public $ssl = false;
  153. public $debug_level = 3; // max 3: almost silent
  154. public $alert_on_end_tag; // debugging purpose: echo "END tag OK" if (1 and reads while end tag)
  155. public $with_exceptions = 0; // compatibility mode for old scripts
  156. public $handle_http_exceptions = 1;
  157. // readables variables
  158. public $jobs = array();
  159. public $jobs_uri = array();
  160. public $status = array();
  161. public $response_completed = array();
  162. public $last_job = "";
  163. public $attributes; // object you can read: attributes after validateJob()
  164. public $printer_attributes; // object you can read: printer's attributes after getPrinterAttributes()
  165. public $job_attributes; // object you can read: last job attributes
  166. public $jobs_attributes; // object you can read: jobs attributes after getJobs()
  167. public $available_printers = array();
  168. public $printers_uri = array();
  169. public $debug = array();
  170. public $response;
  171. // protected variables;
  172. protected $log_level = 2; // max 3: very verbose
  173. protected $log_type = 3; // 3: file | 1: e-mail | 0: logger
  174. protected $log_destination; // e-mail or file
  175. protected $serveroutput;
  176. protected $setup;
  177. protected $stringjob;
  178. protected $data;
  179. protected $debug_count = 0;
  180. protected $username;
  181. protected $charset;
  182. protected $password;
  183. protected $requesring_user;
  184. protected $client_hostname = "localhost";
  185. protected $stream;
  186. protected $host = "localhost";
  187. protected $port = "631";
  188. protected $printer_uri;
  189. protected $timeout = "20"; //20 secs
  190. protected $errNo;
  191. protected $errStr;
  192. protected $datatype;
  193. protected $datahead;
  194. protected $datatail;
  195. public $meta;
  196. protected $operation_id;
  197. protected $delay;
  198. protected $error_generation; //devel feature
  199. protected $debug_http = 0;
  200. protected $no_disconnect;
  201. protected $job_tags;
  202. protected $operation_tags;
  203. protected $index;
  204. protected $collection; //RFC3382
  205. protected $collection_index; //RFC3382
  206. protected $collection_key = array(); //RFC3382
  207. protected $collection_depth = - 1; //RFC3382
  208. protected $end_collection = false; //RFC3382
  209. protected $collection_nbr = array(); //RFC3382
  210. protected $unix = false; // true -> use unix sockets instead of http
  211. // constructor
  212. public function __construct()
  213. {
  214. $tz = getenv("date.timezone");
  215. if (!$tz) $tz = @date_default_timezone_get();
  216. date_default_timezone_set($tz);
  217. $this->meta = new stdClass();
  218. $this->setup = new stdClass();
  219. $this->values = new stdClass();
  220. $this->serveroutput = new stdClass();
  221. $this->error_generation = new stdClass();
  222. $this->_parsing = new stdClass();
  223. self::_initTags();
  224. }
  225. /*****************
  226. *
  227. * PUBLIC FUNCTIONS
  228. *
  229. *******************/
  230. //
  231. // SETUP
  232. //
  233. public function setPort($port = '631')
  234. {
  235. $this->port = $port;
  236. self::_putDebug("Port is " . $this->port, 2);
  237. }
  238. public function setUnix($socket = '/var/run/cups/cups.sock')
  239. {
  240. $this->host = $socket;
  241. $this->unix = true;
  242. self::_putDebug("Host is " . $this->host, 2);
  243. }
  244. public function setHost($host = 'localhost')
  245. {
  246. $this->host = $host;
  247. $this->unix = false;
  248. self::_putDebug("Host is " . $this->host, 2);
  249. }
  250. public function setTimeout($timeout)
  251. {
  252. $this->timeout = $timeout;
  253. }
  254. public function setPrinterURI($uri)
  255. {
  256. $length = strlen($uri);
  257. $length = chr($length);
  258. while (strlen($length) < 2) $length = chr(0x00) . $length;
  259. $this->meta->printer_uri = chr(0x45) // uri type | value-tag
  260. . chr(0x00) . chr(0x0B) // name-length
  261. . "printer-uri" // printer-uri | name
  262. . $length . $uri;
  263. $this->printer_uri = $uri;
  264. self::_putDebug(sprintf(_("Printer URI: %s") , $uri) , 2);
  265. $this->setup->uri = 1;
  266. }
  267. public function setData($data)
  268. {
  269. $this->data = $data;
  270. self::_putDebug("Data set", 2);
  271. }
  272. public function setRawText()
  273. {
  274. $this->setup->datatype = 'TEXT';
  275. $this->meta->mime_media_type = "";
  276. $this->setup->mime_media_type = 1;
  277. $this->datahead = chr(0x16);
  278. if (is_readable($this->data))
  279. {
  280. //It's a filename. Open and stream.
  281. $data = fopen($this->data, "rb");
  282. while (!feof($data)) $output = fread($data, 8192);
  283. }
  284. else
  285. {
  286. $output = $this->data;
  287. }
  288. if (substr($output, -1, 1) != chr(0x0c)) if (!isset($this->setup->noFormFeed)) $this->datatail = chr(0x0c);
  289. self::_putDebug(_("Forcing data to be interpreted as RAW TEXT") , 2);
  290. }
  291. public function unsetRawText()
  292. {
  293. $this->setup->datatype = 'BINARY';
  294. $this->datahead = '';
  295. $this->datatail = '';
  296. self::_putDebug(_("Unset forcing data to be interpreted as RAW TEXT") , 2);
  297. }
  298. public function setBinary()
  299. {
  300. self::unsetRawText();
  301. }
  302. public function setFormFeed()
  303. {
  304. $this->datatail = "\r\n" . chr(0x0c);
  305. unset($this->setup->noFormFeed);
  306. }
  307. public function unsetFormFeed()
  308. {
  309. $this->datatail = '';
  310. $this->setup->noFormFeed = 1;
  311. }
  312. public function setCharset($charset = 'us-ascii')
  313. {
  314. $charset = strtolower($charset);
  315. $this->charset = $charset;
  316. $this->meta->charset = chr(0x47) // charset type | value-tag
  317. . chr(0x00) . chr(0x12) // name-length
  318. . "attributes-charset" // attributes-charset | name
  319. . self::_giveMeStringLength($charset) // value-length
  320. . $charset; // value
  321. self::_putDebug(sprintf(_("Charset: %s") , $charset) , 2);
  322. $this->setup->charset = 1;
  323. }
  324. public function setLanguage($language = 'en_us')
  325. {
  326. $language = strtolower($language);
  327. $this->meta->language = chr(0x48) // natural-language type | value-tag
  328. . chr(0x00) . chr(0x1B) // name-length
  329. . "attributes-natural-language" //attributes-natural-language
  330. . self::_giveMeStringLength($language) // value-length
  331. . $language; // value
  332. self::_putDebug(sprintf(_("Language: %s") , $language) , 2);
  333. $this->setup->language = 1;
  334. }
  335. public function setDocumentFormat($mime_media_type = 'application/octet-stream')
  336. {
  337. self::setBinary();
  338. $length = chr(strlen($mime_media_type));
  339. while (strlen($length) < 2) $length = chr(0x00) . $length;
  340. self::_putDebug(sprintf(_("mime type: %s") , $mime_media_type) , 2);
  341. $this->meta->mime_media_type = chr(0x49) // document-format tag
  342. . self::_giveMeStringLength('document-format') . 'document-format' //
  343. . self::_giveMeStringLength($mime_media_type) . $mime_media_type; // value
  344. $this->setup->mime_media_type = 1;
  345. }
  346. // setDocumentFormat alias for backward compatibility
  347. public function setMimeMediaType($mime_media_type = "application/octet-stream")
  348. {
  349. self::setDocumentFormat($mime_media_type);
  350. }
  351. public function setCopies($nbrcopies = 1)
  352. {
  353. $this->meta->copies = "";
  354. if ($nbrcopies == 1 || !$nbrcopies) return true;
  355. $copies = self::_integerBuild($nbrcopies);
  356. $this->meta->copies = chr(0x21) // integer type | value-tag
  357. . chr(0x00) . chr(0x06) // name-length
  358. . "copies" // copies | name
  359. . self::_giveMeStringLength($copies) // value-length
  360. . $copies;
  361. self::_putDebug(sprintf(_("Copies: %s") , $nbrcopies) , 2);
  362. $this->setup->copies = 1;
  363. }
  364. public function setDocumentName($document_name = "")
  365. {
  366. $this->meta->document_name = "";
  367. if (!$document_name) return true;
  368. $document_name = substr($document_name, 0, 1023);
  369. $length = strlen($document_name);
  370. $length = chr($length);
  371. while (strlen($length) < 2) $length = chr(0x00) . $length;
  372. self::_putDebug(sprintf(_("document name: %s") , $document_name) , 2);
  373. $this->meta->document_name = chr(0x41) // textWithoutLanguage tag
  374. . chr(0x00) . chr(0x0d) // name-length
  375. . "document-name" // mimeMediaType
  376. . self::_giveMeStringLength($document_name) . $document_name; // value
  377. }
  378. public function setJobName($jobname = '', $absolute = false)
  379. {
  380. $this->meta->jobname = '';
  381. if ($jobname == '')
  382. {
  383. $this->meta->jobname = '';
  384. return true;
  385. }
  386. $postpend = date('-H:i:s-') . $this->_setJobId();
  387. if ($absolute) $postpend = '';
  388. if (isset($this->values->jobname) && $jobname == '(PHP)')
  389. {
  390. $jobname = $this->values->jobname;
  391. }
  392. $this->values->jobname = $jobname;
  393. $jobname.= $postpend;
  394. $this->meta->jobname = chr(0x42) // nameWithoutLanguage type || value-tag
  395. . chr(0x00) . chr(0x08) // name-length
  396. . "job-name" // job-name || name
  397. . self::_giveMeStringLength($jobname) // value-length
  398. . $jobname; // value
  399. self::_putDebug(sprintf(_("Job name: %s") , $jobname) , 2);
  400. $this->setup->jobname = 1;
  401. }
  402. public function setUserName($username = 'PHP-SERVER')
  403. {
  404. $this->requesting_user = $username;
  405. $this->meta->username = '';
  406. if (!$username) return true;
  407. if ($username == 'PHP-SERVER' && isset($this->meta->username)) return TRUE;
  408. /*
  409. $value_length = 0x00;
  410. for ($i = 0; $i < strlen($username); $i++)
  411. {
  412. $value_length+= 0x01;
  413. }
  414. $value_length = chr($value_length);
  415. while (strlen($value_length) < 2) $value_length = chr(0x00) . $value_length;
  416. */
  417. $this->meta->username = chr(0x42) // keyword type || value-tag
  418. . chr(0x00) . chr(0x14) // name-length
  419. . "requesting-user-name"
  420. . self::_giveMeStringLength($username) // value-length
  421. . $username;
  422. self::_putDebug(sprintf(_("Username: %s") , $username) , 2);
  423. $this->setup->username = 1;
  424. }
  425. public function setAuthentification($username, $password)
  426. {
  427. self::setAuthentication($username, $password);
  428. }
  429. public function setAuthentication($username, $password)
  430. {
  431. $this->password = $password;
  432. $this->username = $username;
  433. self::_putDebug(_("Setting password") , 2);
  434. $this->setup->password = 1;
  435. }
  436. public function setSides($sides = 2)
  437. {
  438. $this->meta->sides = '';
  439. if (!$sides) return true;
  440. switch ($sides)
  441. {
  442. case 1:
  443. $sides = "one-sided";
  444. break;
  445. case 2:
  446. $sides = "two-sided-long-edge";
  447. break;
  448. case "2CE":
  449. $sides = "two-sided-short-edge";
  450. break;
  451. default:
  452. $sides = $sides; // yeah, what ?
  453. break;
  454. }
  455. $this->meta->sides = chr(0x44) // keyword type | value-tag
  456. . chr(0x00) . chr(0x05) // name-length
  457. . "sides" // sides | name
  458. . self::_giveMeStringLength($sides) // value-length
  459. . $sides; // one-sided | value
  460. self::_putDebug(sprintf(_("Sides value set to %s") , $sides) , 2);
  461. }
  462. public function setFidelity()
  463. {
  464. // whether the server can't replace any attributes
  465. // (eg, 2 sided print is not possible,
  466. // so print one sided) and DO NOT THE JOB.
  467. $this->meta->fidelity = chr(0x22) // boolean type | value-tag
  468. . chr(0x00) . chr(0x16) // name-length
  469. . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name
  470. . chr(0x00) . chr(0x01) // value-length
  471. . chr(0x01); // true | value
  472. self::_putDebug(_("Fidelity attribute is set (paranoid mode)") , 3);
  473. }
  474. public function unsetFidelity()
  475. {
  476. // whether the server can replace any attributes
  477. // (eg, 2 sided print is not possible,
  478. // so print one sided) and DO THE JOB.
  479. $this->meta->fidelity = chr(0x22) // boolean type | value-tag
  480. . chr(0x00) . chr(0x16) // name-length
  481. . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name
  482. . chr(0x00) . chr(0x01) // value-length
  483. . chr(0x00); // false | value
  484. self::_putDebug(_("Fidelity attribute is unset") , 2);
  485. }
  486. public function setMessage($message = '')
  487. {
  488. $this->meta->message = '';
  489. if (!$message) return true;
  490. $this->meta->message =
  491. chr(0x41) // attribute type = textWithoutLanguage
  492. . chr(0x00)
  493. . chr(0x07)
  494. . "message"
  495. . self::_giveMeStringLength(substr($message, 0, 127))
  496. . substr($message, 0, 127);
  497. self::_putDebug(sprintf(_('Setting message to "%s"') , $message) , 2);
  498. }
  499. public function setPageRanges($page_ranges)
  500. {
  501. // $pages_ranges = string: "1:5 10:25 40:52 ..."
  502. // to unset, specify an empty string.
  503. $this->meta->page_range = '';
  504. if (!$page_ranges) return true;
  505. $page_ranges = trim(str_replace("-", ":", $page_ranges));
  506. $first = true;
  507. #$page_ranges = split(' ', $page_ranges);
  508. $page_ranges = preg_split('# #', $page_ranges);
  509. foreach($page_ranges as $page_range)
  510. {
  511. $value = self::_rangeOfIntegerBuild($page_range);
  512. if ($first)
  513. {
  514. $this->meta->page_ranges .=
  515. $this->tags_types['rangeOfInteger']['tag']
  516. . self::_giveMeStringLength('page-ranges')
  517. . 'page-ranges'
  518. . self::_giveMeStringLength($value)
  519. . $value;
  520. }
  521. else
  522. {
  523. $this->meta->page_ranges .=
  524. $this->tags_types['rangeOfInteger']['tag']
  525. . self::_giveMeStringLength('')
  526. . self::_giveMeStringLength($value)
  527. . $value;
  528. $first = false;
  529. }
  530. }
  531. }
  532. public function setAttribute($attribute, $values)
  533. {
  534. $operation_attributes_tags = array_keys($this->operation_tags);
  535. $job_attributes_tags = array_keys($this->job_tags);
  536. $printer_attributes_tags = array_keys($this->printer_tags);
  537. self::unsetAttribute($attribute);
  538. if (in_array($attribute, $operation_attributes_tags))
  539. {
  540. if (!is_array($values))
  541. {
  542. self::_setOperationAttribute($attribute, $values);
  543. }
  544. else
  545. {
  546. foreach($values as $value)
  547. {
  548. self::_setOperationAttribute($attribute, $value);
  549. }
  550. }
  551. }
  552. elseif (in_array($attribute, $job_attributes_tags))
  553. {
  554. if (!is_array($values))
  555. {
  556. self::_setJobAttribute($attribute, $values);
  557. }
  558. else
  559. {
  560. foreach($values as $value)
  561. {
  562. self::_setJobAttribute($attribute, $value);
  563. }
  564. }
  565. }
  566. elseif (in_array($attribute, $printer_attributes_tags))
  567. {
  568. if (!is_array($values))
  569. {
  570. self::_setPrinterAttribute($attribute, $values);
  571. }
  572. else
  573. {
  574. foreach($values as $value)
  575. {
  576. self::_setPrinterAttribute($attribute, $value);
  577. }
  578. }
  579. }
  580. else
  581. {
  582. trigger_error(
  583. sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),
  584. $attribute) , E_USER_NOTICE);
  585. self::_putDebug(
  586. sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),
  587. $attribute) , 3);
  588. self::_errorLog(
  589. sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),
  590. $attribute) , 2);
  591. return FALSE;
  592. }
  593. }
  594. public function unsetAttribute($attribute)
  595. {
  596. $operation_attributes_tags = array_keys($this->operation_tags);
  597. $job_attributes_tags = array_keys($this->job_tags);
  598. $printer_attributes_tags = array_keys($this->printer_tags);
  599. if (in_array($attribute, $operation_attributes_tags))
  600. {
  601. unset(
  602. $this->operation_tags[$attribute]['value'],
  603. $this->operation_tags[$attribute]['systag']
  604. );
  605. }
  606. elseif (in_array($attribute, $job_attributes_tags))
  607. {
  608. unset(
  609. $this->job_tags[$attribute]['value'],
  610. $this->job_tags[$attribute]['systag']
  611. );
  612. }
  613. elseif (in_array($attribute, $printer_attributes_tags))
  614. {
  615. unset(
  616. $this->printer_tags[$attribute]['value'],
  617. $this->printer_tags[$attribute]['systag']
  618. );
  619. }
  620. else
  621. {
  622. trigger_error(
  623. sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),
  624. $attribute) , E_USER_NOTICE);
  625. self::_putDebug(
  626. sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),
  627. $attribute) , 3);
  628. self::_errorLog(
  629. sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),
  630. $attribute) , 2);
  631. return FALSE;
  632. }
  633. return true;
  634. }
  635. //
  636. // LOGGING / DEBUGGING
  637. //
  638. public function setLog($log_destination, $destination_type = 'file', $level = 2)
  639. {
  640. if (is_string($log_destination) && !empty($log_destination))
  641. {
  642. $this->log_destination = $log_destination;
  643. }
  644. switch ($destination_type)
  645. {
  646. case 'file':
  647. case 3:
  648. $this->log_destination = $log_destination;
  649. $this->log_type = 3;
  650. break;
  651. case 'logger':
  652. case 0:
  653. $this->log_destination = '';
  654. $this->log_type = 0;
  655. break;
  656. case 'e-mail':
  657. case 1:
  658. $this->log_destination = $log_destination;
  659. $this->log_type = 1;
  660. break;
  661. }
  662. $this->log_level = $level;
  663. }
  664. public function printDebug()
  665. {
  666. for ($i = 0; $i < $this->debug_count; $i++)
  667. {
  668. echo $this->debug[$i], "\n";
  669. }
  670. $this->debug = array();
  671. $this->debug_count = 0;
  672. }
  673. public function getDebug()
  674. {
  675. $debug = '';
  676. for ($i = 0; $i < $this->debug_count; $i++)
  677. {
  678. $debug.= $this->debug[$i];
  679. }
  680. $this->debug = array();
  681. $this->debug_count = 0;
  682. return $debug;
  683. }
  684. //
  685. // OPERATIONS
  686. //
  687. public function printJob()
  688. {
  689. // this BASIC version of printJob do not parse server
  690. // output for job's attributes
  691. self::_putDebug(
  692. sprintf(
  693. "************** Date: %s ***********",
  694. date('Y-m-d H:i:s')
  695. )
  696. );
  697. if (!$this->_stringJob()) return FALSE;
  698. if (is_readable($this->data))
  699. {
  700. self::_putDebug(_("Printing a FILE"));
  701. $this->output = $this->stringjob;
  702. if ($this->setup->datatype == "TEXT")
  703. {
  704. $this->output.= chr(0x16);
  705. }
  706. $post_values = array(
  707. "Content-Type" => "application/ipp",
  708. "Data" => $this->output,
  709. "File" => $this->data
  710. );
  711. if ($this->setup->datatype == "TEXT" && !isset($this->setup->noFormFeed))
  712. {
  713. $post_values = array_merge(
  714. $post_values,
  715. array(
  716. "Filetype" => "TEXT"
  717. )
  718. );
  719. }
  720. }
  721. else
  722. {
  723. self::_putDebug(_("Printing DATA"));
  724. $this->output =
  725. $this->stringjob
  726. . $this->datahead
  727. . $this->data
  728. . $this->datatail;
  729. $post_values = array(
  730. "Content-Type" => "application/ipp",
  731. "Data" => $this->output
  732. );
  733. }
  734. if (self::_sendHttp($post_values, $this->paths["printers"]))
  735. {
  736. self::_parseServerOutput();
  737. }
  738. if (isset($this->serveroutput) && isset($this->serveroutput->status))
  739. {
  740. $this->status = array_merge($this->status, array(
  741. $this->serveroutput->status
  742. ));
  743. if ($this->serveroutput->status == "successfull-ok")
  744. {
  745. self::_errorLog(
  746. sprintf("printing job %s: ", $this->last_job)
  747. . $this->serveroutput->status,
  748. 3);
  749. }
  750. else
  751. {
  752. self::_errorLog(
  753. sprintf("printing job: ", $this->last_job)
  754. . $this->serveroutput->status,
  755. 1);
  756. }
  757. return $this->serveroutput->status;
  758. }
  759. $this->status =
  760. array_merge($this->status, array("OPERATION FAILED"));
  761. $this->jobs =
  762. array_merge($this->jobs, array(""));
  763. $this->jobs_uri =
  764. array_merge($this->jobs_uri, array(""));
  765. self::_errorLog("printing job : OPERATION FAILED", 1);
  766. return false;
  767. }
  768. /******************
  769. *
  770. * PROTECTED FUNCTIONS
  771. *
  772. *******************/
  773. //
  774. // HTTP OUTPUT
  775. //
  776. protected function _sendHttp($post_values, $uri)
  777. {
  778. /*
  779. This function Copyright (C) 2005-2006 Thomas Harding, Manuel Lemos
  780. */
  781. $this->response_completed[] = "no";
  782. unset($this->serverouptut);
  783. self::_putDebug(_("Processing HTTP request") , 2);
  784. $this->serveroutput->headers = array();
  785. $this->serveroutput->body = "";
  786. $http = new http_class;
  787. if (!$this->unix) $http->host = $this->host;
  788. else $http->host = "localhost";
  789. $http->with_exceptions = $this->with_exceptions;
  790. if ($this->debug_http)
  791. {
  792. $http->debug = 1;
  793. $http->html_debug = 0;
  794. }
  795. else
  796. {
  797. $http->debug = 0;
  798. $http->html_debug = 0;
  799. }
  800. $url = "http://" . $this->host;
  801. if ($this->ssl) $url = "https://" . $this->host;
  802. if ($this->unix) $url = "unix://" . $this->host;
  803. $http->port = $this->port;
  804. $http->timeout = $this->http_timeout;
  805. $http->data_timeout = $this->http_data_timeout;
  806. $http->force_multipart_form_post = false;
  807. $http->user = $this->username;
  808. $http->password = $this->password;
  809. $error = $http->GetRequestArguments($url, $arguments);
  810. $arguments["RequestMethod"] = "POST";
  811. $arguments["Headers"] = array(
  812. "Content-Type" => "application/ipp"
  813. );
  814. $arguments["BodyStream"] = array(
  815. array(
  816. "Data" => $post_values["Data"]
  817. )
  818. );
  819. if (isset($post_values["File"])) $arguments["BodyStream"][] = array(
  820. "File" => $post_values["File"]
  821. );
  822. if (isset($post_values["FileType"])
  823. && !strcmp($post_values["FileType"], "TEXT"))
  824. {
  825. $arguments["BodyStream"][] = array("Data" => Chr(12));
  826. }
  827. $arguments["RequestURI"] = $uri;
  828. if ($this->with_exceptions && $this->handle_http_exceptions)
  829. {
  830. try
  831. {
  832. $success = $http->Open($arguments);
  833. }
  834. catch(httpException $e)
  835. {
  836. throw new ippException(
  837. sprintf("http error: %s", $e->getMessage()),
  838. $e->getErrno());
  839. }
  840. }
  841. else
  842. {
  843. $success = $http->Open($arguments);
  844. }
  845. if ($success[0] == true)
  846. {
  847. $success = $http->SendRequest($arguments);
  848. if ($success[0] == true)
  849. {
  850. self::_putDebug("H T T P R E Q U E S T :");
  851. self::_putDebug("Request headers:");
  852. for (Reset($http->request_headers) , $header = 0; $header < count($http->request_headers); Next($http->request_headers) , $header++)
  853. {
  854. $header_name = Key($http->request_headers);
  855. if (GetType($http->request_headers[$header_name]) == "array")
  856. {
  857. for ($header_value = 0; $header_value < count($http->request_headers[$header_name]); $header_value++)
  858. {
  859. self::_putDebug($header_name . ": " . $http->request_headers[$header_name][$header_value]);
  860. }
  861. }
  862. else
  863. {
  864. self::_putDebug($header_name . ": " . $http->request_headers[$header_name]);
  865. }
  866. }
  867. self::_putDebug("Request body:");
  868. self::_putDebug(
  869. htmlspecialchars($http->request_body)
  870. . "*********** END REQUEST BODY *********"
  871. );
  872. $i = 0;
  873. $headers = array();
  874. unset($this->serveroutput->headers);
  875. $http->ReadReplyHeaders($headers);
  876. self::_putDebug("H T T P R E S P O N S E :");
  877. self::_putDebug("Response headers:");
  878. for (Reset($headers) , $header = 0; $header < count($headers); Next($headers) , $header++)
  879. {
  880. $header_name = Key($headers);
  881. if (GetType($headers[$header_name]) == "array")
  882. {
  883. for ($header_value = 0; $header_value < count($headers[$header_name]); $header_value++)
  884. {
  885. self::_putDebug($header_name . ": " . $headers[$header_name][$header_value]);
  886. $this->serveroutput->headers[$i] =
  887. $header_name . ": "
  888. . $headers[$header_name][$header_value];
  889. $i++;
  890. }
  891. }
  892. else
  893. {
  894. self::_putDebug($header_name . ": " . $headers[$header_name]);
  895. $this->serveroutput->headers[$i] =
  896. $header_name
  897. . ": "
  898. . $headers[$header_name];
  899. $i++;
  900. }
  901. }
  902. self::_putDebug("\n\nResponse body:\n");
  903. $this->serveroutput->body = "";
  904. for (;;)
  905. {
  906. $http->ReadReplyBody($body, 1024);
  907. if (strlen($body) == 0) break;
  908. self::_putDebug(htmlentities($body));
  909. $this->serveroutput->body.= $body;
  910. }
  911. self::_putDebug("********* END RESPONSE BODY ********");
  912. }
  913. }
  914. $http->Close();
  915. return true;
  916. }
  917. //
  918. // INIT
  919. //
  920. protected function _initTags()
  921. {
  922. $this->tags_types = array(
  923. "unsupported" => array(
  924. "tag" => chr(0x10) ,
  925. "build" => ""
  926. ) ,
  927. "reserved" => array(
  928. "tag" => chr(0x11) ,
  929. "build" => ""
  930. ) ,
  931. "unknown" => array(
  932. "tag" => chr(0x12) ,
  933. "build" => ""
  934. ) ,
  935. "no-value" => array(
  936. "tag" => chr(0x13) ,
  937. "build" => "no_value"
  938. ) ,
  939. "integer" => array(
  940. "tag" => chr(0x21) ,
  941. "build" => "integer"
  942. ) ,
  943. "boolean" => array(
  944. "tag" => chr(0x22) ,
  945. "build" => "boolean"
  946. ) ,
  947. "enum" => array(
  948. "tag" => chr(0x23) ,
  949. "build" => "enum"
  950. ) ,
  951. "octetString" => array(
  952. "tag" => chr(0x30) ,
  953. "build" => "octet_string"
  954. ) ,
  955. "datetime" => array(
  956. "tag" => chr(0x31) ,
  957. "build" => "datetime"
  958. ) ,
  959. "resolution" => array(
  960. "tag" => chr(0x32) ,
  961. "build" => "resolution"
  962. ) ,
  963. "rangeOfInteger" => array(
  964. "tag" => chr(0x33) ,
  965. "build" => "range_of_integers"
  966. ) ,
  967. "textWithLanguage" => array(
  968. "tag" => chr(0x35) ,
  969. "build" => "string"
  970. ) ,
  971. "nameWithLanguage" => array(
  972. "tag" => chr(0x36) ,
  973. "build" => "string"
  974. ) ,
  975. /*
  976. "text" => array ("tag" => chr(0x40),
  977. "build" => "string"),
  978. "text string" => array ("tag" => chr(0x40),
  979. "build" => "string"),
  980. */
  981. "textWithoutLanguage" => array(
  982. "tag" => chr(0x41) ,
  983. "build" => "string"
  984. ) ,
  985. "nameWithoutLanguage" => array(
  986. "tag" => chr(0x42) ,
  987. "buid" => "string"
  988. ) ,
  989. "keyword" => array(
  990. "tag" => chr(0x44) ,
  991. "build" => "string"
  992. ) ,
  993. "uri" => array(
  994. "tag" => chr(0x45) ,
  995. "build" => "string"
  996. ) ,
  997. "uriScheme" => array(
  998. "tag" => chr(0x46) ,
  999. "build" => "string"
  1000. ) ,
  1001. "charset" => array(
  1002. "tag" => chr(0x47) ,
  1003. "build" => "string"
  1004. ) ,
  1005. "naturalLanguage" => array(
  1006. "tag" => chr(0x48) ,
  1007. "build" => "string"
  1008. ) ,
  1009. "mimeMediaType" => array(
  1010. "tag" => chr(0x49) ,
  1011. "build" => "string"
  1012. ) ,
  1013. "extendedAttributes" => array(
  1014. "tag" => chr(0x7F) ,
  1015. "build" => "extended"
  1016. ) ,
  1017. );
  1018. $this->operation_tags = array(
  1019. "compression" => array(
  1020. "tag" => "keyword"
  1021. ) ,
  1022. "document-natural-language" => array(
  1023. "tag" => "naturalLanguage"
  1024. ) ,
  1025. "job-k-octets" => array(
  1026. "tag" => "integer"
  1027. ) ,
  1028. "job-impressions" => array(
  1029. "tag" => "integer"
  1030. ) ,
  1031. "job-media-sheets" => array(
  1032. "tag" => "integer"
  1033. ) ,
  1034. );
  1035. $this->job_tags = array(
  1036. "job-priority" => array(
  1037. "tag" => "integer"
  1038. ) ,
  1039. "job-hold-until" => array(
  1040. "tag" => "keyword"
  1041. ) ,
  1042. "job-sheets" => array(
  1043. "tag" => "keyword"
  1044. ) , //banner page
  1045. "multiple-document-handling" => array(
  1046. "tag" => "keyword"
  1047. ) ,
  1048. //"copies" => array("tag" => "integer"),
  1049. "finishings" => array(
  1050. "tag" => "enum"
  1051. ) ,
  1052. //"page-ranges" => array("tag" => "rangeOfInteger"), // has its own function
  1053. //"sides" => array("tag" => "keyword"), // has its own function
  1054. "number-up" => array(
  1055. "tag" => "integer"
  1056. ) ,
  1057. "orientation-requested" => array(
  1058. "tag" => "enum"
  1059. ) ,
  1060. "media" => array(
  1061. "tag" => "keyword"
  1062. ) ,
  1063. "printer-resolution" => array(
  1064. "tag" => "resolution"
  1065. ) ,
  1066. "print-quality" => array(
  1067. "tag" => "enum"
  1068. ) ,
  1069. "job-message-from-operator" => array(
  1070. "tag" => "textWithoutLanguage"
  1071. ) ,
  1072. );
  1073. $this->printer_tags = array(
  1074. "requested-attributes" => array(
  1075. "tag" => "keyword"
  1076. )
  1077. );
  1078. }
  1079. //
  1080. // SETUP
  1081. //
  1082. protected function _setOperationId()
  1083. {
  1084. $prepend = '';
  1085. $this->operation_id+= 1;
  1086. $this->meta->operation_id = self::_integerBuild($this->operation_id);
  1087. self::_putDebug("operation id is: " . $this->operation_id, 2);
  1088. }
  1089. protected function _setJobId()
  1090. {
  1091. $this->meta->jobid+= 1;
  1092. $prepend = '';
  1093. $prepend_length = 4 - strlen($this->meta->jobid);
  1094. for ($i = 0; $i < $prepend_length; $i++) $prepend.= '0';
  1095. return $prepend . $this->meta->jobid;
  1096. }
  1097. protected function _setJobUri($job_uri)
  1098. {
  1099. $this->meta->job_uri = chr(0x45) // type uri
  1100. . chr(0x00) . chr(0x07) // name-length
  1101. . "job-uri"
  1102. //. chr(0x00).chr(strlen($job_uri))
  1103. . self::_giveMeStringLength($job_uri) . $job_uri;
  1104. self::_putDebug("job-uri is: " . $job_uri, 2);
  1105. }
  1106. //
  1107. // RESPONSE PARSING
  1108. //
  1109. protected function _parseServerOutput()
  1110. {
  1111. $this->serveroutput->response = array();
  1112. if (!self::_parseHttpHeaders()) return FALSE;
  1113. $this->_parsing->offset = 0;
  1114. self::_parseIppVersion();
  1115. self::_parseStatusCode();
  1116. self::_parseRequestID();
  1117. $this->_parseResponse();
  1118. //devel
  1119. self::_putDebug(
  1120. sprintf("***** IPP STATUS: %s ******", $this->serveroutput->status),
  1121. 4);
  1122. self::_putDebug("****** END OF OPERATION ****");
  1123. return true;
  1124. }
  1125. protected function _parseHttpHeaders()
  1126. {
  1127. $response = "";
  1128. switch ($this->serveroutput->headers[0])
  1129. {
  1130. case "http/1.1 200 ok: ":
  1131. $this->serveroutput->httpstatus = "HTTP/1.1 200 OK";
  1132. $response = "OK";
  1133. break;
  1134. // primitive http/1.0 for Lexmark printers (from Rick Baril)
  1135. case "http/1.0 200 ok: ":
  1136. $this->serveroutput->httpstatus = "HTTP/1.0 200 OK";
  1137. $response = "OK";
  1138. break;
  1139. case "http/1.1 100 continue: ":
  1140. $this->serveroutput->httpstatus = "HTTP/1.1 100 CONTINUE";
  1141. $response = "OK";
  1142. break;
  1143. case "":
  1144. $this->serveroutput->httpstatus = "HTTP/1.1 000 No Response From Server";
  1145. $this->serveroutput->status = "HTTP-ERROR-000_NO_RESPONSE_FROM_SERVER";
  1146. trigger_error("No Response From Server", E_USER_WARNING);
  1147. self::_errorLog("No Response From Server", 1);
  1148. $this->disconnected = 1;
  1149. return FALSE;
  1150. break;
  1151. default:
  1152. $server_response = preg_replace("/: $/", '', $this->serveroutput->headers[0]);
  1153. #$strings = split(' ', $server_response, 3);
  1154. $strings = preg_split('# #', $server_response, 3);
  1155. $errno = $strings[1];
  1156. $string = strtoupper(str_replace(' ', '_', $strings[2]));
  1157. trigger_error(
  1158. sprintf(_("server responds %s") , $server_response),
  1159. E_USER_WARNING);
  1160. self::_errorLog("server responds " . $server_response, 1);
  1161. $this->serveroutput->httpstatus =
  1162. strtoupper($strings[0])
  1163. . " "
  1164. . $errno
  1165. . " "
  1166. . ucfirst($strings[2]);
  1167. $this->serveroutput->status =
  1168. "HTTP-ERROR-"
  1169. . $errno
  1170. . "-"
  1171. . $string;
  1172. $this->disconnected = 1;
  1173. return FALSE;
  1174. break;
  1175. }
  1176. unset($this->serveroutput->headers);
  1177. return TRUE;
  1178. }
  1179. protected function _parseIppVersion()
  1180. {
  1181. $ippversion =
  1182. (ord($this->serveroutput->body[$this->_parsing->offset]) * 256)
  1183. + ord($this->serveroutput->body[$this->_parsing->offset + 1]);
  1184. switch ($ippversion)
  1185. {
  1186. case 0x0101:
  1187. $this->serveroutput->ipp_version = "1.1";
  1188. break;
  1189. default:
  1190. $this->serveroutput->ipp_version =
  1191. sprintf("%u.%u (Unknown)",
  1192. ord($this->serveroutput->body[$this->_parsing->offset]) * 256,
  1193. ord($this->serveroutput->body[$this->_parsing->offset + 1]));
  1194. break;
  1195. }
  1196. self::_putDebug("I P P R E S P O N S E :\n\n");
  1197. self::_putDebug(
  1198. sprintf("IPP version %s%s: %s",
  1199. ord($this->serveroutput->body[$this->_parsing->offset]),
  1200. ord($this->serveroutput->body[$this->_parsing->offset + 1]),
  1201. $this->serveroutput->ipp_version));
  1202. $this->_parsing->offset+= 2;
  1203. return;
  1204. }
  1205. protected function _parseStatusCode()
  1206. {
  1207. $status_code =
  1208. (ord($this->serveroutput->body[$this->_parsing->offset]) * 256)
  1209. + ord($this->serveroutput->body[$this->_parsing->offset + 1]);
  1210. $this->serveroutput->status = "NOT PARSED";
  1211. $this->_parsing->offset+= 2;
  1212. if (strlen($this->serveroutput->body) < $this->_parsing->offset)
  1213. {
  1214. return false;
  1215. }
  1216. if ($status_code < 0x00FF)
  1217. {
  1218. $this->serveroutput->status = "successfull";
  1219. }
  1220. elseif ($status_code < 0x01FF)
  1221. {
  1222. $this->serveroutput->status = "informational";
  1223. }
  1224. elseif ($status_code < 0x02FF)
  1225. {
  1226. $this->serveroutput->status = "redirection";
  1227. }
  1228. elseif ($status_code < 0x04FF)
  1229. {
  1230. $this->serveroutput->status = "client-error";
  1231. }
  1232. elseif ($status_code < 0x05FF)
  1233. {
  1234. $this->serveroutput->status = "server-error";
  1235. }
  1236. switch ($status_code)
  1237. {
  1238. case 0x0000:
  1239. $this->serveroutput->status = "successfull-ok";
  1240. break;
  1241. case 0x0001:
  1242. $this->serveroutput->status = "successful-ok-ignored-or-substituted-attributes";
  1243. break;
  1244. case 0x002:
  1245. $this->serveroutput->status = "successful-ok-conflicting-attributes";
  1246. break;
  1247. case 0x0400:
  1248. $this->serveroutput->status = "client-error-bad-request";
  1249. break;
  1250. case 0x0401:
  1251. $this->serveroutput->status = "client-error-forbidden";
  1252. break;
  1253. case 0x0402:
  1254. $this->serveroutput->status = "client-error-not-authenticated";
  1255. break;
  1256. case 0x0403:
  1257. $this->serveroutput->status = "client-error-not-authorized";
  1258. break;
  1259. case 0x0404:
  1260. $this->serveroutput->status = "client-error-not-possible";
  1261. break;
  1262. case 0x0405:
  1263. $this->serveroutput->status = "client-error-timeout";
  1264. break;
  1265. case 0x0406:
  1266. $this->serveroutput->status = "client-error-not-found";
  1267. break;
  1268. case 0x0407:
  1269. $this->serveroutput->status = "client-error-gone";
  1270. break;
  1271. case 0x0408:
  1272. $this->serveroutput->status = "client-error-request-entity-too-large";
  1273. break;
  1274. case 0x0409:
  1275. $this->serveroutput->status = "client-error-request-value-too-long";
  1276. break;
  1277. case 0x040A:
  1278. $this->serveroutput->status = "client-error-document-format-not-supported";
  1279. break;
  1280. case 0x040B:
  1281. $this->serveroutput->status = "client-error-attributes-or-values-not-supported";
  1282. break;
  1283. case 0x040C:
  1284. $this->serveroutput->status = "client-error-uri-scheme-not-supported";
  1285. break;
  1286. case 0x040D:
  1287. $this->serveroutput->status = "client-error-charset-not-supported";
  1288. break;
  1289. case 0x040E:
  1290. $this->serveroutput->status = "client-error-conflicting-attributes";
  1291. break;
  1292. case 0x040F:
  1293. $this->serveroutput->status = "client-error-compression-not-supported";
  1294. break;
  1295. case 0x0410:
  1296. $this->serveroutput->status = "client-error-compression-error";
  1297. break;
  1298. case 0x0411:
  1299. $this->serveroutput->status = "client-error-document-format-error";
  1300. break;
  1301. case 0x0412:
  1302. $this->serveroutput->status = "client-error-document-access-error";
  1303. break;
  1304. case 0x0413: // RFC3380
  1305. $this->serveroutput->status = "client-error-attributes-not-settable";
  1306. break;
  1307. case 0x0500:
  1308. $this->serveroutput->status = "server-error-internal-error";
  1309. break;
  1310. case 0x0501:
  1311. $this->serveroutput->status = "server-error-operation-not-supported";
  1312. break;
  1313. case 0x0502:
  1314. $this->serveroutput->status = "server-error-service-unavailable";
  1315. break;
  1316. case 0x0503:
  1317. $this->serveroutput->status = "server-error-version-not-supported";
  1318. break;
  1319. case 0x0504:
  1320. $this->serveroutput->status = "server-error-device-error";
  1321. break;
  1322. case 0x0505:
  1323. $this->serveroutput->status = "server-error-temporary-error";
  1324. break;
  1325. case 0x0506:
  1326. $this->serveroutput->status = "server-error-not-accepting-jobs";
  1327. break;
  1328. case 0x0507:
  1329. $this->serveroutput->status = "server-error-busy";
  1330. break;
  1331. case 0x0508:
  1332. $this->serveroutput->status = "server-error-job-canceled";
  1333. break;
  1334. case 0x0509:
  1335. $this->serveroutput->status = "server-error-multiple-document-jobs-not-supported";
  1336. break;
  1337. default:
  1338. break;
  1339. }
  1340. self::_putDebug(
  1341. sprintf(
  1342. "status-code: %s%s: %s ",
  1343. $this->serveroutput->body[$this->_parsing->offset],
  1344. $this->serveroutput->body[$this->_parsing->offset + 1],
  1345. $this->serveroutput->status),
  1346. 4);
  1347. return;
  1348. }
  1349. protected function _parseRequestID()
  1350. {
  1351. $this->serveroutput->request_id =
  1352. self::_interpretInteger(
  1353. substr($this->serveroutput->body, $this->_parsing->offset, 4)
  1354. );
  1355. self::_putDebug("request-id " . $this->serveroutput->request_id, 2);
  1356. $this->_parsing->offset+= 4;
  1357. return;
  1358. }
  1359. protected function _interpretInteger($value)
  1360. {
  1361. // they are _signed_ integers
  1362. $value_parsed = 0;
  1363. for ($i = strlen($value); $i > 0; $i --)
  1364. {
  1365. $value_parsed +=
  1366. (
  1367. (1 << (($i - 1) * 8))
  1368. *
  1369. ord($value[strlen($value) - $i])
  1370. );
  1371. }
  1372. if ($value_parsed >= 2147483648)
  1373. {
  1374. $value_parsed -= 4294967296;
  1375. }
  1376. return $value_parsed;
  1377. }
  1378. protected function _parseResponse()
  1379. {
  1380. }
  1381. //
  1382. // REQUEST BUILDING
  1383. //
  1384. protected function _stringJob()
  1385. {
  1386. if (!isset($this->setup->charset)) self::setCharset('us-ascii');
  1387. if (!isset($this->setup->datatype)) self::setBinary();
  1388. if (!isset($this->setup->uri))
  1389. {
  1390. $this->getPrinters();
  1391. unset($this->jobs[count($this->jobs) - 1]);
  1392. unset($this->jobs_uri[count($this->jobs_uri) - 1]);
  1393. unset($this->status[count($this->status) - 1]);
  1394. if (array_key_exists(0, $this->available_printers))
  1395. {
  1396. self::setPrinterURI($this->available_printers[0]);
  1397. }
  1398. else
  1399. {
  1400. trigger_error(
  1401. _("_stringJob: Printer URI is not set: die"),
  1402. E_USER_WARNING);
  1403. self::_putDebug(_("_stringJob: Printer URI is not set: die") , 4);
  1404. self::_errorLog(" Printer URI is not set, die", 2);
  1405. return FALSE;
  1406. }
  1407. }
  1408. if (!isset($this->setup->copies)) self::setCopies(1);
  1409. if (!isset($this->setup->language)) self::setLanguage('en_us');
  1410. if (!isset($this->setup->mime_media_type)) self::setMimeMediaType();
  1411. if (!isset($this->setup->jobname)) self::setJobName();
  1412. unset($this->setup->jobname);
  1413. if (!isset($this->meta->username)) self::setUserName();
  1414. if (!isset($this->meta->fidelity)) $this->meta->fidelity = '';
  1415. if (!isset($this->meta->document_name)) $this->meta->document_name = '';
  1416. if (!isset($this->meta->sides)) $this->meta->sides = '';
  1417. if (!isset($this->meta->page_ranges)) $this->meta->page_ranges = '';
  1418. $jobattributes = '';
  1419. $operationattributes = '';
  1420. $printerattributes = '';
  1421. $this->_buildValues($operationattributes, $jobattributes, $printerattributes);
  1422. self::_setOperationId();
  1423. if (!isset($this->error_generation->request_body_malformed))
  1424. {
  1425. $this->error_generation->request_body_malformed = "";
  1426. }
  1427. $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number
  1428. . chr(0x00) . chr(0x02) // Print-Job | operation-id
  1429. . $this->meta->operation_id // request-id
  1430. . chr(0x01) // start operation-attributes | operation-attributes-tag
  1431. . $this->meta->charset
  1432. . $this->meta->language
  1433. . $this->meta->printer_uri
  1434. . $this->meta->username
  1435. . $this->meta->jobname
  1436. . $this->meta->fidelity
  1437. . $this->meta->document_name
  1438. . $this->meta->mime_media_type
  1439. . $operationattributes;
  1440. if ($this->meta->copies || $this->meta->sides || $this->meta->page_ranges || !empty($jobattributes))
  1441. {
  1442. $this->stringjob .=
  1443. chr(0x02) // start job-attributes | job-attributes-tag
  1444. . $this->meta->copies
  1445. . $this->meta->sides
  1446. . $this->meta->page_ranges
  1447. . $jobattributes
  1448. ;
  1449. }
  1450. $this->stringjob.= chr(0x03); // end-of-attributes | end-of-attributes-tag
  1451. self::_putDebug(
  1452. sprintf(_("String sent to the server is: %s"),
  1453. $this->stringjob)
  1454. );
  1455. return TRUE;
  1456. }
  1457. protected function _buildValues(&$operationattributes, &$jobattributes, &$printerattributes)
  1458. {
  1459. $operationattributes = '';
  1460. foreach($this->operation_tags as $key => $values)
  1461. {
  1462. $item = 0;
  1463. if (array_key_exists('value', $values))
  1464. {
  1465. foreach($values['value'] as $item_value)
  1466. {
  1467. if ($item == 0)
  1468. {
  1469. $operationattributes .=
  1470. $values['systag']
  1471. . self::_giveMeStringLength($key)
  1472. . $key
  1473. . self::_giveMeStringLength($item_value)
  1474. . $item_value;
  1475. }
  1476. else
  1477. {
  1478. $operationattributes .=
  1479. $values['systag']
  1480. . self::_giveMeStringLength('')
  1481. . self::_giveMeStringLength($item_value)
  1482. . $item_value;
  1483. }
  1484. $item++;
  1485. }
  1486. }
  1487. }
  1488. $jobattributes = '';
  1489. foreach($this->job_tags as $key => $values)
  1490. {
  1491. $item = 0;
  1492. if (array_key_exists('value', $values))
  1493. {
  1494. foreach($values['value'] as $item_value)
  1495. {
  1496. if ($item == 0)
  1497. {
  1498. $jobattributes .=
  1499. $values['systag']
  1500. . self::_giveMeStringLength($key)
  1501. . $key
  1502. . self::_giveMeStringLength($item_value)
  1503. . $item_value;
  1504. }
  1505. else
  1506. {
  1507. $jobattributes .=
  1508. $values['systag']
  1509. . self::_giveMeStringLength('')
  1510. . self::_giveMeStringLength($item_value)
  1511. . $item_value;
  1512. }
  1513. $item++;
  1514. }
  1515. }
  1516. }
  1517. $printerattributes = '';
  1518. foreach($this->printer_tags as $key => $values)
  1519. {
  1520. $item = 0;
  1521. if (array_key_exists('value', $values))
  1522. {
  1523. foreach($values['value'] as $item_value)
  1524. {
  1525. if ($item == 0)
  1526. {
  1527. $printerattributes .=
  1528. $values['systag']
  1529. . self::_giveMeStringLength($key)
  1530. . $key
  1531. . self::_giveMeStringLength($item_value)
  1532. . $item_value;
  1533. }
  1534. else
  1535. {
  1536. $printerattributes .=
  1537. $values['systag']
  1538. . self::_giveMeStringLength('')
  1539. . self::_giveMeStringLength($item_value)
  1540. . $item_value;
  1541. }
  1542. $item++;
  1543. }
  1544. }
  1545. }
  1546. reset($this->job_tags);
  1547. reset($this->operation_tags);
  1548. reset($this->printer_tags);
  1549. return true;
  1550. }
  1551. protected function _giveMeStringLength($string)
  1552. {
  1553. $length = strlen($string);
  1554. if ($length > ((0xFF << 8) + 0xFF) )
  1555. {
  1556. $errmsg = sprintf (
  1557. _('max string length for an ipp meta-information = %d, while here %d'),
  1558. ((0xFF << 8) + 0xFF), $length);
  1559. if ($this->with_exceptions)
  1560. {
  1561. throw new ippException($errmsg);
  1562. }
  1563. else
  1564. {
  1565. trigger_error ($errmsg, E_USER_ERROR);
  1566. }
  1567. }
  1568. $int1 = $length & 0xFF;
  1569. $length -= $int1;
  1570. $length = $length >> 8;
  1571. $int2 = $length & 0xFF;
  1572. return chr($int2) . chr($int1);
  1573. }
  1574. protected function _enumBuild($tag, $value)
  1575. {
  1576. switch ($tag)
  1577. {
  1578. case "orientation-requested":
  1579. switch ($value)
  1580. {
  1581. case 'portrait':
  1582. $value = chr(3);
  1583. break;
  1584. case 'landscape':
  1585. $value = chr(4);
  1586. break;
  1587. case 'reverse-landscape':
  1588. $value = chr(5);
  1589. break;
  1590. case 'reverse-portrait':
  1591. $value = chr(6);
  1592. break;
  1593. }
  1594. break;
  1595. case "print-quality":
  1596. switch ($value)
  1597. {
  1598. case 'draft':
  1599. $value = chr(3);
  1600. break;
  1601. case 'normal':
  1602. $value = chr(4);
  1603. break;
  1604. case 'high':
  1605. $value = chr(5);
  1606. break;
  1607. }
  1608. break;
  1609. case "finishing":
  1610. switch ($value)
  1611. {
  1612. case 'none':
  1613. $value = chr(3);
  1614. break;
  1615. case 'staple':
  1616. $value = chr(4);
  1617. break;
  1618. case 'punch':
  1619. $value = chr(5);
  1620. break;
  1621. case 'cover':
  1622. $value = chr(6);
  1623. break;
  1624. case 'bind':
  1625. $value = chr(7);
  1626. break;
  1627. case 'saddle-stitch':
  1628. $value = chr(8);
  1629. break;
  1630. case 'edge-stitch':
  1631. $value = chr(9);
  1632. break;
  1633. case 'staple-top-left':
  1634. $value = chr(20);
  1635. break;
  1636. case 'staple-bottom-left':
  1637. $value = chr(21);
  1638. break;
  1639. case 'staple-top-right':
  1640. $value = chr(22);
  1641. break;
  1642. case 'staple-bottom-right':
  1643. $value = chr(23);
  1644. break;
  1645. case 'edge-stitch-left':
  1646. $value = chr(24);
  1647. break;
  1648. case 'edge-stitch-top':
  1649. $value = chr(25);
  1650. break;
  1651. case 'edge-stitch-right':
  1652. $value = chr(26);
  1653. break;
  1654. case 'edge-stitch-bottom':
  1655. $value = chr(27);
  1656. break;
  1657. case 'staple-dual-left':
  1658. $value = chr(28);
  1659. break;
  1660. case 'staple-dual-top':
  1661. $value = chr(29);
  1662. break;
  1663. case 'staple-dual-right':
  1664. $value = chr(30);
  1665. break;
  1666. case 'staple-dual-bottom':
  1667. $value = chr(31);
  1668. break;
  1669. }
  1670. break;
  1671. }
  1672. $prepend = '';
  1673. while ((strlen($value) + strlen($prepend)) < 4)
  1674. {
  1675. $prepend .= chr(0);
  1676. }
  1677. return $prepend . $value;
  1678. }
  1679. protected function _integerBuild($value)
  1680. {
  1681. if ($value >= 2147483647 || $value < - 2147483648)
  1682. {
  1683. trigger_error(
  1684. _("Values must be between -2147483648 and 2147483647: assuming '0'") , E_USER_WARNING);
  1685. return chr(0x00) . chr(0x00) . chr(0x00) . chr(0x00);
  1686. }
  1687. $initial_value = $value;
  1688. $int1 = $value & 0xFF;
  1689. $value -= $int1;
  1690. $value = $value >> 8;
  1691. $int2 = $value & 0xFF;
  1692. $value-= $int2;
  1693. $value = $value >> 8;
  1694. $int3 = $value & 0xFF;
  1695. $value-= $int3;
  1696. $value = $value >> 8;
  1697. $int4 = $value & 0xFF; //64bits
  1698. if ($initial_value < 0) $int4 = chr($int4) | chr(0x80);
  1699. else $int4 = chr($int4);
  1700. $value = $int4 . chr($int3) . chr($int2) . chr($int1);
  1701. return $value;
  1702. }
  1703. protected function _rangeOfIntegerBuild($integers)
  1704. {
  1705. #$integers = split(":", $integers);
  1706. $integers = preg_split("#:#", $integers);
  1707. for ($i = 0; $i < 2; $i++) $outvalue[$i] = self::_integerBuild($integers[$i]);
  1708. return $outvalue[0] . $outvalue[1];
  1709. }
  1710. protected function _setJobAttribute($attribute, $value)
  1711. {
  1712. //used by setAttribute
  1713. $tag_type = $this->job_tags[$attribute]['tag'];
  1714. switch ($tag_type)
  1715. {
  1716. case 'integer':
  1717. $this->job_tags[$attribute]['value'][] = self::_integerBuild($value);
  1718. break;
  1719. case 'nameWithoutLanguage':
  1720. case 'nameWithLanguage':
  1721. case 'textWithoutLanguage':
  1722. case 'textWithLanguage':
  1723. case 'keyword':
  1724. case 'naturalLanguage':
  1725. $this->job_tags[$attribute]['value'][] = $value;
  1726. break;
  1727. case 'enum':
  1728. $value = $this->_enumBuild($attribute, $value); // may be overwritten by children
  1729. $this->job_tags[$attribute]['value'][] = $value;
  1730. break;
  1731. case 'rangeOfInteger':
  1732. // $value have to be: INT1:INT2 , eg 100:1000
  1733. $this->job_tags[$attribute]['value'][] = self::_rangeOfIntegerBuild($value);
  1734. break;
  1735. case 'resolution':
  1736. if (preg_match("#dpi#", $value)) $unit = chr(0x3);
  1737. if (preg_match("#dpc#", $value)) $unit = chr(0x4);
  1738. $search = array(
  1739. "#(dpi|dpc)#",
  1740. '#(x|-)#'
  1741. );
  1742. $replace = array(
  1743. "",
  1744. ":"
  1745. );
  1746. $value = self::_rangeOfIntegerBuild(preg_replace($search, $replace, $value)) . $unit;
  1747. $this->job_tags[$attribute]['value'][] = $value;
  1748. break;
  1749. default:
  1750. trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , E_USER_NOTICE);
  1751. self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2);
  1752. self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2);
  1753. return FALSE;
  1754. break;
  1755. }
  1756. $this->job_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag'];
  1757. }
  1758. protected function _setOperationAttribute($attribute, $value)
  1759. {
  1760. //used by setAttribute
  1761. $tag_type = $this->operation_tags[$attribute]['tag'];
  1762. switch ($tag_type)
  1763. {
  1764. case 'integer':
  1765. $this->operation_tags[$attribute]['value'][] = self::_integerBuild($value);
  1766. break;
  1767. case 'keyword':
  1768. case 'naturalLanguage':
  1769. $this->operation_tags[$attribute]['value'][] = $value;
  1770. break;
  1771. default:
  1772. trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , E_USER_NOTICE);
  1773. self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2);
  1774. self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2);
  1775. return FALSE;
  1776. break;
  1777. }
  1778. $this->operation_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag'];
  1779. }
  1780. protected function _setPrinterAttribute($attribute, $value)
  1781. {
  1782. //used by setAttribute
  1783. $tag_type = $this->printer_tags

Large files files are truncated, but you can click here to view the full file