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