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