2 * Support code for Novell iPrint using the Common UNIX Printing
3 * System ("CUPS") libraries
5 * Copyright 1999-2003 by Michael R Sweet.
6 * Portions Copyright 2005 by Joel J. Smith.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "printing/pcap.h"
25 #include "lib/util/string_wrappers.h"
28 #include <cups/cups.h>
29 #include <cups/language.h>
31 #define OPERATION_NOVELL_LIST_PRINTERS 0x401A
32 #define OPERATION_NOVELL_MGMT 0x401C
33 #define NOVELL_SERVER_SYSNAME "sysname="
34 #define NOVELL_SERVER_SYSNAME_NETWARE "NetWare IA32"
35 #define NOVELL_SERVER_VERSION_STRING "iprintserverversion="
36 #define NOVELL_SERVER_VERSION_OES_SP1 33554432
38 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
39 #define HAVE_CUPS_1_6 1
43 #define ippGetCount(attr) attr->num_values
44 #define ippGetGroupTag(attr) attr->group_tag
45 #define ippGetName(attr) attr->name
46 #define ippGetValueTag(attr) attr->value_tag
47 #define ippGetStatusCode(ipp) ipp->request.status.status_code
48 #define ippGetBoolean(attr, element) attr->values[element].boolean
49 #define ippGetInteger(attr, element) attr->values[element].integer
50 #define ippGetString(attr, element, language) attr->values[element].string.text
52 static ipp_attribute_t
*
53 ippFirstAttribute(ipp_t
*ipp
)
57 return (ipp
->current
= ipp
->attrs
);
60 static ipp_attribute_t
*
61 ippNextAttribute(ipp_t
*ipp
)
63 if (!ipp
|| !ipp
->current
)
65 return (ipp
->current
= ipp
->current
->next
);
68 static int ippSetOperation(ipp_t
*ipp
, ipp_op_t op
)
70 ipp
->request
.op
.operation_id
= op
;
74 static int ippSetRequestId(ipp_t
*ipp
, int request_id
)
76 ipp
->request
.any
.request_id
= request_id
;
82 * 'iprint_passwd_cb()' - The iPrint password callback...
85 static const char * /* O - Password or NULL */
86 iprint_passwd_cb(const char *prompt
) /* I - Prompt */
89 * Always return NULL to indicate that no password is available...
95 static const char *iprint_server(void)
97 const struct loadparm_substitution
*lp_sub
=
98 loadparm_s3_global_substitution();
99 const char *server
= lp_iprint_server(talloc_tos(), lp_sub
);
101 if ((server
!= NULL
) && (strlen(server
) > 0)) {
102 DEBUG(10, ("iprint server explicitly set to %s\n",
107 DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
112 * Pass in an already connected http_t*
113 * Returns the server version if one can be found, multiplied by
114 * -1 for all NetWare versions. Returns 0 if a server version
115 * cannot be determined
118 static int iprint_get_server_version(http_t
*http
, char* serviceUri
)
120 ipp_t
*request
= NULL
, /* IPP Request */
121 *response
= NULL
; /* IPP Response */
122 ipp_attribute_t
*attr
; /* Current attribute */
123 cups_lang_t
*language
= NULL
; /* Default language */
124 char *ver
; /* server version pointer */
125 char *vertmp
; /* server version tmp pointer */
126 int serverVersion
= 0; /* server version */
127 char *os
; /* server os */
128 int osFlag
= 0; /* 0 for NetWare, 1 for anything else */
129 char *temp
; /* pointer for string manipulation */
132 * Build an OPERATION_NOVELL_MGMT("get-server-version") request,
133 * which requires the following attributes:
136 * attributes-natural-language
143 ippSetOperation(request
, (ipp_op_t
)OPERATION_NOVELL_MGMT
);
144 ippSetRequestId(request
, 1);
146 language
= cupsLangDefault();
148 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
149 "attributes-charset", NULL
, "utf-8");
151 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
152 "attributes-natural-language", NULL
, language
->language
);
154 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
155 "service-uri", NULL
, serviceUri
);
157 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
158 "operation-name", NULL
, "get-server-version");
161 * Do the request and get back a response...
164 if (((response
= cupsDoRequest(http
, request
, "/ipp/")) == NULL
) ||
165 (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
))
168 if (((attr
= ippFindAttribute(response
, "server-version",
169 IPP_TAG_STRING
)) != NULL
)) {
170 if ((ver
= strstr(ippGetString(attr
, 0, NULL
),
171 NOVELL_SERVER_VERSION_STRING
)) != NULL
) {
172 ver
+= strlen(NOVELL_SERVER_VERSION_STRING
);
174 * Strangely, libcups stores a IPP_TAG_STRING (octet
175 * string) as a null-terminated string with no length
176 * even though it could be binary data with nulls in
177 * it. Luckily, in this case the value is not binary.
179 serverVersion
= strtol(ver
, &vertmp
, 10);
181 /* Check for not found, overflow or negative version */
182 if ((ver
== vertmp
) || (serverVersion
< 0))
186 if ((os
= strstr(ippGetString(attr
, 0, NULL
),
187 NOVELL_SERVER_SYSNAME
)) != NULL
) {
188 os
+= strlen(NOVELL_SERVER_SYSNAME
);
189 if ((temp
= strchr(os
,'<')) != NULL
)
191 if (strcmp(os
,NOVELL_SERVER_SYSNAME_NETWARE
))
192 osFlag
= 1; /* 1 for non-NetWare systems */
201 cupsLangFree(language
);
206 return serverVersion
;
210 static int iprint_cache_add_printer(http_t
*http
,
213 struct pcap_cache
**pcache
)
215 ipp_t
*request
= NULL
, /* IPP Request */
216 *response
= NULL
; /* IPP Response */
217 ipp_attribute_t
*attr
; /* Current attribute */
218 cups_lang_t
*language
= NULL
; /* Default language */
219 const char *name
, /* printer-name attribute */
220 *info
; /* printer-info attribute */
221 char smb_enabled
, /* smb-enabled attribute */
222 secure
; /* security-enabled attrib. */
224 const char *httpPath
; /* path portion of the printer-uri */
226 static const char *pattrs
[] = /* Requested printer attributes */
236 ippSetOperation(request
, IPP_GET_PRINTER_ATTRIBUTES
);
237 ippSetRequestId(request
, reqId
);
239 language
= cupsLangDefault();
241 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
242 "attributes-charset", NULL
, "utf-8");
244 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
245 "attributes-natural-language", NULL
, language
->language
);
247 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, url
);
249 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
250 "requested-attributes",
251 (sizeof(pattrs
) / sizeof(pattrs
[0])),
255 * Do the request and get back a response...
258 if ((httpPath
= strstr(url
,"://")) == NULL
||
259 (httpPath
= strchr(httpPath
+3,'/')) == NULL
)
266 if ((response
= cupsDoRequest(http
, request
, httpPath
)) == NULL
) {
267 ipp_status_t lastErr
= cupsLastError();
270 * Ignore printers that cannot be queried without credentials
272 if (lastErr
== IPP_FORBIDDEN
||
273 lastErr
== IPP_NOT_AUTHENTICATED
||
274 lastErr
== IPP_NOT_AUTHORIZED
)
277 DEBUG(0,("Unable to get printer list - %s\n",
278 ippErrorString(lastErr
)));
282 for (attr
= ippFirstAttribute(response
); attr
!= NULL
;) {
284 * Skip leading attributes until we hit a printer...
287 while (attr
!= NULL
&& ippGetGroupTag(attr
) != IPP_TAG_PRINTER
)
288 attr
= ippNextAttribute(response
);
294 * Pull the needed attributes from this printer...
302 while (attr
!= NULL
&& ippGetGroupTag(attr
) == IPP_TAG_PRINTER
) {
303 if (strcmp(ippGetName(attr
), "printer-name") == 0 &&
304 ippGetValueTag(attr
) == IPP_TAG_NAME
)
305 name
= ippGetString(attr
, 0, NULL
);
307 if (strcmp(ippGetName(attr
), "printer-info") == 0 &&
308 (ippGetValueTag(attr
) == IPP_TAG_TEXT
||
309 ippGetValueTag(attr
) == IPP_TAG_TEXTLANG
))
310 info
= ippGetString(attr
, 0, NULL
);
313 * If the smb-enabled attribute is present and the
314 * value is set to 0, don't show the printer.
315 * If the attribute is not present, assume that the
316 * printer should show up
318 if (!strcmp(ippGetName(attr
), "smb-enabled") &&
319 ((ippGetValueTag(attr
) == IPP_TAG_INTEGER
&&
320 !ippGetInteger(attr
, 0)) ||
321 (ippGetValueTag(attr
) == IPP_TAG_BOOLEAN
&&
322 !ippGetBoolean(attr
, 0))))
326 * If the security-enabled attribute is present and the
327 * value is set to 1, don't show the printer.
328 * If the attribute is not present, assume that the
329 * printer should show up
331 if (!strcmp(ippGetName(attr
), "security-enabled") &&
332 ((ippGetValueTag(attr
) == IPP_TAG_INTEGER
&&
333 ippGetInteger(attr
, 0)) ||
334 (ippGetValueTag(attr
) == IPP_TAG_BOOLEAN
&&
335 ippGetBoolean(attr
, 0))))
338 attr
= ippNextAttribute(response
);
342 * See if we have everything needed...
343 * Make sure the printer is not a secure printer
344 * and make sure smb printing hasn't been explicitly
345 * disabled for the printer
348 if (name
!= NULL
&& !secure
&& smb_enabled
)
349 pcap_cache_add_specific(pcache
, name
, info
, NULL
);
358 bool iprint_cache_reload(struct pcap_cache
**_pcache
)
360 http_t
*http
= NULL
; /* HTTP connection to server */
361 ipp_t
*request
= NULL
, /* IPP Request */
362 *response
= NULL
; /* IPP Response */
363 ipp_attribute_t
*attr
; /* Current attribute */
364 cups_lang_t
*language
= NULL
; /* Default language */
367 struct pcap_cache
*pcache
= NULL
;
369 DEBUG(5, ("reloading iprint printcap cache\n"));
372 * Make sure we don't ask for passwords...
375 cupsSetPasswordCB(iprint_passwd_cb
);
378 * Try to connect to the server...
381 #ifdef HAVE_HTTPCONNECT2
382 http
= httpConnect2(iprint_server(),
386 HTTP_ENCRYPTION_NEVER
,
388 30 * 1000, /* timeout */
391 http
= httpConnect(iprint_server(), ippPort());
394 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
395 iprint_server(), strerror(errno
)));
400 * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
403 * attributes-natural-language
408 ippSetOperation(request
, (ipp_op_t
)OPERATION_NOVELL_LIST_PRINTERS
);
409 ippSetRequestId(request
, 1);
411 language
= cupsLangDefault();
413 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
414 "attributes-charset", NULL
, "utf-8");
416 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
417 "attributes-natural-language", NULL
, language
->language
);
419 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
420 "ipp-server", NULL
, "ippSrvr");
423 * Do the request and get back a response...
426 if ((response
= cupsDoRequest(http
, request
, "/ipp")) == NULL
) {
427 DEBUG(0,("Unable to get printer list - %s\n",
428 ippErrorString(cupsLastError())));
432 for (attr
= ippFirstAttribute(response
); attr
!= NULL
;) {
434 * Skip leading attributes until we hit a printer...
437 while (attr
!= NULL
&& ippGetGroupTag(attr
) != IPP_TAG_PRINTER
)
438 attr
= ippNextAttribute(response
);
444 * Pull the needed attributes from this printer...
447 while (attr
!= NULL
&& ippGetGroupTag(attr
) == IPP_TAG_PRINTER
)
449 if (strcmp(ippGetName(attr
), "printer-name") == 0 &&
450 (ippGetValueTag(attr
) == IPP_TAG_URI
||
451 ippGetValueTag(attr
) == IPP_TAG_NAME
||
452 ippGetValueTag(attr
) == IPP_TAG_TEXT
||
453 ippGetValueTag(attr
) == IPP_TAG_NAMELANG
||
454 ippGetValueTag(attr
) == IPP_TAG_TEXTLANG
))
456 for (i
= 0; i
<ippGetCount(attr
); i
++)
458 const char *url
= ippGetString(attr
, i
, NULL
);
459 if (!url
|| !strlen(url
))
461 iprint_cache_add_printer(http
, i
+2, url
,
465 attr
= ippNextAttribute(response
);
477 cupsLangFree(language
);
487 * 'iprint_job_delete()' - Delete a job.
490 static int iprint_job_delete(const char *sharename
, const char *lprm_command
, struct printjob
*pjob
)
492 int ret
= 1; /* Return value */
493 http_t
*http
= NULL
; /* HTTP connection to server */
494 ipp_t
*request
= NULL
, /* IPP Request */
495 *response
= NULL
; /* IPP Response */
496 cups_lang_t
*language
= NULL
; /* Default language */
497 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
498 char httpPath
[HTTP_MAX_URI
]; /* path portion of the printer-uri */
501 DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename
, pjob
, pjob
->sysjob
));
504 * Make sure we don't ask for passwords...
507 cupsSetPasswordCB(iprint_passwd_cb
);
510 * Try to connect to the server...
513 #ifdef HAVE_HTTPCONNECT2
514 http
= httpConnect2(iprint_server(),
518 HTTP_ENCRYPTION_NEVER
,
520 30 * 1000, /* timeout */
523 http
= httpConnect(iprint_server(), ippPort());
526 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
527 iprint_server(), strerror(errno
)));
532 * Build an IPP_CANCEL_JOB request, which uses the following
536 * attributes-natural-language
539 * requesting-user-name
544 ippSetOperation(request
, IPP_CANCEL_JOB
);
545 ippSetRequestId(request
, 1);
547 language
= cupsLangDefault();
549 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
550 "attributes-charset", NULL
, "utf-8");
552 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
553 "attributes-natural-language", NULL
, language
->language
);
555 slprintf(uri
, sizeof(uri
) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename
);
557 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
559 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", pjob
->sysjob
);
561 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
565 * Do the request and get back a response...
568 slprintf(httpPath
, sizeof(httpPath
) - 1, "/ipp/%s", sharename
);
570 if ((response
= cupsDoRequest(http
, request
, httpPath
)) != NULL
) {
571 if (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
) {
572 DEBUG(0,("Unable to cancel job %d - %s\n", pjob
->sysjob
,
573 ippErrorString(cupsLastError())));
578 DEBUG(0,("Unable to cancel job %d - %s\n", pjob
->sysjob
,
579 ippErrorString(cupsLastError())));
587 cupsLangFree(language
);
597 * 'iprint_job_pause()' - Pause a job.
600 static int iprint_job_pause(int snum
, struct printjob
*pjob
)
602 int ret
= 1; /* Return value */
603 http_t
*http
= NULL
; /* HTTP connection to server */
604 ipp_t
*request
= NULL
, /* IPP Request */
605 *response
= NULL
; /* IPP Response */
606 cups_lang_t
*language
= NULL
; /* Default language */
607 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
608 char httpPath
[HTTP_MAX_URI
]; /* path portion of the printer-uri */
609 const struct loadparm_substitution
*lp_sub
=
610 loadparm_s3_global_substitution();
613 DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
616 * Make sure we don't ask for passwords...
619 cupsSetPasswordCB(iprint_passwd_cb
);
622 * Try to connect to the server...
625 #ifdef HAVE_HTTPCONNECT2
626 http
= httpConnect2(iprint_server(),
630 HTTP_ENCRYPTION_NEVER
,
632 30 * 1000, /* timeout */
635 http
= httpConnect(iprint_server(), ippPort());
638 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
639 iprint_server(), strerror(errno
)));
644 * Build an IPP_HOLD_JOB request, which requires the following
648 * attributes-natural-language
651 * requesting-user-name
656 ippSetOperation(request
, IPP_HOLD_JOB
);
657 ippSetRequestId(request
, 1);
659 language
= cupsLangDefault();
661 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
662 "attributes-charset", NULL
, "utf-8");
664 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
665 "attributes-natural-language", NULL
, language
->language
);
667 slprintf(uri
, sizeof(uri
) - 1, "ipp://%s/ipp/%s", iprint_server(),
668 lp_printername(talloc_tos(), lp_sub
, snum
));
670 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
672 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", pjob
->sysjob
);
674 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
678 * Do the request and get back a response...
681 slprintf(httpPath
, sizeof(httpPath
) - 1, "/ipp/%s",
682 lp_printername(talloc_tos(), lp_sub
, snum
));
684 if ((response
= cupsDoRequest(http
, request
, httpPath
)) != NULL
) {
685 if (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
) {
686 DEBUG(0,("Unable to hold job %d - %s\n", pjob
->sysjob
,
687 ippErrorString(cupsLastError())));
692 DEBUG(0,("Unable to hold job %d - %s\n", pjob
->sysjob
,
693 ippErrorString(cupsLastError())));
701 cupsLangFree(language
);
711 * 'iprint_job_resume()' - Resume a paused job.
714 static int iprint_job_resume(int snum
, struct printjob
*pjob
)
716 int ret
= 1; /* Return value */
717 http_t
*http
= NULL
; /* HTTP connection to server */
718 ipp_t
*request
= NULL
, /* IPP Request */
719 *response
= NULL
; /* IPP Response */
720 cups_lang_t
*language
= NULL
; /* Default language */
721 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
722 char httpPath
[HTTP_MAX_URI
]; /* path portion of the printer-uri */
723 const struct loadparm_substitution
*lp_sub
=
724 loadparm_s3_global_substitution();
727 DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
730 * Make sure we don't ask for passwords...
733 cupsSetPasswordCB(iprint_passwd_cb
);
736 * Try to connect to the server...
739 #ifdef HAVE_HTTPCONNECT2
740 http
= httpConnect2(iprint_server(),
744 HTTP_ENCRYPTION_NEVER
,
746 30 * 1000, /* timeout */
749 http
= httpConnect(iprint_server(), ippPort());
752 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
753 iprint_server(), strerror(errno
)));
758 * Build an IPP_RELEASE_JOB request, which requires the following
762 * attributes-natural-language
765 * requesting-user-name
770 ippSetOperation(request
, IPP_RELEASE_JOB
);
771 ippSetRequestId(request
, 1);
773 language
= cupsLangDefault();
775 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
776 "attributes-charset", NULL
, "utf-8");
778 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
779 "attributes-natural-language", NULL
, language
->language
);
781 slprintf(uri
, sizeof(uri
) - 1, "ipp://%s/ipp/%s", iprint_server(),
782 lp_printername(talloc_tos(), lp_sub
, snum
));
784 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
786 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", pjob
->sysjob
);
788 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
792 * Do the request and get back a response...
795 slprintf(httpPath
, sizeof(httpPath
) - 1, "/ipp/%s",
796 lp_printername(talloc_tos(), lp_sub
, snum
));
798 if ((response
= cupsDoRequest(http
, request
, httpPath
)) != NULL
) {
799 if (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
) {
800 DEBUG(0,("Unable to release job %d - %s\n", pjob
->sysjob
,
801 ippErrorString(cupsLastError())));
806 DEBUG(0,("Unable to release job %d - %s\n", pjob
->sysjob
,
807 ippErrorString(cupsLastError())));
815 cupsLangFree(language
);
825 * 'iprint_job_submit()' - Submit a job for printing.
828 static int iprint_job_submit(int snum
, struct printjob
*pjob
,
829 enum printing_types printing_type
,
832 int ret
= 1; /* Return value */
833 http_t
*http
= NULL
; /* HTTP connection to server */
834 ipp_t
*request
= NULL
, /* IPP Request */
835 *response
= NULL
; /* IPP Response */
836 ipp_attribute_t
*attr
; /* Current attribute */
837 cups_lang_t
*language
= NULL
; /* Default language */
838 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
839 const struct loadparm_substitution
*lp_sub
=
840 loadparm_s3_global_substitution();
842 DEBUG(5,("iprint_job_submit(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
845 * Make sure we don't ask for passwords...
848 cupsSetPasswordCB(iprint_passwd_cb
);
851 * Try to connect to the server...
854 #ifdef HAVE_HTTPCONNECT2
855 http
= httpConnect2(iprint_server(),
859 HTTP_ENCRYPTION_NEVER
,
861 30 * 1000, /* timeout */
864 http
= httpConnect(iprint_server(), ippPort());
867 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
868 iprint_server(), strerror(errno
)));
873 * Build an IPP_PRINT_JOB request, which requires the following
877 * attributes-natural-language
879 * requesting-user-name
885 ippSetOperation(request
, IPP_PRINT_JOB
);
886 ippSetRequestId(request
, 1);
888 language
= cupsLangDefault();
890 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
891 "attributes-charset", NULL
, "utf-8");
893 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
894 "attributes-natural-language", NULL
, language
->language
);
896 slprintf(uri
, sizeof(uri
) - 1, "ipp://%s/ipp/%s", iprint_server(),
897 lp_printername(talloc_tos(), lp_sub
, snum
));
899 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
900 "printer-uri", NULL
, uri
);
902 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
905 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
906 "job-originating-host-name", NULL
,
907 pjob
->clientmachine
);
909 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
913 * Do the request and get back a response...
916 slprintf(uri
, sizeof(uri
) - 1, "/ipp/%s", lp_printername(talloc_tos(), lp_sub
, snum
));
918 if ((response
= cupsDoFileRequest(http
, request
, uri
, pjob
->filename
)) != NULL
) {
919 if (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
) {
920 DEBUG(0,("Unable to print file to %s - %s\n",
921 lp_printername(talloc_tos(), lp_sub
, snum
),
922 ippErrorString(cupsLastError())));
927 DEBUG(0,("Unable to print file to `%s' - %s\n",
928 lp_printername(talloc_tos(), lp_sub
, snum
),
929 ippErrorString(cupsLastError())));
933 unlink(pjob
->filename
);
934 /* else print_job_end will do it for us */
938 attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
);
939 if (attr
!= NULL
&& ippGetGroupTag(attr
) == IPP_TAG_JOB
)
941 pjob
->sysjob
= ippGetInteger(attr
, 0);
950 cupsLangFree(language
);
959 * 'iprint_queue_get()' - Get all the jobs in the print queue.
962 static int iprint_queue_get(const char *sharename
,
963 enum printing_types printing_type
,
965 print_queue_struct
**q
,
966 print_status_struct
*status
)
969 http_t
*http
= NULL
; /* HTTP connection to server */
970 ipp_t
*request
= NULL
, /* IPP Request */
971 *response
= NULL
; /* IPP Response */
972 ipp_attribute_t
*attr
= NULL
; /* Current attribute */
973 cups_lang_t
*language
= NULL
; /* Default language */
974 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
975 char serviceUri
[HTTP_MAX_URI
]; /* service-uri attribute */
976 char httpPath
[HTTP_MAX_URI
]; /* path portion of the uri */
977 int jobUseUnixTime
= 0; /* Whether job times should
978 * be assumed to be Unix time */
979 int qcount
= 0, /* Number of active queue entries */
980 qalloc
= 0; /* Number of queue entries allocated */
981 print_queue_struct
*queue
= NULL
, /* Queue entries */
982 *temp
; /* Temporary pointer for queue */
983 const char *user_name
, /* job-originating-user-name attribute */
984 *job_name
; /* job-name attribute */
985 int job_id
; /* job-id attribute */
986 int job_k_octets
; /* job-k-octets attribute */
987 time_t job_time
; /* time-at-creation attribute */
988 time_t printer_up_time
= 0; /* printer's uptime */
989 ipp_jstate_t job_status
; /* job-status attribute */
990 int job_priority
; /* job-priority attribute */
991 static const char *jattrs
[] = /* Requested job attributes */
996 "job-originating-user-name",
1001 static const char *pattrs
[] = /* Requested printer attributes */
1004 "printer-state-message",
1005 "printer-current-time",
1011 /* HACK ALERT!!! The porblem with support the 'printer name'
1012 option is that we key the tdb off the sharename. So we will
1013 overload the lpq_command string to pass in the printername
1014 (which is basically what we do for non-cups printers ... using
1015 the lpq_command to get the queue listing). */
1017 fstrcpy( printername
, lpq_command
);
1019 DEBUG(5,("iprint_queue_get(%s, %p, %p)\n", printername
, q
, status
));
1022 * Make sure we don't ask for passwords...
1025 cupsSetPasswordCB(iprint_passwd_cb
);
1028 * Try to connect to the server...
1031 #ifdef HAVE_HTTPCONNECT2
1032 http
= httpConnect2(iprint_server(),
1036 HTTP_ENCRYPTION_NEVER
,
1038 30 * 1000, /* timeout */
1041 http
= httpConnect(iprint_server(), ippPort());
1044 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
1045 iprint_server(), strerror(errno
)));
1050 * Generate the printer URI and the service URI that goes with it...
1053 slprintf(uri
, sizeof(uri
) - 1, "ipp://%s/ipp/%s", iprint_server(), printername
);
1054 slprintf(serviceUri
, sizeof(serviceUri
) - 1, "ipp://%s/ipp/", iprint_server());
1057 * For Linux iPrint servers from OES SP1 on, the iPrint server
1058 * uses Unix time for job start times unless it detects the iPrint
1059 * client in an http User-Agent header. (This was done to accomodate
1060 * CUPS broken behavior. According to RFC 2911, section 4.3.14, job
1061 * start times are supposed to be relative to how long the printer has
1062 * been up.) Since libcups doesn't allow us to set that header before
1063 * the request is sent, this ugly hack allows us to detect the server
1064 * version and decide how to interpret the job time.
1066 if (iprint_get_server_version(http
, serviceUri
) >=
1067 NOVELL_SERVER_VERSION_OES_SP1
)
1072 ippSetOperation(request
, IPP_GET_PRINTER_ATTRIBUTES
);
1073 ippSetRequestId(request
, 2);
1075 language
= cupsLangDefault();
1077 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1078 "attributes-charset", NULL
, "utf-8");
1080 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1081 "attributes-natural-language", NULL
, language
->language
);
1083 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1084 "printer-uri", NULL
, uri
);
1086 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1087 "requested-attributes",
1088 (sizeof(pattrs
) / sizeof(pattrs
[0])),
1092 * Do the request and get back a response...
1095 slprintf(httpPath
, sizeof(httpPath
) - 1, "/ipp/%s", printername
);
1097 if ((response
= cupsDoRequest(http
, request
, httpPath
)) == NULL
) {
1098 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1099 ippErrorString(cupsLastError())));
1104 if (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
) {
1105 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1106 ippErrorString(ippGetStatusCode(response
))));
1112 * Get the current printer status and convert it to the SAMBA values.
1115 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
) {
1116 if (ippGetInteger(attr
, 0) == IPP_PRINTER_STOPPED
)
1117 status
->status
= LPSTAT_STOPPED
;
1119 status
->status
= LPSTAT_OK
;
1122 if ((attr
= ippFindAttribute(response
, "printer-state-message",
1123 IPP_TAG_TEXT
)) != NULL
)
1124 fstrcpy(status
->message
, ippGetString(attr
, 0, NULL
));
1126 if ((attr
= ippFindAttribute(response
, "printer-up-time",
1127 IPP_TAG_INTEGER
)) != NULL
)
1128 printer_up_time
= ippGetInteger(attr
, 0);
1130 ippDelete(response
);
1134 * Build an IPP_GET_JOBS request, which requires the following
1137 * attributes-charset
1138 * attributes-natural-language
1139 * requested-attributes
1145 ippSetOperation(request
, IPP_GET_JOBS
);
1146 ippSetRequestId(request
, 3);
1148 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1149 "attributes-charset", NULL
, "utf-8");
1151 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1152 "attributes-natural-language", NULL
, language
->language
);
1154 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1155 "printer-uri", NULL
, uri
);
1157 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1158 "requested-attributes",
1159 (sizeof(jattrs
) / sizeof(jattrs
[0])),
1163 * Do the request and get back a response...
1166 slprintf(httpPath
, sizeof(httpPath
) - 1, "/ipp/%s", printername
);
1168 if ((response
= cupsDoRequest(http
, request
, httpPath
)) == NULL
) {
1169 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1170 ippErrorString(cupsLastError())));
1174 if (ippGetStatusCode(response
) >= IPP_OK_CONFLICT
) {
1175 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1176 ippErrorString(ippGetStatusCode(response
))));
1181 * Process the jobs...
1188 for (attr
= ippFirstAttribute(response
); attr
!= NULL
; attr
= ippNextAttribute(response
)) {
1190 * Skip leading attributes until we hit a job...
1193 while (attr
!= NULL
&& ippGetGroupTag(attr
) != IPP_TAG_JOB
)
1194 attr
= ippNextAttribute(response
);
1200 * Allocate memory as needed...
1202 if (qcount
>= qalloc
) {
1205 queue
= SMB_REALLOC_ARRAY(queue
, print_queue_struct
, qalloc
);
1207 if (queue
== NULL
) {
1208 DEBUG(0,("iprint_queue_get: Not enough memory!"));
1214 temp
= queue
+ qcount
;
1215 memset(temp
, 0, sizeof(print_queue_struct
));
1218 * Pull the needed attributes from this job...
1223 job_status
= IPP_JOB_PENDING
;
1229 while (attr
!= NULL
&& ippGetGroupTag(attr
) == IPP_TAG_JOB
) {
1230 if (ippGetName(attr
) == NULL
) {
1231 attr
= ippNextAttribute(response
);
1235 if (strcmp(ippGetName(attr
), "job-id") == 0 &&
1236 ippGetValueTag(attr
) == IPP_TAG_INTEGER
)
1237 job_id
= ippGetInteger(attr
, 0);
1239 if (strcmp(ippGetName(attr
), "job-k-octets") == 0 &&
1240 ippGetValueTag(attr
) == IPP_TAG_INTEGER
)
1241 job_k_octets
= ippGetInteger(attr
, 0);
1243 if (strcmp(ippGetName(attr
), "job-priority") == 0 &&
1244 ippGetValueTag(attr
) == IPP_TAG_INTEGER
)
1245 job_priority
= ippGetInteger(attr
, 0);
1247 if (strcmp(ippGetName(attr
), "job-state") == 0 &&
1248 ippGetValueTag(attr
) == IPP_TAG_ENUM
)
1249 job_status
= (ipp_jstate_t
)ippGetInteger(attr
, 0);
1251 if (strcmp(ippGetName(attr
), "time-at-creation") == 0 &&
1252 ippGetValueTag(attr
) == IPP_TAG_INTEGER
)
1255 * If jobs times are in Unix time, the accuracy of the job
1256 * start time depends upon the iPrint server's time being
1257 * set correctly. Otherwise, the accuracy depends upon
1258 * the Samba server's time being set correctly
1262 job_time
= ippGetInteger(attr
, 0);
1264 job_time
= time(NULL
) - printer_up_time
+ ippGetInteger(attr
, 0);
1267 if (strcmp(ippGetName(attr
), "job-name") == 0 &&
1268 (ippGetValueTag(attr
) == IPP_TAG_NAMELANG
||
1269 ippGetValueTag(attr
) == IPP_TAG_NAME
))
1270 job_name
= ippGetString(attr
, 0, NULL
);
1272 if (strcmp(ippGetName(attr
), "job-originating-user-name") == 0 &&
1273 (ippGetValueTag(attr
) == IPP_TAG_NAMELANG
||
1274 ippGetValueTag(attr
) == IPP_TAG_NAME
))
1275 user_name
= ippGetString(attr
, 0, NULL
);
1277 attr
= ippNextAttribute(response
);
1281 * See if we have everything needed...
1284 if (user_name
== NULL
|| job_name
== NULL
|| job_id
== 0) {
1291 temp
->sysjob
= job_id
;
1292 temp
->size
= job_k_octets
* 1024;
1293 temp
->status
= job_status
== IPP_JOB_PENDING
? LPQ_QUEUED
:
1294 job_status
== IPP_JOB_STOPPED
? LPQ_PAUSED
:
1295 job_status
== IPP_JOB_HELD
? LPQ_PAUSED
:
1297 temp
->priority
= job_priority
;
1298 temp
->time
= job_time
;
1299 strncpy(temp
->fs_user
, user_name
, sizeof(temp
->fs_user
) - 1);
1300 strncpy(temp
->fs_file
, job_name
, sizeof(temp
->fs_file
) - 1);
1309 * Return the job queue...
1316 ippDelete(response
);
1319 cupsLangFree(language
);
1329 * 'iprint_queue_pause()' - Pause a print queue.
1332 static int iprint_queue_pause(int snum
)
1334 return(-1); /* Not supported without credentials */
1339 * 'iprint_queue_resume()' - Restart a print queue.
1342 static int iprint_queue_resume(int snum
)
1344 return(-1); /* Not supported without credentials */
1347 /*******************************************************************
1348 * iPrint printing interface definitions...
1349 ******************************************************************/
1351 struct printif iprint_printif
=
1356 iprint_queue_resume
,
1364 /* this keeps fussy compilers happy */
1365 void print_iprint_dummy(void);
1366 void print_iprint_dummy(void) {}
1367 #endif /* HAVE_IPRINT */