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