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