]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | package com.easysw.cups; |
2 | ||
3 | /** | |
b423cd4c | 4 | * @version 1.2 26-FEB-2006 |
bc44d920 | 5 | * @author Apple Inc. |
ef416fc2 | 6 | * |
7 | * Internet Printing Protocol definitions for the Common UNIX Printing | |
8 | * System (CUPS). | |
9 | * | |
080811b1 | 10 | * Copyright 2007-2008 by Apple Inc. |
b423cd4c | 11 | * Copyright 1997-2006 by Easy Software Products. |
ef416fc2 | 12 | * |
13 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 14 | * property of Apple Inc. and are protected by Federal copyright |
15 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
16 | * which should have been included with this file. If this file is | |
17 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
ef416fc2 | 18 | */ |
19 | ||
20 | /** | |
21 | * An <code>Cups</code> object is used for connecting to servers, | |
22 | * reading and writing data, and performing common CUPS operations. | |
23 | * | |
24 | * @author TDB | |
b423cd4c | 25 | * @version 1.2 |
ef416fc2 | 26 | * @since JDK1.3 |
27 | */ | |
28 | ||
29 | import java.io.*; | |
30 | import java.util.*; | |
31 | import java.net.*; | |
32 | ||
33 | public class Cups | |
34 | { | |
35 | ||
36 | static final int REQ_STATE_CREATE_HTTP = 0; | |
37 | static final int REQ_STATE_WRITE_HTTP_HEADER = 1; | |
38 | static final int REQ_STATE_WRITE_IPP_HEADER = 2; | |
39 | static final int REQ_STATE_WRITE_IPP_ATTRS = 3; | |
40 | static final int REQ_STATE_FINISH_IPP_ATTRS = 4; | |
41 | static final int REQ_STATE_READ_RESPONSE = 5; | |
42 | static final int REQ_STATE_DONE = 6; | |
43 | static final String[] req_state_names = | |
44 | { "Create HTTP", | |
45 | "Write Http Header", | |
46 | "Write IPP Header", | |
47 | "Write IPP Attrs", | |
48 | "Finish IPP Attrs", | |
49 | "Read Response", | |
50 | "Done" | |
51 | }; | |
52 | ||
53 | ||
54 | static final int FILEREQ_STATE_CREATE_HTTP = 0; | |
55 | static final int FILEREQ_STATE_WRITE_HTTP_HEADER = 1; | |
56 | static final int FILEREQ_STATE_WRITE_IPP_HEADER = 2; | |
57 | static final int FILEREQ_STATE_WRITE_IPP_ATTRS = 3; | |
58 | static final int FILEREQ_STATE_FINISH_IPP_ATTRS = 4; | |
59 | static final int FILEREQ_STATE_WRITE_FILE_DATA = 5; | |
60 | static final int FILEREQ_STATE_READ_RESPONSE = 6; | |
61 | static final int FILEREQ_STATE_DONE = 7; | |
62 | static final String[] filereq_state_names = | |
63 | { "Create HTTP", | |
64 | "Write Http Header", | |
65 | "Write IPP Header", | |
66 | "Write IPP Attrs", | |
67 | "Finish IPP Attrs", | |
68 | "Write File Data", | |
69 | "Read Response", | |
70 | "Done" | |
71 | }; | |
72 | ||
73 | ||
74 | IPP ipp; // IPP Request | |
75 | IPPHttp http; // Connection to server | |
76 | ||
77 | ||
78 | String protocol; // Protocol name | |
79 | String address; // address/name of server | |
80 | int port; // Port # | |
81 | String path; // Path .... | |
82 | String dest; // Name of destination printer | |
83 | String instance; // Instance of printer | |
84 | ||
85 | // | |
86 | // encrypt, user, and passwd are not fully implemented! | |
87 | // | |
88 | boolean encrypt; // Open encrypted connection. | |
89 | String user; // User to login as. | |
90 | String passwd; // Password if needed. | |
91 | ||
92 | String site; // URL of site. | |
93 | ||
94 | int last_error; // Last error # | |
95 | String error_text; // Text for error | |
96 | ||
97 | /** | |
98 | * Void constructor. | |
99 | */ | |
100 | public Cups() | |
101 | { | |
102 | http = null; | |
103 | ipp = null; | |
104 | ||
105 | protocol = "http"; | |
106 | address = "localhost"; | |
107 | port = 631; | |
108 | path = "/"; | |
109 | site = "http://localhost:631/"; | |
110 | dest = ""; | |
111 | instance = ""; | |
112 | user = ""; | |
113 | passwd = ""; | |
114 | encrypt = false; | |
115 | } | |
116 | ||
117 | /** | |
118 | * Constructor using a <code>URL</code>. | |
119 | * | |
120 | * @param <code>p_url</code> A <code>URL</code> object. | |
121 | */ | |
122 | public Cups( URL p_url ) | |
123 | { | |
124 | http = null; | |
125 | ipp = null; | |
126 | ||
127 | protocol = p_url.getProtocol() + "://"; | |
128 | address = p_url.getHost(); | |
129 | port = p_url.getPort(); | |
130 | path = p_url.getPath(); | |
131 | ||
132 | site = protocol + address; | |
133 | if (port > 0) | |
134 | site = site + ":" + port; | |
135 | ||
136 | if (path.length() > 0) | |
137 | site = site + path; | |
138 | ||
139 | dest = ""; | |
140 | instance = ""; | |
141 | user = ""; | |
142 | passwd = ""; | |
143 | encrypt = false; | |
144 | } | |
145 | ||
146 | ||
147 | /** | |
148 | * Set the value of the <code>protocol</code> member. Valid values | |
149 | * are ipp or http. | |
150 | * | |
151 | * @param <code>p_protocol</code> String with protocol. | |
152 | */ | |
153 | public void setProtocol( String p_protocol ) | |
154 | { | |
155 | protocol = p_protocol; | |
156 | site = protocol + "://" + address + ":" + port + path; | |
157 | } | |
158 | ||
159 | /** | |
160 | * Set the value of the <code>server</code> member. This is an | |
161 | * IP address or a hostname. | |
162 | * | |
163 | * @param <code>p_server</code> IP address or hostname. | |
164 | */ | |
165 | public void setServer( String p_server ) | |
166 | { | |
167 | address = p_server; | |
168 | site = protocol + "://" + address + ":" + port + path; | |
169 | } | |
170 | ||
171 | ||
172 | /** | |
173 | * Set the value of the <code>port</code> member. | |
174 | * | |
175 | * @param <code>p_port</code> Port number. | |
176 | */ | |
177 | public void setPort( int p_port ) | |
178 | { | |
179 | port = p_port; | |
180 | site = protocol + "://" + address + ":" + port + path; | |
181 | } | |
182 | ||
183 | ||
184 | /** | |
185 | * Set the value of the <code>user</code> member. | |
186 | * | |
187 | * @param <code>p_user</code> User name. | |
188 | */ | |
189 | public void setUser( String p_user ) | |
190 | { | |
191 | user = p_user; | |
192 | } | |
193 | ||
194 | ||
195 | /** | |
196 | * Set the value of the <code>passwd</code> member. | |
197 | * | |
198 | * @param <code>p_passwd</code> Password. | |
199 | */ | |
200 | public void setPasswd( String p_passwd ) | |
201 | { | |
202 | passwd = p_passwd; | |
203 | } | |
204 | ||
205 | ||
206 | /** | |
207 | * Set the value of the <code>dest</code> member. | |
208 | * | |
209 | * @param <code>p_dest</code> Destination. | |
210 | */ | |
211 | public void setDest( String p_dest ) | |
212 | { | |
213 | dest = p_dest; | |
214 | } | |
215 | ||
216 | ||
217 | /** | |
218 | * Set the value of the <code>instance</code> member. | |
219 | * | |
220 | * @param <code>p_instance</code> Instance. | |
221 | */ | |
222 | public void setInstance( String p_instance) | |
223 | { | |
224 | instance = p_instance; | |
225 | } | |
226 | ||
227 | ||
228 | /** | |
229 | * Set the value of the <code>encrypt</code> member. | |
230 | * | |
231 | * @param <code>p_enrypt</code> Yes or no. | |
232 | */ | |
233 | public void setEncrypt( boolean p_encrypt ) | |
234 | { | |
235 | encrypt = p_encrypt; | |
236 | } | |
237 | ||
238 | ||
239 | /** | |
240 | * Get the value of the <code>encrypt</code> member. | |
241 | * | |
242 | * @return <code>boolean</code> Encryption on or off. | |
243 | */ | |
244 | public boolean getEncrypt() | |
245 | { | |
246 | return(encrypt); | |
247 | } | |
248 | ||
249 | ||
250 | /** | |
251 | * Set the value of the <code>path</code> member. This is the | |
252 | * path that will be used in the POST method. | |
253 | * | |
254 | * @param <code>p_path</code> Path on server. | |
255 | */ | |
256 | public void setPath( String p_path ) | |
257 | { | |
258 | path = p_path; | |
259 | site = protocol + "://" + address + ":" + port + path; | |
260 | } | |
261 | ||
262 | ||
263 | ||
264 | public boolean doRequest(String from) throws IOException | |
265 | { | |
266 | // System.out.println("doRequest From: " + from ); | |
267 | return(doRequest()); | |
268 | } | |
269 | ||
270 | ||
271 | ||
272 | /** | |
273 | * Do a CUPS request to the server. | |
274 | * | |
275 | * @param <code>p_dest</code> Destination name. | |
276 | * @return <code>boolean</code> True on success, false otherwise | |
277 | * @throw <code>IOException</code> | |
278 | */ | |
279 | public boolean doRequest() throws IOException | |
280 | { | |
281 | IPPAttribute attr; | |
282 | int state = REQ_STATE_CREATE_HTTP; | |
283 | int errors = 0; | |
284 | ||
285 | while (true) | |
286 | { | |
287 | switch( state ) | |
288 | { | |
289 | ||
290 | case REQ_STATE_CREATE_HTTP: | |
291 | String url_str = site + dest; | |
292 | ||
293 | try | |
294 | { | |
295 | if (user.length() > 0 && passwd.length() > 0) | |
296 | http = new IPPHttp(url_str, "", user, passwd ); | |
297 | else | |
298 | http = new IPPHttp(url_str); | |
299 | state++; | |
300 | } | |
301 | catch (IOException e) | |
302 | { | |
303 | throw(e); | |
304 | } | |
305 | break; | |
306 | ||
307 | ||
308 | ||
309 | case REQ_STATE_WRITE_HTTP_HEADER: | |
310 | // | |
311 | // Send the HTTP header. | |
312 | // | |
313 | switch( http.writeHeader( http.path, ipp.sizeInBytes() )) | |
314 | { | |
315 | case IPPHttp.HTTP_FORBIDDEN: | |
316 | case IPPHttp.HTTP_NOT_FOUND: | |
317 | case IPPHttp.HTTP_BAD_REQUEST: | |
318 | case IPPHttp.HTTP_METHOD_NOT_ALLOWED: | |
319 | case IPPHttp.HTTP_PAYMENT_REQUIRED: | |
320 | case IPPHttp.HTTP_UPGRADE_REQUIRED: | |
321 | case IPPHttp.HTTP_ERROR: | |
322 | case IPPHttp.HTTP_UNAUTHORIZED: | |
323 | errors++; | |
324 | if (errors < 5) | |
325 | { | |
326 | if (!http.reConnect()) | |
327 | { | |
328 | System.out.println("Could not reConnect(0)!"); | |
329 | return(false); | |
330 | } | |
331 | } | |
332 | else | |
333 | { | |
334 | return(false); | |
335 | } | |
336 | break; | |
337 | ||
338 | default: state++; | |
339 | } | |
340 | break; | |
341 | ||
342 | ||
343 | ||
344 | case REQ_STATE_WRITE_IPP_HEADER: | |
345 | // | |
346 | // Send the request header. | |
347 | // | |
348 | byte[] header = new byte[8]; | |
349 | header[0] = (byte)1; | |
350 | header[1] = (byte)1; | |
351 | header[2] = (byte)((ipp.request.operation_id & 0xff00) >> 8); | |
352 | header[3] = (byte)(ipp.request.operation_id & 0xff); | |
353 | header[4] = (byte)((ipp.request.request_id & 0xff000000) >> 24); | |
354 | header[5] = (byte)((ipp.request.request_id & 0xff0000) >> 16); | |
355 | header[6] = (byte)((ipp.request.request_id & 0xff00) >> 8); | |
356 | header[7] = (byte)(ipp.request.request_id & 0xff); | |
357 | http.write( header ); | |
358 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
359 | { | |
360 | errors++; | |
361 | if (errors < 5) | |
362 | { | |
363 | if (http.reConnect()) | |
364 | state = REQ_STATE_WRITE_HTTP_HEADER; | |
365 | else | |
366 | { | |
367 | System.out.println("Could not reConnect(1)\n"); | |
368 | return(false); | |
369 | } | |
370 | } | |
371 | else | |
372 | { | |
373 | return(false); | |
374 | } | |
375 | } | |
376 | else state++; | |
377 | break; | |
378 | ||
379 | ||
380 | case REQ_STATE_WRITE_IPP_ATTRS: | |
381 | // | |
382 | // Send the attributes list. | |
383 | // | |
384 | byte[] bytes; | |
385 | int sz; | |
386 | int last_group = -1; | |
387 | boolean auth_error = false; | |
388 | for (int i=0; i < ipp.attrs.size() && !auth_error; i++) | |
389 | { | |
390 | attr = (IPPAttribute)ipp.attrs.get(i); | |
391 | sz = attr.sizeInBytes(last_group); | |
392 | bytes = attr.getBytes(sz,last_group); | |
393 | last_group = attr.group_tag; | |
394 | http.write(bytes); | |
395 | ||
396 | // | |
397 | // Check for server response between each attribute. | |
398 | // | |
399 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
400 | { | |
401 | errors++; | |
402 | if (errors < 5) | |
403 | { | |
404 | if (!http.reConnect()) | |
405 | { | |
406 | System.out.println("Could not reConnect(2)"); | |
407 | return(false); | |
408 | } | |
409 | state = REQ_STATE_WRITE_HTTP_HEADER; | |
410 | auth_error = true; | |
411 | } | |
412 | else | |
413 | { | |
414 | return(false); | |
415 | } | |
416 | } | |
417 | ||
418 | } | |
419 | if (!auth_error) | |
420 | state++; | |
421 | break; | |
422 | ||
423 | ||
424 | ||
425 | case REQ_STATE_FINISH_IPP_ATTRS: | |
426 | // | |
427 | // Send the end of attributes tag. | |
428 | // | |
429 | byte[] footer = new byte[1]; | |
430 | footer[0] = (byte)IPPDefs.TAG_END; | |
431 | http.write( footer ); | |
432 | ||
433 | // | |
434 | // Keep checking ..... | |
435 | // | |
436 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
437 | { | |
438 | errors++; | |
439 | if (errors < 5) | |
440 | { | |
441 | if (!http.reConnect()) | |
442 | { | |
443 | System.out.println("Could not reConnect(3)"); | |
444 | return(false); | |
445 | } | |
446 | state = REQ_STATE_WRITE_HTTP_HEADER; | |
447 | } | |
448 | else | |
449 | { | |
450 | return(false); | |
451 | } | |
452 | } | |
453 | else state++; | |
454 | break; | |
455 | ||
456 | ||
457 | ||
458 | case REQ_STATE_READ_RESPONSE: | |
459 | // | |
460 | // Now read back response | |
461 | // | |
462 | int read_length; | |
463 | read_length = http.read_header(); | |
464 | switch( http.status ) | |
465 | { | |
466 | case IPPHttp.HTTP_OK: | |
467 | break; | |
468 | ||
469 | case IPPHttp.HTTP_UNAUTHORIZED: | |
470 | http.reConnect(); | |
471 | state = REQ_STATE_WRITE_HTTP_HEADER; | |
472 | errors = 0; | |
473 | break; | |
474 | ||
475 | default: | |
476 | errors++; | |
477 | if (errors < 5) | |
478 | { | |
479 | if (!http.reConnect()) | |
480 | { | |
481 | System.out.println("Could not reConnect(4)"); | |
482 | return(false); | |
483 | } | |
484 | state = REQ_STATE_WRITE_HTTP_HEADER; | |
485 | } | |
486 | else | |
487 | { | |
488 | System.out.println("Too many errors: " + errors ); | |
489 | return(false); | |
490 | } | |
491 | break; | |
492 | } | |
493 | ||
494 | if ((read_length > 0) && (state == REQ_STATE_READ_RESPONSE)) | |
495 | { | |
496 | http.read_buffer = http.read(read_length); | |
497 | ipp = http.processResponse(); | |
498 | state++; | |
499 | } | |
500 | break; | |
501 | ||
502 | case REQ_STATE_DONE: | |
503 | // | |
504 | // success. | |
505 | // | |
506 | http.conn.close(); | |
507 | http = null; | |
508 | return(true); | |
509 | } | |
510 | } | |
511 | ||
512 | } // End of doRequest | |
513 | ||
514 | ||
515 | ||
516 | /** | |
517 | * Send a FILE to the CUPS server. | |
518 | * | |
519 | * @param <code>file</code> File to send. | |
520 | * @return <code>boolean</code> True on success, false otherwise | |
521 | * @throw <code>IOException</code> | |
522 | */ | |
523 | public boolean doRequest(File file) throws IOException | |
524 | { | |
525 | IPPAttribute attr; | |
526 | int state = FILEREQ_STATE_CREATE_HTTP; | |
527 | int errors = 0; | |
528 | FileInputStream fis = null; | |
529 | ||
530 | while (true) | |
531 | { | |
532 | switch( state ) | |
533 | { | |
534 | ||
535 | case FILEREQ_STATE_CREATE_HTTP: | |
536 | String url_str = site + dest; | |
537 | try | |
538 | { | |
539 | if (user.length() > 0 && passwd.length() > 0) | |
540 | http = new IPPHttp(url_str, "", user, passwd ); | |
541 | else | |
542 | http = new IPPHttp(url_str); | |
543 | state++; | |
544 | } | |
545 | catch (IOException e) | |
546 | { | |
547 | throw(e); | |
548 | } | |
549 | break; | |
550 | ||
551 | ||
552 | ||
553 | case FILEREQ_STATE_WRITE_HTTP_HEADER: | |
554 | ||
555 | if (fis != null) | |
556 | { | |
557 | fis.close(); | |
558 | } | |
559 | ||
560 | // | |
561 | // Open an input stream to the file. | |
562 | // | |
563 | try | |
564 | { | |
565 | fis = new FileInputStream(file); | |
566 | } | |
567 | catch (IOException e) | |
568 | { | |
569 | last_error = -1; | |
570 | error_text = "Error opening file input stream."; | |
571 | throw(e); | |
572 | } | |
573 | ||
574 | // | |
575 | // Send the HTTP header. | |
576 | // | |
577 | int ippSz = ipp.sizeInBytes() + (int)file.length(); | |
578 | switch( http.writeHeader( http.path, ippSz )) | |
579 | { | |
580 | case IPPHttp.HTTP_FORBIDDEN: | |
581 | case IPPHttp.HTTP_NOT_FOUND: | |
582 | case IPPHttp.HTTP_BAD_REQUEST: | |
583 | case IPPHttp.HTTP_METHOD_NOT_ALLOWED: | |
584 | case IPPHttp.HTTP_PAYMENT_REQUIRED: | |
585 | case IPPHttp.HTTP_UPGRADE_REQUIRED: | |
586 | case IPPHttp.HTTP_ERROR: | |
587 | case IPPHttp.HTTP_UNAUTHORIZED: | |
588 | errors++; | |
589 | if (errors < 5) | |
590 | { | |
591 | http.reConnect(); | |
592 | } | |
593 | else | |
594 | return(false); | |
595 | break; | |
596 | ||
597 | default: state++; | |
598 | } | |
599 | break; | |
600 | ||
601 | ||
602 | ||
603 | case FILEREQ_STATE_WRITE_IPP_HEADER: | |
604 | // | |
605 | // Send the request header. | |
606 | // | |
607 | byte[] header = new byte[8]; | |
608 | header[0] = (byte)1; | |
609 | header[1] = (byte)1; | |
610 | header[2] = (byte)((ipp.request.operation_id & 0xff00) >> 8); | |
611 | header[3] = (byte)(ipp.request.operation_id & 0xff); | |
612 | header[4] = (byte)((ipp.request.request_id & 0xff000000) >> 24); | |
613 | header[5] = (byte)((ipp.request.request_id & 0xff0000) >> 16); | |
614 | header[6] = (byte)((ipp.request.request_id & 0xff00) >> 8); | |
615 | header[7] = (byte)(ipp.request.request_id & 0xff); | |
616 | http.write( header ); | |
617 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
618 | { | |
619 | errors++; | |
620 | if (errors < 5) | |
621 | { | |
622 | http.reConnect(); | |
623 | state = FILEREQ_STATE_WRITE_HTTP_HEADER; | |
624 | } | |
625 | else | |
626 | return(false); | |
627 | } | |
628 | else state++; | |
629 | break; | |
630 | ||
631 | ||
632 | case FILEREQ_STATE_WRITE_IPP_ATTRS: | |
633 | // | |
634 | // Send the attributes list. | |
635 | // | |
636 | byte[] bytes; | |
637 | int sz; | |
638 | int last_group = -1; | |
639 | boolean auth_error = false; | |
640 | for (int i=0; i < ipp.attrs.size() && !auth_error; i++) | |
641 | { | |
642 | attr = (IPPAttribute)ipp.attrs.get(i); | |
643 | sz = attr.sizeInBytes(last_group); | |
644 | bytes = attr.getBytes(sz,last_group); | |
645 | last_group = attr.group_tag; | |
646 | http.write(bytes); | |
647 | ||
648 | // | |
649 | // Check for server response between each attribute. | |
650 | // | |
651 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
652 | { | |
653 | errors++; | |
654 | if (errors < 5) | |
655 | { | |
656 | http.reConnect(); | |
657 | state = FILEREQ_STATE_WRITE_HTTP_HEADER; | |
658 | auth_error = true; | |
659 | } | |
660 | else | |
661 | return(false); | |
662 | } | |
663 | ||
664 | } | |
665 | if (!auth_error) | |
666 | state++; | |
667 | break; | |
668 | ||
669 | ||
670 | ||
671 | case FILEREQ_STATE_FINISH_IPP_ATTRS: | |
672 | // | |
673 | // Send the end of attributes tag. | |
674 | // | |
675 | byte[] footer = new byte[1]; | |
676 | footer[0] = (byte)IPPDefs.TAG_END; | |
677 | http.write( footer ); | |
678 | ||
679 | // | |
680 | // Keep checking ..... | |
681 | // | |
682 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
683 | { | |
684 | errors++; | |
685 | if (errors < 5) | |
686 | { | |
687 | http.reConnect(); | |
688 | state = FILEREQ_STATE_WRITE_HTTP_HEADER; | |
689 | } | |
690 | else | |
691 | return(false); | |
692 | } | |
693 | else state++; | |
694 | break; | |
695 | ||
696 | ||
697 | ||
698 | case FILEREQ_STATE_WRITE_FILE_DATA: | |
699 | // | |
700 | // Send the file data - this could be improved on ALOT. | |
701 | // | |
702 | int count; | |
703 | byte[] b = new byte[1024]; | |
704 | while ((state == FILEREQ_STATE_WRITE_FILE_DATA) && | |
705 | ((count = fis.read(b)) != -1)) | |
706 | { | |
707 | // | |
708 | // Keep checking ..... | |
709 | // | |
710 | if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) | |
711 | { | |
712 | errors++; | |
713 | if (errors < 5) | |
714 | { | |
715 | http.reConnect(); | |
716 | state = FILEREQ_STATE_WRITE_HTTP_HEADER; | |
717 | } | |
718 | else | |
719 | { | |
720 | return(false); | |
721 | } | |
722 | } | |
723 | else | |
724 | { | |
725 | if (count > 0) | |
726 | http.write( b, count ); | |
727 | } | |
728 | ||
729 | } // while | |
730 | ||
731 | if (state == FILEREQ_STATE_WRITE_FILE_DATA) | |
732 | { | |
733 | fis.close(); | |
734 | fis = null; | |
735 | state++; | |
736 | } | |
737 | break; | |
738 | ||
739 | ||
740 | ||
741 | case FILEREQ_STATE_READ_RESPONSE: | |
742 | // | |
743 | // Now read back response | |
744 | // | |
745 | int read_length; | |
746 | read_length = http.read_header(); | |
747 | switch( http.status ) | |
748 | { | |
749 | case IPPHttp.HTTP_OK: | |
750 | break; | |
751 | ||
752 | case IPPHttp.HTTP_UNAUTHORIZED: | |
753 | http.reConnect(); | |
754 | state = FILEREQ_STATE_WRITE_HTTP_HEADER; | |
755 | errors = 0; | |
756 | break; | |
757 | ||
758 | default: | |
759 | errors++; | |
760 | if (errors < 5) | |
761 | { | |
762 | http.reConnect(); | |
763 | state = FILEREQ_STATE_WRITE_HTTP_HEADER; | |
764 | } | |
765 | else | |
766 | { | |
767 | return(false); | |
768 | } | |
769 | break; | |
770 | } | |
771 | ||
772 | if ((read_length > 0) && (state == FILEREQ_STATE_READ_RESPONSE)) | |
773 | { | |
774 | http.read_buffer = http.read(read_length); | |
775 | ipp = http.processResponse(); | |
776 | state++; | |
777 | } | |
778 | break; | |
779 | ||
780 | case FILEREQ_STATE_DONE: | |
781 | // | |
782 | // success. | |
783 | // | |
784 | http.conn.close(); | |
785 | http = null; | |
786 | return(true); | |
787 | } | |
788 | } | |
789 | ||
790 | } // End of doRequest(file) | |
791 | ||
792 | ||
793 | ||
794 | ||
795 | ||
796 | ||
797 | ||
798 | /** | |
799 | * Get a list of jobs. | |
800 | * | |
801 | * @param <code>showMyJobs</code> Show only jobs for user. | |
802 | * @param <code>showCompleted</code> Show completed OR active jobs. | |
803 | * | |
804 | * @return <code>CupsJob[]</code> Array of job objects, or null. | |
805 | * @throw <code>IOException</code> | |
806 | */ | |
807 | public CupsJob[] cupsGetJobs( boolean showMyJobs, boolean showCompleted ) | |
808 | throws IOException | |
809 | { | |
810 | ||
811 | IPPAttribute a; | |
812 | ||
813 | String req_attrs[] = /* Requested attributes */ | |
814 | { | |
815 | "job-id", | |
816 | "job-priority", | |
817 | "job-k-octets", | |
818 | "job-state", | |
819 | "time-at-completed", | |
820 | "time-at-creation", | |
821 | "time-at-processing", | |
822 | "job-printer-uri", | |
823 | "document-format", | |
824 | "job-name", | |
825 | "job-originating-user-name" | |
826 | }; | |
827 | ||
828 | ||
829 | ipp = new IPP(); | |
830 | ipp.request = new IPPRequest( 1, (short)IPPDefs.GET_JOBS ); | |
831 | ||
832 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
833 | "attributes-charset" ); | |
080811b1 | 834 | a.addString( "", "utf-8" ); |
ef416fc2 | 835 | ipp.addAttribute(a); |
836 | ||
837 | ||
838 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
839 | "attributes-natural-language" ); | |
840 | a.addString( "", "en" ); | |
841 | ipp.addAttribute(a); | |
842 | ||
843 | ||
844 | // | |
845 | // Add the printer uri | |
846 | // | |
847 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, | |
848 | "printer-uri" ); | |
849 | ||
850 | if (site != null) | |
851 | a.addString( "", site ); | |
852 | else | |
853 | a.addString( "", "ipp://localhost/jobs" ); // Default ... | |
854 | // a.dump_values(); | |
855 | ipp.addAttribute(a); | |
856 | ||
857 | ||
858 | // | |
859 | // Add the requesting user name | |
860 | // **FIX** This should be fixed to use the user member. | |
861 | // | |
862 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, | |
863 | "requesting-user-name" ); | |
864 | a.addString( "", "root" ); | |
865 | ipp.addAttribute(a); | |
866 | ||
867 | // | |
868 | // Show only my jobs? | |
869 | // | |
870 | if (showMyJobs) | |
871 | { | |
872 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_BOOLEAN, | |
873 | "my-jobs" ); | |
874 | a.addBoolean( true ); | |
875 | ipp.addAttribute(a); | |
876 | } | |
877 | ||
878 | // | |
879 | // Show completed jobs? | |
880 | // | |
881 | if (showCompleted) | |
882 | { | |
883 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_KEYWORD, | |
884 | "which-jobs" ); | |
885 | a.addString( "", "completed" ); | |
886 | ipp.addAttribute(a); | |
887 | } | |
888 | ||
889 | // | |
890 | // Get ALL attributes - to get only listed ones, | |
891 | // uncomment this and fill in req_attrs. | |
892 | // | |
893 | // a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_KEYWORD, | |
894 | // "requested-attributes" ); | |
895 | // a.addStrings( "", req_attrs ); | |
896 | // ipp.addAttribute(a); | |
897 | ||
898 | // | |
899 | // Do the request and process the response. | |
900 | // | |
901 | if (doRequest("cupsGetJobs")) | |
902 | { | |
903 | ||
904 | ||
905 | // | |
906 | // First we have to figure out how many jobs there are | |
907 | // so we can create the array. | |
908 | // | |
909 | ||
910 | // | |
911 | // Skip past leading attributes | |
912 | // | |
913 | int i = 0; | |
914 | int group_tag = -1; | |
915 | while ((i < ipp.attrs.size()) && (group_tag != IPPDefs.TAG_JOB)) | |
916 | { | |
917 | a = (IPPAttribute)ipp.attrs.get(i); | |
918 | group_tag = a.group_tag; | |
919 | if (group_tag != IPPDefs.TAG_JOB) | |
920 | i++; | |
921 | } | |
922 | ||
923 | int num_jobs = 0; | |
924 | group_tag = IPPDefs.TAG_JOB; | |
925 | while ((i < ipp.attrs.size()) && (group_tag == IPPDefs.TAG_JOB)) | |
926 | { | |
927 | a = (IPPAttribute)ipp.attrs.get(i++); | |
928 | if ((a != null) && (a.name.compareTo("job-id") == 0)) | |
929 | num_jobs++; | |
930 | // a.dump_values(); | |
931 | } | |
932 | ||
933 | if (num_jobs < 1) | |
934 | return(null); | |
935 | ||
936 | ||
937 | // | |
938 | // Now create the array of the proper size. | |
939 | // | |
940 | int n = 0; | |
941 | CupsJob[] jobs = new CupsJob[num_jobs]; | |
942 | for (n=0; n < num_jobs; n++) | |
943 | { | |
944 | jobs[n] = new CupsJob(); | |
945 | } | |
946 | ||
947 | ||
948 | ||
949 | ||
950 | // | |
951 | // Skip past leading attributes | |
952 | // | |
953 | group_tag = -1; | |
954 | i = 0; | |
955 | while ((i < ipp.attrs.size()) && (group_tag != IPPDefs.TAG_JOB)) | |
956 | { | |
957 | a = (IPPAttribute)ipp.attrs.get(i); | |
958 | group_tag = a.group_tag; | |
959 | if (group_tag != IPPDefs.TAG_JOB) | |
960 | i++; | |
961 | } | |
962 | ||
963 | // | |
964 | // Now we actually fill the array with the job data. | |
965 | // | |
966 | n = 0; | |
967 | for (;i < ipp.attrs.size(); i++) | |
968 | { | |
969 | a = (IPPAttribute)ipp.attrs.get(i); | |
970 | ||
971 | if (a.group_tag == IPPDefs.TAG_ZERO) | |
972 | { | |
973 | n++; | |
974 | continue; | |
975 | } | |
976 | else | |
977 | { | |
978 | try | |
979 | { | |
980 | jobs[n].updateAttribute( a ); | |
981 | } | |
982 | catch (ArrayIndexOutOfBoundsException e) | |
983 | { | |
984 | return(jobs); | |
985 | } | |
986 | } | |
987 | } | |
988 | return( jobs ); | |
989 | } | |
990 | return(null); | |
991 | ||
992 | } // End of cupsGetJobs | |
993 | ||
994 | ||
995 | ||
996 | /** | |
997 | * Get a list of printers. | |
998 | * | |
999 | * @return <code>String[]</code> Array of printers, or null. | |
1000 | * @throw <code>IOException</code> | |
1001 | */ | |
1002 | public String[] cupsGetPrinters() | |
1003 | throws IOException | |
1004 | { | |
1005 | ||
1006 | IPPAttribute a; | |
1007 | ||
1008 | ipp = new IPP(); | |
1009 | ||
1010 | // | |
1011 | // Fill in the required attributes | |
1012 | // | |
1013 | ipp.request = new IPPRequest( 1, (short)IPPDefs.CUPS_GET_PRINTERS ); | |
1014 | ||
1015 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
1016 | "attributes-charset" ); | |
080811b1 | 1017 | a.addString( "", "utf-8" ); |
ef416fc2 | 1018 | ipp.addAttribute(a); |
1019 | ||
1020 | ||
1021 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
1022 | "attributes-natural-language" ); | |
1023 | a.addString( "", "en" ); | |
1024 | ipp.addAttribute(a); | |
1025 | ||
1026 | ||
1027 | if (doRequest("cupsGetPrinters")) | |
1028 | { | |
1029 | int num_printers = 0; | |
1030 | for (int i=0; i < ipp.attrs.size(); i++) | |
1031 | { | |
1032 | a = (IPPAttribute)ipp.attrs.get(i); | |
1033 | if ((a.name.compareTo("printer-name") == 0) && | |
1034 | (a.value_tag == IPPDefs.TAG_NAME)) | |
1035 | { | |
1036 | num_printers++; | |
1037 | } | |
1038 | } | |
1039 | if (num_printers < 1) | |
1040 | return(null); | |
1041 | ||
1042 | String[] printers = new String[num_printers]; | |
1043 | IPPValue val; | |
1044 | int n = 0; | |
1045 | for (int i=0; i < ipp.attrs.size(); i++) | |
1046 | { | |
1047 | a = (IPPAttribute)ipp.attrs.get(i); | |
1048 | if (a.group_tag < 2) | |
1049 | continue; | |
1050 | ||
1051 | if ((a.name.compareTo("printer-name") == 0) && | |
1052 | (a.value_tag == IPPDefs.TAG_NAME)) | |
1053 | { | |
1054 | val = (IPPValue)a.values.get(0); | |
1055 | if (val != null) | |
1056 | { | |
1057 | printers[n] = val.text; | |
1058 | n++; | |
1059 | } | |
1060 | } | |
1061 | } | |
1062 | return( printers ); | |
1063 | ||
1064 | } // if doRequest ... | |
1065 | ||
1066 | return(null); | |
1067 | ||
1068 | } // End of cupsGetPrinters | |
1069 | ||
1070 | ||
1071 | ||
1072 | ||
1073 | /** | |
1074 | * Get default destination. | |
1075 | * | |
1076 | * @return <code>String</code> Name of default printer, or null. | |
1077 | * @throw <code>IOException</code> | |
1078 | */ | |
1079 | public String cupsGetDefault() | |
1080 | throws IOException | |
1081 | { | |
1082 | ||
1083 | IPPAttribute a; | |
1084 | ||
1085 | ||
1086 | ipp = new IPP(); | |
1087 | // | |
1088 | // Fill in the required attributes | |
1089 | // | |
1090 | ipp.request = new IPPRequest( 1, (short)IPPDefs.CUPS_GET_DEFAULT); | |
1091 | ||
1092 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
1093 | "attributes-charset" ); | |
080811b1 | 1094 | a.addString( "", "utf-8" ); |
ef416fc2 | 1095 | ipp.addAttribute(a); |
1096 | ||
1097 | ||
1098 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
1099 | "attributes-natural-language" ); | |
1100 | a.addString( "", "en" ); | |
1101 | ipp.addAttribute(a); | |
1102 | ||
1103 | ||
1104 | if (doRequest("cupsGetDefault")) | |
1105 | { | |
1106 | if ((ipp == null) || (ipp.attrs == null)) | |
1107 | return(null); | |
1108 | ||
1109 | int num_printers = 0; | |
1110 | for (int i=0; i < ipp.attrs.size(); i++) | |
1111 | { | |
1112 | a = (IPPAttribute)ipp.attrs.get(i); | |
1113 | if ((a.name.compareTo("printer-name") == 0) && | |
1114 | (a.value_tag == IPPDefs.TAG_NAME)) | |
1115 | { | |
1116 | IPPValue val = (IPPValue)a.values.get(0); | |
1117 | if (val != null) | |
1118 | { | |
1119 | return( val.text ); | |
1120 | } | |
1121 | } | |
1122 | } | |
1123 | } // if doRequest ... | |
1124 | ||
1125 | return(null); | |
1126 | ||
1127 | } // End of cupsGetDefault | |
1128 | ||
1129 | ||
1130 | ||
1131 | ||
1132 | ||
1133 | ||
1134 | /** | |
1135 | * Get printer attributes | |
1136 | * | |
1137 | * @param <code>printer_name</code> Name of printer to get info for. | |
1138 | * @return <code>List</code> List of attributes. | |
1139 | * @throw <code>IOException</code> | |
1140 | * | |
1141 | * @see <code>CupsPrinter</code> | |
1142 | */ | |
1143 | public List cupsGetPrinterAttributes( String printer_name ) | |
1144 | throws IOException | |
1145 | { | |
1146 | ||
1147 | IPPAttribute a; | |
1148 | ||
1149 | ipp = new IPP(); | |
1150 | ||
1151 | // | |
1152 | // Fill in the required attributes | |
1153 | // | |
1154 | ipp.request = new IPPRequest( 1, (short)IPPDefs.GET_PRINTER_ATTRIBUTES ); | |
1155 | ||
1156 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
1157 | "attributes-charset" ); | |
080811b1 | 1158 | a.addString( "", "utf-8" ); |
ef416fc2 | 1159 | ipp.addAttribute(a); |
1160 | ||
1161 | ||
1162 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
1163 | "attributes-natural-language" ); | |
1164 | a.addString( "", "en" ); | |
1165 | ipp.addAttribute(a); | |
1166 | ||
1167 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, | |
1168 | "printer-uri" ); | |
b423cd4c | 1169 | String p_uri = "ipp://" + address + ":" + |
1170 | port + "/printers/" + printer_name; | |
1171 | a.addString( "", p_uri ); | |
ef416fc2 | 1172 | ipp.addAttribute(a); |
1173 | ||
1174 | if (doRequest("cupsGetPrinterAttributes")) | |
1175 | { | |
1176 | return(ipp.attrs); | |
1177 | } | |
1178 | ||
1179 | return(null); | |
1180 | ||
1181 | } // End of cupsGetPrinterAttributes | |
1182 | ||
1183 | ||
1184 | ||
1185 | ||
1186 | /** | |
1187 | * Print a file. | |
1188 | * | |
1189 | * @param <code>p_filename</code> Path of file to print. | |
1190 | * @param <code>p_attrs[]</code> Array of print job attributes. | |
1191 | * | |
1192 | * @return <code>CupsJob</code> Object with job info. | |
1193 | * | |
1194 | * @throw <code>IOException</code> | |
1195 | * | |
1196 | * @see <code>CupsJob</code> | |
1197 | */ | |
1198 | public CupsJob cupsPrintFile( String p_filename, | |
1199 | IPPAttribute p_attrs[] ) | |
1200 | throws IOException | |
1201 | { | |
1202 | ||
1203 | CupsJob job; | |
1204 | IPPAttribute a; | |
1205 | File file; | |
1206 | ||
1207 | ||
1208 | file = new File(p_filename); | |
1209 | if (!file.exists()) | |
1210 | { | |
1211 | last_error = -1; | |
1212 | error_text = "File does not exist."; | |
1213 | return(null); | |
1214 | } | |
1215 | ||
1216 | if (!file.canRead()) | |
1217 | { | |
1218 | last_error = -1; | |
1219 | error_text = "File cannot be read."; | |
1220 | return(null); | |
1221 | } | |
1222 | ||
1223 | ||
1224 | ipp = new IPP(); | |
1225 | // | |
1226 | // Fill in the required attributes | |
1227 | // | |
1228 | ipp.request = new IPPRequest( 1, (short)IPPDefs.PRINT_JOB ); | |
1229 | ||
1230 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
1231 | "attributes-charset" ); | |
080811b1 | 1232 | a.addString( "", "utf-8" ); |
ef416fc2 | 1233 | ipp.addAttribute(a); |
1234 | ||
1235 | // ------------ | |
1236 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
1237 | "attributes-natural-language" ); | |
1238 | a.addString( "", "en" ); | |
1239 | ipp.addAttribute(a); | |
1240 | ||
1241 | // ------------ | |
1242 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, | |
1243 | "printer-uri" ); | |
1244 | a.addString( "", site + dest ); | |
1245 | ipp.addAttribute(a); | |
1246 | ||
1247 | // ------------ | |
1248 | // **FIX** Fix this later. | |
1249 | /* | |
1250 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, | |
1251 | "requesting-user-name" ); | |
1252 | // a.addString( "", p_username ); | |
1253 | a.addString( "", "root"); | |
1254 | ipp.addAttribute(a); | |
1255 | */ | |
1256 | ||
1257 | // ------------ | |
1258 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, | |
1259 | "job-name" ); | |
1260 | a.addString( "", file.getName() ); | |
1261 | ipp.addAttribute(a); | |
1262 | ||
1263 | if (p_attrs != null) | |
1264 | { | |
1265 | for (int i=0; i < p_attrs.length; i++) | |
1266 | { | |
1267 | a = p_attrs[i]; | |
1268 | ipp.addAttribute(a); | |
1269 | } | |
1270 | } | |
1271 | ||
1272 | if (doRequest(file)) | |
1273 | { | |
1274 | job = new CupsJob(); | |
1275 | for (int i=0; i < ipp.attrs.size(); i++) | |
1276 | { | |
1277 | a = (IPPAttribute)ipp.attrs.get(i); | |
1278 | job.updateAttribute(a); | |
1279 | } | |
1280 | return(job); | |
1281 | ||
1282 | } // if doRequest ... | |
1283 | ||
1284 | return(null); | |
1285 | ||
1286 | } // End of cupsPrintFile | |
1287 | ||
1288 | ||
1289 | ||
1290 | ||
1291 | ||
1292 | /** | |
1293 | * Cancel a job - send a job cancel request to the server. | |
1294 | * | |
1295 | * @param <code>printer_name</code> Destination. | |
1296 | * @param <code>p_job_id</code> ID of job. | |
1297 | * @param <code>p_user_name</code> Requesting user name. | |
1298 | * | |
1299 | * @throw <code>IOException</code> | |
1300 | */ | |
1301 | public int cupsCancelJob( String printer_name, | |
1302 | int p_job_id, | |
1303 | String p_user_name ) | |
1304 | throws IOException | |
1305 | { | |
1306 | ||
1307 | IPPAttribute a; | |
1308 | ||
1309 | ipp = new IPP(); | |
1310 | ||
1311 | // | |
1312 | // Fill in the required attributes | |
1313 | // | |
1314 | ipp.request = new IPPRequest( 1, (short)IPPDefs.CANCEL_JOB ); | |
1315 | ||
1316 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
1317 | "attributes-charset" ); | |
080811b1 | 1318 | a.addString( "", "utf-8" ); |
ef416fc2 | 1319 | ipp.addAttribute(a); |
1320 | ||
1321 | // ------------ | |
1322 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
1323 | "attributes-natural-language" ); | |
1324 | a.addString( "", "en" ); | |
1325 | ipp.addAttribute(a); | |
1326 | ||
1327 | // ------------ | |
1328 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, | |
1329 | "printer-uri" ); | |
1330 | a.addString( "", site + dest ); | |
1331 | ipp.addAttribute(a); | |
1332 | ||
1333 | // ------------ | |
1334 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_INTEGER, | |
1335 | "job-id" ); | |
1336 | a.addInteger( p_job_id ); | |
1337 | ipp.addAttribute(a); | |
1338 | ||
1339 | // ------------ | |
1340 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, | |
1341 | "requesting-user-name" ); | |
1342 | a.addString( "", p_user_name ); | |
1343 | ipp.addAttribute(a); | |
1344 | ||
1345 | if (doRequest("cupsCancelJob")) | |
1346 | { | |
1347 | for (int i=0; i < ipp.attrs.size(); i++) | |
1348 | { | |
1349 | a = (IPPAttribute)ipp.attrs.get(i); | |
1350 | a.dump_values(); | |
1351 | } | |
1352 | return(0); | |
1353 | ||
1354 | } // if doRequest ... | |
1355 | ||
1356 | return(0); | |
1357 | ||
1358 | } // End of cupsCancelJob | |
1359 | ||
1360 | ||
1361 | ||
1362 | ||
1363 | public List cupsGetPrinterStatus(String printer_name) | |
1364 | throws IOException | |
1365 | { | |
1366 | IPPAttribute a; | |
1367 | String p_uri; | |
1368 | ||
1369 | ipp = new IPP(); | |
1370 | ||
1371 | // | |
1372 | // Fill in the required attributes | |
1373 | // | |
1374 | ipp.request = new IPPRequest(1,(short)IPPDefs.GET_PRINTER_ATTRIBUTES); | |
1375 | ||
1376 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, | |
1377 | "attributes-charset" ); | |
080811b1 | 1378 | a.addString( "", "utf-8" ); |
ef416fc2 | 1379 | ipp.addAttribute(a); |
1380 | ||
1381 | ||
1382 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, | |
1383 | "attributes-natural-language" ); | |
1384 | a.addString( "", "en" ); | |
1385 | ipp.addAttribute(a); | |
1386 | ||
1387 | a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, | |
1388 | "printer-uri" ); | |
1389 | p_uri = "ipp://" + address + ":" + | |
1390 | port + "/printers/" + printer_name; | |
1391 | a.addString( "", p_uri ); | |
1392 | ipp.addAttribute(a); | |
1393 | ||
1394 | if (doRequest("cupsGetPrinterStatus")) | |
1395 | { | |
1396 | return(ipp.attrs); | |
1397 | } | |
1398 | return(null); | |
1399 | } | |
1400 | ||
1401 | ||
1402 | ||
1403 | ||
1404 | ||
1405 | } // End of Cups class | |
1406 |