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