Ensure we do reinit_after_fork().
[ddiss/samba.git] / source3 / printing / print_cups.c
1 /*
2  * Support code for the Common UNIX Printing System ("CUPS")
3  *
4  * Copyright 1999-2003 by Michael R Sweet.
5  * 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         /* Set up an async refresh. */
557         if (!cups_pcap_load_async(p_pipe_fd)) {
558                 return false;
559         }
560         if (!local_pcap_copy) {
561                 /* We have no local cache, wait directly for
562                  * async refresh to complete.
563                  */
564                 DEBUG(10,("cups_cache_reload: sync read on fd %d\n",
565                         *p_pipe_fd ));
566
567                 cups_async_callback(smbd_event_context(),
568                                         NULL,
569                                         EVENT_FD_READ,
570                                         (void *)p_pipe_fd);
571                 if (!local_pcap_copy) {
572                         return false;
573                 }
574         } else {
575                 /* Replace the system cache with our
576                  * local copy. */
577                 pcap_cache_replace(local_pcap_copy);
578
579                 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
580                         *p_pipe_fd ));
581
582                 /* Trigger an event when the pipe can be read. */
583                 cache_fd_event = event_add_fd(smbd_event_context(),
584                                         NULL, *p_pipe_fd,
585                                         EVENT_FD_READ,
586                                         cups_async_callback,
587                                         (void *)p_pipe_fd);
588                 if (!cache_fd_event) {
589                         close(*p_pipe_fd);
590                         TALLOC_FREE(p_pipe_fd);
591                         return false;
592                 }
593         }
594         return true;
595 }
596
597 /*
598  * 'cups_job_delete()' - Delete a job.
599  */
600
601 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
602 {
603         TALLOC_CTX *frame = talloc_stackframe();
604         int             ret = 1;                /* Return value */
605         http_t          *http = NULL;           /* HTTP connection to server */
606         ipp_t           *request = NULL,        /* IPP Request */
607                         *response = NULL;       /* IPP Response */
608         cups_lang_t     *language = NULL;       /* Default language */
609         char *user = NULL;
610         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
611         size_t size;
612
613         DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
614
615        /*
616         * Make sure we don't ask for passwords...
617         */
618
619         cupsSetPasswordCB(cups_passwd_cb);
620
621        /*
622         * Try to connect to the server...
623         */
624
625         if ((http = cups_connect(frame)) == NULL) {
626                 goto out;
627         }
628
629        /*
630         * Build an IPP_CANCEL_JOB request, which requires the following
631         * attributes:
632         *
633         *    attributes-charset
634         *    attributes-natural-language
635         *    job-uri
636         *    requesting-user-name
637         */
638
639         request = ippNew();
640
641         request->request.op.operation_id = IPP_CANCEL_JOB;
642         request->request.op.request_id   = 1;
643
644         language = cupsLangDefault();
645
646         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
647                      "attributes-charset", NULL, "utf-8");
648
649         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
650                      "attributes-natural-language", NULL, language->language);
651
652         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
653
654         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
655
656         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
657                 goto out;
658         }
659
660         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
661                      NULL, user);
662
663        /*
664         * Do the request and get back a response...
665         */
666
667         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
668                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
669                         DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
670                                 ippErrorString(cupsLastError())));
671                 } else {
672                         ret = 0;
673                 }
674         } else {
675                 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
676                         ippErrorString(cupsLastError())));
677         }
678
679  out:
680         if (response)
681                 ippDelete(response);
682
683         if (language)
684                 cupsLangFree(language);
685
686         if (http)
687                 httpClose(http);
688
689         TALLOC_FREE(frame);
690         return ret;
691 }
692
693
694 /*
695  * 'cups_job_pause()' - Pause a job.
696  */
697
698 static int cups_job_pause(int snum, struct printjob *pjob)
699 {
700         TALLOC_CTX *frame = talloc_stackframe();
701         int             ret = 1;                /* Return value */
702         http_t          *http = NULL;           /* HTTP connection to server */
703         ipp_t           *request = NULL,        /* IPP Request */
704                         *response = NULL;       /* IPP Response */
705         cups_lang_t     *language = NULL;       /* Default language */
706         char *user = NULL;
707         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
708         size_t size;
709
710         DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
711
712        /*
713         * Make sure we don't ask for passwords...
714         */
715
716         cupsSetPasswordCB(cups_passwd_cb);
717
718        /*
719         * Try to connect to the server...
720         */
721
722         if ((http = cups_connect(frame)) == NULL) {
723                 goto out;
724         }
725
726        /*
727         * Build an IPP_HOLD_JOB request, which requires the following
728         * attributes:
729         *
730         *    attributes-charset
731         *    attributes-natural-language
732         *    job-uri
733         *    requesting-user-name
734         */
735
736         request = ippNew();
737
738         request->request.op.operation_id = IPP_HOLD_JOB;
739         request->request.op.request_id   = 1;
740
741         language = cupsLangDefault();
742
743         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
744                      "attributes-charset", NULL, "utf-8");
745
746         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
747                      "attributes-natural-language", NULL, language->language);
748
749         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
750
751         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
752
753         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
754                 goto out;
755         }
756         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
757                      NULL, user);
758
759        /*
760         * Do the request and get back a response...
761         */
762
763         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
764                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
765                         DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
766                                 ippErrorString(cupsLastError())));
767                 } else {
768                         ret = 0;
769                 }
770         } else {
771                 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
772                         ippErrorString(cupsLastError())));
773         }
774
775  out:
776         if (response)
777                 ippDelete(response);
778
779         if (language)
780                 cupsLangFree(language);
781
782         if (http)
783                 httpClose(http);
784
785         TALLOC_FREE(frame);
786         return ret;
787 }
788
789
790 /*
791  * 'cups_job_resume()' - Resume a paused job.
792  */
793
794 static int cups_job_resume(int snum, struct printjob *pjob)
795 {
796         TALLOC_CTX *frame = talloc_stackframe();
797         int             ret = 1;                /* Return value */
798         http_t          *http = NULL;           /* HTTP connection to server */
799         ipp_t           *request = NULL,        /* IPP Request */
800                         *response = NULL;       /* IPP Response */
801         cups_lang_t     *language = NULL;       /* Default language */
802         char *user = NULL;
803         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
804         size_t size;
805
806         DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
807
808        /*
809         * Make sure we don't ask for passwords...
810         */
811
812         cupsSetPasswordCB(cups_passwd_cb);
813
814        /*
815         * Try to connect to the server...
816         */
817
818         if ((http = cups_connect(frame)) == NULL) {
819                 goto out;
820         }
821
822        /*
823         * Build an IPP_RELEASE_JOB request, which requires the following
824         * attributes:
825         *
826         *    attributes-charset
827         *    attributes-natural-language
828         *    job-uri
829         *    requesting-user-name
830         */
831
832         request = ippNew();
833
834         request->request.op.operation_id = IPP_RELEASE_JOB;
835         request->request.op.request_id   = 1;
836
837         language = cupsLangDefault();
838
839         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
840                      "attributes-charset", NULL, "utf-8");
841
842         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
843                      "attributes-natural-language", NULL, language->language);
844
845         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
846
847         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
848
849         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
850                 goto out;
851         }
852         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
853                      NULL, user);
854
855        /*
856         * Do the request and get back a response...
857         */
858
859         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
860                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
861                         DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
862                                 ippErrorString(cupsLastError())));
863                 } else {
864                         ret = 0;
865                 }
866         } else {
867                 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
868                         ippErrorString(cupsLastError())));
869         }
870
871  out:
872         if (response)
873                 ippDelete(response);
874
875         if (language)
876                 cupsLangFree(language);
877
878         if (http)
879                 httpClose(http);
880
881         TALLOC_FREE(frame);
882         return ret;
883 }
884
885
886 /*
887  * 'cups_job_submit()' - Submit a job for printing.
888  */
889
890 static int cups_job_submit(int snum, struct printjob *pjob)
891 {
892         TALLOC_CTX *frame = talloc_stackframe();
893         int             ret = 1;                /* Return value */
894         http_t          *http = NULL;           /* HTTP connection to server */
895         ipp_t           *request = NULL,        /* IPP Request */
896                         *response = NULL;       /* IPP Response */
897         cups_lang_t     *language = NULL;       /* Default language */
898         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
899         const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
900         char *new_jobname = NULL;
901         int             num_options = 0;
902         cups_option_t   *options = NULL;
903         char *printername = NULL;
904         char *user = NULL;
905         char *jobname = NULL;
906         char *cupsoptions = NULL;
907         char *filename = NULL;
908         size_t size;
909         char addr[INET6_ADDRSTRLEN];
910
911         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
912
913        /*
914         * Make sure we don't ask for passwords...
915         */
916
917         cupsSetPasswordCB(cups_passwd_cb);
918
919        /*
920         * Try to connect to the server...
921         */
922
923         if ((http = cups_connect(frame)) == NULL) {
924                 goto out;
925         }
926
927        /*
928         * Build an IPP_PRINT_JOB request, which requires the following
929         * attributes:
930         *
931         *    attributes-charset
932         *    attributes-natural-language
933         *    printer-uri
934         *    requesting-user-name
935         *    [document-data]
936         */
937
938         request = ippNew();
939
940         request->request.op.operation_id = IPP_PRINT_JOB;
941         request->request.op.request_id   = 1;
942
943         language = cupsLangDefault();
944
945         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
946                      "attributes-charset", NULL, "utf-8");
947
948         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
949                      "attributes-natural-language", NULL, language->language);
950
951         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
952                 goto out;
953         }
954         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
955                  printername);
956
957         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
958                      "printer-uri", NULL, uri);
959
960         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
961                 goto out;
962         }
963         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
964                      NULL, user);
965
966         clientname = client_name(get_client_fd());
967         if (strcmp(clientname, "UNKNOWN") == 0) {
968                 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
969         }
970
971         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
972                      "job-originating-host-name", NULL,
973                       clientname);
974
975         if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
976                 goto out;
977         }
978         new_jobname = talloc_asprintf(frame,
979                         "%s%.8u %s", PRINT_SPOOL_PREFIX,
980                         (unsigned int)pjob->smbjob,
981                         jobname);
982         if (new_jobname == NULL) {
983                 goto out;
984         }
985
986         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
987                      new_jobname);
988
989         /*
990          * add any options defined in smb.conf
991          */
992
993         if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
994                 goto out;
995         }
996         num_options = 0;
997         options     = NULL;
998         num_options = cupsParseOptions(cupsoptions, num_options, &options);
999
1000         if ( num_options )
1001                 cupsEncodeOptions(request, num_options, options);
1002
1003        /*
1004         * Do the request and get back a response...
1005         */
1006
1007         slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
1008
1009         if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1010                 goto out;
1011         }
1012         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1013                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1014                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
1015                                  ippErrorString(cupsLastError())));
1016                 } else {
1017                         ret = 0;
1018                 }
1019         } else {
1020                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
1021                          ippErrorString(cupsLastError())));
1022         }
1023
1024         if ( ret == 0 )
1025                 unlink(pjob->filename);
1026         /* else print_job_end will do it for us */
1027
1028  out:
1029         if (response)
1030                 ippDelete(response);
1031
1032         if (language)
1033                 cupsLangFree(language);
1034
1035         if (http)
1036                 httpClose(http);
1037
1038         TALLOC_FREE(frame);
1039
1040         return ret;
1041 }
1042
1043 /*
1044  * 'cups_queue_get()' - Get all the jobs in the print queue.
1045  */
1046
1047 static int cups_queue_get(const char *sharename,
1048                enum printing_types printing_type,
1049                char *lpq_command,
1050                print_queue_struct **q,
1051                print_status_struct *status)
1052 {
1053         TALLOC_CTX *frame = talloc_stackframe();
1054         char *printername = NULL;
1055         http_t          *http = NULL;           /* HTTP connection to server */
1056         ipp_t           *request = NULL,        /* IPP Request */
1057                         *response = NULL;       /* IPP Response */
1058         ipp_attribute_t *attr = NULL;           /* Current attribute */
1059         cups_lang_t     *language = NULL;       /* Default language */
1060         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1061         int             qcount = 0,             /* Number of active queue entries */
1062                         qalloc = 0;             /* Number of queue entries allocated */
1063         print_queue_struct *queue = NULL,       /* Queue entries */
1064                         *temp;          /* Temporary pointer for queue */
1065         char            *user_name = NULL,      /* job-originating-user-name attribute */
1066                         *job_name = NULL;       /* job-name attribute */
1067         int             job_id;         /* job-id attribute */
1068         int             job_k_octets;   /* job-k-octets attribute */
1069         time_t          job_time;       /* time-at-creation attribute */
1070         ipp_jstate_t    job_status;     /* job-status attribute */
1071         int             job_priority;   /* job-priority attribute */
1072         size_t size;
1073         static const char *jattrs[] =   /* Requested job attributes */
1074                         {
1075                           "job-id",
1076                           "job-k-octets",
1077                           "job-name",
1078                           "job-originating-user-name",
1079                           "job-priority",
1080                           "job-state",
1081                           "time-at-creation",
1082                         };
1083         static const char *pattrs[] =   /* Requested printer attributes */
1084                         {
1085                           "printer-state",
1086                           "printer-state-message"
1087                         };
1088
1089         *q = NULL;
1090
1091         /* HACK ALERT!!!  The problem with support the 'printer name'
1092            option is that we key the tdb off the sharename.  So we will
1093            overload the lpq_command string to pass in the printername
1094            (which is basically what we do for non-cups printers ... using
1095            the lpq_command to get the queue listing). */
1096
1097         if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1098                 goto out;
1099         }
1100         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1101
1102        /*
1103         * Make sure we don't ask for passwords...
1104         */
1105
1106         cupsSetPasswordCB(cups_passwd_cb);
1107
1108        /*
1109         * Try to connect to the server...
1110         */
1111
1112         if ((http = cups_connect(frame)) == NULL) {
1113                 goto out;
1114         }
1115
1116        /*
1117         * Generate the printer URI...
1118         */
1119
1120         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1121
1122        /*
1123         * Build an IPP_GET_JOBS request, which requires the following
1124         * attributes:
1125         *
1126         *    attributes-charset
1127         *    attributes-natural-language
1128         *    requested-attributes
1129         *    printer-uri
1130         */
1131
1132         request = ippNew();
1133
1134         request->request.op.operation_id = IPP_GET_JOBS;
1135         request->request.op.request_id   = 1;
1136
1137         language = cupsLangDefault();
1138
1139         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1140                      "attributes-charset", NULL, "utf-8");
1141
1142         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1143                      "attributes-natural-language", NULL, language->language);
1144
1145         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1146                       "requested-attributes",
1147                       (sizeof(jattrs) / sizeof(jattrs[0])),
1148                       NULL, jattrs);
1149
1150         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1151                      "printer-uri", NULL, uri);
1152
1153        /*
1154         * Do the request and get back a response...
1155         */
1156
1157         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1158                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1159                          ippErrorString(cupsLastError())));
1160                 goto out;
1161         }
1162
1163         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1164                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1165                          ippErrorString(response->request.status.status_code)));
1166                 goto out;
1167         }
1168
1169        /*
1170         * Process the jobs...
1171         */
1172
1173         qcount = 0;
1174         qalloc = 0;
1175         queue  = NULL;
1176
1177         for (attr = response->attrs; attr != NULL; attr = attr->next) {
1178                /*
1179                 * Skip leading attributes until we hit a job...
1180                 */
1181
1182                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1183                         attr = attr->next;
1184
1185                 if (attr == NULL)
1186                         break;
1187
1188                /*
1189                 * Allocate memory as needed...
1190                 */
1191                 if (qcount >= qalloc) {
1192                         qalloc += 16;
1193
1194                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1195
1196                         if (queue == NULL) {
1197                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
1198                                 qcount = 0;
1199                                 goto out;
1200                         }
1201                 }
1202
1203                 temp = queue + qcount;
1204                 memset(temp, 0, sizeof(print_queue_struct));
1205
1206                /*
1207                 * Pull the needed attributes from this job...
1208                 */
1209
1210                 job_id       = 0;
1211                 job_priority = 50;
1212                 job_status   = IPP_JOB_PENDING;
1213                 job_time     = 0;
1214                 job_k_octets = 0;
1215                 user_name    = NULL;
1216                 job_name     = NULL;
1217
1218                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1219                         if (attr->name == NULL) {
1220                                 attr = attr->next;
1221                                 break;
1222                         }
1223
1224                         if (strcmp(attr->name, "job-id") == 0 &&
1225                             attr->value_tag == IPP_TAG_INTEGER)
1226                                 job_id = attr->values[0].integer;
1227
1228                         if (strcmp(attr->name, "job-k-octets") == 0 &&
1229                             attr->value_tag == IPP_TAG_INTEGER)
1230                                 job_k_octets = attr->values[0].integer;
1231
1232                         if (strcmp(attr->name, "job-priority") == 0 &&
1233                             attr->value_tag == IPP_TAG_INTEGER)
1234                                 job_priority = attr->values[0].integer;
1235
1236                         if (strcmp(attr->name, "job-state") == 0 &&
1237                             attr->value_tag == IPP_TAG_ENUM)
1238                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
1239
1240                         if (strcmp(attr->name, "time-at-creation") == 0 &&
1241                             attr->value_tag == IPP_TAG_INTEGER)
1242                                 job_time = attr->values[0].integer;
1243
1244                         if (strcmp(attr->name, "job-name") == 0 &&
1245                             attr->value_tag == IPP_TAG_NAME) {
1246                                 if (!pull_utf8_talloc(frame,
1247                                                 &job_name,
1248                                                 attr->values[0].string.text,
1249                                                 &size)) {
1250                                         goto out;
1251                                 }
1252                         }
1253
1254                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1255                             attr->value_tag == IPP_TAG_NAME) {
1256                                 if (!pull_utf8_talloc(frame,
1257                                                 &user_name,
1258                                                 attr->values[0].string.text,
1259                                                 &size)) {
1260                                         goto out;
1261                                 }
1262                         }
1263
1264                         attr = attr->next;
1265                 }
1266
1267                /*
1268                 * See if we have everything needed...
1269                 */
1270
1271                 if (user_name == NULL || job_name == NULL || job_id == 0) {
1272                         if (attr == NULL)
1273                                 break;
1274                         else
1275                                 continue;
1276                 }
1277
1278                 temp->job      = job_id;
1279                 temp->size     = job_k_octets * 1024;
1280                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1281                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1282                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1283                                  LPQ_PRINTING;
1284                 temp->priority = job_priority;
1285                 temp->time     = job_time;
1286                 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1287                 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1288
1289                 qcount ++;
1290
1291                 if (attr == NULL)
1292                         break;
1293         }
1294
1295         ippDelete(response);
1296         response = NULL;
1297
1298        /*
1299         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1300         * following attributes:
1301         *
1302         *    attributes-charset
1303         *    attributes-natural-language
1304         *    requested-attributes
1305         *    printer-uri
1306         */
1307
1308         request = ippNew();
1309
1310         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1311         request->request.op.request_id   = 1;
1312
1313         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1314                      "attributes-charset", NULL, "utf-8");
1315
1316         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1317                      "attributes-natural-language", NULL, language->language);
1318
1319         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1320                       "requested-attributes",
1321                       (sizeof(pattrs) / sizeof(pattrs[0])),
1322                       NULL, pattrs);
1323
1324         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1325                      "printer-uri", NULL, uri);
1326
1327        /*
1328         * Do the request and get back a response...
1329         */
1330
1331         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1332                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1333                          ippErrorString(cupsLastError())));
1334                 *q = queue;
1335                 goto out;
1336         }
1337
1338         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1339                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1340                          ippErrorString(response->request.status.status_code)));
1341                 *q = queue;
1342                 goto out;
1343         }
1344
1345        /*
1346         * Get the current printer status and convert it to the SAMBA values.
1347         */
1348
1349         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1350                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1351                         status->status = LPSTAT_STOPPED;
1352                 else
1353                         status->status = LPSTAT_OK;
1354         }
1355
1356         if ((attr = ippFindAttribute(response, "printer-state-message",
1357                                      IPP_TAG_TEXT)) != NULL) {
1358                 char *msg = NULL;
1359                 if (!pull_utf8_talloc(frame, &msg,
1360                                 attr->values[0].string.text,
1361                                 &size)) {
1362                         goto out;
1363                 }
1364                 fstrcpy(status->message, msg);
1365         }
1366
1367        /*
1368         * Return the job queue...
1369         */
1370
1371         *q = queue;
1372
1373  out:
1374         if (response)
1375                 ippDelete(response);
1376
1377         if (language)
1378                 cupsLangFree(language);
1379
1380         if (http)
1381                 httpClose(http);
1382
1383         TALLOC_FREE(frame);
1384         return qcount;
1385 }
1386
1387
1388 /*
1389  * 'cups_queue_pause()' - Pause a print queue.
1390  */
1391
1392 static int cups_queue_pause(int snum)
1393 {
1394         TALLOC_CTX *frame = talloc_stackframe();
1395         int             ret = 1;                /* Return value */
1396         http_t          *http = NULL;           /* HTTP connection to server */
1397         ipp_t           *request = NULL,        /* IPP Request */
1398                         *response = NULL;       /* IPP Response */
1399         cups_lang_t     *language = NULL;       /* Default language */
1400         char *printername = NULL;
1401         char *username = NULL;
1402         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1403         size_t size;
1404
1405         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1406
1407         /*
1408          * Make sure we don't ask for passwords...
1409          */
1410
1411         cupsSetPasswordCB(cups_passwd_cb);
1412
1413         /*
1414          * Try to connect to the server...
1415          */
1416
1417         if ((http = cups_connect(frame)) == NULL) {
1418                 goto out;
1419         }
1420
1421         /*
1422          * Build an IPP_PAUSE_PRINTER request, which requires the following
1423          * attributes:
1424          *
1425          *    attributes-charset
1426          *    attributes-natural-language
1427          *    printer-uri
1428          *    requesting-user-name
1429          */
1430
1431         request = ippNew();
1432
1433         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1434         request->request.op.request_id   = 1;
1435
1436         language = cupsLangDefault();
1437
1438         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1439                      "attributes-charset", NULL, "utf-8");
1440
1441         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1442                      "attributes-natural-language", NULL, language->language);
1443
1444         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1445                 goto out;
1446         }
1447         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1448                  printername);
1449
1450         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1451
1452         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1453                 goto out;
1454         }
1455         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1456                      NULL, username);
1457
1458        /*
1459         * Do the request and get back a response...
1460         */
1461
1462         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1463                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1464                         DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1465                                 ippErrorString(cupsLastError())));
1466                 } else {
1467                         ret = 0;
1468                 }
1469         } else {
1470                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1471                         ippErrorString(cupsLastError())));
1472         }
1473
1474  out:
1475         if (response)
1476                 ippDelete(response);
1477
1478         if (language)
1479                 cupsLangFree(language);
1480
1481         if (http)
1482                 httpClose(http);
1483
1484         TALLOC_FREE(frame);
1485         return ret;
1486 }
1487
1488
1489 /*
1490  * 'cups_queue_resume()' - Restart a print queue.
1491  */
1492
1493 static int cups_queue_resume(int snum)
1494 {
1495         TALLOC_CTX *frame = talloc_stackframe();
1496         int             ret = 1;                /* Return value */
1497         http_t          *http = NULL;           /* HTTP connection to server */
1498         ipp_t           *request = NULL,        /* IPP Request */
1499                         *response = NULL;       /* IPP Response */
1500         cups_lang_t     *language = NULL;       /* Default language */
1501         char *printername = NULL;
1502         char *username = NULL;
1503         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1504         size_t size;
1505
1506         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1507
1508        /*
1509         * Make sure we don't ask for passwords...
1510         */
1511
1512         cupsSetPasswordCB(cups_passwd_cb);
1513
1514        /*
1515         * Try to connect to the server...
1516         */
1517
1518         if ((http = cups_connect(frame)) == NULL) {
1519                 goto out;
1520         }
1521
1522        /*
1523         * Build an IPP_RESUME_PRINTER request, which requires the following
1524         * attributes:
1525         *
1526         *    attributes-charset
1527         *    attributes-natural-language
1528         *    printer-uri
1529         *    requesting-user-name
1530         */
1531
1532         request = ippNew();
1533
1534         request->request.op.operation_id = IPP_RESUME_PRINTER;
1535         request->request.op.request_id   = 1;
1536
1537         language = cupsLangDefault();
1538
1539         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1540                      "attributes-charset", NULL, "utf-8");
1541
1542         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1543                      "attributes-natural-language", NULL, language->language);
1544
1545         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1546                 goto out;
1547         }
1548         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1549                  printername);
1550
1551         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1552
1553         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1554                 goto out;
1555         }
1556         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1557                      NULL, username);
1558
1559        /*
1560         * Do the request and get back a response...
1561         */
1562
1563         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1564                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1565                         DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1566                                 ippErrorString(cupsLastError())));
1567                 } else {
1568                         ret = 0;
1569                 }
1570         } else {
1571                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1572                         ippErrorString(cupsLastError())));
1573         }
1574
1575  out:
1576         if (response)
1577                 ippDelete(response);
1578
1579         if (language)
1580                 cupsLangFree(language);
1581
1582         if (http)
1583                 httpClose(http);
1584
1585         TALLOC_FREE(frame);
1586         return ret;
1587 }
1588
1589 /*******************************************************************
1590  * CUPS printing interface definitions...
1591  ******************************************************************/
1592
1593 struct printif  cups_printif =
1594 {
1595         PRINT_CUPS,
1596         cups_queue_get,
1597         cups_queue_pause,
1598         cups_queue_resume,
1599         cups_job_delete,
1600         cups_job_pause,
1601         cups_job_resume,
1602         cups_job_submit,
1603 };
1604
1605 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1606 {
1607         TALLOC_CTX *frame = talloc_stackframe();
1608         http_t          *http = NULL;           /* HTTP connection to server */
1609         ipp_t           *request = NULL,        /* IPP Request */
1610                         *response = NULL;       /* IPP Response */
1611         ipp_attribute_t *attr;          /* Current attribute */
1612         cups_lang_t     *language = NULL;       /* Default language */
1613         char            uri[HTTP_MAX_URI];
1614         char *server = NULL;
1615         char *sharename = NULL;
1616         char *name = NULL;
1617         static const char *requested[] =/* Requested attributes */
1618                         {
1619                           "printer-name",
1620                           "printer-info",
1621                           "printer-location"
1622                         };
1623         bool ret = False;
1624         size_t size;
1625
1626         DEBUG(5, ("pulling %s location\n", printer->sharename));
1627
1628         /*
1629          * Make sure we don't ask for passwords...
1630          */
1631
1632         cupsSetPasswordCB(cups_passwd_cb);
1633
1634         /*
1635          * Try to connect to the server...
1636          */
1637
1638         if ((http = cups_connect(frame)) == NULL) {
1639                 goto out;
1640         }
1641
1642         request = ippNew();
1643
1644         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1645         request->request.op.request_id   = 1;
1646
1647         language = cupsLangDefault();
1648
1649         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1650                      "attributes-charset", NULL, "utf-8");
1651
1652         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1653                      "attributes-natural-language", NULL, language->language);
1654
1655         if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1656                 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1657                         goto out;
1658                 }
1659         } else {
1660                 server = talloc_strdup(frame,cupsServer());
1661         }
1662         if (server) {
1663                 goto out;
1664         }
1665         if (!push_utf8_talloc(frame, &sharename, printer->sharename, &size)) {
1666                 goto out;
1667         }
1668         slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1669                  server, sharename);
1670
1671         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1672                      "printer-uri", NULL, uri);
1673
1674         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1675                       "requested-attributes",
1676                       (sizeof(requested) / sizeof(requested[0])),
1677                       NULL, requested);
1678
1679         /*
1680          * Do the request and get back a response...
1681          */
1682
1683         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1684                 DEBUG(0,("Unable to get printer attributes - %s\n",
1685                          ippErrorString(cupsLastError())));
1686                 goto out;
1687         }
1688
1689         for (attr = response->attrs; attr != NULL;) {
1690                 /*
1691                  * Skip leading attributes until we hit a printer...
1692                  */
1693
1694                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1695                         attr = attr->next;
1696
1697                 if (attr == NULL)
1698                         break;
1699
1700                 /*
1701                  * Pull the needed attributes from this printer...
1702                  */
1703
1704                 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1705                         if (strcmp(attr->name, "printer-name") == 0 &&
1706                             attr->value_tag == IPP_TAG_NAME) {
1707                                 if (!pull_utf8_talloc(frame,
1708                                                 &name,
1709                                                 attr->values[0].string.text,
1710                                                 &size)) {
1711                                         goto out;
1712                                 }
1713                         }
1714
1715                         /* Grab the comment if we don't have one */
1716                         if ( (strcmp(attr->name, "printer-info") == 0)
1717                              && (attr->value_tag == IPP_TAG_TEXT)
1718                              && !strlen(printer->comment) )
1719                         {
1720                                 char *comment = NULL;
1721                                 if (!pull_utf8_talloc(frame,
1722                                                 &comment,
1723                                                 attr->values[0].string.text,
1724                                                 &size)) {
1725                                         goto out;
1726                                 }
1727                                 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1728                                          comment));
1729                                 strlcpy(printer->comment,
1730                                         comment,
1731                                         sizeof(printer->comment));
1732                         }
1733
1734                         /* Grab the location if we don't have one */
1735                         if ( (strcmp(attr->name, "printer-location") == 0)
1736                              && (attr->value_tag == IPP_TAG_TEXT)
1737                              && !strlen(printer->location) )
1738                         {
1739                                 char *location = NULL;
1740                                 if (!pull_utf8_talloc(frame,
1741                                                 &location,
1742                                                 attr->values[0].string.text,
1743                                                 &size)) {
1744                                         goto out;
1745                                 }
1746                                 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1747                                          location));
1748                                 strlcpy(printer->location,
1749                                         location,
1750                                         sizeof(printer->location));
1751                         }
1752
1753                         attr = attr->next;
1754                 }
1755
1756                 /*
1757                  * We have everything needed...
1758                  */
1759
1760                 if (name != NULL)
1761                         break;
1762         }
1763
1764         ret = True;
1765
1766  out:
1767         if (response)
1768                 ippDelete(response);
1769
1770         if (language)
1771                 cupsLangFree(language);
1772
1773         if (http)
1774                 httpClose(http);
1775
1776         TALLOC_FREE(frame);
1777         return ret;
1778 }
1779
1780 #else
1781  /* this keeps fussy compilers happy */
1782  void print_cups_dummy(void);
1783  void print_cups_dummy(void) {}
1784 #endif /* HAVE_CUPS */