s3:smbd: add vfs_fake_fd_close() helper
[Samba.git] / source3 / printing / print_iprint.c
blobf75aa0a12ac3ae3fc8bf6a61dadd962b4b1763a0
1 /*
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/>.
22 #include "includes.h"
23 #include "printing.h"
24 #include "printing/pcap.h"
26 #ifdef HAVE_IPRINT
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
39 #endif
41 #ifndef HAVE_CUPS_1_6
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)
54 if (!ipp)
55 return (NULL);
56 return (ipp->current = ipp->attrs);
59 static ipp_attribute_t *
60 ippNextAttribute(ipp_t *ipp)
62 if (!ipp || !ipp->current)
63 return (NULL);
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;
70 return (1);
73 static int ippSetRequestId(ipp_t *ipp, int request_id)
75 ipp->request.any.request_id = request_id;
76 return (1);
78 #endif
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...
91 return (NULL);
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",
102 server));
103 return server;
106 DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
107 return 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:
134 * attributes-charset
135 * attributes-natural-language
136 * operation-name
137 * service-uri
140 request = ippNew();
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))
165 goto out;
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))
182 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)
189 *temp = '\0';
190 if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE))
191 osFlag = 1; /* 1 for non-NetWare systems */
195 out:
196 if (response)
197 ippDelete(response);
199 if (language)
200 cupsLangFree(language);
202 if (osFlag == 0)
203 serverVersion *= -1;
205 return serverVersion;
209 static int iprint_cache_add_printer(http_t *http,
210 int reqId,
211 const char *url,
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 */
227 "printer-name",
228 "security-enabled",
229 "printer-info",
230 "smb-enabled"
233 request = ippNew();
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])),
251 NULL, pattrs);
254 * Do the request and get back a response...
257 if ((httpPath = strstr(url,"://")) == NULL ||
258 (httpPath = strchr(httpPath+3,'/')) == NULL)
260 ippDelete(request);
261 request = NULL;
262 goto out;
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)
274 goto out;
276 DEBUG(0,("Unable to get printer list - %s\n",
277 ippErrorString(lastErr)));
278 goto out;
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);
289 if (attr == NULL)
290 break;
293 * Pull the needed attributes from this printer...
296 name = NULL;
297 info = NULL;
298 smb_enabled= 1;
299 secure = 0;
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))))
322 smb_enabled = 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))))
335 secure = 1;
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);
351 out:
352 if (response)
353 ippDelete(response);
354 return(0);
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 */
364 int i;
365 bool ret = false;
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(),
382 ippPort(),
383 NULL,
384 AF_UNSPEC,
385 HTTP_ENCRYPTION_NEVER,
386 1, /* blocking */
387 30 * 1000, /* timeout */
388 NULL);
389 #else
390 http = httpConnect(iprint_server(), ippPort());
391 #endif
392 if (http == NULL) {
393 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
394 iprint_server(), strerror(errno)));
395 goto out;
399 * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
401 * attributes-charset
402 * attributes-natural-language
405 request = ippNew();
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())));
428 goto out;
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);
439 if (attr == NULL)
440 break;
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))
459 continue;
460 iprint_cache_add_printer(http, i+2, url,
461 &pcache);
464 attr = ippNextAttribute(response);
468 ret = true;
469 *_pcache = pcache;
471 out:
472 if (response)
473 ippDelete(response);
475 if (language)
476 cupsLangFree(language);
478 if (http)
479 httpClose(http);
481 return ret;
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(),
514 ippPort(),
515 NULL,
516 AF_UNSPEC,
517 HTTP_ENCRYPTION_NEVER,
518 1, /* blocking */
519 30 * 1000, /* timeout */
520 NULL);
521 #else
522 http = httpConnect(iprint_server(), ippPort());
523 #endif
524 if (http == NULL) {
525 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
526 iprint_server(), strerror(errno)));
527 goto out;
531 * Build an IPP_CANCEL_JOB request, which uses the following
532 * attributes:
534 * attributes-charset
535 * attributes-natural-language
536 * printer-uri
537 * job-id
538 * requesting-user-name
541 request = ippNew();
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",
561 NULL, pjob->user);
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())));
573 } else {
574 ret = 0;
576 } else {
577 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
578 ippErrorString(cupsLastError())));
581 out:
582 if (response)
583 ippDelete(response);
585 if (language)
586 cupsLangFree(language);
588 if (http)
589 httpClose(http);
591 return ret;
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(),
626 ippPort(),
627 NULL,
628 AF_UNSPEC,
629 HTTP_ENCRYPTION_NEVER,
630 1, /* blocking */
631 30 * 1000, /* timeout */
632 NULL);
633 #else
634 http = httpConnect(iprint_server(), ippPort());
635 #endif
636 if (http == NULL) {
637 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
638 iprint_server(), strerror(errno)));
639 goto out;
643 * Build an IPP_HOLD_JOB request, which requires the following
644 * attributes:
646 * attributes-charset
647 * attributes-natural-language
648 * printer-uri
649 * job-id
650 * requesting-user-name
653 request = ippNew();
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",
674 NULL, pjob->user);
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())));
687 } else {
688 ret = 0;
690 } else {
691 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
692 ippErrorString(cupsLastError())));
695 out:
696 if (response)
697 ippDelete(response);
699 if (language)
700 cupsLangFree(language);
702 if (http)
703 httpClose(http);
705 return ret;
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(),
740 ippPort(),
741 NULL,
742 AF_UNSPEC,
743 HTTP_ENCRYPTION_NEVER,
744 1, /* blocking */
745 30 * 1000, /* timeout */
746 NULL);
747 #else
748 http = httpConnect(iprint_server(), ippPort());
749 #endif
750 if (http == NULL) {
751 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
752 iprint_server(), strerror(errno)));
753 goto out;
757 * Build an IPP_RELEASE_JOB request, which requires the following
758 * attributes:
760 * attributes-charset
761 * attributes-natural-language
762 * printer-uri
763 * job-id
764 * requesting-user-name
767 request = ippNew();
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",
788 NULL, pjob->user);
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())));
801 } else {
802 ret = 0;
804 } else {
805 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
806 ippErrorString(cupsLastError())));
809 out:
810 if (response)
811 ippDelete(response);
813 if (language)
814 cupsLangFree(language);
816 if (http)
817 httpClose(http);
819 return ret;
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,
829 char *lpq_cmd)
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(),
855 ippPort(),
856 NULL,
857 AF_UNSPEC,
858 HTTP_ENCRYPTION_NEVER,
859 1, /* blocking */
860 30 * 1000, /* timeout */
861 NULL);
862 #else
863 http = httpConnect(iprint_server(), ippPort());
864 #endif
865 if (http == NULL) {
866 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
867 iprint_server(), strerror(errno)));
868 goto out;
872 * Build an IPP_PRINT_JOB request, which requires the following
873 * attributes:
875 * attributes-charset
876 * attributes-natural-language
877 * printer-uri
878 * requesting-user-name
879 * [document-data]
882 request = ippNew();
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",
902 NULL, pjob->user);
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,
909 pjob->jobname);
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())));
922 } else {
923 ret = 0;
925 } else {
926 DEBUG(0,("Unable to print file to `%s' - %s\n",
927 lp_printername(talloc_tos(), lp_sub, snum),
928 ippErrorString(cupsLastError())));
931 if ( ret == 0 )
932 unlink(pjob->filename);
933 /* else print_job_end will do it for us */
935 if ( ret == 0 ) {
937 attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
938 if (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB)
940 pjob->sysjob = ippGetInteger(attr, 0);
944 out:
945 if (response)
946 ippDelete(response);
948 if (language)
949 cupsLangFree(language);
951 if (http)
952 httpClose(http);
954 return ret;
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,
963 char *lpq_command,
964 print_queue_struct **q,
965 print_status_struct *status)
967 fstring printername;
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 */
992 "job-id",
993 "job-k-octets",
994 "job-name",
995 "job-originating-user-name",
996 "job-priority",
997 "job-state",
998 "time-at-creation",
1000 static const char *pattrs[] = /* Requested printer attributes */
1002 "printer-state",
1003 "printer-state-message",
1004 "printer-current-time",
1005 "printer-up-time"
1008 *q = NULL;
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(),
1032 ippPort(),
1033 NULL,
1034 AF_UNSPEC,
1035 HTTP_ENCRYPTION_NEVER,
1036 1, /* blocking */
1037 30 * 1000, /* timeout */
1038 NULL);
1039 #else
1040 http = httpConnect(iprint_server(), ippPort());
1041 #endif
1042 if (http == NULL) {
1043 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
1044 iprint_server(), strerror(errno)));
1045 goto out;
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)
1067 jobUseUnixTime = 1;
1069 request = ippNew();
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])),
1088 NULL, pattrs);
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())));
1099 *q = queue;
1100 goto out;
1103 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1104 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1105 ippErrorString(ippGetStatusCode(response))));
1106 *q = queue;
1107 goto out;
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;
1117 else
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);
1130 response = NULL;
1133 * Build an IPP_GET_JOBS request, which requires the following
1134 * attributes:
1136 * attributes-charset
1137 * attributes-natural-language
1138 * requested-attributes
1139 * printer-uri
1142 request = ippNew();
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])),
1159 NULL, jattrs);
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())));
1170 goto out;
1173 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1174 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1175 ippErrorString(ippGetStatusCode(response))));
1176 goto out;
1180 * Process the jobs...
1183 qcount = 0;
1184 qalloc = 0;
1185 queue = NULL;
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);
1195 if (attr == NULL)
1196 break;
1199 * Allocate memory as needed...
1201 if (qcount >= qalloc) {
1202 qalloc += 16;
1204 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1206 if (queue == NULL) {
1207 DEBUG(0,("iprint_queue_get: Not enough memory!"));
1208 qcount = 0;
1209 goto out;
1213 temp = queue + qcount;
1214 memset(temp, 0, sizeof(print_queue_struct));
1217 * Pull the needed attributes from this job...
1220 job_id = 0;
1221 job_priority = 50;
1222 job_status = IPP_JOB_PENDING;
1223 job_time = 0;
1224 job_k_octets = 0;
1225 user_name = NULL;
1226 job_name = NULL;
1228 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB) {
1229 if (ippGetName(attr) == NULL) {
1230 attr = ippNextAttribute(response);
1231 break;
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
1260 if (jobUseUnixTime)
1261 job_time = ippGetInteger(attr, 0);
1262 else
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) {
1284 if (attr == NULL)
1285 break;
1286 else
1287 continue;
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 :
1295 LPQ_PRINTING;
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);
1301 qcount ++;
1303 if (attr == NULL)
1304 break;
1308 * Return the job queue...
1311 *q = queue;
1313 out:
1314 if (response)
1315 ippDelete(response);
1317 if (language)
1318 cupsLangFree(language);
1320 if (http)
1321 httpClose(http);
1323 return qcount;
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 =
1352 PRINT_IPRINT,
1353 iprint_queue_get,
1354 iprint_queue_pause,
1355 iprint_queue_resume,
1356 iprint_job_delete,
1357 iprint_job_pause,
1358 iprint_job_resume,
1359 iprint_job_submit,
1362 #else
1363 /* this keeps fussy compilers happy */
1364 void print_iprint_dummy(void);
1365 void print_iprint_dummy(void) {}
1366 #endif /* HAVE_IPRINT */