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