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