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