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