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