Merge branch 'master' of ssh://git.samba.org/data/git/samba into selftest
[tprouty/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  * Copyright 2008 Jeremy Allison.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /*
22  * JRA. Converted to utf8 pull/push.
23  */
24
25 #include "includes.h"
26 #include "printing.h"
27
28 #ifdef HAVE_CUPS
29 #include <cups/cups.h>
30 #include <cups/language.h>
31
32 static SIG_ATOMIC_T gotalarm;
33
34 /***************************************************************
35  Signal function to tell us we timed out.
36 ****************************************************************/
37
38 static void gotalarm_sig(void)
39 {
40         gotalarm = 1;
41 }
42
43 extern userdom_struct current_user_info;
44
45 /*
46  * 'cups_passwd_cb()' - The CUPS password callback...
47  */
48
49 static const char *                             /* O - Password or NULL */
50 cups_passwd_cb(const char *prompt)      /* I - Prompt */
51 {
52         /*
53          * Always return NULL to indicate that no password is available...
54          */
55
56         return (NULL);
57 }
58
59 static http_t *cups_connect(TALLOC_CTX *frame)
60 {
61         http_t *http = NULL;
62         char *server = NULL, *p = NULL;
63         int port;
64         int timeout = lp_cups_connection_timeout();
65         size_t size;
66
67         if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
68                 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
69                         return NULL;
70                 }
71         } else {
72                 server = talloc_strdup(frame,cupsServer());
73         }
74         if (!server) {
75                 return NULL;
76         }
77
78         p = strchr(server, ':');
79         if (p) {
80                 port = atoi(p+1);
81                 *p = '\0';
82         } else {
83                 port = ippPort();
84         }
85
86         DEBUG(10, ("connecting to cups server %s:%d\n",
87                    server, port));
88
89         gotalarm = 0;
90
91         if (timeout) {
92                 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
93                 alarm(timeout);
94         }
95
96         http = httpConnect(server, port);
97
98         CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
99         alarm(0);
100
101         if (http == NULL) {
102                 DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
103                          server, port, strerror(errno)));
104         }
105
106         return http;
107 }
108
109 static void send_pcap_info(const char *name, const char *info, void *pd)
110 {
111         int fd = *(int *)pd;
112         size_t namelen = name ? strlen(name)+1 : 0;
113         size_t infolen = info ? strlen(info)+1 : 0;
114
115         DEBUG(11,("send_pcap_info: writing namelen %u\n", (unsigned int)namelen));
116         if (sys_write(fd, &namelen, sizeof(namelen)) != sizeof(namelen)) {
117                 DEBUG(10,("send_pcap_info: namelen write failed %s\n",
118                         strerror(errno)));
119                 return;
120         }
121         DEBUG(11,("send_pcap_info: writing infolen %u\n", (unsigned int)infolen));
122         if (sys_write(fd, &infolen, sizeof(infolen)) != sizeof(infolen)) {
123                 DEBUG(10,("send_pcap_info: infolen write failed %s\n",
124                         strerror(errno)));
125                 return;
126         }
127         if (namelen) {
128                 DEBUG(11,("send_pcap_info: writing name %s\n", name));
129                 if (sys_write(fd, name, namelen) != namelen) {
130                         DEBUG(10,("send_pcap_info: name write failed %s\n",
131                                 strerror(errno)));
132                         return;
133                 }
134         }
135         if (infolen) {
136                 DEBUG(11,("send_pcap_info: writing info %s\n", info));
137                 if (sys_write(fd, info, infolen) != infolen) {
138                         DEBUG(10,("send_pcap_info: info write failed %s\n",
139                                 strerror(errno)));
140                         return;
141                 }
142         }
143 }
144
145 static bool cups_cache_reload_async(int fd)
146 {
147         TALLOC_CTX *frame = talloc_stackframe();
148         struct pcap_cache *tmp_pcap_cache = NULL;
149         http_t          *http = NULL;           /* HTTP connection to server */
150         ipp_t           *request = NULL,        /* IPP Request */
151                         *response = NULL;       /* IPP Response */
152         ipp_attribute_t *attr;          /* Current attribute */
153         cups_lang_t     *language = NULL;       /* Default language */
154         char            *name,          /* printer-name attribute */
155                         *info;          /* printer-info attribute */
156         static const char *requested[] =/* Requested attributes */
157                         {
158                           "printer-name",
159                           "printer-info"
160                         };
161         bool ret = False;
162         size_t size;
163
164         DEBUG(5, ("reloading cups printcap cache\n"));
165
166        /*
167         * Make sure we don't ask for passwords...
168         */
169
170         cupsSetPasswordCB(cups_passwd_cb);
171
172        /*
173         * Try to connect to the server...
174         */
175
176         if ((http = cups_connect(frame)) == NULL) {
177                 goto out;
178         }
179
180        /*
181         * Build a CUPS_GET_PRINTERS request, which requires the following
182         * attributes:
183         *
184         *    attributes-charset
185         *    attributes-natural-language
186         *    requested-attributes
187         */
188
189         request = ippNew();
190
191         request->request.op.operation_id = CUPS_GET_PRINTERS;
192         request->request.op.request_id   = 1;
193
194         language = cupsLangDefault();
195
196         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
197                      "attributes-charset", NULL, "utf-8");
198
199         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
200                      "attributes-natural-language", NULL, language->language);
201
202         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
203                       "requested-attributes",
204                       (sizeof(requested) / sizeof(requested[0])),
205                       NULL, requested);
206
207        /*
208         * Do the request and get back a response...
209         */
210
211         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
212                 DEBUG(0,("Unable to get printer list - %s\n",
213                          ippErrorString(cupsLastError())));
214                 goto out;
215         }
216
217         for (attr = response->attrs; attr != NULL;) {
218                /*
219                 * Skip leading attributes until we hit a printer...
220                 */
221
222                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
223                         attr = attr->next;
224
225                 if (attr == NULL)
226                         break;
227
228                /*
229                 * Pull the needed attributes from this printer...
230                 */
231
232                 name       = NULL;
233                 info       = NULL;
234
235                 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
236                         if (strcmp(attr->name, "printer-name") == 0 &&
237                             attr->value_tag == IPP_TAG_NAME) {
238                                 if (!pull_utf8_talloc(frame,
239                                                 &name,
240                                                 attr->values[0].string.text,
241                                                 &size)) {
242                                         goto out;
243                                 }
244                         }
245
246                         if (strcmp(attr->name, "printer-info") == 0 &&
247                             attr->value_tag == IPP_TAG_TEXT) {
248                                 if (!pull_utf8_talloc(frame,
249                                                 &info,
250                                                 attr->values[0].string.text,
251                                                 &size)) {
252                                         goto out;
253                                 }
254                         }
255
256                         attr = attr->next;
257                 }
258
259                /*
260                 * See if we have everything needed...
261                 */
262
263                 if (name == NULL)
264                         break;
265
266                 if (!pcap_cache_add_specific(&tmp_pcap_cache, name, info)) {
267                         goto out;
268                 }
269         }
270
271         ippDelete(response);
272         response = NULL;
273
274        /*
275         * Build a CUPS_GET_CLASSES request, which requires the following
276         * attributes:
277         *
278         *    attributes-charset
279         *    attributes-natural-language
280         *    requested-attributes
281         */
282
283         request = ippNew();
284
285         request->request.op.operation_id = CUPS_GET_CLASSES;
286         request->request.op.request_id   = 1;
287
288         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
289                      "attributes-charset", NULL, "utf-8");
290
291         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
292                      "attributes-natural-language", NULL, language->language);
293
294         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
295                       "requested-attributes",
296                       (sizeof(requested) / sizeof(requested[0])),
297                       NULL, requested);
298
299        /*
300         * Do the request and get back a response...
301         */
302
303         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
304                 DEBUG(0,("Unable to get printer list - %s\n",
305                          ippErrorString(cupsLastError())));
306                 goto out;
307         }
308
309         for (attr = response->attrs; attr != NULL;) {
310                /*
311                 * Skip leading attributes until we hit a printer...
312                 */
313
314                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
315                         attr = attr->next;
316
317                 if (attr == NULL)
318                         break;
319
320                /*
321                 * Pull the needed attributes from this printer...
322                 */
323
324                 name       = NULL;
325                 info       = NULL;
326
327                 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
328                         if (strcmp(attr->name, "printer-name") == 0 &&
329                             attr->value_tag == IPP_TAG_NAME) {
330                                 if (!pull_utf8_talloc(frame,
331                                                 &name,
332                                                 attr->values[0].string.text,
333                                                 &size)) {
334                                         goto out;
335                                 }
336                         }
337
338                         if (strcmp(attr->name, "printer-info") == 0 &&
339                             attr->value_tag == IPP_TAG_TEXT) {
340                                 if (!pull_utf8_talloc(frame,
341                                                 &info,
342                                                 attr->values[0].string.text,
343                                                 &size)) {
344                                         goto out;
345                                 }
346                         }
347
348                         attr = attr->next;
349                 }
350
351                /*
352                 * See if we have everything needed...
353                 */
354
355                 if (name == NULL)
356                         break;
357
358                 if (!pcap_cache_add_specific(&tmp_pcap_cache, name, info)) {
359                         goto out;
360                 }
361         }
362
363         ret = True;
364
365  out:
366         if (response)
367                 ippDelete(response);
368
369         if (language)
370                 cupsLangFree(language);
371
372         if (http)
373                 httpClose(http);
374
375         /* Send all the entries up the pipe. */
376         if (tmp_pcap_cache) {
377                 pcap_printer_fn_specific(tmp_pcap_cache,
378                                 send_pcap_info,
379                                 (void *)&fd);
380
381                 pcap_cache_destroy_specific(&tmp_pcap_cache);
382         }
383         TALLOC_FREE(frame);
384         return ret;
385 }
386
387 static struct pcap_cache *local_pcap_copy;
388 struct fd_event *cache_fd_event;
389
390 static bool cups_pcap_load_async(int *pfd)
391 {
392         int fds[2];
393         pid_t pid;
394
395         *pfd = -1;
396
397         if (cache_fd_event) {
398                 DEBUG(3,("cups_pcap_load_async: already waiting for "
399                         "a refresh event\n" ));
400                 return false;
401         }
402
403         DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
404
405         if (pipe(fds) == -1) {
406                 return false;
407         }
408
409         pid = sys_fork();
410         if (pid == (pid_t)-1) {
411                 DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
412                         strerror(errno) ));
413                 close(fds[0]);
414                 close(fds[1]);
415                 return false;
416         }
417
418         if (pid) {
419                 DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
420                         (unsigned int)pid ));
421                 /* Parent. */
422                 close(fds[1]);
423                 *pfd = fds[0];
424                 return true;
425         }
426
427         /* Child. */
428         if (!reinit_after_fork(smbd_messaging_context(), true)) {
429                 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
430                 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
431         }
432
433         close(fds[0]);
434         cups_cache_reload_async(fds[1]);
435         close(fds[1]);
436         _exit(0);
437 }
438
439 static void cups_async_callback(struct event_context *event_ctx,
440                                 struct fd_event *event,
441                                 uint16 flags,
442                                 void *p)
443 {
444         TALLOC_CTX *frame = talloc_stackframe();
445         int fd = *(int *)p;
446         struct pcap_cache *tmp_pcap_cache = NULL;
447
448         DEBUG(5,("cups_async_callback: callback received for printer data. "
449                 "fd = %d\n", fd));
450
451         while (1) {
452                 char *name = NULL, *info = NULL;
453                 size_t namelen = 0, infolen = 0;
454                 ssize_t ret = -1;
455
456                 ret = sys_read(fd, &namelen, sizeof(namelen));
457                 if (ret == 0) {
458                         /* EOF */
459                         break;
460                 }
461                 if (ret != sizeof(namelen)) {
462                         DEBUG(10,("cups_async_callback: namelen read failed %d %s\n",
463                                 errno, strerror(errno)));
464                         break;
465                 }
466
467                 DEBUG(11,("cups_async_callback: read namelen %u\n",
468                         (unsigned int)namelen));
469
470                 ret = sys_read(fd, &infolen, sizeof(infolen));
471                 if (ret == 0) {
472                         /* EOF */
473                         break;
474                 }
475                 if (ret != sizeof(infolen)) {
476                         DEBUG(10,("cups_async_callback: infolen read failed %s\n",
477                                 strerror(errno)));
478                         break;
479                 }
480
481                 DEBUG(11,("cups_async_callback: read infolen %u\n",
482                         (unsigned int)infolen));
483
484                 if (namelen) {
485                         name = TALLOC_ARRAY(frame, char, namelen);
486                         if (!name) {
487                                 break;
488                         }
489                         ret = sys_read(fd, name, namelen);
490                         if (ret == 0) {
491                                 /* EOF */
492                                 break;
493                         }
494                         if (ret != namelen) {
495                                 DEBUG(10,("cups_async_callback: name read failed %s\n",
496                                         strerror(errno)));
497                                 break;
498                         }
499                         DEBUG(11,("cups_async_callback: read name %s\n",
500                                 name));
501                 } else {
502                         name = NULL;
503                 }
504                 if (infolen) {
505                         info = TALLOC_ARRAY(frame, char, infolen);
506                         if (!info) {
507                                 break;
508                         }
509                         ret = sys_read(fd, info, infolen);
510                         if (ret == 0) {
511                                 /* EOF */
512                                 break;
513                         }
514                         if (ret != infolen) {
515                                 DEBUG(10,("cups_async_callback: info read failed %s\n",
516                                         strerror(errno)));
517                                 break;
518                         }
519                         DEBUG(11,("cups_async_callback: read info %s\n",
520                                 info));
521                 } else {
522                         info = NULL;
523                 }
524
525                 /* Add to our local pcap cache. */
526                 pcap_cache_add_specific(&tmp_pcap_cache, name, info);
527                 TALLOC_FREE(name);
528                 TALLOC_FREE(info);
529         }
530
531         TALLOC_FREE(frame);
532         if (tmp_pcap_cache) {
533                 /* We got a namelist, replace our local cache. */
534                 pcap_cache_destroy_specific(&local_pcap_copy);
535                 local_pcap_copy = tmp_pcap_cache;
536
537                 /* And the systemwide pcap cache. */
538                 pcap_cache_replace(local_pcap_copy);
539         } else {
540                 DEBUG(2,("cups_async_callback: failed to read a new "
541                         "printer list\n"));
542         }
543         close(fd);
544         TALLOC_FREE(p);
545         TALLOC_FREE(cache_fd_event);
546 }
547
548 bool cups_cache_reload(void)
549 {
550         int *p_pipe_fd = TALLOC_P(NULL, int);
551
552         if (!p_pipe_fd) {
553                 return false;
554         }
555
556         *p_pipe_fd = -1;
557
558         /* Set up an async refresh. */
559         if (!cups_pcap_load_async(p_pipe_fd)) {
560                 return false;
561         }
562         if (!local_pcap_copy) {
563                 /* We have no local cache, wait directly for
564                  * async refresh to complete.
565                  */
566                 DEBUG(10,("cups_cache_reload: sync read on fd %d\n",
567                         *p_pipe_fd ));
568
569                 cups_async_callback(smbd_event_context(),
570                                         NULL,
571                                         EVENT_FD_READ,
572                                         (void *)p_pipe_fd);
573                 if (!local_pcap_copy) {
574                         return false;
575                 }
576         } else {
577                 /* Replace the system cache with our
578                  * local copy. */
579                 pcap_cache_replace(local_pcap_copy);
580
581                 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
582                         *p_pipe_fd ));
583
584                 /* Trigger an event when the pipe can be read. */
585                 cache_fd_event = event_add_fd(smbd_event_context(),
586                                         NULL, *p_pipe_fd,
587                                         EVENT_FD_READ,
588                                         cups_async_callback,
589                                         (void *)p_pipe_fd);
590                 if (!cache_fd_event) {
591                         close(*p_pipe_fd);
592                         TALLOC_FREE(p_pipe_fd);
593                         return false;
594                 }
595         }
596         return true;
597 }
598
599 /*
600  * 'cups_job_delete()' - Delete a job.
601  */
602
603 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
604 {
605         TALLOC_CTX *frame = talloc_stackframe();
606         int             ret = 1;                /* Return value */
607         http_t          *http = NULL;           /* HTTP connection to server */
608         ipp_t           *request = NULL,        /* IPP Request */
609                         *response = NULL;       /* IPP Response */
610         cups_lang_t     *language = NULL;       /* Default language */
611         char *user = NULL;
612         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
613         size_t size;
614
615         DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
616
617        /*
618         * Make sure we don't ask for passwords...
619         */
620
621         cupsSetPasswordCB(cups_passwd_cb);
622
623        /*
624         * Try to connect to the server...
625         */
626
627         if ((http = cups_connect(frame)) == NULL) {
628                 goto out;
629         }
630
631        /*
632         * Build an IPP_CANCEL_JOB request, which requires the following
633         * attributes:
634         *
635         *    attributes-charset
636         *    attributes-natural-language
637         *    job-uri
638         *    requesting-user-name
639         */
640
641         request = ippNew();
642
643         request->request.op.operation_id = IPP_CANCEL_JOB;
644         request->request.op.request_id   = 1;
645
646         language = cupsLangDefault();
647
648         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
649                      "attributes-charset", NULL, "utf-8");
650
651         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
652                      "attributes-natural-language", NULL, language->language);
653
654         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
655
656         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
657
658         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
659                 goto out;
660         }
661
662         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
663                      NULL, user);
664
665        /*
666         * Do the request and get back a response...
667         */
668
669         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
670                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
671                         DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
672                                 ippErrorString(cupsLastError())));
673                 } else {
674                         ret = 0;
675                 }
676         } else {
677                 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
678                         ippErrorString(cupsLastError())));
679         }
680
681  out:
682         if (response)
683                 ippDelete(response);
684
685         if (language)
686                 cupsLangFree(language);
687
688         if (http)
689                 httpClose(http);
690
691         TALLOC_FREE(frame);
692         return ret;
693 }
694
695
696 /*
697  * 'cups_job_pause()' - Pause a job.
698  */
699
700 static int cups_job_pause(int snum, struct printjob *pjob)
701 {
702         TALLOC_CTX *frame = talloc_stackframe();
703         int             ret = 1;                /* Return value */
704         http_t          *http = NULL;           /* HTTP connection to server */
705         ipp_t           *request = NULL,        /* IPP Request */
706                         *response = NULL;       /* IPP Response */
707         cups_lang_t     *language = NULL;       /* Default language */
708         char *user = NULL;
709         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
710         size_t size;
711
712         DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
713
714        /*
715         * Make sure we don't ask for passwords...
716         */
717
718         cupsSetPasswordCB(cups_passwd_cb);
719
720        /*
721         * Try to connect to the server...
722         */
723
724         if ((http = cups_connect(frame)) == NULL) {
725                 goto out;
726         }
727
728        /*
729         * Build an IPP_HOLD_JOB request, which requires the following
730         * attributes:
731         *
732         *    attributes-charset
733         *    attributes-natural-language
734         *    job-uri
735         *    requesting-user-name
736         */
737
738         request = ippNew();
739
740         request->request.op.operation_id = IPP_HOLD_JOB;
741         request->request.op.request_id   = 1;
742
743         language = cupsLangDefault();
744
745         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
746                      "attributes-charset", NULL, "utf-8");
747
748         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
749                      "attributes-natural-language", NULL, language->language);
750
751         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
752
753         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
754
755         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
756                 goto out;
757         }
758         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
759                      NULL, user);
760
761        /*
762         * Do the request and get back a response...
763         */
764
765         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
766                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
767                         DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
768                                 ippErrorString(cupsLastError())));
769                 } else {
770                         ret = 0;
771                 }
772         } else {
773                 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
774                         ippErrorString(cupsLastError())));
775         }
776
777  out:
778         if (response)
779                 ippDelete(response);
780
781         if (language)
782                 cupsLangFree(language);
783
784         if (http)
785                 httpClose(http);
786
787         TALLOC_FREE(frame);
788         return ret;
789 }
790
791
792 /*
793  * 'cups_job_resume()' - Resume a paused job.
794  */
795
796 static int cups_job_resume(int snum, struct printjob *pjob)
797 {
798         TALLOC_CTX *frame = talloc_stackframe();
799         int             ret = 1;                /* Return value */
800         http_t          *http = NULL;           /* HTTP connection to server */
801         ipp_t           *request = NULL,        /* IPP Request */
802                         *response = NULL;       /* IPP Response */
803         cups_lang_t     *language = NULL;       /* Default language */
804         char *user = NULL;
805         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
806         size_t size;
807
808         DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
809
810        /*
811         * Make sure we don't ask for passwords...
812         */
813
814         cupsSetPasswordCB(cups_passwd_cb);
815
816        /*
817         * Try to connect to the server...
818         */
819
820         if ((http = cups_connect(frame)) == NULL) {
821                 goto out;
822         }
823
824        /*
825         * Build an IPP_RELEASE_JOB request, which requires the following
826         * attributes:
827         *
828         *    attributes-charset
829         *    attributes-natural-language
830         *    job-uri
831         *    requesting-user-name
832         */
833
834         request = ippNew();
835
836         request->request.op.operation_id = IPP_RELEASE_JOB;
837         request->request.op.request_id   = 1;
838
839         language = cupsLangDefault();
840
841         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
842                      "attributes-charset", NULL, "utf-8");
843
844         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
845                      "attributes-natural-language", NULL, language->language);
846
847         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
848
849         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
850
851         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
852                 goto out;
853         }
854         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
855                      NULL, user);
856
857        /*
858         * Do the request and get back a response...
859         */
860
861         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
862                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
863                         DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
864                                 ippErrorString(cupsLastError())));
865                 } else {
866                         ret = 0;
867                 }
868         } else {
869                 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
870                         ippErrorString(cupsLastError())));
871         }
872
873  out:
874         if (response)
875                 ippDelete(response);
876
877         if (language)
878                 cupsLangFree(language);
879
880         if (http)
881                 httpClose(http);
882
883         TALLOC_FREE(frame);
884         return ret;
885 }
886
887
888 /*
889  * 'cups_job_submit()' - Submit a job for printing.
890  */
891
892 static int cups_job_submit(int snum, struct printjob *pjob)
893 {
894         TALLOC_CTX *frame = talloc_stackframe();
895         int             ret = 1;                /* Return value */
896         http_t          *http = NULL;           /* HTTP connection to server */
897         ipp_t           *request = NULL,        /* IPP Request */
898                         *response = NULL;       /* IPP Response */
899         cups_lang_t     *language = NULL;       /* Default language */
900         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
901         const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
902         char *new_jobname = NULL;
903         int             num_options = 0;
904         cups_option_t   *options = NULL;
905         char *printername = NULL;
906         char *user = NULL;
907         char *jobname = NULL;
908         char *cupsoptions = NULL;
909         char *filename = NULL;
910         size_t size;
911         char addr[INET6_ADDRSTRLEN];
912
913         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
914
915        /*
916         * Make sure we don't ask for passwords...
917         */
918
919         cupsSetPasswordCB(cups_passwd_cb);
920
921        /*
922         * Try to connect to the server...
923         */
924
925         if ((http = cups_connect(frame)) == NULL) {
926                 goto out;
927         }
928
929        /*
930         * Build an IPP_PRINT_JOB request, which requires the following
931         * attributes:
932         *
933         *    attributes-charset
934         *    attributes-natural-language
935         *    printer-uri
936         *    requesting-user-name
937         *    [document-data]
938         */
939
940         request = ippNew();
941
942         request->request.op.operation_id = IPP_PRINT_JOB;
943         request->request.op.request_id   = 1;
944
945         language = cupsLangDefault();
946
947         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
948                      "attributes-charset", NULL, "utf-8");
949
950         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
951                      "attributes-natural-language", NULL, language->language);
952
953         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
954                 goto out;
955         }
956         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
957                  printername);
958
959         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
960                      "printer-uri", NULL, uri);
961
962         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
963                 goto out;
964         }
965         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
966                      NULL, user);
967
968         clientname = client_name(get_client_fd());
969         if (strcmp(clientname, "UNKNOWN") == 0) {
970                 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
971         }
972
973         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
974                      "job-originating-host-name", NULL,
975                       clientname);
976
977         if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
978                 goto out;
979         }
980         new_jobname = talloc_asprintf(frame,
981                         "%s%.8u %s", PRINT_SPOOL_PREFIX,
982                         (unsigned int)pjob->smbjob,
983                         jobname);
984         if (new_jobname == NULL) {
985                 goto out;
986         }
987
988         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
989                      new_jobname);
990
991         /*
992          * add any options defined in smb.conf
993          */
994
995         if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
996                 goto out;
997         }
998         num_options = 0;
999         options     = NULL;
1000         num_options = cupsParseOptions(cupsoptions, num_options, &options);
1001
1002         if ( num_options )
1003                 cupsEncodeOptions(request, num_options, options);
1004
1005        /*
1006         * Do the request and get back a response...
1007         */
1008
1009         slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
1010
1011         if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1012                 goto out;
1013         }
1014         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1015                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1016                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
1017                                  ippErrorString(cupsLastError())));
1018                 } else {
1019                         ret = 0;
1020                 }
1021         } else {
1022                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
1023                          ippErrorString(cupsLastError())));
1024         }
1025
1026         if ( ret == 0 )
1027                 unlink(pjob->filename);
1028         /* else print_job_end will do it for us */
1029
1030  out:
1031         if (response)
1032                 ippDelete(response);
1033
1034         if (language)
1035                 cupsLangFree(language);
1036
1037         if (http)
1038                 httpClose(http);
1039
1040         TALLOC_FREE(frame);
1041
1042         return ret;
1043 }
1044
1045 /*
1046  * 'cups_queue_get()' - Get all the jobs in the print queue.
1047  */
1048
1049 static int cups_queue_get(const char *sharename,
1050                enum printing_types printing_type,
1051                char *lpq_command,
1052                print_queue_struct **q,
1053                print_status_struct *status)
1054 {
1055         TALLOC_CTX *frame = talloc_stackframe();
1056         char *printername = NULL;
1057         http_t          *http = NULL;           /* HTTP connection to server */
1058         ipp_t           *request = NULL,        /* IPP Request */
1059                         *response = NULL;       /* IPP Response */
1060         ipp_attribute_t *attr = NULL;           /* Current attribute */
1061         cups_lang_t     *language = NULL;       /* Default language */
1062         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1063         int             qcount = 0,             /* Number of active queue entries */
1064                         qalloc = 0;             /* Number of queue entries allocated */
1065         print_queue_struct *queue = NULL,       /* Queue entries */
1066                         *temp;          /* Temporary pointer for queue */
1067         char            *user_name = NULL,      /* job-originating-user-name attribute */
1068                         *job_name = NULL;       /* job-name attribute */
1069         int             job_id;         /* job-id attribute */
1070         int             job_k_octets;   /* job-k-octets attribute */
1071         time_t          job_time;       /* time-at-creation attribute */
1072         ipp_jstate_t    job_status;     /* job-status attribute */
1073         int             job_priority;   /* job-priority attribute */
1074         size_t size;
1075         static const char *jattrs[] =   /* Requested job attributes */
1076                         {
1077                           "job-id",
1078                           "job-k-octets",
1079                           "job-name",
1080                           "job-originating-user-name",
1081                           "job-priority",
1082                           "job-state",
1083                           "time-at-creation",
1084                         };
1085         static const char *pattrs[] =   /* Requested printer attributes */
1086                         {
1087                           "printer-state",
1088                           "printer-state-message"
1089                         };
1090
1091         *q = NULL;
1092
1093         /* HACK ALERT!!!  The problem with support the 'printer name'
1094            option is that we key the tdb off the sharename.  So we will
1095            overload the lpq_command string to pass in the printername
1096            (which is basically what we do for non-cups printers ... using
1097            the lpq_command to get the queue listing). */
1098
1099         if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1100                 goto out;
1101         }
1102         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1103
1104        /*
1105         * Make sure we don't ask for passwords...
1106         */
1107
1108         cupsSetPasswordCB(cups_passwd_cb);
1109
1110        /*
1111         * Try to connect to the server...
1112         */
1113
1114         if ((http = cups_connect(frame)) == NULL) {
1115                 goto out;
1116         }
1117
1118        /*
1119         * Generate the printer URI...
1120         */
1121
1122         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1123
1124        /*
1125         * Build an IPP_GET_JOBS request, which requires the following
1126         * attributes:
1127         *
1128         *    attributes-charset
1129         *    attributes-natural-language
1130         *    requested-attributes
1131         *    printer-uri
1132         */
1133
1134         request = ippNew();
1135
1136         request->request.op.operation_id = IPP_GET_JOBS;
1137         request->request.op.request_id   = 1;
1138
1139         language = cupsLangDefault();
1140
1141         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1142                      "attributes-charset", NULL, "utf-8");
1143
1144         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1145                      "attributes-natural-language", NULL, language->language);
1146
1147         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1148                       "requested-attributes",
1149                       (sizeof(jattrs) / sizeof(jattrs[0])),
1150                       NULL, jattrs);
1151
1152         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1153                      "printer-uri", NULL, uri);
1154
1155        /*
1156         * Do the request and get back a response...
1157         */
1158
1159         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1160                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1161                          ippErrorString(cupsLastError())));
1162                 goto out;
1163         }
1164
1165         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1166                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1167                          ippErrorString(response->request.status.status_code)));
1168                 goto out;
1169         }
1170
1171        /*
1172         * Process the jobs...
1173         */
1174
1175         qcount = 0;
1176         qalloc = 0;
1177         queue  = NULL;
1178
1179         for (attr = response->attrs; attr != NULL; attr = attr->next) {
1180                /*
1181                 * Skip leading attributes until we hit a job...
1182                 */
1183
1184                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1185                         attr = attr->next;
1186
1187                 if (attr == NULL)
1188                         break;
1189
1190                /*
1191                 * Allocate memory as needed...
1192                 */
1193                 if (qcount >= qalloc) {
1194                         qalloc += 16;
1195
1196                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1197
1198                         if (queue == NULL) {
1199                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
1200                                 qcount = 0;
1201                                 goto out;
1202                         }
1203                 }
1204
1205                 temp = queue + qcount;
1206                 memset(temp, 0, sizeof(print_queue_struct));
1207
1208                /*
1209                 * Pull the needed attributes from this job...
1210                 */
1211
1212                 job_id       = 0;
1213                 job_priority = 50;
1214                 job_status   = IPP_JOB_PENDING;
1215                 job_time     = 0;
1216                 job_k_octets = 0;
1217                 user_name    = NULL;
1218                 job_name     = NULL;
1219
1220                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1221                         if (attr->name == NULL) {
1222                                 attr = attr->next;
1223                                 break;
1224                         }
1225
1226                         if (strcmp(attr->name, "job-id") == 0 &&
1227                             attr->value_tag == IPP_TAG_INTEGER)
1228                                 job_id = attr->values[0].integer;
1229
1230                         if (strcmp(attr->name, "job-k-octets") == 0 &&
1231                             attr->value_tag == IPP_TAG_INTEGER)
1232                                 job_k_octets = attr->values[0].integer;
1233
1234                         if (strcmp(attr->name, "job-priority") == 0 &&
1235                             attr->value_tag == IPP_TAG_INTEGER)
1236                                 job_priority = attr->values[0].integer;
1237
1238                         if (strcmp(attr->name, "job-state") == 0 &&
1239                             attr->value_tag == IPP_TAG_ENUM)
1240                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
1241
1242                         if (strcmp(attr->name, "time-at-creation") == 0 &&
1243                             attr->value_tag == IPP_TAG_INTEGER)
1244                                 job_time = attr->values[0].integer;
1245
1246                         if (strcmp(attr->name, "job-name") == 0 &&
1247                             attr->value_tag == IPP_TAG_NAME) {
1248                                 if (!pull_utf8_talloc(frame,
1249                                                 &job_name,
1250                                                 attr->values[0].string.text,
1251                                                 &size)) {
1252                                         goto out;
1253                                 }
1254                         }
1255
1256                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1257                             attr->value_tag == IPP_TAG_NAME) {
1258                                 if (!pull_utf8_talloc(frame,
1259                                                 &user_name,
1260                                                 attr->values[0].string.text,
1261                                                 &size)) {
1262                                         goto out;
1263                                 }
1264                         }
1265
1266                         attr = attr->next;
1267                 }
1268
1269                /*
1270                 * See if we have everything needed...
1271                 */
1272
1273                 if (user_name == NULL || job_name == NULL || job_id == 0) {
1274                         if (attr == NULL)
1275                                 break;
1276                         else
1277                                 continue;
1278                 }
1279
1280                 temp->job      = job_id;
1281                 temp->size     = job_k_octets * 1024;
1282                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1283                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1284                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1285                                  LPQ_PRINTING;
1286                 temp->priority = job_priority;
1287                 temp->time     = job_time;
1288                 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1289                 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1290
1291                 qcount ++;
1292
1293                 if (attr == NULL)
1294                         break;
1295         }
1296
1297         ippDelete(response);
1298         response = NULL;
1299
1300        /*
1301         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1302         * following attributes:
1303         *
1304         *    attributes-charset
1305         *    attributes-natural-language
1306         *    requested-attributes
1307         *    printer-uri
1308         */
1309
1310         request = ippNew();
1311
1312         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1313         request->request.op.request_id   = 1;
1314
1315         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1316                      "attributes-charset", NULL, "utf-8");
1317
1318         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1319                      "attributes-natural-language", NULL, language->language);
1320
1321         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1322                       "requested-attributes",
1323                       (sizeof(pattrs) / sizeof(pattrs[0])),
1324                       NULL, pattrs);
1325
1326         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1327                      "printer-uri", NULL, uri);
1328
1329        /*
1330         * Do the request and get back a response...
1331         */
1332
1333         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1334                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1335                          ippErrorString(cupsLastError())));
1336                 *q = queue;
1337                 goto out;
1338         }
1339
1340         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1341                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1342                          ippErrorString(response->request.status.status_code)));
1343                 *q = queue;
1344                 goto out;
1345         }
1346
1347        /*
1348         * Get the current printer status and convert it to the SAMBA values.
1349         */
1350
1351         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1352                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1353                         status->status = LPSTAT_STOPPED;
1354                 else
1355                         status->status = LPSTAT_OK;
1356         }
1357
1358         if ((attr = ippFindAttribute(response, "printer-state-message",
1359                                      IPP_TAG_TEXT)) != NULL) {
1360                 char *msg = NULL;
1361                 if (!pull_utf8_talloc(frame, &msg,
1362                                 attr->values[0].string.text,
1363                                 &size)) {
1364                         goto out;
1365                 }
1366                 fstrcpy(status->message, msg);
1367         }
1368
1369        /*
1370         * Return the job queue...
1371         */
1372
1373         *q = queue;
1374
1375  out:
1376         if (response)
1377                 ippDelete(response);
1378
1379         if (language)
1380                 cupsLangFree(language);
1381
1382         if (http)
1383                 httpClose(http);
1384
1385         TALLOC_FREE(frame);
1386         return qcount;
1387 }
1388
1389
1390 /*
1391  * 'cups_queue_pause()' - Pause a print queue.
1392  */
1393
1394 static int cups_queue_pause(int snum)
1395 {
1396         TALLOC_CTX *frame = talloc_stackframe();
1397         int             ret = 1;                /* Return value */
1398         http_t          *http = NULL;           /* HTTP connection to server */
1399         ipp_t           *request = NULL,        /* IPP Request */
1400                         *response = NULL;       /* IPP Response */
1401         cups_lang_t     *language = NULL;       /* Default language */
1402         char *printername = NULL;
1403         char *username = NULL;
1404         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1405         size_t size;
1406
1407         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1408
1409         /*
1410          * Make sure we don't ask for passwords...
1411          */
1412
1413         cupsSetPasswordCB(cups_passwd_cb);
1414
1415         /*
1416          * Try to connect to the server...
1417          */
1418
1419         if ((http = cups_connect(frame)) == NULL) {
1420                 goto out;
1421         }
1422
1423         /*
1424          * Build an IPP_PAUSE_PRINTER request, which requires the following
1425          * attributes:
1426          *
1427          *    attributes-charset
1428          *    attributes-natural-language
1429          *    printer-uri
1430          *    requesting-user-name
1431          */
1432
1433         request = ippNew();
1434
1435         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1436         request->request.op.request_id   = 1;
1437
1438         language = cupsLangDefault();
1439
1440         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1441                      "attributes-charset", NULL, "utf-8");
1442
1443         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1444                      "attributes-natural-language", NULL, language->language);
1445
1446         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1447                 goto out;
1448         }
1449         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1450                  printername);
1451
1452         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1453
1454         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1455                 goto out;
1456         }
1457         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1458                      NULL, username);
1459
1460        /*
1461         * Do the request and get back a response...
1462         */
1463
1464         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1465                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1466                         DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1467                                 ippErrorString(cupsLastError())));
1468                 } else {
1469                         ret = 0;
1470                 }
1471         } else {
1472                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1473                         ippErrorString(cupsLastError())));
1474         }
1475
1476  out:
1477         if (response)
1478                 ippDelete(response);
1479
1480         if (language)
1481                 cupsLangFree(language);
1482
1483         if (http)
1484                 httpClose(http);
1485
1486         TALLOC_FREE(frame);
1487         return ret;
1488 }
1489
1490
1491 /*
1492  * 'cups_queue_resume()' - Restart a print queue.
1493  */
1494
1495 static int cups_queue_resume(int snum)
1496 {
1497         TALLOC_CTX *frame = talloc_stackframe();
1498         int             ret = 1;                /* Return value */
1499         http_t          *http = NULL;           /* HTTP connection to server */
1500         ipp_t           *request = NULL,        /* IPP Request */
1501                         *response = NULL;       /* IPP Response */
1502         cups_lang_t     *language = NULL;       /* Default language */
1503         char *printername = NULL;
1504         char *username = NULL;
1505         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1506         size_t size;
1507
1508         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1509
1510        /*
1511         * Make sure we don't ask for passwords...
1512         */
1513
1514         cupsSetPasswordCB(cups_passwd_cb);
1515
1516        /*
1517         * Try to connect to the server...
1518         */
1519
1520         if ((http = cups_connect(frame)) == NULL) {
1521                 goto out;
1522         }
1523
1524        /*
1525         * Build an IPP_RESUME_PRINTER request, which requires the following
1526         * attributes:
1527         *
1528         *    attributes-charset
1529         *    attributes-natural-language
1530         *    printer-uri
1531         *    requesting-user-name
1532         */
1533
1534         request = ippNew();
1535
1536         request->request.op.operation_id = IPP_RESUME_PRINTER;
1537         request->request.op.request_id   = 1;
1538
1539         language = cupsLangDefault();
1540
1541         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1542                      "attributes-charset", NULL, "utf-8");
1543
1544         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1545                      "attributes-natural-language", NULL, language->language);
1546
1547         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1548                 goto out;
1549         }
1550         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1551                  printername);
1552
1553         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1554
1555         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1556                 goto out;
1557         }
1558         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1559                      NULL, username);
1560
1561        /*
1562         * Do the request and get back a response...
1563         */
1564
1565         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1566                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1567                         DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1568                                 ippErrorString(cupsLastError())));
1569                 } else {
1570                         ret = 0;
1571                 }
1572         } else {
1573                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1574                         ippErrorString(cupsLastError())));
1575         }
1576
1577  out:
1578         if (response)
1579                 ippDelete(response);
1580
1581         if (language)
1582                 cupsLangFree(language);
1583
1584         if (http)
1585                 httpClose(http);
1586
1587         TALLOC_FREE(frame);
1588         return ret;
1589 }
1590
1591 /*******************************************************************
1592  * CUPS printing interface definitions...
1593  ******************************************************************/
1594
1595 struct printif  cups_printif =
1596 {
1597         PRINT_CUPS,
1598         cups_queue_get,
1599         cups_queue_pause,
1600         cups_queue_resume,
1601         cups_job_delete,
1602         cups_job_pause,
1603         cups_job_resume,
1604         cups_job_submit,
1605 };
1606
1607 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1608 {
1609         TALLOC_CTX *frame = talloc_stackframe();
1610         http_t          *http = NULL;           /* HTTP connection to server */
1611         ipp_t           *request = NULL,        /* IPP Request */
1612                         *response = NULL;       /* IPP Response */
1613         ipp_attribute_t *attr;          /* Current attribute */
1614         cups_lang_t     *language = NULL;       /* Default language */
1615         char            uri[HTTP_MAX_URI];
1616         char *server = NULL;
1617         char *sharename = NULL;
1618         char *name = NULL;
1619         static const char *requested[] =/* Requested attributes */
1620                         {
1621                           "printer-name",
1622                           "printer-info",
1623                           "printer-location"
1624                         };
1625         bool ret = False;
1626         size_t size;
1627
1628         DEBUG(5, ("pulling %s location\n", printer->sharename));
1629
1630         /*
1631          * Make sure we don't ask for passwords...
1632          */
1633
1634         cupsSetPasswordCB(cups_passwd_cb);
1635
1636         /*
1637          * Try to connect to the server...
1638          */
1639
1640         if ((http = cups_connect(frame)) == NULL) {
1641                 goto out;
1642         }
1643
1644         request = ippNew();
1645
1646         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1647         request->request.op.request_id   = 1;
1648
1649         language = cupsLangDefault();
1650
1651         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1652                      "attributes-charset", NULL, "utf-8");
1653
1654         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1655                      "attributes-natural-language", NULL, language->language);
1656
1657         if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1658                 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1659                         goto out;
1660                 }
1661         } else {
1662                 server = talloc_strdup(frame,cupsServer());
1663         }
1664         if (server) {
1665                 goto out;
1666         }
1667         if (!push_utf8_talloc(frame, &sharename, printer->sharename, &size)) {
1668                 goto out;
1669         }
1670         slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1671                  server, sharename);
1672
1673         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1674                      "printer-uri", NULL, uri);
1675
1676         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1677                       "requested-attributes",
1678                       (sizeof(requested) / sizeof(requested[0])),
1679                       NULL, requested);
1680
1681         /*
1682          * Do the request and get back a response...
1683          */
1684
1685         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1686                 DEBUG(0,("Unable to get printer attributes - %s\n",
1687                          ippErrorString(cupsLastError())));
1688                 goto out;
1689         }
1690
1691         for (attr = response->attrs; attr != NULL;) {
1692                 /*
1693                  * Skip leading attributes until we hit a printer...
1694                  */
1695
1696                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1697                         attr = attr->next;
1698
1699                 if (attr == NULL)
1700                         break;
1701
1702                 /*
1703                  * Pull the needed attributes from this printer...
1704                  */
1705
1706                 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1707                         if (strcmp(attr->name, "printer-name") == 0 &&
1708                             attr->value_tag == IPP_TAG_NAME) {
1709                                 if (!pull_utf8_talloc(frame,
1710                                                 &name,
1711                                                 attr->values[0].string.text,
1712                                                 &size)) {
1713                                         goto out;
1714                                 }
1715                         }
1716
1717                         /* Grab the comment if we don't have one */
1718                         if ( (strcmp(attr->name, "printer-info") == 0)
1719                              && (attr->value_tag == IPP_TAG_TEXT)
1720                              && !strlen(printer->comment) )
1721                         {
1722                                 char *comment = NULL;
1723                                 if (!pull_utf8_talloc(frame,
1724                                                 &comment,
1725                                                 attr->values[0].string.text,
1726                                                 &size)) {
1727                                         goto out;
1728                                 }
1729                                 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1730                                          comment));
1731                                 strlcpy(printer->comment,
1732                                         comment,
1733                                         sizeof(printer->comment));
1734                         }
1735
1736                         /* Grab the location if we don't have one */
1737                         if ( (strcmp(attr->name, "printer-location") == 0)
1738                              && (attr->value_tag == IPP_TAG_TEXT)
1739                              && !strlen(printer->location) )
1740                         {
1741                                 char *location = NULL;
1742                                 if (!pull_utf8_talloc(frame,
1743                                                 &location,
1744                                                 attr->values[0].string.text,
1745                                                 &size)) {
1746                                         goto out;
1747                                 }
1748                                 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1749                                          location));
1750                                 strlcpy(printer->location,
1751                                         location,
1752                                         sizeof(printer->location));
1753                         }
1754
1755                         attr = attr->next;
1756                 }
1757
1758                 /*
1759                  * We have everything needed...
1760                  */
1761
1762                 if (name != NULL)
1763                         break;
1764         }
1765
1766         ret = True;
1767
1768  out:
1769         if (response)
1770                 ippDelete(response);
1771
1772         if (language)
1773                 cupsLangFree(language);
1774
1775         if (http)
1776                 httpClose(http);
1777
1778         TALLOC_FREE(frame);
1779         return ret;
1780 }
1781
1782 #else
1783  /* this keeps fussy compilers happy */
1784  void print_cups_dummy(void);
1785  void print_cups_dummy(void) {}
1786 #endif /* HAVE_CUPS */