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