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