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