allow users to delete jobs with cups printing backend
[ddiss/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         char            *clientname;    /* hostname of client for job-originating-host attribute */
684         pstring         new_jobname;
685
686         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
687
688        /*
689         * Make sure we don't ask for passwords...
690         */
691
692         cupsSetPasswordCB(cups_passwd_cb);
693
694        /*
695         * Try to connect to the server...
696         */
697
698         if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
699         {
700                 DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
701                          cupsServer(), strerror(errno)));
702                 return (1);
703         }
704
705        /*
706         * Build an IPP_PRINT_JOB request, which requires the following
707         * attributes:
708         *
709         *    attributes-charset
710         *    attributes-natural-language
711         *    printer-uri
712         *    requesting-user-name
713         *    [document-data]
714         */
715
716         request = ippNew();
717
718         request->request.op.operation_id = IPP_PRINT_JOB;
719         request->request.op.request_id   = 1;
720
721         language = cupsLangDefault();
722
723         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
724                      "attributes-charset", NULL, cupsLangEncoding(language));
725
726         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
727                      "attributes-natural-language", NULL, language->language);
728
729         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
730                  PRINTERNAME(snum));
731
732         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
733                      "printer-uri", NULL, uri);
734
735         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
736                      NULL, pjob->user);
737
738         clientname = client_name();
739         if (strcmp(clientname, "UNKNOWN") == 0) {
740                 clientname = client_addr();
741         }
742
743         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
744                      "job-originating-host-name", NULL,
745                       clientname);
746
747         pstr_sprintf(new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX, 
748                 (unsigned int)pjob->smbjob, pjob->jobname);
749
750         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
751                      new_jobname);
752
753        /*
754         * Do the request and get back a response...
755         */
756
757         slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
758
759         ret = 1;
760         if ((response = cupsDoFileRequest(http, request, uri,
761                                           pjob->filename)) != NULL)
762         {
763                 if (response->request.status.status_code >= IPP_OK_CONFLICT)
764                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
765                                  ippErrorString(cupsLastError())));
766                 else
767                         ret = 0;
768
769                 ippDelete(response);
770         }
771         else
772                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
773                          ippErrorString(cupsLastError())));
774
775         httpClose(http);
776
777         if ( ret == 0 )
778                 unlink(pjob->filename);
779         /* else print_job_end will do it for us */
780
781         return (ret);
782 }
783
784
785 /*
786  * 'cups_queue_get()' - Get all the jobs in the print queue.
787  */
788
789 static int
790 cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
791 {
792         http_t          *http;          /* HTTP connection to server */
793         ipp_t           *request,       /* IPP Request */
794                         *response;      /* IPP Response */
795         ipp_attribute_t *attr;          /* Current attribute */
796         cups_lang_t     *language;      /* Default language */
797         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
798         int             qcount,         /* Number of active queue entries */
799                         qalloc;         /* Number of queue entries allocated */
800         print_queue_struct *queue,      /* Queue entries */
801                         *temp;          /* Temporary pointer for queue */
802         const char      *user_name,     /* job-originating-user-name attribute */
803                         *job_name;      /* job-name attribute */
804         int             job_id;         /* job-id attribute */
805         int             job_k_octets;   /* job-k-octets attribute */
806         time_t          job_time;       /* time-at-creation attribute */
807         ipp_jstate_t    job_status;     /* job-status attribute */
808         int             job_priority;   /* job-priority attribute */
809         static const char *jattrs[] =   /* Requested job attributes */
810                         {
811                           "job-id",
812                           "job-k-octets",
813                           "job-name",
814                           "job-originating-user-name",
815                           "job-priority",
816                           "job-state",
817                           "time-at-creation",
818                         };
819         static const char *pattrs[] =   /* Requested printer attributes */
820                         {
821                           "printer-state",
822                           "printer-state-message"
823                         };
824
825
826         DEBUG(5,("cups_queue_get(%d, %p, %p)\n", snum, q, status));
827
828        /*
829         * Make sure we don't ask for passwords...
830         */
831
832         cupsSetPasswordCB(cups_passwd_cb);
833
834        /*
835         * Try to connect to the server...
836         */
837
838         if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
839         {
840                 DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
841                          cupsServer(), strerror(errno)));
842                 return (0);
843         }
844
845        /*
846         * Generate the printer URI...
847         */
848
849         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
850                  PRINTERNAME(snum));
851
852        /*
853         * Build an IPP_GET_JOBS request, which requires the following
854         * attributes:
855         *
856         *    attributes-charset
857         *    attributes-natural-language
858         *    requested-attributes
859         *    printer-uri
860         */
861
862         request = ippNew();
863
864         request->request.op.operation_id = IPP_GET_JOBS;
865         request->request.op.request_id   = 1;
866
867         language = cupsLangDefault();
868
869         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
870                      "attributes-charset", NULL, cupsLangEncoding(language));
871
872         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
873                      "attributes-natural-language", NULL, language->language);
874
875         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
876                       "requested-attributes",
877                       (sizeof(jattrs) / sizeof(jattrs[0])),
878                       NULL, jattrs);
879
880         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
881                      "printer-uri", NULL, uri);
882
883        /*
884         * Do the request and get back a response...
885         */
886
887         if ((response = cupsDoRequest(http, request, "/")) == NULL)
888         {
889                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
890                          ippErrorString(cupsLastError())));
891                 httpClose(http);
892                 return (0);
893         }
894
895         if (response->request.status.status_code >= IPP_OK_CONFLICT)
896         {
897                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
898                          ippErrorString(response->request.status.status_code)));
899                 ippDelete(response);
900                 httpClose(http);
901
902                 return (0);
903         }
904
905        /*
906         * Process the jobs...
907         */
908
909         qcount = 0;
910         qalloc = 0;
911         queue  = NULL;
912
913         for (attr = response->attrs; attr != NULL; attr = attr->next)
914         {
915                /*
916                 * Skip leading attributes until we hit a job...
917                 */
918
919                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
920                         attr = attr->next;
921
922                 if (attr == NULL)
923                         break;
924
925                /*
926                 * Allocate memory as needed...
927                 */
928                 if (qcount >= qalloc)
929                 {
930                         qalloc += 16;
931
932                         temp = Realloc(queue, sizeof(print_queue_struct) * qalloc);
933
934                         if (temp == NULL)
935                         {
936                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
937                                 ippDelete(response);
938                                 httpClose(http);
939
940                                 SAFE_FREE(queue);
941                                 return (0);
942                         }
943
944                         queue = temp;
945                 }
946
947                 temp = queue + qcount;
948                 memset(temp, 0, sizeof(print_queue_struct));
949
950                /*
951                 * Pull the needed attributes from this job...
952                 */
953
954                 job_id       = 0;
955                 job_priority = 50;
956                 job_status   = IPP_JOB_PENDING;
957                 job_time     = 0;
958                 job_k_octets = 0;
959                 user_name    = NULL;
960                 job_name     = NULL;
961
962                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
963                 {
964                         if (attr->name == NULL)
965                         {
966                                 attr = attr->next;
967                                 break;
968                         }
969
970                         if (strcmp(attr->name, "job-id") == 0 &&
971                             attr->value_tag == IPP_TAG_INTEGER)
972                                 job_id = attr->values[0].integer;
973
974                         if (strcmp(attr->name, "job-k-octets") == 0 &&
975                             attr->value_tag == IPP_TAG_INTEGER)
976                                 job_k_octets = attr->values[0].integer;
977
978                         if (strcmp(attr->name, "job-priority") == 0 &&
979                             attr->value_tag == IPP_TAG_INTEGER)
980                                 job_priority = attr->values[0].integer;
981
982                         if (strcmp(attr->name, "job-state") == 0 &&
983                             attr->value_tag == IPP_TAG_ENUM)
984                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
985
986                         if (strcmp(attr->name, "time-at-creation") == 0 &&
987                             attr->value_tag == IPP_TAG_INTEGER)
988                                 job_time = attr->values[0].integer;
989
990                         if (strcmp(attr->name, "job-name") == 0 &&
991                             attr->value_tag == IPP_TAG_NAME)
992                                 job_name = attr->values[0].string.text;
993
994                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
995                             attr->value_tag == IPP_TAG_NAME)
996                                 user_name = attr->values[0].string.text;
997
998                         attr = attr->next;
999                 }
1000
1001                /*
1002                 * See if we have everything needed...
1003                 */
1004
1005                 if (user_name == NULL || job_name == NULL || job_id == 0)
1006                 {
1007                   if (attr == NULL)
1008                     break;
1009                   else
1010                     continue;
1011                 }
1012
1013                 temp->job      = job_id;
1014                 temp->size     = job_k_octets * 1024;
1015                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1016                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1017                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1018                                  LPQ_PRINTING;
1019                 temp->priority = job_priority;
1020                 temp->time     = job_time;
1021                 strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
1022                 strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
1023
1024                 qcount ++;
1025
1026                 if (attr == NULL)
1027                   break;
1028         }
1029
1030         ippDelete(response);
1031
1032        /*
1033         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1034         * following attributes:
1035         *
1036         *    attributes-charset
1037         *    attributes-natural-language
1038         *    requested-attributes
1039         *    printer-uri
1040         */
1041
1042         request = ippNew();
1043
1044         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1045         request->request.op.request_id   = 1;
1046
1047         language = cupsLangDefault();
1048
1049         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1050                      "attributes-charset", NULL, cupsLangEncoding(language));
1051
1052         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1053                      "attributes-natural-language", NULL, language->language);
1054
1055         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1056                       "requested-attributes",
1057                       (sizeof(pattrs) / sizeof(pattrs[0])),
1058                       NULL, pattrs);
1059
1060         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1061                      "printer-uri", NULL, uri);
1062
1063        /*
1064         * Do the request and get back a response...
1065         */
1066
1067         if ((response = cupsDoRequest(http, request, "/")) == NULL)
1068         {
1069                 DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum),
1070                          ippErrorString(cupsLastError())));
1071                 httpClose(http);
1072                 *q = queue;
1073                 return (qcount);
1074         }
1075
1076         if (response->request.status.status_code >= IPP_OK_CONFLICT)
1077         {
1078                 DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum),
1079                          ippErrorString(response->request.status.status_code)));
1080                 ippDelete(response);
1081                 httpClose(http);
1082                 *q = queue;
1083                 return (qcount);
1084         }
1085
1086        /*
1087         * Get the current printer status and convert it to the SAMBA values.
1088         */
1089
1090         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
1091         {
1092                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1093                         status->status = LPSTAT_STOPPED;
1094                 else
1095                         status->status = LPSTAT_OK;
1096         }
1097
1098         if ((attr = ippFindAttribute(response, "printer-state-message",
1099                                      IPP_TAG_TEXT)) != NULL)
1100                 fstrcpy(status->message, attr->values[0].string.text);
1101
1102         ippDelete(response);
1103
1104        /*
1105         * Return the job queue...
1106         */
1107
1108         httpClose(http);
1109
1110         *q = queue;
1111         return (qcount);
1112 }
1113
1114
1115 /*
1116  * 'cups_queue_pause()' - Pause a print queue.
1117  */
1118
1119 static int
1120 cups_queue_pause(int snum)
1121 {
1122         extern userdom_struct current_user_info;
1123         int             ret;            /* Return value */
1124         http_t          *http;          /* HTTP connection to server */
1125         ipp_t           *request,       /* IPP Request */
1126                         *response;      /* IPP Response */
1127         cups_lang_t     *language;      /* Default language */
1128         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1129
1130
1131         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1132
1133         /*
1134          * Make sure we don't ask for passwords...
1135          */
1136
1137         cupsSetPasswordCB(cups_passwd_cb);
1138
1139         /*
1140          * Try to connect to the server...
1141          */
1142
1143         if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
1144         {
1145                 DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
1146                          cupsServer(), strerror(errno)));
1147                 return (1);
1148         }
1149
1150         /*
1151          * Build an IPP_PAUSE_PRINTER request, which requires the following
1152          * attributes:
1153          *
1154          *    attributes-charset
1155          *    attributes-natural-language
1156          *    printer-uri
1157          *    requesting-user-name
1158          */
1159
1160         request = ippNew();
1161
1162         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1163         request->request.op.request_id   = 1;
1164
1165         language = cupsLangDefault();
1166
1167         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1168                      "attributes-charset", NULL, cupsLangEncoding(language));
1169
1170         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1171                      "attributes-natural-language", NULL, language->language);
1172
1173         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1174                  PRINTERNAME(snum));
1175
1176         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1177
1178         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1179                      NULL, current_user_info.unix_name);
1180
1181        /*
1182         * Do the request and get back a response...
1183         */
1184
1185         ret = 1;
1186
1187         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
1188         {
1189           if (response->request.status.status_code >= IPP_OK_CONFLICT)
1190                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1191                          ippErrorString(cupsLastError())));
1192           else
1193                 ret = 0;
1194
1195           ippDelete(response);
1196         }
1197         else
1198           DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1199                    ippErrorString(cupsLastError())));
1200
1201         httpClose(http);
1202
1203         return (ret);
1204 }
1205
1206
1207 /*
1208  * 'cups_queue_resume()' - Restart a print queue.
1209  */
1210
1211 static int
1212 cups_queue_resume(int snum)
1213 {
1214         extern userdom_struct current_user_info;
1215         int             ret;            /* Return value */
1216         http_t          *http;          /* HTTP connection to server */
1217         ipp_t           *request,       /* IPP Request */
1218                         *response;      /* IPP Response */
1219         cups_lang_t     *language;      /* Default language */
1220         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1221
1222
1223         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1224
1225        /*
1226         * Make sure we don't ask for passwords...
1227         */
1228
1229         cupsSetPasswordCB(cups_passwd_cb);
1230
1231        /*
1232         * Try to connect to the server...
1233         */
1234
1235         if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
1236         {
1237                 DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
1238                          cupsServer(), strerror(errno)));
1239                 return (1);
1240         }
1241
1242        /*
1243         * Build an IPP_RESUME_PRINTER request, which requires the following
1244         * attributes:
1245         *
1246         *    attributes-charset
1247         *    attributes-natural-language
1248         *    printer-uri
1249         *    requesting-user-name
1250         */
1251
1252         request = ippNew();
1253
1254         request->request.op.operation_id = IPP_RESUME_PRINTER;
1255         request->request.op.request_id   = 1;
1256
1257         language = cupsLangDefault();
1258
1259         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1260                      "attributes-charset", NULL, cupsLangEncoding(language));
1261
1262         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1263                      "attributes-natural-language", NULL, language->language);
1264
1265         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1266                  PRINTERNAME(snum));
1267
1268         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1269
1270         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1271                      NULL, current_user_info.unix_name);
1272
1273        /*
1274         * Do the request and get back a response...
1275         */
1276
1277         ret = 1;
1278
1279         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
1280         {
1281           if (response->request.status.status_code >= IPP_OK_CONFLICT)
1282                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1283                          ippErrorString(cupsLastError())));
1284           else
1285                 ret = 0;
1286
1287           ippDelete(response);
1288         }
1289         else
1290           DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1291                    ippErrorString(cupsLastError())));
1292
1293         httpClose(http);
1294
1295         return (ret);
1296 }
1297
1298
1299 #else
1300  /* this keeps fussy compilers happy */
1301  void print_cups_dummy(void) {}
1302 #endif /* HAVE_CUPS */