• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.0.25b/source/printing/
1/*
2 * Support code for Novell iPrint using the Common UNIX Printing
3 * System ("CUPS") libraries
4 *
5 * Copyright 1999-2003 by Michael R Sweet.
6 * Portions Copyright 2005 by Joel J. Smith.
7 *
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 2 of the License, or
11 * (at your option) any later version.
12 *
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.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include "includes.h"
24#include "printing.h"
25
26#ifdef HAVE_IPRINT
27#include <cups/cups.h>
28#include <cups/language.h>
29
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
36
37/*
38 * 'iprint_passwd_cb()' - The iPrint password callback...
39 */
40
41static const char *				/* O - Password or NULL */
42iprint_passwd_cb(const char *prompt)	/* I - Prompt */
43{
44       /*
45	* Always return NULL to indicate that no password is available...
46	*/
47
48	return (NULL);
49}
50
51static const char *iprint_server(void)
52{
53	if ((lp_iprint_server() != NULL) && (strlen(lp_iprint_server()) > 0)) {
54		DEBUG(10, ("iprint server explicitly set to %s\n",
55			   lp_iprint_server()));
56		return lp_iprint_server();
57	}
58
59	DEBUG(10, ("iprint server left to default %s\n", cupsServer()));
60	return cupsServer();
61}
62
63/*
64 * Pass in an already connected http_t*
65 * Returns the server version if one can be found, multiplied by
66 * -1 for all NetWare versions.  Returns 0 if a server version
67 * cannot be determined
68 */
69
70static int iprint_get_server_version(http_t *http, char* serviceUri)
71{
72	ipp_t		*request = NULL,	/* IPP Request */
73			*response = NULL;	/* IPP Response */
74	ipp_attribute_t	*attr;			/* Current attribute */
75	cups_lang_t	*language = NULL;	/* Default language */
76	char		*ver;			/* server version pointer */
77	char		*vertmp;		/* server version tmp pointer */
78	int		serverVersion = 0;	/* server version */
79	char		*os;			/* server os */
80	int		osFlag = 0;		/* 0 for NetWare, 1 for anything else */
81	char		*temp;			/* pointer for string manipulation */
82
83       /*
84	* Build an OPERATION_NOVELL_MGMT("get-server-version") request,
85	* which requires the following attributes:
86	*
87	*    attributes-charset
88	*    attributes-natural-language
89	*    operation-name
90	*    service-uri
91	*/
92
93	request = ippNew();
94
95	request->request.op.operation_id = (ipp_op_t)OPERATION_NOVELL_MGMT;
96	request->request.op.request_id   = 1;
97
98	language = cupsLangDefault();
99
100	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
101	             "attributes-charset", NULL, "utf-8");
102
103	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
104	             "attributes-natural-language", NULL, language->language);
105
106	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
107	             "service-uri", NULL, serviceUri);
108
109	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
110	              "operation-name", NULL, "get-server-version");
111
112       /*
113	* Do the request and get back a response...
114	*/
115
116	if (((response = cupsDoRequest(http, request, "/ipp/")) == NULL) ||
117	    (response->request.status.status_code >= IPP_OK_CONFLICT))
118		goto out;
119
120	if (((attr = ippFindAttribute(response, "server-version",
121	                              IPP_TAG_STRING)) != NULL)) {
122		if ((ver = strstr(attr->values[0].string.text,
123                                  NOVELL_SERVER_VERSION_STRING)) != NULL) {
124			ver += strlen(NOVELL_SERVER_VERSION_STRING);
125		       /*
126			* Strangely, libcups stores a IPP_TAG_STRING (octet
127			* string) as a null-terminated string with no length
128			* even though it could be binary data with nulls in
129			* it.  Luckily, in this case the value is not binary.
130			*/
131			serverVersion = strtol(ver, &vertmp, 10);
132
133			/* Check for not found, overflow or negative version */
134			if ((ver == vertmp) || (serverVersion < 0))
135				serverVersion = 0;
136		}
137
138		if ((os = strstr(attr->values[0].string.text,
139                                  NOVELL_SERVER_SYSNAME)) != NULL) {
140			os += strlen(NOVELL_SERVER_SYSNAME);
141			if ((temp = strchr(os,'<')) != NULL)
142				*temp = '\0';
143			if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE))
144				osFlag = 1; /* 1 for non-NetWare systems */
145		}
146	}
147
148 out:
149	if (response)
150		ippDelete(response);
151
152	if (language)
153		cupsLangFree(language);
154
155	if (osFlag == 0)
156		serverVersion *= -1;
157
158	return serverVersion;
159}
160
161
162static int iprint_cache_add_printer(http_t *http,
163				   int reqId,
164				   char* url)
165{
166	ipp_t		*request = NULL,	/* IPP Request */
167			*response = NULL;	/* IPP Response */
168	ipp_attribute_t	*attr;			/* Current attribute */
169	cups_lang_t	*language = NULL;	/* Default language */
170	char		*name,			/* printer-name attribute */
171			*info,			/* printer-info attribute */
172			smb_enabled,		/* smb-enabled attribute */
173			secure;			/* security-enabled attrib. */
174
175	char		*httpPath;	/* path portion of the printer-uri */
176
177	static const char *pattrs[] =	/* Requested printer attributes */
178			{
179			  "printer-name",
180			  "security-enabled",
181			  "printer-info",
182			  "smb-enabled"
183			};
184
185	request = ippNew();
186
187	request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
188	request->request.op.request_id   = reqId;
189
190	language = cupsLangDefault();
191
192	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
193	             "attributes-charset", NULL, "utf-8");
194
195	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
196	             "attributes-natural-language", NULL, language->language);
197
198	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, url);
199
200	ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
201	              "requested-attributes",
202	              (sizeof(pattrs) / sizeof(pattrs[0])),
203	              NULL, pattrs);
204
205	/*
206	 * Do the request and get back a response...
207	 */
208
209	if ((httpPath = strstr(url,"://")) == NULL ||
210			(httpPath = strchr(httpPath+3,'/')) == NULL)
211	{
212		ippDelete(request);
213		request = NULL;
214		goto out;
215	}
216
217	if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
218		ipp_status_t lastErr = cupsLastError();
219
220	       /*
221		* Ignore printers that cannot be queried without credentials
222		*/
223		if (lastErr == IPP_FORBIDDEN ||
224		    lastErr == IPP_NOT_AUTHENTICATED ||
225		    lastErr == IPP_NOT_AUTHORIZED)
226			goto out;
227
228		DEBUG(0,("Unable to get printer list - %s\n",
229		      ippErrorString(lastErr)));
230		goto out;
231	}
232
233	for (attr = response->attrs; attr != NULL;) {
234	       /*
235		* Skip leading attributes until we hit a printer...
236		*/
237
238		while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
239			attr = attr->next;
240
241		if (attr == NULL)
242			break;
243
244	       /*
245		* Pull the needed attributes from this printer...
246		*/
247
248		name       = NULL;
249		info       = NULL;
250		smb_enabled= 1;
251		secure     = 0;
252
253		while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
254			if (strcmp(attr->name, "printer-name") == 0 &&
255			    attr->value_tag == IPP_TAG_NAME)
256				name = attr->values[0].string.text;
257
258			if (strcmp(attr->name, "printer-info") == 0 &&
259			    (attr->value_tag == IPP_TAG_TEXT ||
260			    attr->value_tag == IPP_TAG_TEXTLANG))
261				info = attr->values[0].string.text;
262
263		       /*
264			* If the smb-enabled attribute is present and the
265			* value is set to 0, don't show the printer.
266			* If the attribute is not present, assume that the
267			* printer should show up
268			*/
269			if (!strcmp(attr->name, "smb-enabled") &&
270			    ((attr->value_tag == IPP_TAG_INTEGER &&
271			    !attr->values[0].integer) ||
272			    (attr->value_tag == IPP_TAG_BOOLEAN &&
273			    !attr->values[0].boolean)))
274				smb_enabled = 0;
275
276		       /*
277			* If the security-enabled attribute is present and the
278			* value is set to 1, don't show the printer.
279			* If the attribute is not present, assume that the
280			* printer should show up
281			*/
282			if (!strcmp(attr->name, "security-enabled") &&
283			    ((attr->value_tag == IPP_TAG_INTEGER &&
284			    attr->values[0].integer) ||
285			    (attr->value_tag == IPP_TAG_BOOLEAN &&
286			    attr->values[0].boolean)))
287				secure = 1;
288
289			attr = attr->next;
290		}
291
292	       /*
293		* See if we have everything needed...
294		* Make sure the printer is not a secure printer
295		* and make sure smb printing hasn't been explicitly
296		* disabled for the printer
297		*/
298
299		if (name != NULL && !secure && smb_enabled)
300			pcap_cache_add(name, info);
301	}
302
303 out:
304	if (response)
305		ippDelete(response);
306	return(0);
307}
308
309BOOL iprint_cache_reload(void)
310{
311	http_t		*http = NULL;		/* HTTP connection to server */
312	ipp_t		*request = NULL,	/* IPP Request */
313			*response = NULL;	/* IPP Response */
314	ipp_attribute_t	*attr;			/* Current attribute */
315	cups_lang_t	*language = NULL;	/* Default language */
316	int		i;
317	BOOL ret = False;
318
319	DEBUG(5, ("reloading iprint printcap cache\n"));
320
321       /*
322	* Make sure we don't ask for passwords...
323	*/
324
325	cupsSetPasswordCB(iprint_passwd_cb);
326
327       /*
328	* Try to connect to the server...
329	*/
330
331	if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
332		DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
333			 iprint_server(), strerror(errno)));
334		goto out;
335	}
336
337       /*
338	* Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes:
339	*
340	*    attributes-charset
341	*    attributes-natural-language
342	*/
343
344	request = ippNew();
345
346	request->request.op.operation_id =
347		(ipp_op_t)OPERATION_NOVELL_LIST_PRINTERS;
348	request->request.op.request_id   = 1;
349
350	language = cupsLangDefault();
351
352	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
353	             "attributes-charset", NULL, "utf-8");
354
355	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
356	             "attributes-natural-language", NULL, language->language);
357
358	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
359	             "ipp-server", NULL, "ippSrvr");
360
361       /*
362	* Do the request and get back a response...
363	*/
364
365	if ((response = cupsDoRequest(http, request, "/ipp")) == NULL) {
366		DEBUG(0,("Unable to get printer list - %s\n",
367			 ippErrorString(cupsLastError())));
368		goto out;
369	}
370
371	for (attr = response->attrs; attr != NULL;) {
372	       /*
373		* Skip leading attributes until we hit a printer...
374		*/
375
376		while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
377			attr = attr->next;
378
379		if (attr == NULL)
380			break;
381
382	       /*
383		* Pull the needed attributes from this printer...
384		*/
385
386		while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
387		{
388			if (strcmp(attr->name, "printer-name") == 0 &&
389			    (attr->value_tag == IPP_TAG_URI ||
390			     attr->value_tag == IPP_TAG_NAME ||
391			     attr->value_tag == IPP_TAG_TEXT ||
392			     attr->value_tag == IPP_TAG_NAMELANG ||
393			     attr->value_tag == IPP_TAG_TEXTLANG))
394			{
395				for (i = 0; i<attr->num_values; i++)
396				{
397					char *url = attr->values[i].string.text;
398					if (!url || !strlen(url))
399						continue;
400					iprint_cache_add_printer(http, i+2, url);
401				}
402			}
403			attr = attr->next;
404		}
405	}
406
407	ret = True;
408
409 out:
410	if (response)
411		ippDelete(response);
412
413	if (language)
414		cupsLangFree(language);
415
416	if (http)
417		httpClose(http);
418
419	return ret;
420}
421
422
423/*
424 * 'iprint_job_delete()' - Delete a job.
425 */
426
427static int iprint_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
428{
429	int		ret = 1;		/* Return value */
430	http_t		*http = NULL;		/* HTTP connection to server */
431	ipp_t		*request = NULL,	/* IPP Request */
432			*response = NULL;	/* IPP Response */
433	cups_lang_t	*language = NULL;	/* Default language */
434	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
435	char		httpPath[HTTP_MAX_URI];	/* path portion of the printer-uri */
436
437
438	DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
439
440       /*
441	* Make sure we don't ask for passwords...
442	*/
443
444	cupsSetPasswordCB(iprint_passwd_cb);
445
446       /*
447	* Try to connect to the server...
448	*/
449
450	if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
451		DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
452			 iprint_server(), strerror(errno)));
453		goto out;
454	}
455
456       /*
457	* Build an IPP_CANCEL_JOB request, which uses the following
458	* attributes:
459	*
460	*    attributes-charset
461	*    attributes-natural-language
462	*    printer-uri
463	*    job-id
464	*    requesting-user-name
465	*/
466
467	request = ippNew();
468
469	request->request.op.operation_id = IPP_CANCEL_JOB;
470	request->request.op.request_id   = 1;
471
472	language = cupsLangDefault();
473
474	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
475	             "attributes-charset", NULL, "utf-8");
476
477	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
478	             "attributes-natural-language", NULL, language->language);
479
480	slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename);
481
482	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
483
484	ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
485
486	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
487	             NULL, pjob->user);
488
489       /*
490	* Do the request and get back a response...
491	*/
492
493	slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", sharename);
494
495	if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
496		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
497			DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
498				ippErrorString(cupsLastError())));
499		} else {
500			ret = 0;
501		}
502	} else {
503		DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
504			ippErrorString(cupsLastError())));
505	}
506
507 out:
508	if (response)
509		ippDelete(response);
510
511	if (language)
512		cupsLangFree(language);
513
514	if (http)
515		httpClose(http);
516
517	return ret;
518}
519
520
521/*
522 * 'iprint_job_pause()' - Pause a job.
523 */
524
525static int iprint_job_pause(int snum, struct printjob *pjob)
526{
527	int		ret = 1;		/* Return value */
528	http_t		*http = NULL;		/* HTTP connection to server */
529	ipp_t		*request = NULL,	/* IPP Request */
530			*response = NULL;	/* IPP Response */
531	cups_lang_t	*language = NULL;	/* Default language */
532	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
533	char		httpPath[HTTP_MAX_URI];	/* path portion of the printer-uri */
534
535
536	DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
537
538       /*
539	* Make sure we don't ask for passwords...
540	*/
541
542	cupsSetPasswordCB(iprint_passwd_cb);
543
544       /*
545	* Try to connect to the server...
546	*/
547
548	if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
549		DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
550			 iprint_server(), strerror(errno)));
551		goto out;
552	}
553
554       /*
555	* Build an IPP_HOLD_JOB request, which requires the following
556	* attributes:
557	*
558	*    attributes-charset
559	*    attributes-natural-language
560	*    printer-uri
561	*    job-id
562	*    requesting-user-name
563	*/
564
565	request = ippNew();
566
567	request->request.op.operation_id = IPP_HOLD_JOB;
568	request->request.op.request_id   = 1;
569
570	language = cupsLangDefault();
571
572	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
573	             "attributes-charset", NULL, "utf-8");
574
575	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
576	             "attributes-natural-language", NULL, language->language);
577
578	slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
579
580	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
581
582	ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
583
584	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
585	             NULL, pjob->user);
586
587       /*
588	* Do the request and get back a response...
589	*/
590
591	slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum));
592
593	if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
594		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
595			DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
596				ippErrorString(cupsLastError())));
597		} else {
598			ret = 0;
599		}
600	} else {
601		DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
602			ippErrorString(cupsLastError())));
603	}
604
605 out:
606	if (response)
607		ippDelete(response);
608
609	if (language)
610		cupsLangFree(language);
611
612	if (http)
613		httpClose(http);
614
615	return ret;
616}
617
618
619/*
620 * 'iprint_job_resume()' - Resume a paused job.
621 */
622
623static int iprint_job_resume(int snum, struct printjob *pjob)
624{
625	int		ret = 1;		/* Return value */
626	http_t		*http = NULL;		/* HTTP connection to server */
627	ipp_t		*request = NULL,	/* IPP Request */
628			*response = NULL;	/* IPP Response */
629	cups_lang_t	*language = NULL;	/* Default language */
630	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
631	char		httpPath[HTTP_MAX_URI];	/* path portion of the printer-uri */
632
633
634	DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
635
636       /*
637	* Make sure we don't ask for passwords...
638	*/
639
640	cupsSetPasswordCB(iprint_passwd_cb);
641
642       /*
643	* Try to connect to the server...
644	*/
645
646	if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
647		DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
648			 iprint_server(), strerror(errno)));
649		goto out;
650	}
651
652       /*
653	* Build an IPP_RELEASE_JOB request, which requires the following
654	* attributes:
655	*
656	*    attributes-charset
657	*    attributes-natural-language
658	*    printer-uri
659	*    job-id
660	*    requesting-user-name
661	*/
662
663	request = ippNew();
664
665	request->request.op.operation_id = IPP_RELEASE_JOB;
666	request->request.op.request_id   = 1;
667
668	language = cupsLangDefault();
669
670	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
671	             "attributes-charset", NULL, "utf-8");
672
673	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
674	             "attributes-natural-language", NULL, language->language);
675
676	slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
677
678	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
679
680	ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob);
681
682	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
683	             NULL, pjob->user);
684
685       /*
686	* Do the request and get back a response...
687	*/
688
689	slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum));
690
691	if ((response = cupsDoRequest(http, request, httpPath)) != NULL) {
692		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
693			DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
694				ippErrorString(cupsLastError())));
695		} else {
696			ret = 0;
697		}
698	} else {
699		DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
700			ippErrorString(cupsLastError())));
701	}
702
703 out:
704	if (response)
705		ippDelete(response);
706
707	if (language)
708		cupsLangFree(language);
709
710	if (http)
711		httpClose(http);
712
713	return ret;
714}
715
716
717/*
718 * 'iprint_job_submit()' - Submit a job for printing.
719 */
720
721static int iprint_job_submit(int snum, struct printjob *pjob)
722{
723	int		ret = 1;		/* Return value */
724	http_t		*http = NULL;		/* HTTP connection to server */
725	ipp_t		*request = NULL,	/* IPP Request */
726			*response = NULL;	/* IPP Response */
727	ipp_attribute_t	*attr;		/* Current attribute */
728	cups_lang_t	*language = NULL;	/* Default language */
729	char		uri[HTTP_MAX_URI]; /* printer-uri attribute */
730	char 		*clientname = NULL; 	/* hostname of client for job-originating-host attribute */
731
732	DEBUG(5,("iprint_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
733
734       /*
735	* Make sure we don't ask for passwords...
736	*/
737
738	cupsSetPasswordCB(iprint_passwd_cb);
739
740       /*
741	* Try to connect to the server...
742	*/
743
744	if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
745		DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
746			 iprint_server(), strerror(errno)));
747		goto out;
748	}
749
750       /*
751	* Build an IPP_PRINT_JOB request, which requires the following
752	* attributes:
753	*
754	*    attributes-charset
755	*    attributes-natural-language
756	*    printer-uri
757	*    requesting-user-name
758	*    [document-data]
759	*/
760
761	request = ippNew();
762
763	request->request.op.operation_id = IPP_PRINT_JOB;
764	request->request.op.request_id   = 1;
765
766	language = cupsLangDefault();
767
768	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
769	             "attributes-charset", NULL, "utf-8");
770
771	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
772	             "attributes-natural-language", NULL, language->language);
773
774	slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum));
775
776	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
777	             "printer-uri", NULL, uri);
778
779	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
780	             NULL, pjob->user);
781
782	clientname = client_name();
783	if (strcmp(clientname, "UNKNOWN") == 0) {
784		clientname = client_addr();
785	}
786
787	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
788	             "job-originating-host-name", NULL,
789	             clientname);
790
791	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
792	             pjob->jobname);
793
794       /*
795	* Do the request and get back a response...
796	*/
797
798	slprintf(uri, sizeof(uri) - 1, "/ipp/%s", PRINTERNAME(snum));
799
800	if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
801		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
802			DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
803			         ippErrorString(cupsLastError())));
804		} else {
805			ret = 0;
806		}
807	} else {
808		DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
809			 ippErrorString(cupsLastError())));
810	}
811
812	if ( ret == 0 )
813		unlink(pjob->filename);
814	/* else print_job_end will do it for us */
815
816	if ( ret == 0 ) {
817
818		attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
819		if (attr != NULL && attr->group_tag == IPP_TAG_JOB)
820		{
821			pjob->sysjob = attr->values[0].integer;
822		}
823	}
824
825 out:
826	if (response)
827		ippDelete(response);
828
829	if (language)
830		cupsLangFree(language);
831
832	if (http)
833		httpClose(http);
834
835	return ret;
836}
837
838/*
839 * 'iprint_queue_get()' - Get all the jobs in the print queue.
840 */
841
842static int iprint_queue_get(const char *sharename,
843			    enum printing_types printing_type,
844			    char *lpq_command,
845			    print_queue_struct **q,
846			    print_status_struct *status)
847{
848	fstring		printername;
849	http_t		*http = NULL;		/* HTTP connection to server */
850	ipp_t		*request = NULL,	/* IPP Request */
851			*response = NULL;	/* IPP Response */
852	ipp_attribute_t	*attr = NULL;		/* Current attribute */
853	cups_lang_t	*language = NULL;	/* Default language */
854	char		uri[HTTP_MAX_URI]; /* printer-uri attribute */
855	char		serviceUri[HTTP_MAX_URI]; /* service-uri attribute */
856	char		httpPath[HTTP_MAX_URI];	/* path portion of the uri */
857	int		jobUseUnixTime = 0;	/* Whether job times should
858                                                 * be assumed to be Unix time */
859	int		qcount = 0,		/* Number of active queue entries */
860			qalloc = 0;		/* Number of queue entries allocated */
861	print_queue_struct *queue = NULL,	/* Queue entries */
862			*temp;		/* Temporary pointer for queue */
863	const char	*user_name,	/* job-originating-user-name attribute */
864			*job_name;	/* job-name attribute */
865	int		job_id;		/* job-id attribute */
866	int		job_k_octets;	/* job-k-octets attribute */
867	time_t		job_time;	/* time-at-creation attribute */
868	time_t		printer_current_time = 0;	/* printer's current time */
869	time_t		printer_up_time = 0;	/* printer's uptime */
870	ipp_jstate_t	job_status;	/* job-status attribute */
871	int		job_priority;	/* job-priority attribute */
872	static const char *jattrs[] =	/* Requested job attributes */
873			{
874			  "job-id",
875			  "job-k-octets",
876			  "job-name",
877			  "job-originating-user-name",
878			  "job-priority",
879			  "job-state",
880			  "time-at-creation",
881			};
882	static const char *pattrs[] =	/* Requested printer attributes */
883			{
884			  "printer-state",
885			  "printer-state-message",
886			  "printer-current-time",
887			  "printer-up-time"
888			};
889
890	*q = NULL;
891
892	/* HACK ALERT!!!  The porblem with support the 'printer name'
893	   option is that we key the tdb off the sharename.  So we will
894	   overload the lpq_command string to pass in the printername
895	   (which is basically what we do for non-cups printers ... using
896	   the lpq_command to get the queue listing). */
897
898	fstrcpy( printername, lpq_command );
899
900	DEBUG(5,("iprint_queue_get(%s, %p, %p)\n", printername, q, status));
901
902       /*
903	* Make sure we don't ask for passwords...
904	*/
905
906	cupsSetPasswordCB(iprint_passwd_cb);
907
908       /*
909	* Try to connect to the server...
910	*/
911
912	if ((http = httpConnect(iprint_server(), ippPort())) == NULL) {
913		DEBUG(0,("Unable to connect to iPrint server %s - %s\n",
914			 iprint_server(), strerror(errno)));
915		goto out;
916	}
917
918       /*
919	* Generate the printer URI and the service URI that goes with it...
920	*/
921
922	slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), printername);
923	slprintf(serviceUri, sizeof(serviceUri) - 1, "ipp://%s/ipp/", iprint_server());
924
925       /*
926	* For Linux iPrint servers from OES SP1 on, the iPrint server
927	* uses Unix time for job start times unless it detects the iPrint
928	* client in an http User-Agent header.  (This was done to accomodate
929	* CUPS broken behavior.  According to RFC 2911, section 4.3.14, job
930	* start times are supposed to be relative to how long the printer has
931	* been up.)  Since libcups doesn't allow us to set that header before
932	* the request is sent, this ugly hack allows us to detect the server
933	* version and decide how to interpret the job time.
934	*/
935	if (iprint_get_server_version(http, serviceUri) >=
936	    NOVELL_SERVER_VERSION_OES_SP1)
937		jobUseUnixTime = 1;
938
939	request = ippNew();
940
941	request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
942	request->request.op.request_id   = 2;
943
944	language = cupsLangDefault();
945
946	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
947	             "attributes-charset", NULL, "utf-8");
948
949	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
950	             "attributes-natural-language", NULL, language->language);
951
952	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
953	             "printer-uri", NULL, uri);
954
955	ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
956	              "requested-attributes",
957	              (sizeof(pattrs) / sizeof(pattrs[0])),
958	              NULL, pattrs);
959
960       /*
961	* Do the request and get back a response...
962	*/
963
964	slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
965
966	if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
967		DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
968			 ippErrorString(cupsLastError())));
969		*q = queue;
970		goto out;
971	}
972
973	if (response->request.status.status_code >= IPP_OK_CONFLICT) {
974		DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
975			 ippErrorString(response->request.status.status_code)));
976		*q = queue;
977		goto out;
978	}
979
980       /*
981	* Get the current printer status and convert it to the SAMBA values.
982	*/
983
984	if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
985		if (attr->values[0].integer == IPP_PRINTER_STOPPED)
986			status->status = LPSTAT_STOPPED;
987		else
988			status->status = LPSTAT_OK;
989	}
990
991	if ((attr = ippFindAttribute(response, "printer-state-message",
992	                             IPP_TAG_TEXT)) != NULL)
993		fstrcpy(status->message, attr->values[0].string.text);
994
995	if ((attr = ippFindAttribute(response, "printer-current-time",
996	                             IPP_TAG_DATE)) != NULL)
997		printer_current_time = ippDateToTime(attr->values[0].date);
998
999	if ((attr = ippFindAttribute(response, "printer-up-time",
1000	                             IPP_TAG_INTEGER)) != NULL)
1001		printer_up_time = attr->values[0].integer;
1002
1003	ippDelete(response);
1004	response = NULL;
1005
1006       /*
1007	* Build an IPP_GET_JOBS request, which requires the following
1008	* attributes:
1009	*
1010	*    attributes-charset
1011	*    attributes-natural-language
1012	*    requested-attributes
1013	*    printer-uri
1014	*/
1015
1016	request = ippNew();
1017
1018	request->request.op.operation_id = IPP_GET_JOBS;
1019	request->request.op.request_id   = 3;
1020
1021	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1022	             "attributes-charset", NULL, "utf-8");
1023
1024	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1025	             "attributes-natural-language", NULL, language->language);
1026
1027	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1028	             "printer-uri", NULL, uri);
1029
1030	ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1031	              "requested-attributes",
1032	              (sizeof(jattrs) / sizeof(jattrs[0])),
1033	              NULL, jattrs);
1034
1035       /*
1036	* Do the request and get back a response...
1037	*/
1038
1039	slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername);
1040
1041	if ((response = cupsDoRequest(http, request, httpPath)) == NULL) {
1042		DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1043			 ippErrorString(cupsLastError())));
1044		goto out;
1045	}
1046
1047	if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1048		DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1049			 ippErrorString(response->request.status.status_code)));
1050		goto out;
1051	}
1052
1053       /*
1054	* Process the jobs...
1055	*/
1056
1057	qcount = 0;
1058	qalloc = 0;
1059	queue  = NULL;
1060
1061	for (attr = response->attrs; attr != NULL; attr = attr->next) {
1062	       /*
1063		* Skip leading attributes until we hit a job...
1064		*/
1065
1066		while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1067			attr = attr->next;
1068
1069		if (attr == NULL)
1070			break;
1071
1072	       /*
1073		* Allocate memory as needed...
1074		*/
1075		if (qcount >= qalloc) {
1076			qalloc += 16;
1077
1078			queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1079
1080			if (queue == NULL) {
1081				DEBUG(0,("iprint_queue_get: Not enough memory!"));
1082				qcount = 0;
1083				goto out;
1084			}
1085		}
1086
1087		temp = queue + qcount;
1088		memset(temp, 0, sizeof(print_queue_struct));
1089
1090	       /*
1091		* Pull the needed attributes from this job...
1092		*/
1093
1094		job_id       = 0;
1095		job_priority = 50;
1096		job_status   = IPP_JOB_PENDING;
1097		job_time     = 0;
1098		job_k_octets = 0;
1099		user_name    = NULL;
1100		job_name     = NULL;
1101
1102		while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1103			if (attr->name == NULL) {
1104				attr = attr->next;
1105				break;
1106			}
1107
1108			if (strcmp(attr->name, "job-id") == 0 &&
1109			    attr->value_tag == IPP_TAG_INTEGER)
1110				job_id = attr->values[0].integer;
1111
1112			if (strcmp(attr->name, "job-k-octets") == 0 &&
1113			    attr->value_tag == IPP_TAG_INTEGER)
1114				job_k_octets = attr->values[0].integer;
1115
1116			if (strcmp(attr->name, "job-priority") == 0 &&
1117			    attr->value_tag == IPP_TAG_INTEGER)
1118				job_priority = attr->values[0].integer;
1119
1120			if (strcmp(attr->name, "job-state") == 0 &&
1121			    attr->value_tag == IPP_TAG_ENUM)
1122				job_status = (ipp_jstate_t)(attr->values[0].integer);
1123
1124			if (strcmp(attr->name, "time-at-creation") == 0 &&
1125			    attr->value_tag == IPP_TAG_INTEGER)
1126			{
1127			       /*
1128				* If jobs times are in Unix time, the accuracy of the job
1129				* start time depends upon the iPrint server's time being
1130				* set correctly.  Otherwise, the accuracy depends upon
1131				* the Samba server's time being set correctly
1132				*/
1133
1134				if (jobUseUnixTime)
1135					job_time = attr->values[0].integer;
1136				else
1137					job_time = time(NULL) - printer_up_time + attr->values[0].integer;
1138			}
1139
1140			if (strcmp(attr->name, "job-name") == 0 &&
1141			    (attr->value_tag == IPP_TAG_NAMELANG ||
1142			     attr->value_tag == IPP_TAG_NAME))
1143				job_name = attr->values[0].string.text;
1144
1145			if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1146			    (attr->value_tag == IPP_TAG_NAMELANG ||
1147			     attr->value_tag == IPP_TAG_NAME))
1148				user_name = attr->values[0].string.text;
1149
1150			attr = attr->next;
1151		}
1152
1153	       /*
1154		* See if we have everything needed...
1155		*/
1156
1157		if (user_name == NULL || job_name == NULL || job_id == 0) {
1158			if (attr == NULL)
1159				break;
1160			else
1161				continue;
1162		}
1163
1164		temp->job      = job_id;
1165		temp->size     = job_k_octets * 1024;
1166		temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1167		                 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1168                                 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1169                                 LPQ_PRINTING;
1170		temp->priority = job_priority;
1171		temp->time     = job_time;
1172		strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
1173		strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
1174
1175		qcount ++;
1176
1177		if (attr == NULL)
1178			break;
1179	}
1180
1181       /*
1182	* Return the job queue...
1183	*/
1184
1185	*q = queue;
1186
1187 out:
1188	if (response)
1189		ippDelete(response);
1190
1191	if (language)
1192		cupsLangFree(language);
1193
1194	if (http)
1195		httpClose(http);
1196
1197	return qcount;
1198}
1199
1200
1201/*
1202 * 'iprint_queue_pause()' - Pause a print queue.
1203 */
1204
1205static int iprint_queue_pause(int snum)
1206{
1207	return(-1); /* Not supported without credentials */
1208}
1209
1210
1211/*
1212 * 'iprint_queue_resume()' - Restart a print queue.
1213 */
1214
1215static int iprint_queue_resume(int snum)
1216{
1217	return(-1); /* Not supported without credentials */
1218}
1219
1220/*******************************************************************
1221 * iPrint printing interface definitions...
1222 ******************************************************************/
1223
1224struct printif	iprint_printif =
1225{
1226	PRINT_IPRINT,
1227	iprint_queue_get,
1228	iprint_queue_pause,
1229	iprint_queue_resume,
1230	iprint_job_delete,
1231	iprint_job_pause,
1232	iprint_job_resume,
1233	iprint_job_submit,
1234};
1235
1236#else
1237 /* this keeps fussy compilers happy */
1238 void print_iprint_dummy(void);
1239 void print_iprint_dummy(void) {}
1240#endif /* HAVE_IPRINT */
1241