BasicIPP.php 64 KB

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