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