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