RIP BOOL. Convert BOOL -> bool. I found a few interesting
[nivanova/samba-autobuild/.git] / source3 / printing / print_cups.c
1 /*
2  * Support code for the Common UNIX Printing System ("CUPS")
3  *
4  * Copyright 1999-2003 by Michael R Sweet.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 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         pstring         new_jobname;
568         int             num_options = 0; 
569         cups_option_t   *options = NULL;
570
571         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
572
573        /*
574         * Make sure we don't ask for passwords...
575         */
576
577         cupsSetPasswordCB(cups_passwd_cb);
578
579        /*
580         * Try to connect to the server...
581         */
582
583         if ((http = cups_connect()) == NULL) {
584                 goto out;
585         }
586
587        /*
588         * Build an IPP_PRINT_JOB request, which requires the following
589         * attributes:
590         *
591         *    attributes-charset
592         *    attributes-natural-language
593         *    printer-uri
594         *    requesting-user-name
595         *    [document-data]
596         */
597
598         request = ippNew();
599
600         request->request.op.operation_id = IPP_PRINT_JOB;
601         request->request.op.request_id   = 1;
602
603         language = cupsLangDefault();
604
605         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
606                      "attributes-charset", NULL, cupsLangEncoding(language));
607
608         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
609                      "attributes-natural-language", NULL, language->language);
610
611         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
612                  PRINTERNAME(snum));
613
614         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
615                      "printer-uri", NULL, uri);
616
617         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
618                      NULL, pjob->user);
619
620         clientname = client_name();
621         if (strcmp(clientname, "UNKNOWN") == 0) {
622                 clientname = client_addr();
623         }
624
625         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
626                      "job-originating-host-name", NULL,
627                       clientname);
628
629         pstr_sprintf(new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX, 
630                 (unsigned int)pjob->smbjob, pjob->jobname);
631
632         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
633                      new_jobname);
634
635         /* 
636          * add any options defined in smb.conf 
637          */
638
639         num_options = 0;
640         options     = NULL;
641         num_options = cupsParseOptions(lp_cups_options(snum), num_options, &options);
642
643         if ( num_options )
644                 cupsEncodeOptions(request, num_options, options); 
645
646        /*
647         * Do the request and get back a response...
648         */
649
650         slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
651
652         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
653                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
654                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
655                                  ippErrorString(cupsLastError())));
656                 } else {
657                         ret = 0;
658                 }
659         } else {
660                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
661                          ippErrorString(cupsLastError())));
662         }
663
664         if ( ret == 0 )
665                 unlink(pjob->filename);
666         /* else print_job_end will do it for us */
667
668  out:
669         if (response)
670                 ippDelete(response);
671
672         if (language)
673                 cupsLangFree(language);
674
675         if (http)
676                 httpClose(http);
677
678         return ret;
679 }
680
681 /*
682  * 'cups_queue_get()' - Get all the jobs in the print queue.
683  */
684
685 static int cups_queue_get(const char *sharename,
686                enum printing_types printing_type,
687                char *lpq_command,
688                print_queue_struct **q, 
689                print_status_struct *status)
690 {
691         fstring         printername;
692         http_t          *http = NULL;           /* HTTP connection to server */
693         ipp_t           *request = NULL,        /* IPP Request */
694                         *response = NULL;       /* IPP Response */
695         ipp_attribute_t *attr = NULL;           /* Current attribute */
696         cups_lang_t     *language = NULL;       /* Default language */
697         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
698         int             qcount = 0,             /* Number of active queue entries */
699                         qalloc = 0;             /* Number of queue entries allocated */
700         print_queue_struct *queue = NULL,       /* Queue entries */
701                         *temp;          /* Temporary pointer for queue */
702         const char      *user_name,     /* job-originating-user-name attribute */
703                         *job_name;      /* job-name attribute */
704         int             job_id;         /* job-id attribute */
705         int             job_k_octets;   /* job-k-octets attribute */
706         time_t          job_time;       /* time-at-creation attribute */
707         ipp_jstate_t    job_status;     /* job-status attribute */
708         int             job_priority;   /* job-priority attribute */
709         static const char *jattrs[] =   /* Requested job attributes */
710                         {
711                           "job-id",
712                           "job-k-octets",
713                           "job-name",
714                           "job-originating-user-name",
715                           "job-priority",
716                           "job-state",
717                           "time-at-creation",
718                         };
719         static const char *pattrs[] =   /* Requested printer attributes */
720                         {
721                           "printer-state",
722                           "printer-state-message"
723                         };
724
725         *q = NULL;
726
727         /* HACK ALERT!!!  The problem with support the 'printer name' 
728            option is that we key the tdb off the sharename.  So we will 
729            overload the lpq_command string to pass in the printername 
730            (which is basically what we do for non-cups printers ... using 
731            the lpq_command to get the queue listing). */
732
733         fstrcpy( printername, lpq_command );
734
735         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", printername, q, status));
736
737        /*
738         * Make sure we don't ask for passwords...
739         */
740
741         cupsSetPasswordCB(cups_passwd_cb);
742
743        /*
744         * Try to connect to the server...
745         */
746
747         if ((http = cups_connect()) == NULL) {
748                 goto out;
749         }
750
751        /*
752         * Generate the printer URI...
753         */
754
755         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
756
757        /*
758         * Build an IPP_GET_JOBS request, which requires the following
759         * attributes:
760         *
761         *    attributes-charset
762         *    attributes-natural-language
763         *    requested-attributes
764         *    printer-uri
765         */
766
767         request = ippNew();
768
769         request->request.op.operation_id = IPP_GET_JOBS;
770         request->request.op.request_id   = 1;
771
772         language = cupsLangDefault();
773
774         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
775                      "attributes-charset", NULL, cupsLangEncoding(language));
776
777         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
778                      "attributes-natural-language", NULL, language->language);
779
780         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
781                       "requested-attributes",
782                       (sizeof(jattrs) / sizeof(jattrs[0])),
783                       NULL, jattrs);
784
785         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
786                      "printer-uri", NULL, uri);
787
788        /*
789         * Do the request and get back a response...
790         */
791
792         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
793                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
794                          ippErrorString(cupsLastError())));
795                 goto out;
796         }
797
798         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
799                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
800                          ippErrorString(response->request.status.status_code)));
801                 goto out;
802         }
803
804        /*
805         * Process the jobs...
806         */
807
808         qcount = 0;
809         qalloc = 0;
810         queue  = NULL;
811
812         for (attr = response->attrs; attr != NULL; attr = attr->next) {
813                /*
814                 * Skip leading attributes until we hit a job...
815                 */
816
817                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
818                         attr = attr->next;
819
820                 if (attr == NULL)
821                         break;
822
823                /*
824                 * Allocate memory as needed...
825                 */
826                 if (qcount >= qalloc) {
827                         qalloc += 16;
828
829                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
830
831                         if (queue == NULL) {
832                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
833                                 qcount = 0;
834                                 goto out;
835                         }
836                 }
837
838                 temp = queue + qcount;
839                 memset(temp, 0, sizeof(print_queue_struct));
840
841                /*
842                 * Pull the needed attributes from this job...
843                 */
844
845                 job_id       = 0;
846                 job_priority = 50;
847                 job_status   = IPP_JOB_PENDING;
848                 job_time     = 0;
849                 job_k_octets = 0;
850                 user_name    = NULL;
851                 job_name     = NULL;
852
853                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
854                         if (attr->name == NULL) {
855                                 attr = attr->next;
856                                 break;
857                         }
858
859                         if (strcmp(attr->name, "job-id") == 0 &&
860                             attr->value_tag == IPP_TAG_INTEGER)
861                                 job_id = attr->values[0].integer;
862
863                         if (strcmp(attr->name, "job-k-octets") == 0 &&
864                             attr->value_tag == IPP_TAG_INTEGER)
865                                 job_k_octets = attr->values[0].integer;
866
867                         if (strcmp(attr->name, "job-priority") == 0 &&
868                             attr->value_tag == IPP_TAG_INTEGER)
869                                 job_priority = attr->values[0].integer;
870
871                         if (strcmp(attr->name, "job-state") == 0 &&
872                             attr->value_tag == IPP_TAG_ENUM)
873                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
874
875                         if (strcmp(attr->name, "time-at-creation") == 0 &&
876                             attr->value_tag == IPP_TAG_INTEGER)
877                                 job_time = attr->values[0].integer;
878
879                         if (strcmp(attr->name, "job-name") == 0 &&
880                             attr->value_tag == IPP_TAG_NAME)
881                                 job_name = attr->values[0].string.text;
882
883                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
884                             attr->value_tag == IPP_TAG_NAME)
885                                 user_name = attr->values[0].string.text;
886
887                         attr = attr->next;
888                 }
889
890                /*
891                 * See if we have everything needed...
892                 */
893
894                 if (user_name == NULL || job_name == NULL || job_id == 0) {
895                         if (attr == NULL)
896                                 break;
897                         else
898                                 continue;
899                 }
900
901                 temp->job      = job_id;
902                 temp->size     = job_k_octets * 1024;
903                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
904                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
905                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
906                                  LPQ_PRINTING;
907                 temp->priority = job_priority;
908                 temp->time     = job_time;
909                 strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
910                 strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
911
912                 qcount ++;
913
914                 if (attr == NULL)
915                         break;
916         }
917
918         ippDelete(response);
919         response = NULL;
920
921        /*
922         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
923         * following attributes:
924         *
925         *    attributes-charset
926         *    attributes-natural-language
927         *    requested-attributes
928         *    printer-uri
929         */
930
931         request = ippNew();
932
933         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
934         request->request.op.request_id   = 1;
935
936         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
937                      "attributes-charset", NULL, cupsLangEncoding(language));
938
939         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
940                      "attributes-natural-language", NULL, language->language);
941
942         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
943                       "requested-attributes",
944                       (sizeof(pattrs) / sizeof(pattrs[0])),
945                       NULL, pattrs);
946
947         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
948                      "printer-uri", NULL, uri);
949
950        /*
951         * Do the request and get back a response...
952         */
953
954         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
955                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
956                          ippErrorString(cupsLastError())));
957                 *q = queue;
958                 goto out;
959         }
960
961         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
962                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
963                          ippErrorString(response->request.status.status_code)));
964                 *q = queue;
965                 goto out;
966         }
967
968        /*
969         * Get the current printer status and convert it to the SAMBA values.
970         */
971
972         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
973                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
974                         status->status = LPSTAT_STOPPED;
975                 else
976                         status->status = LPSTAT_OK;
977         }
978
979         if ((attr = ippFindAttribute(response, "printer-state-message",
980                                      IPP_TAG_TEXT)) != NULL)
981                 fstrcpy(status->message, attr->values[0].string.text);
982
983        /*
984         * Return the job queue...
985         */
986
987         *q = queue;
988
989  out:
990         if (response)
991                 ippDelete(response);
992
993         if (language)
994                 cupsLangFree(language);
995
996         if (http)
997                 httpClose(http);
998
999         return qcount;
1000 }
1001
1002
1003 /*
1004  * 'cups_queue_pause()' - Pause a print queue.
1005  */
1006
1007 static int cups_queue_pause(int snum)
1008 {
1009         int             ret = 1;                /* Return value */
1010         http_t          *http = NULL;           /* HTTP connection to server */
1011         ipp_t           *request = NULL,        /* IPP Request */
1012                         *response = NULL;       /* IPP Response */
1013         cups_lang_t     *language = NULL;       /* Default language */
1014         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1015
1016
1017         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1018
1019         /*
1020          * Make sure we don't ask for passwords...
1021          */
1022
1023         cupsSetPasswordCB(cups_passwd_cb);
1024
1025         /*
1026          * Try to connect to the server...
1027          */
1028
1029         if ((http = cups_connect()) == NULL) {
1030                 goto out;
1031         }
1032
1033         /*
1034          * Build an IPP_PAUSE_PRINTER request, which requires the following
1035          * attributes:
1036          *
1037          *    attributes-charset
1038          *    attributes-natural-language
1039          *    printer-uri
1040          *    requesting-user-name
1041          */
1042
1043         request = ippNew();
1044
1045         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1046         request->request.op.request_id   = 1;
1047
1048         language = cupsLangDefault();
1049
1050         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1051                      "attributes-charset", NULL, cupsLangEncoding(language));
1052
1053         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1054                      "attributes-natural-language", NULL, language->language);
1055
1056         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1057                  PRINTERNAME(snum));
1058
1059         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1060
1061         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1062                      NULL, current_user_info.unix_name);
1063
1064        /*
1065         * Do the request and get back a response...
1066         */
1067
1068         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1069                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1070                         DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1071                                 ippErrorString(cupsLastError())));
1072                 } else {
1073                         ret = 0;
1074                 }
1075         } else {
1076                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1077                         ippErrorString(cupsLastError())));
1078         }
1079
1080  out:
1081         if (response)
1082                 ippDelete(response);
1083
1084         if (language)
1085                 cupsLangFree(language);
1086
1087         if (http)
1088                 httpClose(http);
1089
1090         return ret;
1091 }
1092
1093
1094 /*
1095  * 'cups_queue_resume()' - Restart a print queue.
1096  */
1097
1098 static int cups_queue_resume(int snum)
1099 {
1100         int             ret = 1;                /* Return value */
1101         http_t          *http = NULL;           /* HTTP connection to server */
1102         ipp_t           *request = NULL,        /* IPP Request */
1103                         *response = NULL;       /* IPP Response */
1104         cups_lang_t     *language = NULL;       /* Default language */
1105         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1106
1107
1108         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1109
1110        /*
1111         * Make sure we don't ask for passwords...
1112         */
1113
1114         cupsSetPasswordCB(cups_passwd_cb);
1115
1116        /*
1117         * Try to connect to the server...
1118         */
1119
1120         if ((http = cups_connect()) == NULL) {
1121                 goto out;
1122         }
1123
1124        /*
1125         * Build an IPP_RESUME_PRINTER request, which requires the following
1126         * attributes:
1127         *
1128         *    attributes-charset
1129         *    attributes-natural-language
1130         *    printer-uri
1131         *    requesting-user-name
1132         */
1133
1134         request = ippNew();
1135
1136         request->request.op.operation_id = IPP_RESUME_PRINTER;
1137         request->request.op.request_id   = 1;
1138
1139         language = cupsLangDefault();
1140
1141         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1142                      "attributes-charset", NULL, cupsLangEncoding(language));
1143
1144         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1145                      "attributes-natural-language", NULL, language->language);
1146
1147         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1148                  PRINTERNAME(snum));
1149
1150         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1151
1152         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1153                      NULL, current_user_info.unix_name);
1154
1155        /*
1156         * Do the request and get back a response...
1157         */
1158
1159         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1160                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1161                         DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1162                                 ippErrorString(cupsLastError())));
1163                 } else {
1164                         ret = 0;
1165                 }
1166         } else {
1167                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1168                         ippErrorString(cupsLastError())));
1169         }
1170
1171  out:
1172         if (response)
1173                 ippDelete(response);
1174
1175         if (language)
1176                 cupsLangFree(language);
1177
1178         if (http)
1179                 httpClose(http);
1180
1181         return ret;
1182 }
1183
1184 /*******************************************************************
1185  * CUPS printing interface definitions...
1186  ******************************************************************/
1187
1188 struct printif  cups_printif =
1189 {
1190         PRINT_CUPS,
1191         cups_queue_get,
1192         cups_queue_pause,
1193         cups_queue_resume,
1194         cups_job_delete,
1195         cups_job_pause,
1196         cups_job_resume,
1197         cups_job_submit,
1198 };
1199
1200 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1201 {
1202         http_t          *http = NULL;           /* HTTP connection to server */
1203         ipp_t           *request = NULL,        /* IPP Request */
1204                         *response = NULL;       /* IPP Response */
1205         ipp_attribute_t *attr;          /* Current attribute */
1206         cups_lang_t     *language = NULL;       /* Default language */
1207         char            *name,          /* printer-name attribute */
1208                         *info,          /* printer-info attribute */
1209                         *location;      /* printer-location attribute */
1210         char            uri[HTTP_MAX_URI];
1211         static const char *requested[] =/* Requested attributes */
1212                         {
1213                           "printer-name",
1214                           "printer-info",
1215                           "printer-location"
1216                         };
1217         bool ret = False;
1218
1219         DEBUG(5, ("pulling %s location\n", printer->sharename));
1220
1221         /*
1222          * Make sure we don't ask for passwords...
1223          */
1224
1225         cupsSetPasswordCB(cups_passwd_cb);
1226
1227         /*
1228          * Try to connect to the server...
1229          */
1230
1231         if ((http = cups_connect()) == NULL) {
1232                 goto out;
1233         }
1234
1235         request = ippNew();
1236
1237         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1238         request->request.op.request_id   = 1;
1239
1240         language = cupsLangDefault();
1241
1242         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1243                      "attributes-charset", NULL, cupsLangEncoding(language));
1244
1245         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1246                      "attributes-natural-language", NULL, language->language);
1247
1248         slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1249                  lp_cups_server(), printer->sharename);
1250
1251         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1252                      "printer-uri", NULL, uri);
1253
1254         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1255                       "requested-attributes",
1256                       (sizeof(requested) / sizeof(requested[0])),
1257                       NULL, requested);
1258
1259         /*
1260          * Do the request and get back a response...
1261          */
1262
1263         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1264                 DEBUG(0,("Unable to get printer attributes - %s\n",
1265                          ippErrorString(cupsLastError())));
1266                 goto out;
1267         }
1268
1269         for (attr = response->attrs; attr != NULL;) {
1270                 /*
1271                  * Skip leading attributes until we hit a printer...
1272                  */
1273
1274                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1275                         attr = attr->next;
1276
1277                 if (attr == NULL)
1278                         break;
1279
1280                 /*
1281                  * Pull the needed attributes from this printer...
1282                  */
1283
1284                 name       = NULL;
1285                 info       = NULL;
1286                 location   = NULL;
1287
1288                 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1289                         /* Grab the comment if we don't have one */
1290                         if ( (strcmp(attr->name, "printer-info") == 0)
1291                              && (attr->value_tag == IPP_TAG_TEXT)
1292                              && !strlen(printer->comment) ) 
1293                         {
1294                                 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1295                                          attr->values[0].string.text));                         
1296                                 pstrcpy(printer->comment,attr->values[0].string.text);
1297                         }
1298
1299                         /* Grab the location if we don't have one */ 
1300                         if ( (strcmp(attr->name, "printer-location") == 0)
1301                              && (attr->value_tag == IPP_TAG_TEXT) 
1302                              && !strlen(printer->location) )
1303                         {
1304                                 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1305                                          attr->values[0].string.text));                         
1306                                 fstrcpy(printer->location,attr->values[0].string.text);
1307                         }
1308
1309                         attr = attr->next;
1310                 }
1311
1312                 /*
1313                  * See if we have everything needed...
1314                  */
1315
1316                 if (name == NULL)
1317                         break;
1318
1319         }
1320
1321         ret = True;
1322
1323  out:
1324         if (response)
1325                 ippDelete(response);
1326
1327         if (language)
1328                 cupsLangFree(language);
1329
1330         if (http)
1331                 httpClose(http);
1332
1333         return ret;
1334 }
1335
1336 #else
1337  /* this keeps fussy compilers happy */
1338  void print_cups_dummy(void);
1339  void print_cups_dummy(void) {}
1340 #endif /* HAVE_CUPS */