s3-printing: rename queue->job sysjob
[ddiss/samba.git] / source3 / printing / print_cups.c
1 /*
2  * Support code for the Common UNIX Printing System ("CUPS")
3  *
4  * Copyright 1999-2003 by Michael R Sweet.
5  * Copyright 2008 Jeremy Allison.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /*
22  * JRA. Converted to utf8 pull/push.
23  */
24
25 #include "includes.h"
26 #include "printing.h"
27 #include "printing/pcap.h"
28 #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 = 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, 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
875         DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
876
877        /*
878         * Make sure we don't ask for passwords...
879         */
880
881         cupsSetPasswordCB(cups_passwd_cb);
882
883        /*
884         * Try to connect to the server...
885         */
886
887         if ((http = cups_connect(frame)) == NULL) {
888                 goto out;
889         }
890
891        /*
892         * Build an IPP_PRINT_JOB request, which requires the following
893         * attributes:
894         *
895         *    attributes-charset
896         *    attributes-natural-language
897         *    printer-uri
898         *    requesting-user-name
899         *    [document-data]
900         */
901
902         request = ippNew();
903
904         request->request.op.operation_id = IPP_PRINT_JOB;
905         request->request.op.request_id   = 1;
906
907         language = cupsLangDefault();
908
909         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
910                      "attributes-charset", NULL, "utf-8");
911
912         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
913                      "attributes-natural-language", NULL, language->language);
914
915         if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
916                               &size)) {
917                 goto out;
918         }
919         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
920                  printername);
921
922         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
923                      "printer-uri", NULL, uri);
924
925         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
926                 goto out;
927         }
928         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
929                      NULL, user);
930
931         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
932                      "job-originating-host-name", NULL,
933                      pjob->clientmachine);
934
935         if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
936                 goto out;
937         }
938         new_jobname = talloc_asprintf(frame,
939                         "%s%.8u %s", PRINT_SPOOL_PREFIX,
940                         pjob->jobid, jobname);
941         if (new_jobname == NULL) {
942                 goto out;
943         }
944
945         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
946                      new_jobname);
947
948         /*
949          * add any options defined in smb.conf
950          */
951
952         if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
953                 goto out;
954         }
955         num_options = 0;
956         options     = NULL;
957         num_options = cupsParseOptions(cupsoptions, num_options, &options);
958
959         if ( num_options )
960                 cupsEncodeOptions(request, num_options, options);
961
962        /*
963         * Do the request and get back a response...
964         */
965
966         slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
967
968         if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
969                 goto out;
970         }
971         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
972                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
973                         DEBUG(0,("Unable to print file to %s - %s\n",
974                                  lp_printername(snum),
975                                  ippErrorString(cupsLastError())));
976                 } else {
977                         ret = 0;
978                         attr_job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
979                         if(attr_job_id) {
980                                 pjob->sysjob = attr_job_id->values[0].integer;
981                                 DEBUG(5,("cups_job_submit: job-id %d\n", pjob->sysjob));
982                         } else {
983                                 DEBUG(0,("Missing job-id attribute in IPP response"));
984                         }
985                 }
986         } else {
987                 DEBUG(0,("Unable to print file to `%s' - %s\n",
988                          lp_printername(snum),
989                          ippErrorString(cupsLastError())));
990         }
991
992         if ( ret == 0 )
993                 unlink(pjob->filename);
994         /* else print_job_end will do it for us */
995
996  out:
997         if (response)
998                 ippDelete(response);
999
1000         if (language)
1001                 cupsLangFree(language);
1002
1003         if (http)
1004                 httpClose(http);
1005
1006         TALLOC_FREE(frame);
1007
1008         return ret;
1009 }
1010
1011 /*
1012  * 'cups_queue_get()' - Get all the jobs in the print queue.
1013  */
1014
1015 static int cups_queue_get(const char *sharename,
1016                enum printing_types printing_type,
1017                char *lpq_command,
1018                print_queue_struct **q,
1019                print_status_struct *status)
1020 {
1021         TALLOC_CTX *frame = talloc_stackframe();
1022         char *printername = NULL;
1023         http_t          *http = NULL;           /* HTTP connection to server */
1024         ipp_t           *request = NULL,        /* IPP Request */
1025                         *response = NULL;       /* IPP Response */
1026         ipp_attribute_t *attr = NULL;           /* Current attribute */
1027         cups_lang_t     *language = NULL;       /* Default language */
1028         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1029         int             qcount = 0,             /* Number of active queue entries */
1030                         qalloc = 0;             /* Number of queue entries allocated */
1031         print_queue_struct *queue = NULL,       /* Queue entries */
1032                         *temp;          /* Temporary pointer for queue */
1033         char            *user_name = NULL,      /* job-originating-user-name attribute */
1034                         *job_name = NULL;       /* job-name attribute */
1035         int             job_id;         /* job-id attribute */
1036         int             job_k_octets;   /* job-k-octets attribute */
1037         time_t          job_time;       /* time-at-creation attribute */
1038         ipp_jstate_t    job_status;     /* job-status attribute */
1039         int             job_priority;   /* job-priority attribute */
1040         size_t size;
1041         static const char *jattrs[] =   /* Requested job attributes */
1042                         {
1043                           "job-id",
1044                           "job-k-octets",
1045                           "job-name",
1046                           "job-originating-user-name",
1047                           "job-priority",
1048                           "job-state",
1049                           "time-at-creation",
1050                         };
1051         static const char *pattrs[] =   /* Requested printer attributes */
1052                         {
1053                           "printer-state",
1054                           "printer-state-message"
1055                         };
1056
1057         *q = NULL;
1058
1059         /* HACK ALERT!!!  The problem with support the 'printer name'
1060            option is that we key the tdb off the sharename.  So we will
1061            overload the lpq_command string to pass in the printername
1062            (which is basically what we do for non-cups printers ... using
1063            the lpq_command to get the queue listing). */
1064
1065         if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1066                 goto out;
1067         }
1068         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1069
1070        /*
1071         * Make sure we don't ask for passwords...
1072         */
1073
1074         cupsSetPasswordCB(cups_passwd_cb);
1075
1076        /*
1077         * Try to connect to the server...
1078         */
1079
1080         if ((http = cups_connect(frame)) == NULL) {
1081                 goto out;
1082         }
1083
1084        /*
1085         * Generate the printer URI...
1086         */
1087
1088         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1089
1090        /*
1091         * Build an IPP_GET_JOBS request, which requires the following
1092         * attributes:
1093         *
1094         *    attributes-charset
1095         *    attributes-natural-language
1096         *    requested-attributes
1097         *    printer-uri
1098         */
1099
1100         request = ippNew();
1101
1102         request->request.op.operation_id = IPP_GET_JOBS;
1103         request->request.op.request_id   = 1;
1104
1105         language = cupsLangDefault();
1106
1107         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1108                      "attributes-charset", NULL, "utf-8");
1109
1110         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1111                      "attributes-natural-language", NULL, language->language);
1112
1113         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1114                       "requested-attributes",
1115                       (sizeof(jattrs) / sizeof(jattrs[0])),
1116                       NULL, jattrs);
1117
1118         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1119                      "printer-uri", NULL, uri);
1120
1121        /*
1122         * Do the request and get back a response...
1123         */
1124
1125         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1126                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1127                          ippErrorString(cupsLastError())));
1128                 goto out;
1129         }
1130
1131         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1132                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1133                          ippErrorString(response->request.status.status_code)));
1134                 goto out;
1135         }
1136
1137        /*
1138         * Process the jobs...
1139         */
1140
1141         qcount = 0;
1142         qalloc = 0;
1143         queue  = NULL;
1144
1145         for (attr = response->attrs; attr != NULL; attr = attr->next) {
1146                /*
1147                 * Skip leading attributes until we hit a job...
1148                 */
1149
1150                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1151                         attr = attr->next;
1152
1153                 if (attr == NULL)
1154                         break;
1155
1156                /*
1157                 * Allocate memory as needed...
1158                 */
1159                 if (qcount >= qalloc) {
1160                         qalloc += 16;
1161
1162                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1163
1164                         if (queue == NULL) {
1165                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
1166                                 qcount = 0;
1167                                 goto out;
1168                         }
1169                 }
1170
1171                 temp = queue + qcount;
1172                 memset(temp, 0, sizeof(print_queue_struct));
1173
1174                /*
1175                 * Pull the needed attributes from this job...
1176                 */
1177
1178                 job_id       = 0;
1179                 job_priority = 50;
1180                 job_status   = IPP_JOB_PENDING;
1181                 job_time     = 0;
1182                 job_k_octets = 0;
1183                 user_name    = NULL;
1184                 job_name     = NULL;
1185
1186                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1187                         if (attr->name == NULL) {
1188                                 attr = attr->next;
1189                                 break;
1190                         }
1191
1192                         if (strcmp(attr->name, "job-id") == 0 &&
1193                             attr->value_tag == IPP_TAG_INTEGER)
1194                                 job_id = attr->values[0].integer;
1195
1196                         if (strcmp(attr->name, "job-k-octets") == 0 &&
1197                             attr->value_tag == IPP_TAG_INTEGER)
1198                                 job_k_octets = attr->values[0].integer;
1199
1200                         if (strcmp(attr->name, "job-priority") == 0 &&
1201                             attr->value_tag == IPP_TAG_INTEGER)
1202                                 job_priority = attr->values[0].integer;
1203
1204                         if (strcmp(attr->name, "job-state") == 0 &&
1205                             attr->value_tag == IPP_TAG_ENUM)
1206                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
1207
1208                         if (strcmp(attr->name, "time-at-creation") == 0 &&
1209                             attr->value_tag == IPP_TAG_INTEGER)
1210                                 job_time = attr->values[0].integer;
1211
1212                         if (strcmp(attr->name, "job-name") == 0 &&
1213                             attr->value_tag == IPP_TAG_NAME) {
1214                                 if (!pull_utf8_talloc(frame,
1215                                                 &job_name,
1216                                                 attr->values[0].string.text,
1217                                                 &size)) {
1218                                         goto out;
1219                                 }
1220                         }
1221
1222                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1223                             attr->value_tag == IPP_TAG_NAME) {
1224                                 if (!pull_utf8_talloc(frame,
1225                                                 &user_name,
1226                                                 attr->values[0].string.text,
1227                                                 &size)) {
1228                                         goto out;
1229                                 }
1230                         }
1231
1232                         attr = attr->next;
1233                 }
1234
1235                /*
1236                 * See if we have everything needed...
1237                 */
1238
1239                 if (user_name == NULL || job_name == NULL || job_id == 0) {
1240                         if (attr == NULL)
1241                                 break;
1242                         else
1243                                 continue;
1244                 }
1245
1246                 temp->sysjob   = job_id;
1247                 temp->size     = job_k_octets * 1024;
1248                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1249                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1250                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1251                                  LPQ_PRINTING;
1252                 temp->priority = job_priority;
1253                 temp->time     = job_time;
1254                 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1255                 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1256
1257                 qcount ++;
1258
1259                 if (attr == NULL)
1260                         break;
1261         }
1262
1263         ippDelete(response);
1264         response = NULL;
1265
1266        /*
1267         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1268         * following attributes:
1269         *
1270         *    attributes-charset
1271         *    attributes-natural-language
1272         *    requested-attributes
1273         *    printer-uri
1274         */
1275
1276         request = ippNew();
1277
1278         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1279         request->request.op.request_id   = 1;
1280
1281         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1282                      "attributes-charset", NULL, "utf-8");
1283
1284         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1285                      "attributes-natural-language", NULL, language->language);
1286
1287         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1288                       "requested-attributes",
1289                       (sizeof(pattrs) / sizeof(pattrs[0])),
1290                       NULL, pattrs);
1291
1292         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1293                      "printer-uri", NULL, uri);
1294
1295        /*
1296         * Do the request and get back a response...
1297         */
1298
1299         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1300                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1301                          ippErrorString(cupsLastError())));
1302                 goto out;
1303         }
1304
1305         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1306                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1307                          ippErrorString(response->request.status.status_code)));
1308                 goto out;
1309         }
1310
1311        /*
1312         * Get the current printer status and convert it to the SAMBA values.
1313         */
1314
1315         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1316                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1317                         status->status = LPSTAT_STOPPED;
1318                 else
1319                         status->status = LPSTAT_OK;
1320         }
1321
1322         if ((attr = ippFindAttribute(response, "printer-state-message",
1323                                      IPP_TAG_TEXT)) != NULL) {
1324                 char *msg = NULL;
1325                 if (!pull_utf8_talloc(frame, &msg,
1326                                 attr->values[0].string.text,
1327                                 &size)) {
1328                         SAFE_FREE(queue);
1329                         qcount = 0;
1330                         goto out;
1331                 }
1332                 fstrcpy(status->message, msg);
1333         }
1334
1335  out:
1336
1337        /*
1338         * Return the job queue...
1339         */
1340
1341         *q = queue;
1342
1343         if (response)
1344                 ippDelete(response);
1345
1346         if (language)
1347                 cupsLangFree(language);
1348
1349         if (http)
1350                 httpClose(http);
1351
1352         TALLOC_FREE(frame);
1353         return qcount;
1354 }
1355
1356
1357 /*
1358  * 'cups_queue_pause()' - Pause a print queue.
1359  */
1360
1361 static int cups_queue_pause(int snum)
1362 {
1363         TALLOC_CTX *frame = talloc_stackframe();
1364         int             ret = 1;                /* Return value */
1365         http_t          *http = NULL;           /* HTTP connection to server */
1366         ipp_t           *request = NULL,        /* IPP Request */
1367                         *response = NULL;       /* IPP Response */
1368         cups_lang_t     *language = NULL;       /* Default language */
1369         char *printername = NULL;
1370         char *username = NULL;
1371         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1372         size_t size;
1373
1374         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1375
1376         /*
1377          * Make sure we don't ask for passwords...
1378          */
1379
1380         cupsSetPasswordCB(cups_passwd_cb);
1381
1382         /*
1383          * Try to connect to the server...
1384          */
1385
1386         if ((http = cups_connect(frame)) == NULL) {
1387                 goto out;
1388         }
1389
1390         /*
1391          * Build an IPP_PAUSE_PRINTER request, which requires the following
1392          * attributes:
1393          *
1394          *    attributes-charset
1395          *    attributes-natural-language
1396          *    printer-uri
1397          *    requesting-user-name
1398          */
1399
1400         request = ippNew();
1401
1402         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1403         request->request.op.request_id   = 1;
1404
1405         language = cupsLangDefault();
1406
1407         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1408                      "attributes-charset", NULL, "utf-8");
1409
1410         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1411                      "attributes-natural-language", NULL, language->language);
1412
1413         if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1414                               &size)) {
1415                 goto out;
1416         }
1417         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1418                  printername);
1419
1420         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1421
1422         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1423                 goto out;
1424         }
1425         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1426                      NULL, username);
1427
1428        /*
1429         * Do the request and get back a response...
1430         */
1431
1432         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1433                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1434                         DEBUG(0,("Unable to pause printer %s - %s\n",
1435                                  lp_printername(snum),
1436                                 ippErrorString(cupsLastError())));
1437                 } else {
1438                         ret = 0;
1439                 }
1440         } else {
1441                 DEBUG(0,("Unable to pause printer %s - %s\n",
1442                          lp_printername(snum),
1443                         ippErrorString(cupsLastError())));
1444         }
1445
1446  out:
1447         if (response)
1448                 ippDelete(response);
1449
1450         if (language)
1451                 cupsLangFree(language);
1452
1453         if (http)
1454                 httpClose(http);
1455
1456         TALLOC_FREE(frame);
1457         return ret;
1458 }
1459
1460
1461 /*
1462  * 'cups_queue_resume()' - Restart a print queue.
1463  */
1464
1465 static int cups_queue_resume(int snum)
1466 {
1467         TALLOC_CTX *frame = talloc_stackframe();
1468         int             ret = 1;                /* Return value */
1469         http_t          *http = NULL;           /* HTTP connection to server */
1470         ipp_t           *request = NULL,        /* IPP Request */
1471                         *response = NULL;       /* IPP Response */
1472         cups_lang_t     *language = NULL;       /* Default language */
1473         char *printername = NULL;
1474         char *username = NULL;
1475         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1476         size_t size;
1477
1478         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1479
1480        /*
1481         * Make sure we don't ask for passwords...
1482         */
1483
1484         cupsSetPasswordCB(cups_passwd_cb);
1485
1486        /*
1487         * Try to connect to the server...
1488         */
1489
1490         if ((http = cups_connect(frame)) == NULL) {
1491                 goto out;
1492         }
1493
1494        /*
1495         * Build an IPP_RESUME_PRINTER request, which requires the following
1496         * attributes:
1497         *
1498         *    attributes-charset
1499         *    attributes-natural-language
1500         *    printer-uri
1501         *    requesting-user-name
1502         */
1503
1504         request = ippNew();
1505
1506         request->request.op.operation_id = IPP_RESUME_PRINTER;
1507         request->request.op.request_id   = 1;
1508
1509         language = cupsLangDefault();
1510
1511         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1512                      "attributes-charset", NULL, "utf-8");
1513
1514         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1515                      "attributes-natural-language", NULL, language->language);
1516
1517         if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1518                               &size)) {
1519                 goto out;
1520         }
1521         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1522                  printername);
1523
1524         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1525
1526         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1527                 goto out;
1528         }
1529         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1530                      NULL, username);
1531
1532        /*
1533         * Do the request and get back a response...
1534         */
1535
1536         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1537                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1538                         DEBUG(0,("Unable to resume printer %s - %s\n",
1539                                  lp_printername(snum),
1540                                 ippErrorString(cupsLastError())));
1541                 } else {
1542                         ret = 0;
1543                 }
1544         } else {
1545                 DEBUG(0,("Unable to resume printer %s - %s\n",
1546                          lp_printername(snum),
1547                         ippErrorString(cupsLastError())));
1548         }
1549
1550  out:
1551         if (response)
1552                 ippDelete(response);
1553
1554         if (language)
1555                 cupsLangFree(language);
1556
1557         if (http)
1558                 httpClose(http);
1559
1560         TALLOC_FREE(frame);
1561         return ret;
1562 }
1563
1564 /*******************************************************************
1565  * CUPS printing interface definitions...
1566  ******************************************************************/
1567
1568 struct printif  cups_printif =
1569 {
1570         PRINT_CUPS,
1571         cups_queue_get,
1572         cups_queue_pause,
1573         cups_queue_resume,
1574         cups_job_delete,
1575         cups_job_pause,
1576         cups_job_resume,
1577         cups_job_submit,
1578 };
1579
1580 #else
1581  /* this keeps fussy compilers happy */
1582  void print_cups_dummy(void);
1583  void print_cups_dummy(void) {}
1584 #endif /* HAVE_CUPS */