Merge branch 'v3-3-test' of git://git.samba.org/samba into 3-3
[samba.git] / source / 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         close_all_print_db();
429
430         if (!reinit_after_fork(smbd_messaging_context(),
431                         smbd_event_context(), true)) {
432                 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
433                 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
434         }
435
436         close(fds[0]);
437         cups_cache_reload_async(fds[1]);
438         close(fds[1]);
439         _exit(0);
440 }
441
442 static void cups_async_callback(struct event_context *event_ctx,
443                                 struct fd_event *event,
444                                 uint16 flags,
445                                 void *p)
446 {
447         TALLOC_CTX *frame = talloc_stackframe();
448         int fd = *(int *)p;
449         struct pcap_cache *tmp_pcap_cache = NULL;
450
451         DEBUG(5,("cups_async_callback: callback received for printer data. "
452                 "fd = %d\n", fd));
453
454         while (1) {
455                 char *name = NULL, *info = NULL;
456                 size_t namelen = 0, infolen = 0;
457                 ssize_t ret = -1;
458
459                 ret = sys_read(fd, &namelen, sizeof(namelen));
460                 if (ret == 0) {
461                         /* EOF */
462                         break;
463                 }
464                 if (ret != sizeof(namelen)) {
465                         DEBUG(10,("cups_async_callback: namelen read failed %d %s\n",
466                                 errno, strerror(errno)));
467                         break;
468                 }
469
470                 DEBUG(11,("cups_async_callback: read namelen %u\n",
471                         (unsigned int)namelen));
472
473                 ret = sys_read(fd, &infolen, sizeof(infolen));
474                 if (ret == 0) {
475                         /* EOF */
476                         break;
477                 }
478                 if (ret != sizeof(infolen)) {
479                         DEBUG(10,("cups_async_callback: infolen read failed %s\n",
480                                 strerror(errno)));
481                         break;
482                 }
483
484                 DEBUG(11,("cups_async_callback: read infolen %u\n",
485                         (unsigned int)infolen));
486
487                 if (namelen) {
488                         name = TALLOC_ARRAY(frame, char, namelen);
489                         if (!name) {
490                                 break;
491                         }
492                         ret = sys_read(fd, name, namelen);
493                         if (ret == 0) {
494                                 /* EOF */
495                                 break;
496                         }
497                         if (ret != namelen) {
498                                 DEBUG(10,("cups_async_callback: name read failed %s\n",
499                                         strerror(errno)));
500                                 break;
501                         }
502                         DEBUG(11,("cups_async_callback: read name %s\n",
503                                 name));
504                 } else {
505                         name = NULL;
506                 }
507                 if (infolen) {
508                         info = TALLOC_ARRAY(frame, char, infolen);
509                         if (!info) {
510                                 break;
511                         }
512                         ret = sys_read(fd, info, infolen);
513                         if (ret == 0) {
514                                 /* EOF */
515                                 break;
516                         }
517                         if (ret != infolen) {
518                                 DEBUG(10,("cups_async_callback: info read failed %s\n",
519                                         strerror(errno)));
520                                 break;
521                         }
522                         DEBUG(11,("cups_async_callback: read info %s\n",
523                                 info));
524                 } else {
525                         info = NULL;
526                 }
527
528                 /* Add to our local pcap cache. */
529                 pcap_cache_add_specific(&tmp_pcap_cache, name, info);
530                 TALLOC_FREE(name);
531                 TALLOC_FREE(info);
532         }
533
534         TALLOC_FREE(frame);
535         if (tmp_pcap_cache) {
536                 /* We got a namelist, replace our local cache. */
537                 pcap_cache_destroy_specific(&local_pcap_copy);
538                 local_pcap_copy = tmp_pcap_cache;
539
540                 /* And the systemwide pcap cache. */
541                 pcap_cache_replace(local_pcap_copy);
542         } else {
543                 DEBUG(2,("cups_async_callback: failed to read a new "
544                         "printer list\n"));
545         }
546         close(fd);
547         TALLOC_FREE(p);
548         TALLOC_FREE(cache_fd_event);
549 }
550
551 bool cups_cache_reload(void)
552 {
553         int *p_pipe_fd = TALLOC_P(NULL, int);
554
555         if (!p_pipe_fd) {
556                 return false;
557         }
558
559         *p_pipe_fd = -1;
560
561         /* Set up an async refresh. */
562         if (!cups_pcap_load_async(p_pipe_fd)) {
563                 return false;
564         }
565         if (!local_pcap_copy) {
566                 /* We have no local cache, wait directly for
567                  * async refresh to complete.
568                  */
569                 DEBUG(10,("cups_cache_reload: sync read on fd %d\n",
570                         *p_pipe_fd ));
571
572                 cups_async_callback(smbd_event_context(),
573                                         NULL,
574                                         EVENT_FD_READ,
575                                         (void *)p_pipe_fd);
576                 if (!local_pcap_copy) {
577                         return false;
578                 }
579         } else {
580                 /* Replace the system cache with our
581                  * local copy. */
582                 pcap_cache_replace(local_pcap_copy);
583
584                 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
585                         *p_pipe_fd ));
586
587                 /* Trigger an event when the pipe can be read. */
588                 cache_fd_event = event_add_fd(smbd_event_context(),
589                                         NULL, *p_pipe_fd,
590                                         EVENT_FD_READ,
591                                         cups_async_callback,
592                                         (void *)p_pipe_fd);
593                 if (!cache_fd_event) {
594                         close(*p_pipe_fd);
595                         TALLOC_FREE(p_pipe_fd);
596                         return false;
597                 }
598         }
599         return true;
600 }
601
602 /*
603  * 'cups_job_delete()' - Delete a job.
604  */
605
606 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
607 {
608         TALLOC_CTX *frame = talloc_stackframe();
609         int             ret = 1;                /* Return value */
610         http_t          *http = NULL;           /* HTTP connection to server */
611         ipp_t           *request = NULL,        /* IPP Request */
612                         *response = NULL;       /* IPP Response */
613         cups_lang_t     *language = NULL;       /* Default language */
614         char *user = NULL;
615         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
616         size_t size;
617
618         DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
619
620        /*
621         * Make sure we don't ask for passwords...
622         */
623
624         cupsSetPasswordCB(cups_passwd_cb);
625
626        /*
627         * Try to connect to the server...
628         */
629
630         if ((http = cups_connect(frame)) == NULL) {
631                 goto out;
632         }
633
634        /*
635         * Build an IPP_CANCEL_JOB request, which requires the following
636         * attributes:
637         *
638         *    attributes-charset
639         *    attributes-natural-language
640         *    job-uri
641         *    requesting-user-name
642         */
643
644         request = ippNew();
645
646         request->request.op.operation_id = IPP_CANCEL_JOB;
647         request->request.op.request_id   = 1;
648
649         language = cupsLangDefault();
650
651         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
652                      "attributes-charset", NULL, "utf-8");
653
654         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
655                      "attributes-natural-language", NULL, language->language);
656
657         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
658
659         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
660
661         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
662                 goto out;
663         }
664
665         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
666                      NULL, user);
667
668        /*
669         * Do the request and get back a response...
670         */
671
672         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
673                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
674                         DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
675                                 ippErrorString(cupsLastError())));
676                 } else {
677                         ret = 0;
678                 }
679         } else {
680                 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
681                         ippErrorString(cupsLastError())));
682         }
683
684  out:
685         if (response)
686                 ippDelete(response);
687
688         if (language)
689                 cupsLangFree(language);
690
691         if (http)
692                 httpClose(http);
693
694         TALLOC_FREE(frame);
695         return ret;
696 }
697
698
699 /*
700  * 'cups_job_pause()' - Pause a job.
701  */
702
703 static int cups_job_pause(int snum, struct printjob *pjob)
704 {
705         TALLOC_CTX *frame = talloc_stackframe();
706         int             ret = 1;                /* Return value */
707         http_t          *http = NULL;           /* HTTP connection to server */
708         ipp_t           *request = NULL,        /* IPP Request */
709                         *response = NULL;       /* IPP Response */
710         cups_lang_t     *language = NULL;       /* Default language */
711         char *user = NULL;
712         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
713         size_t size;
714
715         DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
716
717        /*
718         * Make sure we don't ask for passwords...
719         */
720
721         cupsSetPasswordCB(cups_passwd_cb);
722
723        /*
724         * Try to connect to the server...
725         */
726
727         if ((http = cups_connect(frame)) == NULL) {
728                 goto out;
729         }
730
731        /*
732         * Build an IPP_HOLD_JOB request, which requires the following
733         * attributes:
734         *
735         *    attributes-charset
736         *    attributes-natural-language
737         *    job-uri
738         *    requesting-user-name
739         */
740
741         request = ippNew();
742
743         request->request.op.operation_id = IPP_HOLD_JOB;
744         request->request.op.request_id   = 1;
745
746         language = cupsLangDefault();
747
748         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
749                      "attributes-charset", NULL, "utf-8");
750
751         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
752                      "attributes-natural-language", NULL, language->language);
753
754         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
755
756         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
757
758         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
759                 goto out;
760         }
761         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
762                      NULL, user);
763
764        /*
765         * Do the request and get back a response...
766         */
767
768         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
769                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
770                         DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
771                                 ippErrorString(cupsLastError())));
772                 } else {
773                         ret = 0;
774                 }
775         } else {
776                 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
777                         ippErrorString(cupsLastError())));
778         }
779
780  out:
781         if (response)
782                 ippDelete(response);
783
784         if (language)
785                 cupsLangFree(language);
786
787         if (http)
788                 httpClose(http);
789
790         TALLOC_FREE(frame);
791         return ret;
792 }
793
794
795 /*
796  * 'cups_job_resume()' - Resume a paused job.
797  */
798
799 static int cups_job_resume(int snum, struct printjob *pjob)
800 {
801         TALLOC_CTX *frame = talloc_stackframe();
802         int             ret = 1;                /* Return value */
803         http_t          *http = NULL;           /* HTTP connection to server */
804         ipp_t           *request = NULL,        /* IPP Request */
805                         *response = NULL;       /* IPP Response */
806         cups_lang_t     *language = NULL;       /* Default language */
807         char *user = NULL;
808         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
809         size_t size;
810
811         DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
812
813        /*
814         * Make sure we don't ask for passwords...
815         */
816
817         cupsSetPasswordCB(cups_passwd_cb);
818
819        /*
820         * Try to connect to the server...
821         */
822
823         if ((http = cups_connect(frame)) == NULL) {
824                 goto out;
825         }
826
827        /*
828         * Build an IPP_RELEASE_JOB request, which requires the following
829         * attributes:
830         *
831         *    attributes-charset
832         *    attributes-natural-language
833         *    job-uri
834         *    requesting-user-name
835         */
836
837         request = ippNew();
838
839         request->request.op.operation_id = IPP_RELEASE_JOB;
840         request->request.op.request_id   = 1;
841
842         language = cupsLangDefault();
843
844         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
845                      "attributes-charset", NULL, "utf-8");
846
847         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
848                      "attributes-natural-language", NULL, language->language);
849
850         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
851
852         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
853
854         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
855                 goto out;
856         }
857         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
858                      NULL, user);
859
860        /*
861         * Do the request and get back a response...
862         */
863
864         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
865                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
866                         DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
867                                 ippErrorString(cupsLastError())));
868                 } else {
869                         ret = 0;
870                 }
871         } else {
872                 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
873                         ippErrorString(cupsLastError())));
874         }
875
876  out:
877         if (response)
878                 ippDelete(response);
879
880         if (language)
881                 cupsLangFree(language);
882
883         if (http)
884                 httpClose(http);
885
886         TALLOC_FREE(frame);
887         return ret;
888 }
889
890
891 /*
892  * 'cups_job_submit()' - Submit a job for printing.
893  */
894
895 static int cups_job_submit(int snum, struct printjob *pjob)
896 {
897         TALLOC_CTX *frame = talloc_stackframe();
898         int             ret = 1;                /* Return value */
899         http_t          *http = NULL;           /* HTTP connection to server */
900         ipp_t           *request = NULL,        /* IPP Request */
901                         *response = NULL;       /* IPP Response */
902         cups_lang_t     *language = NULL;       /* Default language */
903         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
904         const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
905         char *new_jobname = NULL;
906         int             num_options = 0;
907         cups_option_t   *options = NULL;
908         char *printername = NULL;
909         char *user = NULL;
910         char *jobname = NULL;
911         char *cupsoptions = NULL;
912         char *filename = NULL;
913         size_t size;
914         char addr[INET6_ADDRSTRLEN];
915
916         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
917
918        /*
919         * Make sure we don't ask for passwords...
920         */
921
922         cupsSetPasswordCB(cups_passwd_cb);
923
924        /*
925         * Try to connect to the server...
926         */
927
928         if ((http = cups_connect(frame)) == NULL) {
929                 goto out;
930         }
931
932        /*
933         * Build an IPP_PRINT_JOB request, which requires the following
934         * attributes:
935         *
936         *    attributes-charset
937         *    attributes-natural-language
938         *    printer-uri
939         *    requesting-user-name
940         *    [document-data]
941         */
942
943         request = ippNew();
944
945         request->request.op.operation_id = IPP_PRINT_JOB;
946         request->request.op.request_id   = 1;
947
948         language = cupsLangDefault();
949
950         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
951                      "attributes-charset", NULL, "utf-8");
952
953         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
954                      "attributes-natural-language", NULL, language->language);
955
956         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
957                 goto out;
958         }
959         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
960                  printername);
961
962         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
963                      "printer-uri", NULL, uri);
964
965         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
966                 goto out;
967         }
968         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
969                      NULL, user);
970
971         clientname = client_name(get_client_fd());
972         if (strcmp(clientname, "UNKNOWN") == 0) {
973                 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
974         }
975
976         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
977                      "job-originating-host-name", NULL,
978                       clientname);
979
980         if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
981                 goto out;
982         }
983         new_jobname = talloc_asprintf(frame,
984                         "%s%.8u %s", PRINT_SPOOL_PREFIX,
985                         (unsigned int)pjob->smbjob,
986                         jobname);
987         if (new_jobname == NULL) {
988                 goto out;
989         }
990
991         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
992                      new_jobname);
993
994         /*
995          * add any options defined in smb.conf
996          */
997
998         if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
999                 goto out;
1000         }
1001         num_options = 0;
1002         options     = NULL;
1003         num_options = cupsParseOptions(cupsoptions, num_options, &options);
1004
1005         if ( num_options )
1006                 cupsEncodeOptions(request, num_options, options);
1007
1008        /*
1009         * Do the request and get back a response...
1010         */
1011
1012         slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
1013
1014         if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1015                 goto out;
1016         }
1017         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1018                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1019                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
1020                                  ippErrorString(cupsLastError())));
1021                 } else {
1022                         ret = 0;
1023                 }
1024         } else {
1025                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
1026                          ippErrorString(cupsLastError())));
1027         }
1028
1029         if ( ret == 0 )
1030                 unlink(pjob->filename);
1031         /* else print_job_end will do it for us */
1032
1033  out:
1034         if (response)
1035                 ippDelete(response);
1036
1037         if (language)
1038                 cupsLangFree(language);
1039
1040         if (http)
1041                 httpClose(http);
1042
1043         TALLOC_FREE(frame);
1044
1045         return ret;
1046 }
1047
1048 /*
1049  * 'cups_queue_get()' - Get all the jobs in the print queue.
1050  */
1051
1052 static int cups_queue_get(const char *sharename,
1053                enum printing_types printing_type,
1054                char *lpq_command,
1055                print_queue_struct **q,
1056                print_status_struct *status)
1057 {
1058         TALLOC_CTX *frame = talloc_stackframe();
1059         char *printername = NULL;
1060         http_t          *http = NULL;           /* HTTP connection to server */
1061         ipp_t           *request = NULL,        /* IPP Request */
1062                         *response = NULL;       /* IPP Response */
1063         ipp_attribute_t *attr = NULL;           /* Current attribute */
1064         cups_lang_t     *language = NULL;       /* Default language */
1065         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1066         int             qcount = 0,             /* Number of active queue entries */
1067                         qalloc = 0;             /* Number of queue entries allocated */
1068         print_queue_struct *queue = NULL,       /* Queue entries */
1069                         *temp;          /* Temporary pointer for queue */
1070         char            *user_name = NULL,      /* job-originating-user-name attribute */
1071                         *job_name = NULL;       /* job-name attribute */
1072         int             job_id;         /* job-id attribute */
1073         int             job_k_octets;   /* job-k-octets attribute */
1074         time_t          job_time;       /* time-at-creation attribute */
1075         ipp_jstate_t    job_status;     /* job-status attribute */
1076         int             job_priority;   /* job-priority attribute */
1077         size_t size;
1078         static const char *jattrs[] =   /* Requested job attributes */
1079                         {
1080                           "job-id",
1081                           "job-k-octets",
1082                           "job-name",
1083                           "job-originating-user-name",
1084                           "job-priority",
1085                           "job-state",
1086                           "time-at-creation",
1087                         };
1088         static const char *pattrs[] =   /* Requested printer attributes */
1089                         {
1090                           "printer-state",
1091                           "printer-state-message"
1092                         };
1093
1094         *q = NULL;
1095
1096         /* HACK ALERT!!!  The problem with support the 'printer name'
1097            option is that we key the tdb off the sharename.  So we will
1098            overload the lpq_command string to pass in the printername
1099            (which is basically what we do for non-cups printers ... using
1100            the lpq_command to get the queue listing). */
1101
1102         if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1103                 goto out;
1104         }
1105         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1106
1107        /*
1108         * Make sure we don't ask for passwords...
1109         */
1110
1111         cupsSetPasswordCB(cups_passwd_cb);
1112
1113        /*
1114         * Try to connect to the server...
1115         */
1116
1117         if ((http = cups_connect(frame)) == NULL) {
1118                 goto out;
1119         }
1120
1121        /*
1122         * Generate the printer URI...
1123         */
1124
1125         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1126
1127        /*
1128         * Build an IPP_GET_JOBS request, which requires the following
1129         * attributes:
1130         *
1131         *    attributes-charset
1132         *    attributes-natural-language
1133         *    requested-attributes
1134         *    printer-uri
1135         */
1136
1137         request = ippNew();
1138
1139         request->request.op.operation_id = IPP_GET_JOBS;
1140         request->request.op.request_id   = 1;
1141
1142         language = cupsLangDefault();
1143
1144         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1145                      "attributes-charset", NULL, "utf-8");
1146
1147         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1148                      "attributes-natural-language", NULL, language->language);
1149
1150         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1151                       "requested-attributes",
1152                       (sizeof(jattrs) / sizeof(jattrs[0])),
1153                       NULL, jattrs);
1154
1155         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1156                      "printer-uri", NULL, uri);
1157
1158        /*
1159         * Do the request and get back a response...
1160         */
1161
1162         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1163                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1164                          ippErrorString(cupsLastError())));
1165                 goto out;
1166         }
1167
1168         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1169                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1170                          ippErrorString(response->request.status.status_code)));
1171                 goto out;
1172         }
1173
1174        /*
1175         * Process the jobs...
1176         */
1177
1178         qcount = 0;
1179         qalloc = 0;
1180         queue  = NULL;
1181
1182         for (attr = response->attrs; attr != NULL; attr = attr->next) {
1183                /*
1184                 * Skip leading attributes until we hit a job...
1185                 */
1186
1187                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1188                         attr = attr->next;
1189
1190                 if (attr == NULL)
1191                         break;
1192
1193                /*
1194                 * Allocate memory as needed...
1195                 */
1196                 if (qcount >= qalloc) {
1197                         qalloc += 16;
1198
1199                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1200
1201                         if (queue == NULL) {
1202                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
1203                                 qcount = 0;
1204                                 goto out;
1205                         }
1206                 }
1207
1208                 temp = queue + qcount;
1209                 memset(temp, 0, sizeof(print_queue_struct));
1210
1211                /*
1212                 * Pull the needed attributes from this job...
1213                 */
1214
1215                 job_id       = 0;
1216                 job_priority = 50;
1217                 job_status   = IPP_JOB_PENDING;
1218                 job_time     = 0;
1219                 job_k_octets = 0;
1220                 user_name    = NULL;
1221                 job_name     = NULL;
1222
1223                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1224                         if (attr->name == NULL) {
1225                                 attr = attr->next;
1226                                 break;
1227                         }
1228
1229                         if (strcmp(attr->name, "job-id") == 0 &&
1230                             attr->value_tag == IPP_TAG_INTEGER)
1231                                 job_id = attr->values[0].integer;
1232
1233                         if (strcmp(attr->name, "job-k-octets") == 0 &&
1234                             attr->value_tag == IPP_TAG_INTEGER)
1235                                 job_k_octets = attr->values[0].integer;
1236
1237                         if (strcmp(attr->name, "job-priority") == 0 &&
1238                             attr->value_tag == IPP_TAG_INTEGER)
1239                                 job_priority = attr->values[0].integer;
1240
1241                         if (strcmp(attr->name, "job-state") == 0 &&
1242                             attr->value_tag == IPP_TAG_ENUM)
1243                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
1244
1245                         if (strcmp(attr->name, "time-at-creation") == 0 &&
1246                             attr->value_tag == IPP_TAG_INTEGER)
1247                                 job_time = attr->values[0].integer;
1248
1249                         if (strcmp(attr->name, "job-name") == 0 &&
1250                             attr->value_tag == IPP_TAG_NAME) {
1251                                 if (!pull_utf8_talloc(frame,
1252                                                 &job_name,
1253                                                 attr->values[0].string.text,
1254                                                 &size)) {
1255                                         goto out;
1256                                 }
1257                         }
1258
1259                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1260                             attr->value_tag == IPP_TAG_NAME) {
1261                                 if (!pull_utf8_talloc(frame,
1262                                                 &user_name,
1263                                                 attr->values[0].string.text,
1264                                                 &size)) {
1265                                         goto out;
1266                                 }
1267                         }
1268
1269                         attr = attr->next;
1270                 }
1271
1272                /*
1273                 * See if we have everything needed...
1274                 */
1275
1276                 if (user_name == NULL || job_name == NULL || job_id == 0) {
1277                         if (attr == NULL)
1278                                 break;
1279                         else
1280                                 continue;
1281                 }
1282
1283                 temp->job      = job_id;
1284                 temp->size     = job_k_octets * 1024;
1285                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1286                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1287                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1288                                  LPQ_PRINTING;
1289                 temp->priority = job_priority;
1290                 temp->time     = job_time;
1291                 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1292                 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1293
1294                 qcount ++;
1295
1296                 if (attr == NULL)
1297                         break;
1298         }
1299
1300         ippDelete(response);
1301         response = NULL;
1302
1303        /*
1304         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1305         * following attributes:
1306         *
1307         *    attributes-charset
1308         *    attributes-natural-language
1309         *    requested-attributes
1310         *    printer-uri
1311         */
1312
1313         request = ippNew();
1314
1315         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1316         request->request.op.request_id   = 1;
1317
1318         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1319                      "attributes-charset", NULL, "utf-8");
1320
1321         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1322                      "attributes-natural-language", NULL, language->language);
1323
1324         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1325                       "requested-attributes",
1326                       (sizeof(pattrs) / sizeof(pattrs[0])),
1327                       NULL, pattrs);
1328
1329         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1330                      "printer-uri", NULL, uri);
1331
1332        /*
1333         * Do the request and get back a response...
1334         */
1335
1336         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1337                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1338                          ippErrorString(cupsLastError())));
1339                 *q = queue;
1340                 goto out;
1341         }
1342
1343         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1344                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1345                          ippErrorString(response->request.status.status_code)));
1346                 *q = queue;
1347                 goto out;
1348         }
1349
1350        /*
1351         * Get the current printer status and convert it to the SAMBA values.
1352         */
1353
1354         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1355                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1356                         status->status = LPSTAT_STOPPED;
1357                 else
1358                         status->status = LPSTAT_OK;
1359         }
1360
1361         if ((attr = ippFindAttribute(response, "printer-state-message",
1362                                      IPP_TAG_TEXT)) != NULL) {
1363                 char *msg = NULL;
1364                 if (!pull_utf8_talloc(frame, &msg,
1365                                 attr->values[0].string.text,
1366                                 &size)) {
1367                         SAFE_FREE(queue);
1368                         qcount = 0;
1369                         goto out;
1370                 }
1371                 fstrcpy(status->message, msg);
1372         }
1373
1374        /*
1375         * Return the job queue...
1376         */
1377
1378         *q = queue;
1379
1380  out:
1381         if (response)
1382                 ippDelete(response);
1383
1384         if (language)
1385                 cupsLangFree(language);
1386
1387         if (http)
1388                 httpClose(http);
1389
1390         TALLOC_FREE(frame);
1391         return qcount;
1392 }
1393
1394
1395 /*
1396  * 'cups_queue_pause()' - Pause a print queue.
1397  */
1398
1399 static int cups_queue_pause(int snum)
1400 {
1401         TALLOC_CTX *frame = talloc_stackframe();
1402         int             ret = 1;                /* Return value */
1403         http_t          *http = NULL;           /* HTTP connection to server */
1404         ipp_t           *request = NULL,        /* IPP Request */
1405                         *response = NULL;       /* IPP Response */
1406         cups_lang_t     *language = NULL;       /* Default language */
1407         char *printername = NULL;
1408         char *username = NULL;
1409         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1410         size_t size;
1411
1412         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1413
1414         /*
1415          * Make sure we don't ask for passwords...
1416          */
1417
1418         cupsSetPasswordCB(cups_passwd_cb);
1419
1420         /*
1421          * Try to connect to the server...
1422          */
1423
1424         if ((http = cups_connect(frame)) == NULL) {
1425                 goto out;
1426         }
1427
1428         /*
1429          * Build an IPP_PAUSE_PRINTER request, which requires the following
1430          * attributes:
1431          *
1432          *    attributes-charset
1433          *    attributes-natural-language
1434          *    printer-uri
1435          *    requesting-user-name
1436          */
1437
1438         request = ippNew();
1439
1440         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1441         request->request.op.request_id   = 1;
1442
1443         language = cupsLangDefault();
1444
1445         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1446                      "attributes-charset", NULL, "utf-8");
1447
1448         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1449                      "attributes-natural-language", NULL, language->language);
1450
1451         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1452                 goto out;
1453         }
1454         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1455                  printername);
1456
1457         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1458
1459         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1460                 goto out;
1461         }
1462         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1463                      NULL, username);
1464
1465        /*
1466         * Do the request and get back a response...
1467         */
1468
1469         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1470                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1471                         DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1472                                 ippErrorString(cupsLastError())));
1473                 } else {
1474                         ret = 0;
1475                 }
1476         } else {
1477                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1478                         ippErrorString(cupsLastError())));
1479         }
1480
1481  out:
1482         if (response)
1483                 ippDelete(response);
1484
1485         if (language)
1486                 cupsLangFree(language);
1487
1488         if (http)
1489                 httpClose(http);
1490
1491         TALLOC_FREE(frame);
1492         return ret;
1493 }
1494
1495
1496 /*
1497  * 'cups_queue_resume()' - Restart a print queue.
1498  */
1499
1500 static int cups_queue_resume(int snum)
1501 {
1502         TALLOC_CTX *frame = talloc_stackframe();
1503         int             ret = 1;                /* Return value */
1504         http_t          *http = NULL;           /* HTTP connection to server */
1505         ipp_t           *request = NULL,        /* IPP Request */
1506                         *response = NULL;       /* IPP Response */
1507         cups_lang_t     *language = NULL;       /* Default language */
1508         char *printername = NULL;
1509         char *username = NULL;
1510         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1511         size_t size;
1512
1513         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1514
1515        /*
1516         * Make sure we don't ask for passwords...
1517         */
1518
1519         cupsSetPasswordCB(cups_passwd_cb);
1520
1521        /*
1522         * Try to connect to the server...
1523         */
1524
1525         if ((http = cups_connect(frame)) == NULL) {
1526                 goto out;
1527         }
1528
1529        /*
1530         * Build an IPP_RESUME_PRINTER request, which requires the following
1531         * attributes:
1532         *
1533         *    attributes-charset
1534         *    attributes-natural-language
1535         *    printer-uri
1536         *    requesting-user-name
1537         */
1538
1539         request = ippNew();
1540
1541         request->request.op.operation_id = IPP_RESUME_PRINTER;
1542         request->request.op.request_id   = 1;
1543
1544         language = cupsLangDefault();
1545
1546         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1547                      "attributes-charset", NULL, "utf-8");
1548
1549         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1550                      "attributes-natural-language", NULL, language->language);
1551
1552         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1553                 goto out;
1554         }
1555         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1556                  printername);
1557
1558         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1559
1560         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1561                 goto out;
1562         }
1563         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1564                      NULL, username);
1565
1566        /*
1567         * Do the request and get back a response...
1568         */
1569
1570         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1571                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1572                         DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1573                                 ippErrorString(cupsLastError())));
1574                 } else {
1575                         ret = 0;
1576                 }
1577         } else {
1578                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1579                         ippErrorString(cupsLastError())));
1580         }
1581
1582  out:
1583         if (response)
1584                 ippDelete(response);
1585
1586         if (language)
1587                 cupsLangFree(language);
1588
1589         if (http)
1590                 httpClose(http);
1591
1592         TALLOC_FREE(frame);
1593         return ret;
1594 }
1595
1596 /*******************************************************************
1597  * CUPS printing interface definitions...
1598  ******************************************************************/
1599
1600 struct printif  cups_printif =
1601 {
1602         PRINT_CUPS,
1603         cups_queue_get,
1604         cups_queue_pause,
1605         cups_queue_resume,
1606         cups_job_delete,
1607         cups_job_pause,
1608         cups_job_resume,
1609         cups_job_submit,
1610 };
1611
1612 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1613 {
1614         TALLOC_CTX *frame = talloc_stackframe();
1615         http_t          *http = NULL;           /* HTTP connection to server */
1616         ipp_t           *request = NULL,        /* IPP Request */
1617                         *response = NULL;       /* IPP Response */
1618         ipp_attribute_t *attr;          /* Current attribute */
1619         cups_lang_t     *language = NULL;       /* Default language */
1620         char            uri[HTTP_MAX_URI];
1621         char *server = NULL;
1622         char *sharename = NULL;
1623         char *name = NULL;
1624         static const char *requested[] =/* Requested attributes */
1625                         {
1626                           "printer-name",
1627                           "printer-info",
1628                           "printer-location"
1629                         };
1630         bool ret = False;
1631         size_t size;
1632
1633         DEBUG(5, ("pulling %s location\n", printer->sharename));
1634
1635         /*
1636          * Make sure we don't ask for passwords...
1637          */
1638
1639         cupsSetPasswordCB(cups_passwd_cb);
1640
1641         /*
1642          * Try to connect to the server...
1643          */
1644
1645         if ((http = cups_connect(frame)) == NULL) {
1646                 goto out;
1647         }
1648
1649         request = ippNew();
1650
1651         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1652         request->request.op.request_id   = 1;
1653
1654         language = cupsLangDefault();
1655
1656         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1657                      "attributes-charset", NULL, "utf-8");
1658
1659         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1660                      "attributes-natural-language", NULL, language->language);
1661
1662         if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1663                 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1664                         goto out;
1665                 }
1666         } else {
1667                 server = talloc_strdup(frame,cupsServer());
1668         }
1669         if (server) {
1670                 goto out;
1671         }
1672         if (!push_utf8_talloc(frame, &sharename, printer->sharename, &size)) {
1673                 goto out;
1674         }
1675         slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1676                  server, sharename);
1677
1678         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1679                      "printer-uri", NULL, uri);
1680
1681         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1682                       "requested-attributes",
1683                       (sizeof(requested) / sizeof(requested[0])),
1684                       NULL, requested);
1685
1686         /*
1687          * Do the request and get back a response...
1688          */
1689
1690         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1691                 DEBUG(0,("Unable to get printer attributes - %s\n",
1692                          ippErrorString(cupsLastError())));
1693                 goto out;
1694         }
1695
1696         for (attr = response->attrs; attr != NULL;) {
1697                 /*
1698                  * Skip leading attributes until we hit a printer...
1699                  */
1700
1701                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1702                         attr = attr->next;
1703
1704                 if (attr == NULL)
1705                         break;
1706
1707                 /*
1708                  * Pull the needed attributes from this printer...
1709                  */
1710
1711                 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1712                         if (strcmp(attr->name, "printer-name") == 0 &&
1713                             attr->value_tag == IPP_TAG_NAME) {
1714                                 if (!pull_utf8_talloc(frame,
1715                                                 &name,
1716                                                 attr->values[0].string.text,
1717                                                 &size)) {
1718                                         goto out;
1719                                 }
1720                         }
1721
1722                         /* Grab the comment if we don't have one */
1723                         if ( (strcmp(attr->name, "printer-info") == 0)
1724                              && (attr->value_tag == IPP_TAG_TEXT)
1725                              && !strlen(printer->comment) )
1726                         {
1727                                 char *comment = NULL;
1728                                 if (!pull_utf8_talloc(frame,
1729                                                 &comment,
1730                                                 attr->values[0].string.text,
1731                                                 &size)) {
1732                                         goto out;
1733                                 }
1734                                 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1735                                          comment));
1736                                 strlcpy(printer->comment,
1737                                         comment,
1738                                         sizeof(printer->comment));
1739                         }
1740
1741                         /* Grab the location if we don't have one */
1742                         if ( (strcmp(attr->name, "printer-location") == 0)
1743                              && (attr->value_tag == IPP_TAG_TEXT)
1744                              && !strlen(printer->location) )
1745                         {
1746                                 char *location = NULL;
1747                                 if (!pull_utf8_talloc(frame,
1748                                                 &location,
1749                                                 attr->values[0].string.text,
1750                                                 &size)) {
1751                                         goto out;
1752                                 }
1753                                 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1754                                          location));
1755                                 strlcpy(printer->location,
1756                                         location,
1757                                         sizeof(printer->location));
1758                         }
1759
1760                         attr = attr->next;
1761                 }
1762
1763                 /*
1764                  * We have everything needed...
1765                  */
1766
1767                 if (name != NULL)
1768                         break;
1769         }
1770
1771         ret = True;
1772
1773  out:
1774         if (response)
1775                 ippDelete(response);
1776
1777         if (request) {
1778                 ippDelete(request);
1779         }
1780
1781         if (language)
1782                 cupsLangFree(language);
1783
1784         if (http)
1785                 httpClose(http);
1786
1787         TALLOC_FREE(frame);
1788         return ret;
1789 }
1790
1791 #else
1792  /* this keeps fussy compilers happy */
1793  void print_cups_dummy(void);
1794  void print_cups_dummy(void) {}
1795 #endif /* HAVE_CUPS */