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