smbd: Protect ea-reading on symlinks
[Samba.git] / source3 / printing / print_iprint.c
blob2b2215eb8c3fc9ce5d01de880903dce7eb3420e8
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"
25 #include "lib/util/string_wrappers.h"
27 #ifdef HAVE_IPRINT
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
40 #endif
42 #ifndef HAVE_CUPS_1_6
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)
55 if (!ipp)
56 return (NULL);
57 return (ipp->current = ipp->attrs);
60 static ipp_attribute_t *
61 ippNextAttribute(ipp_t *ipp)
63 if (!ipp || !ipp->current)
64 return (NULL);
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;
71 return (1);
74 static int ippSetRequestId(ipp_t *ipp, int request_id)
76 ipp->request.any.request_id = request_id;
77 return (1);
79 #endif
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...
92 return (NULL);
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",
103 server));
104 return server;
107 DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
108 return 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:
135 * attributes-charset
136 * attributes-natural-language
137 * operation-name
138 * service-uri
141 request = ippNew();
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))
166 goto out;
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))
183 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)
190 *temp = '\0';
191 if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE))
192 osFlag = 1; /* 1 for non-NetWare systems */
196 out:
197 if (response)
198 ippDelete(response);
200 if (language)
201 cupsLangFree(language);
203 if (osFlag == 0)
204 serverVersion *= -1;
206 return serverVersion;
210 static int iprint_cache_add_printer(http_t *http,
211 int reqId,
212 const char *url,
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 */
228 "printer-name",
229 "security-enabled",
230 "printer-info",
231 "smb-enabled"
234 request = ippNew();
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])),
252 NULL, pattrs);
255 * Do the request and get back a response...
258 if ((httpPath = strstr(url,"://")) == NULL ||
259 (httpPath = strchr(httpPath+3,'/')) == NULL)
261 ippDelete(request);
262 request = NULL;
263 goto out;
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)
275 goto out;
277 DEBUG(0,("Unable to get printer list - %s\n",
278 ippErrorString(lastErr)));
279 goto out;
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);
290 if (attr == NULL)
291 break;
294 * Pull the needed attributes from this printer...
297 name = NULL;
298 info = NULL;
299 smb_enabled= 1;
300 secure = 0;
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))))
323 smb_enabled = 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))))
336 secure = 1;
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);
352 out:
353 if (response)
354 ippDelete(response);
355 return(0);
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 */
365 int i;
366 bool ret = false;
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(),
383 ippPort(),
384 NULL,
385 AF_UNSPEC,
386 HTTP_ENCRYPTION_NEVER,
387 1, /* blocking */
388 30 * 1000, /* timeout */
389 NULL);
390 #else
391 http = httpConnect(iprint_server(), ippPort());
392 #endif
393 if (http == NULL) {
394 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
395 iprint_server(), strerror(errno)));
396 goto out;
400 * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
402 * attributes-charset
403 * attributes-natural-language
406 request = ippNew();
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())));
429 goto out;
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);
440 if (attr == NULL)
441 break;
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))
460 continue;
461 iprint_cache_add_printer(http, i+2, url,
462 &pcache);
465 attr = ippNextAttribute(response);
469 ret = true;
470 *_pcache = pcache;
472 out:
473 if (response)
474 ippDelete(response);
476 if (language)
477 cupsLangFree(language);
479 if (http)
480 httpClose(http);
482 return ret;
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(),
515 ippPort(),
516 NULL,
517 AF_UNSPEC,
518 HTTP_ENCRYPTION_NEVER,
519 1, /* blocking */
520 30 * 1000, /* timeout */
521 NULL);
522 #else
523 http = httpConnect(iprint_server(), ippPort());
524 #endif
525 if (http == NULL) {
526 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
527 iprint_server(), strerror(errno)));
528 goto out;
532 * Build an IPP_CANCEL_JOB request, which uses the following
533 * attributes:
535 * attributes-charset
536 * attributes-natural-language
537 * printer-uri
538 * job-id
539 * requesting-user-name
542 request = ippNew();
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",
562 NULL, pjob->user);
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())));
574 } else {
575 ret = 0;
577 } else {
578 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
579 ippErrorString(cupsLastError())));
582 out:
583 if (response)
584 ippDelete(response);
586 if (language)
587 cupsLangFree(language);
589 if (http)
590 httpClose(http);
592 return ret;
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(),
627 ippPort(),
628 NULL,
629 AF_UNSPEC,
630 HTTP_ENCRYPTION_NEVER,
631 1, /* blocking */
632 30 * 1000, /* timeout */
633 NULL);
634 #else
635 http = httpConnect(iprint_server(), ippPort());
636 #endif
637 if (http == NULL) {
638 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
639 iprint_server(), strerror(errno)));
640 goto out;
644 * Build an IPP_HOLD_JOB request, which requires the following
645 * attributes:
647 * attributes-charset
648 * attributes-natural-language
649 * printer-uri
650 * job-id
651 * requesting-user-name
654 request = ippNew();
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",
675 NULL, pjob->user);
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())));
688 } else {
689 ret = 0;
691 } else {
692 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
693 ippErrorString(cupsLastError())));
696 out:
697 if (response)
698 ippDelete(response);
700 if (language)
701 cupsLangFree(language);
703 if (http)
704 httpClose(http);
706 return ret;
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(),
741 ippPort(),
742 NULL,
743 AF_UNSPEC,
744 HTTP_ENCRYPTION_NEVER,
745 1, /* blocking */
746 30 * 1000, /* timeout */
747 NULL);
748 #else
749 http = httpConnect(iprint_server(), ippPort());
750 #endif
751 if (http == NULL) {
752 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
753 iprint_server(), strerror(errno)));
754 goto out;
758 * Build an IPP_RELEASE_JOB request, which requires the following
759 * attributes:
761 * attributes-charset
762 * attributes-natural-language
763 * printer-uri
764 * job-id
765 * requesting-user-name
768 request = ippNew();
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",
789 NULL, pjob->user);
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())));
802 } else {
803 ret = 0;
805 } else {
806 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
807 ippErrorString(cupsLastError())));
810 out:
811 if (response)
812 ippDelete(response);
814 if (language)
815 cupsLangFree(language);
817 if (http)
818 httpClose(http);
820 return ret;
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,
830 char *lpq_cmd)
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(),
856 ippPort(),
857 NULL,
858 AF_UNSPEC,
859 HTTP_ENCRYPTION_NEVER,
860 1, /* blocking */
861 30 * 1000, /* timeout */
862 NULL);
863 #else
864 http = httpConnect(iprint_server(), ippPort());
865 #endif
866 if (http == NULL) {
867 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
868 iprint_server(), strerror(errno)));
869 goto out;
873 * Build an IPP_PRINT_JOB request, which requires the following
874 * attributes:
876 * attributes-charset
877 * attributes-natural-language
878 * printer-uri
879 * requesting-user-name
880 * [document-data]
883 request = ippNew();
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",
903 NULL, pjob->user);
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,
910 pjob->jobname);
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())));
923 } else {
924 ret = 0;
926 } else {
927 DEBUG(0,("Unable to print file to `%s' - %s\n",
928 lp_printername(talloc_tos(), lp_sub, snum),
929 ippErrorString(cupsLastError())));
932 if ( ret == 0 )
933 unlink(pjob->filename);
934 /* else print_job_end will do it for us */
936 if ( ret == 0 ) {
938 attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
939 if (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB)
941 pjob->sysjob = ippGetInteger(attr, 0);
945 out:
946 if (response)
947 ippDelete(response);
949 if (language)
950 cupsLangFree(language);
952 if (http)
953 httpClose(http);
955 return ret;
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,
964 char *lpq_command,
965 print_queue_struct **q,
966 print_status_struct *status)
968 fstring printername;
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 */
993 "job-id",
994 "job-k-octets",
995 "job-name",
996 "job-originating-user-name",
997 "job-priority",
998 "job-state",
999 "time-at-creation",
1001 static const char *pattrs[] = /* Requested printer attributes */
1003 "printer-state",
1004 "printer-state-message",
1005 "printer-current-time",
1006 "printer-up-time"
1009 *q = NULL;
1011 /* HACK ALERT!!! The problem 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(),
1033 ippPort(),
1034 NULL,
1035 AF_UNSPEC,
1036 HTTP_ENCRYPTION_NEVER,
1037 1, /* blocking */
1038 30 * 1000, /* timeout */
1039 NULL);
1040 #else
1041 http = httpConnect(iprint_server(), ippPort());
1042 #endif
1043 if (http == NULL) {
1044 DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
1045 iprint_server(), strerror(errno)));
1046 goto out;
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 accommodate
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)
1068 jobUseUnixTime = 1;
1070 request = ippNew();
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])),
1089 NULL, pattrs);
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())));
1100 *q = queue;
1101 goto out;
1104 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1105 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1106 ippErrorString(ippGetStatusCode(response))));
1107 *q = queue;
1108 goto out;
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;
1118 else
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);
1131 response = NULL;
1134 * Build an IPP_GET_JOBS request, which requires the following
1135 * attributes:
1137 * attributes-charset
1138 * attributes-natural-language
1139 * requested-attributes
1140 * printer-uri
1143 request = ippNew();
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])),
1160 NULL, jattrs);
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())));
1171 goto out;
1174 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1175 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1176 ippErrorString(ippGetStatusCode(response))));
1177 goto out;
1181 * Process the jobs...
1184 qcount = 0;
1185 qalloc = 0;
1186 queue = NULL;
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);
1196 if (attr == NULL)
1197 break;
1200 * Allocate memory as needed...
1202 if (qcount >= qalloc) {
1203 qalloc += 16;
1205 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1207 if (queue == NULL) {
1208 DEBUG(0,("iprint_queue_get: Not enough memory!\n"));
1209 qcount = 0;
1210 goto out;
1214 temp = queue + qcount;
1215 memset(temp, 0, sizeof(print_queue_struct));
1218 * Pull the needed attributes from this job...
1221 job_id = 0;
1222 job_priority = 50;
1223 job_status = IPP_JOB_PENDING;
1224 job_time = 0;
1225 job_k_octets = 0;
1226 user_name = NULL;
1227 job_name = NULL;
1229 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB) {
1230 if (ippGetName(attr) == NULL) {
1231 attr = ippNextAttribute(response);
1232 break;
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
1261 if (jobUseUnixTime)
1262 job_time = ippGetInteger(attr, 0);
1263 else
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) {
1285 if (attr == NULL)
1286 break;
1287 else
1288 continue;
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 :
1296 LPQ_PRINTING;
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);
1302 qcount ++;
1304 if (attr == NULL)
1305 break;
1309 * Return the job queue...
1312 *q = queue;
1314 out:
1315 if (response)
1316 ippDelete(response);
1318 if (language)
1319 cupsLangFree(language);
1321 if (http)
1322 httpClose(http);
1324 return qcount;
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 =
1353 PRINT_IPRINT,
1354 iprint_queue_get,
1355 iprint_queue_pause,
1356 iprint_queue_resume,
1357 iprint_job_delete,
1358 iprint_job_pause,
1359 iprint_job_resume,
1360 iprint_job_submit,
1363 #else
1364 /* this keeps fussy compilers happy */
1365 void print_iprint_dummy(void);
1366 void print_iprint_dummy(void) {}
1367 #endif /* HAVE_IPRINT */