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"
27 #include <cups/cups.h>
28 #include <cups/language.h>
30 #define OPERATION_NOVELL_LIST_PRINTERS 0x401A
31 #define OPERATION_NOVELL_MGMT 0x401C
32 #define NOVELL_SERVER_SYSNAME "sysname="
33 #define NOVELL_SERVER_SYSNAME_NETWARE "NetWare IA32"
34 #define NOVELL_SERVER_VERSION_STRING "iprintserverversion="
35 #define NOVELL_SERVER_VERSION_OES_SP1 33554432
37 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
38 #define HAVE_CUPS_1_6 1
42 #define ippGetCount(attr) attr->num_values
43 #define ippGetGroupTag(attr) attr->group_tag
44 #define ippGetName(attr) attr->name
45 #define ippGetValueTag(attr) attr->value_tag
46 #define ippGetStatusCode(ipp) ipp->request.status.status_code
47 #define ippGetBoolean(attr, element) attr->values[element].boolean
48 #define ippGetInteger(attr, element) attr->values[element].integer
49 #define ippGetString(attr, element, language) attr->values[element].string.text
51 static ipp_attribute_t *
52 ippFirstAttribute(ipp_t *ipp)
56 return (ipp->current = ipp->attrs);
59 static ipp_attribute_t *
60 ippNextAttribute(ipp_t *ipp)
62 if (!ipp || !ipp->current)
64 return (ipp->current = ipp->current->next);
67 static int ippSetOperation(ipp_t *ipp, ipp_op_t op)
69 ipp->request.op.operation_id = op;
73 static int ippSetRequestId(ipp_t *ipp, int request_id)
75 ipp->request.any.request_id = request_id;
81 * 'iprint_passwd_cb()' - The iPrint password callback...
84 static const char * /* O - Password or NULL */
85 iprint_passwd_cb(const char *prompt) /* I - Prompt */
88 * Always return NULL to indicate that no password is available...
94 static const char *iprint_server(void)
96 const struct loadparm_substitution *lp_sub =
97 loadparm_s3_global_substitution();
98 const char *server = lp_iprint_server(talloc_tos(), lp_sub);
100 if ((server != NULL) && (strlen(server) > 0)) {
101 DEBUG(10, ("iprint server explicitly set to %s\n",
106 DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
111 * Pass in an already connected http_t*
112 * Returns the server version if one can be found, multiplied by
113 * -1 for all NetWare versions. Returns 0 if a server version
114 * cannot be determined
117 static int iprint_get_server_version(http_t *http, char* serviceUri)
119 ipp_t *request = NULL, /* IPP Request */
120 *response = NULL; /* IPP Response */
121 ipp_attribute_t *attr; /* Current attribute */
122 cups_lang_t *language = NULL; /* Default language */
123 char *ver; /* server version pointer */
124 char *vertmp; /* server version tmp pointer */
125 int serverVersion = 0; /* server version */
126 char *os; /* server os */
127 int osFlag = 0; /* 0 for NetWare, 1 for anything else */
128 char *temp; /* pointer for string manipulation */
131 * Build an OPERATION_NOVELL_MGMT("get-server-version") request,
132 * which requires the following attributes:
135 * attributes-natural-language
142 ippSetOperation(request, (ipp_op_t)OPERATION_NOVELL_MGMT);
143 ippSetRequestId(request, 1);
145 language = cupsLangDefault();
147 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
148 "attributes-charset", NULL, "utf-8");
150 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
151 "attributes-natural-language", NULL, language->language);
153 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
154 "service-uri", NULL, serviceUri);
156 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
157 "operation-name", NULL, "get-server-version");
160 * Do the request and get back a response...
163 if (((response = cupsDoRequest(http, request, "/ipp/")) == NULL) ||
164 (ippGetStatusCode(response) >= IPP_OK_CONFLICT))
167 if (((attr = ippFindAttribute(response, "server-version",
168 IPP_TAG_STRING)) != NULL)) {
169 if ((ver = strstr(ippGetString(attr, 0, NULL),
170 NOVELL_SERVER_VERSION_STRING)) != NULL) {
171 ver += strlen(NOVELL_SERVER_VERSION_STRING);
173 * Strangely, libcups stores a IPP_TAG_STRING (octet
174 * string) as a null-terminated string with no length
175 * even though it could be binary data with nulls in
176 * it. Luckily, in this case the value is not binary.
178 serverVersion = strtol(ver, &vertmp, 10);
180 /* Check for not found, overflow or negative version */
181 if ((ver == vertmp) || (serverVersion < 0))
185 if ((os = strstr(ippGetString(attr, 0, NULL),
186 NOVELL_SERVER_SYSNAME)) != NULL) {
187 os += strlen(NOVELL_SERVER_SYSNAME);
188 if ((temp = strchr(os,'<')) != NULL)
190 if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE))
191 osFlag = 1; /* 1 for non-NetWare systems */
200 cupsLangFree(language);
205 return serverVersion;
209 static int iprint_cache_add_printer(http_t *http,
212 struct pcap_cache **pcache)
214 ipp_t *request = NULL, /* IPP Request */
215 *response = NULL; /* IPP Response */
216 ipp_attribute_t *attr; /* Current attribute */
217 cups_lang_t *language = NULL; /* Default language */
218 const char *name, /* printer-name attribute */
219 *info; /* printer-info attribute */
220 char smb_enabled, /* smb-enabled attribute */
221 secure; /* security-enabled attrib. */
223 const char *httpPath; /* path portion of the printer-uri */
225 static const char *pattrs[] = /* Requested printer attributes */
235 ippSetOperation(request, IPP_GET_PRINTER_ATTRIBUTES);
236 ippSetRequestId(request, reqId);
238 language = cupsLangDefault();
240 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
241 "attributes-charset", NULL, "utf-8");
243 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
244 "attributes-natural-language", NULL, language->language);
246 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, url);
248 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
249 "requested-attributes",
250 (sizeof(pattrs) / sizeof(pattrs[0])),
254 * Do the request and get back a response...
257 if ((httpPath = strstr(url,"://")) == NULL ||
258 (httpPath = strchr(httpPath+3,'/')) == NULL)
265 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
266 ipp_status_t lastErr = cupsLastError();
269 * Ignore printers that cannot be queried without credentials
271 if (lastErr == IPP_FORBIDDEN ||
272 lastErr == IPP_NOT_AUTHENTICATED ||
273 lastErr == IPP_NOT_AUTHORIZED)
276 DEBUG(0,("Unable to get printer list - %s\n",
277 ippErrorString(lastErr)));
281 for (attr = ippFirstAttribute(response); attr != NULL;) {
283 * Skip leading attributes until we hit a printer...
286 while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_PRINTER)
287 attr = ippNextAttribute(response);
293 * Pull the needed attributes from this printer...
301 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_PRINTER) {
302 if (strcmp(ippGetName(attr), "printer-name") == 0 &&
303 ippGetValueTag(attr) == IPP_TAG_NAME)
304 name = ippGetString(attr, 0, NULL);
306 if (strcmp(ippGetName(attr), "printer-info") == 0 &&
307 (ippGetValueTag(attr) == IPP_TAG_TEXT ||
308 ippGetValueTag(attr) == IPP_TAG_TEXTLANG))
309 info = ippGetString(attr, 0, NULL);
312 * If the smb-enabled attribute is present and the
313 * value is set to 0, don't show the printer.
314 * If the attribute is not present, assume that the
315 * printer should show up
317 if (!strcmp(ippGetName(attr), "smb-enabled") &&
318 ((ippGetValueTag(attr) == IPP_TAG_INTEGER &&
319 !ippGetInteger(attr, 0)) ||
320 (ippGetValueTag(attr) == IPP_TAG_BOOLEAN &&
321 !ippGetBoolean(attr, 0))))
325 * If the security-enabled attribute is present and the
326 * value is set to 1, don't show the printer.
327 * If the attribute is not present, assume that the
328 * printer should show up
330 if (!strcmp(ippGetName(attr), "security-enabled") &&
331 ((ippGetValueTag(attr) == IPP_TAG_INTEGER &&
332 ippGetInteger(attr, 0)) ||
333 (ippGetValueTag(attr) == IPP_TAG_BOOLEAN &&
334 ippGetBoolean(attr, 0))))
337 attr = ippNextAttribute(response);
341 * See if we have everything needed...
342 * Make sure the printer is not a secure printer
343 * and make sure smb printing hasn't been explicitly
344 * disabled for the printer
347 if (name != NULL && !secure && smb_enabled)
348 pcap_cache_add_specific(pcache, name, info, NULL);
357 bool iprint_cache_reload(struct pcap_cache **_pcache)
359 http_t *http = NULL; /* HTTP connection to server */
360 ipp_t *request = NULL, /* IPP Request */
361 *response = NULL; /* IPP Response */
362 ipp_attribute_t *attr; /* Current attribute */
363 cups_lang_t *language = NULL; /* Default language */
366 struct pcap_cache *pcache = NULL;
368 DEBUG(5, ("reloading iprint printcap cache\n"));
371 * Make sure we don't ask for passwords...
374 cupsSetPasswordCB(iprint_passwd_cb);
377 * Try to connect to the server...
380 #ifdef HAVE_HTTPCONNECT2
381 http = httpConnect2(iprint_server(),
385 HTTP_ENCRYPTION_NEVER,
387 30 * 1000, /* timeout */
390 http = httpConnect(iprint_server(), ippPort());
393 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
394 iprint_server(), strerror(errno)));
399 * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
402 * attributes-natural-language
407 ippSetOperation(request, (ipp_op_t)OPERATION_NOVELL_LIST_PRINTERS);
408 ippSetRequestId(request, 1);
410 language = cupsLangDefault();
412 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
413 "attributes-charset", NULL, "utf-8");
415 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
416 "attributes-natural-language", NULL, language->language);
418 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
419 "ipp-server", NULL, "ippSrvr");
422 * Do the request and get back a response...
425 if ((response = cupsDoRequest(http, request, "/ipp")) == NULL) {
426 DEBUG(0,("Unable to get printer list - %s\n",
427 ippErrorString(cupsLastError())));
431 for (attr = ippFirstAttribute(response); attr != NULL;) {
433 * Skip leading attributes until we hit a printer...
436 while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_PRINTER)
437 attr = ippNextAttribute(response);
443 * Pull the needed attributes from this printer...
446 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_PRINTER)
448 if (strcmp(ippGetName(attr), "printer-name") == 0 &&
449 (ippGetValueTag(attr) == IPP_TAG_URI ||
450 ippGetValueTag(attr) == IPP_TAG_NAME ||
451 ippGetValueTag(attr) == IPP_TAG_TEXT ||
452 ippGetValueTag(attr) == IPP_TAG_NAMELANG ||
453 ippGetValueTag(attr) == IPP_TAG_TEXTLANG))
455 for (i = 0; i<ippGetCount(attr); i++)
457 const char *url = ippGetString(attr, i, NULL);
458 if (!url || !strlen(url))
460 iprint_cache_add_printer(http, i+2, url,
464 attr = ippNextAttribute(response);
476 cupsLangFree(language);
486 * 'iprint_job_delete()' - Delete a job.
489 static int iprint_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
491 int ret = 1; /* Return value */
492 http_t *http = NULL; /* HTTP connection to server */
493 ipp_t *request = NULL, /* IPP Request */
494 *response = NULL; /* IPP Response */
495 cups_lang_t *language = NULL; /* Default language */
496 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
497 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
500 DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
503 * Make sure we don't ask for passwords...
506 cupsSetPasswordCB(iprint_passwd_cb);
509 * Try to connect to the server...
512 #ifdef HAVE_HTTPCONNECT2
513 http = httpConnect2(iprint_server(),
517 HTTP_ENCRYPTION_NEVER,
519 30 * 1000, /* timeout */
522 http = httpConnect(iprint_server(), ippPort());
525 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
526 iprint_server(), strerror(errno)));
531 * Build an IPP_CANCEL_JOB request, which uses the following
535 * attributes-natural-language
538 * requesting-user-name
543 ippSetOperation(request, IPP_CANCEL_JOB);
544 ippSetRequestId(request, 1);
546 language = cupsLangDefault();
548 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
549 "attributes-charset", NULL, "utf-8");
551 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
552 "attributes-natural-language", NULL, language->language);
554 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename);
556 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
558 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
560 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
564 * Do the request and get back a response...
567 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", sharename);
569 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
570 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
571 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
572 ippErrorString(cupsLastError())));
577 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
578 ippErrorString(cupsLastError())));
586 cupsLangFree(language);
596 * 'iprint_job_pause()' - Pause a job.
599 static int iprint_job_pause(int snum, struct printjob *pjob)
601 int ret = 1; /* Return value */
602 http_t *http = NULL; /* HTTP connection to server */
603 ipp_t *request = NULL, /* IPP Request */
604 *response = NULL; /* IPP Response */
605 cups_lang_t *language = NULL; /* Default language */
606 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
607 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
608 const struct loadparm_substitution *lp_sub =
609 loadparm_s3_global_substitution();
612 DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
615 * Make sure we don't ask for passwords...
618 cupsSetPasswordCB(iprint_passwd_cb);
621 * Try to connect to the server...
624 #ifdef HAVE_HTTPCONNECT2
625 http = httpConnect2(iprint_server(),
629 HTTP_ENCRYPTION_NEVER,
631 30 * 1000, /* timeout */
634 http = httpConnect(iprint_server(), ippPort());
637 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
638 iprint_server(), strerror(errno)));
643 * Build an IPP_HOLD_JOB request, which requires the following
647 * attributes-natural-language
650 * requesting-user-name
655 ippSetOperation(request, IPP_HOLD_JOB);
656 ippSetRequestId(request, 1);
658 language = cupsLangDefault();
660 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
661 "attributes-charset", NULL, "utf-8");
663 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
664 "attributes-natural-language", NULL, language->language);
666 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(),
667 lp_printername(talloc_tos(), lp_sub, snum));
669 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
671 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
673 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
677 * Do the request and get back a response...
680 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s",
681 lp_printername(talloc_tos(), lp_sub, snum));
683 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
684 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
685 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
686 ippErrorString(cupsLastError())));
691 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
692 ippErrorString(cupsLastError())));
700 cupsLangFree(language);
710 * 'iprint_job_resume()' - Resume a paused job.
713 static int iprint_job_resume(int snum, struct printjob *pjob)
715 int ret = 1; /* Return value */
716 http_t *http = NULL; /* HTTP connection to server */
717 ipp_t *request = NULL, /* IPP Request */
718 *response = NULL; /* IPP Response */
719 cups_lang_t *language = NULL; /* Default language */
720 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
721 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */
722 const struct loadparm_substitution *lp_sub =
723 loadparm_s3_global_substitution();
726 DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
729 * Make sure we don't ask for passwords...
732 cupsSetPasswordCB(iprint_passwd_cb);
735 * Try to connect to the server...
738 #ifdef HAVE_HTTPCONNECT2
739 http = httpConnect2(iprint_server(),
743 HTTP_ENCRYPTION_NEVER,
745 30 * 1000, /* timeout */
748 http = httpConnect(iprint_server(), ippPort());
751 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
752 iprint_server(), strerror(errno)));
757 * Build an IPP_RELEASE_JOB request, which requires the following
761 * attributes-natural-language
764 * requesting-user-name
769 ippSetOperation(request, IPP_RELEASE_JOB);
770 ippSetRequestId(request, 1);
772 language = cupsLangDefault();
774 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
775 "attributes-charset", NULL, "utf-8");
777 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
778 "attributes-natural-language", NULL, language->language);
780 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(),
781 lp_printername(talloc_tos(), lp_sub, snum));
783 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
785 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
787 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
791 * Do the request and get back a response...
794 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s",
795 lp_printername(talloc_tos(), lp_sub, snum));
797 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
798 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
799 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
800 ippErrorString(cupsLastError())));
805 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
806 ippErrorString(cupsLastError())));
814 cupsLangFree(language);
824 * 'iprint_job_submit()' - Submit a job for printing.
827 static int iprint_job_submit(int snum, struct printjob *pjob,
828 enum printing_types printing_type,
831 int ret = 1; /* Return value */
832 http_t *http = NULL; /* HTTP connection to server */
833 ipp_t *request = NULL, /* IPP Request */
834 *response = NULL; /* IPP Response */
835 ipp_attribute_t *attr; /* Current attribute */
836 cups_lang_t *language = NULL; /* Default language */
837 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
838 const struct loadparm_substitution *lp_sub =
839 loadparm_s3_global_substitution();
841 DEBUG(5,("iprint_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
844 * Make sure we don't ask for passwords...
847 cupsSetPasswordCB(iprint_passwd_cb);
850 * Try to connect to the server...
853 #ifdef HAVE_HTTPCONNECT2
854 http = httpConnect2(iprint_server(),
858 HTTP_ENCRYPTION_NEVER,
860 30 * 1000, /* timeout */
863 http = httpConnect(iprint_server(), ippPort());
866 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
867 iprint_server(), strerror(errno)));
872 * Build an IPP_PRINT_JOB request, which requires the following
876 * attributes-natural-language
878 * requesting-user-name
884 ippSetOperation(request, IPP_PRINT_JOB);
885 ippSetRequestId(request, 1);
887 language = cupsLangDefault();
889 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
890 "attributes-charset", NULL, "utf-8");
892 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
893 "attributes-natural-language", NULL, language->language);
895 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(),
896 lp_printername(talloc_tos(), lp_sub, snum));
898 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
899 "printer-uri", NULL, uri);
901 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
904 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
905 "job-originating-host-name", NULL,
906 pjob->clientmachine);
908 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
912 * Do the request and get back a response...
915 slprintf(uri, sizeof(uri) - 1, "/ipp/%s", lp_printername(talloc_tos(), lp_sub, snum));
917 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
918 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
919 DEBUG(0,("Unable to print file to %s - %s\n",
920 lp_printername(talloc_tos(), lp_sub, snum),
921 ippErrorString(cupsLastError())));
926 DEBUG(0,("Unable to print file to `%s' - %s\n",
927 lp_printername(talloc_tos(), lp_sub, snum),
928 ippErrorString(cupsLastError())));
932 unlink(pjob->filename);
933 /* else print_job_end will do it for us */
937 attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
938 if (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB)
940 pjob->sysjob = ippGetInteger(attr, 0);
949 cupsLangFree(language);
958 * 'iprint_queue_get()' - Get all the jobs in the print queue.
961 static int iprint_queue_get(const char *sharename,
962 enum printing_types printing_type,
964 print_queue_struct **q,
965 print_status_struct *status)
968 http_t *http = NULL; /* HTTP connection to server */
969 ipp_t *request = NULL, /* IPP Request */
970 *response = NULL; /* IPP Response */
971 ipp_attribute_t *attr = NULL; /* Current attribute */
972 cups_lang_t *language = NULL; /* Default language */
973 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
974 char serviceUri[HTTP_MAX_URI]; /* service-uri attribute */
975 char httpPath[HTTP_MAX_URI]; /* path portion of the uri */
976 int jobUseUnixTime = 0; /* Whether job times should
977 * be assumed to be Unix time */
978 int qcount = 0, /* Number of active queue entries */
979 qalloc = 0; /* Number of queue entries allocated */
980 print_queue_struct *queue = NULL, /* Queue entries */
981 *temp; /* Temporary pointer for queue */
982 const char *user_name, /* job-originating-user-name attribute */
983 *job_name; /* job-name attribute */
984 int job_id; /* job-id attribute */
985 int job_k_octets; /* job-k-octets attribute */
986 time_t job_time; /* time-at-creation attribute */
987 time_t printer_up_time = 0; /* printer's uptime */
988 ipp_jstate_t job_status; /* job-status attribute */
989 int job_priority; /* job-priority attribute */
990 static const char *jattrs[] = /* Requested job attributes */
995 "job-originating-user-name",
1000 static const char *pattrs[] = /* Requested printer attributes */
1003 "printer-state-message",
1004 "printer-current-time",
1010 /* HACK ALERT!!! The porblem with support the 'printer name'
1011 option is that we key the tdb off the sharename. So we will
1012 overload the lpq_command string to pass in the printername
1013 (which is basically what we do for non-cups printers ... using
1014 the lpq_command to get the queue listing). */
1016 fstrcpy( printername, lpq_command );
1018 DEBUG(5,("iprint_queue_get(%s, %p, %p)\n", printername, q, status));
1021 * Make sure we don't ask for passwords...
1024 cupsSetPasswordCB(iprint_passwd_cb);
1027 * Try to connect to the server...
1030 #ifdef HAVE_HTTPCONNECT2
1031 http = httpConnect2(iprint_server(),
1035 HTTP_ENCRYPTION_NEVER,
1037 30 * 1000, /* timeout */
1040 http = httpConnect(iprint_server(), ippPort());
1043 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
1044 iprint_server(), strerror(errno)));
1049 * Generate the printer URI and the service URI that goes with it...
1052 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), printername);
1053 slprintf(serviceUri, sizeof(serviceUri) - 1, "ipp://%s/ipp/", iprint_server());
1056 * For Linux iPrint servers from OES SP1 on, the iPrint server
1057 * uses Unix time for job start times unless it detects the iPrint
1058 * client in an http User-Agent header. (This was done to accomodate
1059 * CUPS broken behavior. According to RFC 2911, section 4.3.14, job
1060 * start times are supposed to be relative to how long the printer has
1061 * been up.) Since libcups doesn't allow us to set that header before
1062 * the request is sent, this ugly hack allows us to detect the server
1063 * version and decide how to interpret the job time.
1065 if (iprint_get_server_version(http, serviceUri) >=
1066 NOVELL_SERVER_VERSION_OES_SP1)
1071 ippSetOperation(request, IPP_GET_PRINTER_ATTRIBUTES);
1072 ippSetRequestId(request, 2);
1074 language = cupsLangDefault();
1076 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1077 "attributes-charset", NULL, "utf-8");
1079 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1080 "attributes-natural-language", NULL, language->language);
1082 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1083 "printer-uri", NULL, uri);
1085 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1086 "requested-attributes",
1087 (sizeof(pattrs) / sizeof(pattrs[0])),
1091 * Do the request and get back a response...
1094 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
1096 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
1097 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1098 ippErrorString(cupsLastError())));
1103 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1104 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1105 ippErrorString(ippGetStatusCode(response))));
1111 * Get the current printer status and convert it to the SAMBA values.
1114 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1115 if (ippGetInteger(attr, 0) == IPP_PRINTER_STOPPED)
1116 status->status = LPSTAT_STOPPED;
1118 status->status = LPSTAT_OK;
1121 if ((attr = ippFindAttribute(response, "printer-state-message",
1122 IPP_TAG_TEXT)) != NULL)
1123 fstrcpy(status->message, ippGetString(attr, 0, NULL));
1125 if ((attr = ippFindAttribute(response, "printer-up-time",
1126 IPP_TAG_INTEGER)) != NULL)
1127 printer_up_time = ippGetInteger(attr, 0);
1129 ippDelete(response);
1133 * Build an IPP_GET_JOBS request, which requires the following
1136 * attributes-charset
1137 * attributes-natural-language
1138 * requested-attributes
1144 ippSetOperation(request, IPP_GET_JOBS);
1145 ippSetRequestId(request, 3);
1147 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1148 "attributes-charset", NULL, "utf-8");
1150 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1151 "attributes-natural-language", NULL, language->language);
1153 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1154 "printer-uri", NULL, uri);
1156 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1157 "requested-attributes",
1158 (sizeof(jattrs) / sizeof(jattrs[0])),
1162 * Do the request and get back a response...
1165 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
1167 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
1168 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1169 ippErrorString(cupsLastError())));
1173 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1174 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1175 ippErrorString(ippGetStatusCode(response))));
1180 * Process the jobs...
1187 for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) {
1189 * Skip leading attributes until we hit a job...
1192 while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_JOB)
1193 attr = ippNextAttribute(response);
1199 * Allocate memory as needed...
1201 if (qcount >= qalloc) {
1204 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1206 if (queue == NULL) {
1207 DEBUG(0,("iprint_queue_get: Not enough memory!"));
1213 temp = queue + qcount;
1214 memset(temp, 0, sizeof(print_queue_struct));
1217 * Pull the needed attributes from this job...
1222 job_status = IPP_JOB_PENDING;
1228 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB) {
1229 if (ippGetName(attr) == NULL) {
1230 attr = ippNextAttribute(response);
1234 if (strcmp(ippGetName(attr), "job-id") == 0 &&
1235 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1236 job_id = ippGetInteger(attr, 0);
1238 if (strcmp(ippGetName(attr), "job-k-octets") == 0 &&
1239 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1240 job_k_octets = ippGetInteger(attr, 0);
1242 if (strcmp(ippGetName(attr), "job-priority") == 0 &&
1243 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1244 job_priority = ippGetInteger(attr, 0);
1246 if (strcmp(ippGetName(attr), "job-state") == 0 &&
1247 ippGetValueTag(attr) == IPP_TAG_ENUM)
1248 job_status = (ipp_jstate_t)ippGetInteger(attr, 0);
1250 if (strcmp(ippGetName(attr), "time-at-creation") == 0 &&
1251 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1254 * If jobs times are in Unix time, the accuracy of the job
1255 * start time depends upon the iPrint server's time being
1256 * set correctly. Otherwise, the accuracy depends upon
1257 * the Samba server's time being set correctly
1261 job_time = ippGetInteger(attr, 0);
1263 job_time = time(NULL) - printer_up_time + ippGetInteger(attr, 0);
1266 if (strcmp(ippGetName(attr), "job-name") == 0 &&
1267 (ippGetValueTag(attr) == IPP_TAG_NAMELANG ||
1268 ippGetValueTag(attr) == IPP_TAG_NAME))
1269 job_name = ippGetString(attr, 0, NULL);
1271 if (strcmp(ippGetName(attr), "job-originating-user-name") == 0 &&
1272 (ippGetValueTag(attr) == IPP_TAG_NAMELANG ||
1273 ippGetValueTag(attr) == IPP_TAG_NAME))
1274 user_name = ippGetString(attr, 0, NULL);
1276 attr = ippNextAttribute(response);
1280 * See if we have everything needed...
1283 if (user_name == NULL || job_name == NULL || job_id == 0) {
1290 temp->sysjob = job_id;
1291 temp->size = job_k_octets * 1024;
1292 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1293 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1294 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1296 temp->priority = job_priority;
1297 temp->time = job_time;
1298 strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
1299 strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
1308 * Return the job queue...
1315 ippDelete(response);
1318 cupsLangFree(language);
1328 * 'iprint_queue_pause()' - Pause a print queue.
1331 static int iprint_queue_pause(int snum)
1333 return(-1); /* Not supported without credentials */
1338 * 'iprint_queue_resume()' - Restart a print queue.
1341 static int iprint_queue_resume(int snum)
1343 return(-1); /* Not supported without credentials */
1346 /*******************************************************************
1347 * iPrint printing interface definitions...
1348 ******************************************************************/
1350 struct printif iprint_printif =
1355 iprint_queue_resume,
1363 /* this keeps fussy compilers happy */
1364 void print_iprint_dummy(void);
1365 void print_iprint_dummy(void) {}
1366 #endif /* HAVE_IPRINT */