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