Merge branch 'master' of ssh://git.samba.org/data/git/samba
[ira/wip.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 (!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         cups_lang_t     *language = NULL;       /* Default language */
904         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
905         const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
906         char *new_jobname = NULL;
907         int             num_options = 0;
908         cups_option_t   *options = NULL;
909         char *printername = NULL;
910         char *user = NULL;
911         char *jobname = NULL;
912         char *cupsoptions = NULL;
913         char *filename = NULL;
914         size_t size;
915         char addr[INET6_ADDRSTRLEN];
916
917         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
918
919        /*
920         * Make sure we don't ask for passwords...
921         */
922
923         cupsSetPasswordCB(cups_passwd_cb);
924
925        /*
926         * Try to connect to the server...
927         */
928
929         if ((http = cups_connect(frame)) == NULL) {
930                 goto out;
931         }
932
933        /*
934         * Build an IPP_PRINT_JOB request, which requires the following
935         * attributes:
936         *
937         *    attributes-charset
938         *    attributes-natural-language
939         *    printer-uri
940         *    requesting-user-name
941         *    [document-data]
942         */
943
944         request = ippNew();
945
946         request->request.op.operation_id = IPP_PRINT_JOB;
947         request->request.op.request_id   = 1;
948
949         language = cupsLangDefault();
950
951         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
952                      "attributes-charset", NULL, "utf-8");
953
954         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
955                      "attributes-natural-language", NULL, language->language);
956
957         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
958                 goto out;
959         }
960         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
961                  printername);
962
963         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
964                      "printer-uri", NULL, uri);
965
966         if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
967                 goto out;
968         }
969         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
970                      NULL, user);
971
972         clientname = client_name(get_client_fd());
973         if (strcmp(clientname, "UNKNOWN") == 0) {
974                 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
975         }
976
977         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
978                      "job-originating-host-name", NULL,
979                       clientname);
980
981         if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
982                 goto out;
983         }
984         new_jobname = talloc_asprintf(frame,
985                         "%s%.8u %s", PRINT_SPOOL_PREFIX,
986                         (unsigned int)pjob->smbjob,
987                         jobname);
988         if (new_jobname == NULL) {
989                 goto out;
990         }
991
992         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
993                      new_jobname);
994
995         /*
996          * add any options defined in smb.conf
997          */
998
999         if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
1000                 goto out;
1001         }
1002         num_options = 0;
1003         options     = NULL;
1004         num_options = cupsParseOptions(cupsoptions, num_options, &options);
1005
1006         if ( num_options )
1007                 cupsEncodeOptions(request, num_options, options);
1008
1009        /*
1010         * Do the request and get back a response...
1011         */
1012
1013         slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
1014
1015         if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1016                 goto out;
1017         }
1018         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1019                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1020                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
1021                                  ippErrorString(cupsLastError())));
1022                 } else {
1023                         ret = 0;
1024                 }
1025         } else {
1026                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
1027                          ippErrorString(cupsLastError())));
1028         }
1029
1030         if ( ret == 0 )
1031                 unlink(pjob->filename);
1032         /* else print_job_end will do it for us */
1033
1034  out:
1035         if (response)
1036                 ippDelete(response);
1037
1038         if (language)
1039                 cupsLangFree(language);
1040
1041         if (http)
1042                 httpClose(http);
1043
1044         TALLOC_FREE(frame);
1045
1046         return ret;
1047 }
1048
1049 /*
1050  * 'cups_queue_get()' - Get all the jobs in the print queue.
1051  */
1052
1053 static int cups_queue_get(const char *sharename,
1054                enum printing_types printing_type,
1055                char *lpq_command,
1056                print_queue_struct **q,
1057                print_status_struct *status)
1058 {
1059         TALLOC_CTX *frame = talloc_stackframe();
1060         char *printername = NULL;
1061         http_t          *http = NULL;           /* HTTP connection to server */
1062         ipp_t           *request = NULL,        /* IPP Request */
1063                         *response = NULL;       /* IPP Response */
1064         ipp_attribute_t *attr = NULL;           /* Current attribute */
1065         cups_lang_t     *language = NULL;       /* Default language */
1066         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1067         int             qcount = 0,             /* Number of active queue entries */
1068                         qalloc = 0;             /* Number of queue entries allocated */
1069         print_queue_struct *queue = NULL,       /* Queue entries */
1070                         *temp;          /* Temporary pointer for queue */
1071         char            *user_name = NULL,      /* job-originating-user-name attribute */
1072                         *job_name = NULL;       /* job-name attribute */
1073         int             job_id;         /* job-id attribute */
1074         int             job_k_octets;   /* job-k-octets attribute */
1075         time_t          job_time;       /* time-at-creation attribute */
1076         ipp_jstate_t    job_status;     /* job-status attribute */
1077         int             job_priority;   /* job-priority attribute */
1078         size_t size;
1079         static const char *jattrs[] =   /* Requested job attributes */
1080                         {
1081                           "job-id",
1082                           "job-k-octets",
1083                           "job-name",
1084                           "job-originating-user-name",
1085                           "job-priority",
1086                           "job-state",
1087                           "time-at-creation",
1088                         };
1089         static const char *pattrs[] =   /* Requested printer attributes */
1090                         {
1091                           "printer-state",
1092                           "printer-state-message"
1093                         };
1094
1095         *q = NULL;
1096
1097         /* HACK ALERT!!!  The problem with support the 'printer name'
1098            option is that we key the tdb off the sharename.  So we will
1099            overload the lpq_command string to pass in the printername
1100            (which is basically what we do for non-cups printers ... using
1101            the lpq_command to get the queue listing). */
1102
1103         if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1104                 goto out;
1105         }
1106         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1107
1108        /*
1109         * Make sure we don't ask for passwords...
1110         */
1111
1112         cupsSetPasswordCB(cups_passwd_cb);
1113
1114        /*
1115         * Try to connect to the server...
1116         */
1117
1118         if ((http = cups_connect(frame)) == NULL) {
1119                 goto out;
1120         }
1121
1122        /*
1123         * Generate the printer URI...
1124         */
1125
1126         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1127
1128        /*
1129         * Build an IPP_GET_JOBS request, which requires the following
1130         * attributes:
1131         *
1132         *    attributes-charset
1133         *    attributes-natural-language
1134         *    requested-attributes
1135         *    printer-uri
1136         */
1137
1138         request = ippNew();
1139
1140         request->request.op.operation_id = IPP_GET_JOBS;
1141         request->request.op.request_id   = 1;
1142
1143         language = cupsLangDefault();
1144
1145         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1146                      "attributes-charset", NULL, "utf-8");
1147
1148         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1149                      "attributes-natural-language", NULL, language->language);
1150
1151         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1152                       "requested-attributes",
1153                       (sizeof(jattrs) / sizeof(jattrs[0])),
1154                       NULL, jattrs);
1155
1156         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1157                      "printer-uri", NULL, uri);
1158
1159        /*
1160         * Do the request and get back a response...
1161         */
1162
1163         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1164                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1165                          ippErrorString(cupsLastError())));
1166                 goto out;
1167         }
1168
1169         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1170                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1171                          ippErrorString(response->request.status.status_code)));
1172                 goto out;
1173         }
1174
1175        /*
1176         * Process the jobs...
1177         */
1178
1179         qcount = 0;
1180         qalloc = 0;
1181         queue  = NULL;
1182
1183         for (attr = response->attrs; attr != NULL; attr = attr->next) {
1184                /*
1185                 * Skip leading attributes until we hit a job...
1186                 */
1187
1188                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1189                         attr = attr->next;
1190
1191                 if (attr == NULL)
1192                         break;
1193
1194                /*
1195                 * Allocate memory as needed...
1196                 */
1197                 if (qcount >= qalloc) {
1198                         qalloc += 16;
1199
1200                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1201
1202                         if (queue == NULL) {
1203                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
1204                                 qcount = 0;
1205                                 goto out;
1206                         }
1207                 }
1208
1209                 temp = queue + qcount;
1210                 memset(temp, 0, sizeof(print_queue_struct));
1211
1212                /*
1213                 * Pull the needed attributes from this job...
1214                 */
1215
1216                 job_id       = 0;
1217                 job_priority = 50;
1218                 job_status   = IPP_JOB_PENDING;
1219                 job_time     = 0;
1220                 job_k_octets = 0;
1221                 user_name    = NULL;
1222                 job_name     = NULL;
1223
1224                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1225                         if (attr->name == NULL) {
1226                                 attr = attr->next;
1227                                 break;
1228                         }
1229
1230                         if (strcmp(attr->name, "job-id") == 0 &&
1231                             attr->value_tag == IPP_TAG_INTEGER)
1232                                 job_id = attr->values[0].integer;
1233
1234                         if (strcmp(attr->name, "job-k-octets") == 0 &&
1235                             attr->value_tag == IPP_TAG_INTEGER)
1236                                 job_k_octets = attr->values[0].integer;
1237
1238                         if (strcmp(attr->name, "job-priority") == 0 &&
1239                             attr->value_tag == IPP_TAG_INTEGER)
1240                                 job_priority = attr->values[0].integer;
1241
1242                         if (strcmp(attr->name, "job-state") == 0 &&
1243                             attr->value_tag == IPP_TAG_ENUM)
1244                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
1245
1246                         if (strcmp(attr->name, "time-at-creation") == 0 &&
1247                             attr->value_tag == IPP_TAG_INTEGER)
1248                                 job_time = attr->values[0].integer;
1249
1250                         if (strcmp(attr->name, "job-name") == 0 &&
1251                             attr->value_tag == IPP_TAG_NAME) {
1252                                 if (!pull_utf8_talloc(frame,
1253                                                 &job_name,
1254                                                 attr->values[0].string.text,
1255                                                 &size)) {
1256                                         goto out;
1257                                 }
1258                         }
1259
1260                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1261                             attr->value_tag == IPP_TAG_NAME) {
1262                                 if (!pull_utf8_talloc(frame,
1263                                                 &user_name,
1264                                                 attr->values[0].string.text,
1265                                                 &size)) {
1266                                         goto out;
1267                                 }
1268                         }
1269
1270                         attr = attr->next;
1271                 }
1272
1273                /*
1274                 * See if we have everything needed...
1275                 */
1276
1277                 if (user_name == NULL || job_name == NULL || job_id == 0) {
1278                         if (attr == NULL)
1279                                 break;
1280                         else
1281                                 continue;
1282                 }
1283
1284                 temp->job      = job_id;
1285                 temp->size     = job_k_octets * 1024;
1286                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1287                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1288                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1289                                  LPQ_PRINTING;
1290                 temp->priority = job_priority;
1291                 temp->time     = job_time;
1292                 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1293                 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1294
1295                 qcount ++;
1296
1297                 if (attr == NULL)
1298                         break;
1299         }
1300
1301         ippDelete(response);
1302         response = NULL;
1303
1304        /*
1305         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1306         * following attributes:
1307         *
1308         *    attributes-charset
1309         *    attributes-natural-language
1310         *    requested-attributes
1311         *    printer-uri
1312         */
1313
1314         request = ippNew();
1315
1316         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1317         request->request.op.request_id   = 1;
1318
1319         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1320                      "attributes-charset", NULL, "utf-8");
1321
1322         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1323                      "attributes-natural-language", NULL, language->language);
1324
1325         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1326                       "requested-attributes",
1327                       (sizeof(pattrs) / sizeof(pattrs[0])),
1328                       NULL, pattrs);
1329
1330         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1331                      "printer-uri", NULL, uri);
1332
1333        /*
1334         * Do the request and get back a response...
1335         */
1336
1337         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1338                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1339                          ippErrorString(cupsLastError())));
1340                 *q = queue;
1341                 goto out;
1342         }
1343
1344         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1345                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1346                          ippErrorString(response->request.status.status_code)));
1347                 *q = queue;
1348                 goto out;
1349         }
1350
1351        /*
1352         * Get the current printer status and convert it to the SAMBA values.
1353         */
1354
1355         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1356                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1357                         status->status = LPSTAT_STOPPED;
1358                 else
1359                         status->status = LPSTAT_OK;
1360         }
1361
1362         if ((attr = ippFindAttribute(response, "printer-state-message",
1363                                      IPP_TAG_TEXT)) != NULL) {
1364                 char *msg = NULL;
1365                 if (!pull_utf8_talloc(frame, &msg,
1366                                 attr->values[0].string.text,
1367                                 &size)) {
1368                         SAFE_FREE(queue);
1369                         qcount = 0;
1370                         goto out;
1371                 }
1372                 fstrcpy(status->message, msg);
1373         }
1374
1375        /*
1376         * Return the job queue...
1377         */
1378
1379         *q = queue;
1380
1381  out:
1382         if (response)
1383                 ippDelete(response);
1384
1385         if (language)
1386                 cupsLangFree(language);
1387
1388         if (http)
1389                 httpClose(http);
1390
1391         TALLOC_FREE(frame);
1392         return qcount;
1393 }
1394
1395
1396 /*
1397  * 'cups_queue_pause()' - Pause a print queue.
1398  */
1399
1400 static int cups_queue_pause(int snum)
1401 {
1402         TALLOC_CTX *frame = talloc_stackframe();
1403         int             ret = 1;                /* Return value */
1404         http_t          *http = NULL;           /* HTTP connection to server */
1405         ipp_t           *request = NULL,        /* IPP Request */
1406                         *response = NULL;       /* IPP Response */
1407         cups_lang_t     *language = NULL;       /* Default language */
1408         char *printername = NULL;
1409         char *username = NULL;
1410         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1411         size_t size;
1412
1413         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1414
1415         /*
1416          * Make sure we don't ask for passwords...
1417          */
1418
1419         cupsSetPasswordCB(cups_passwd_cb);
1420
1421         /*
1422          * Try to connect to the server...
1423          */
1424
1425         if ((http = cups_connect(frame)) == NULL) {
1426                 goto out;
1427         }
1428
1429         /*
1430          * Build an IPP_PAUSE_PRINTER request, which requires the following
1431          * attributes:
1432          *
1433          *    attributes-charset
1434          *    attributes-natural-language
1435          *    printer-uri
1436          *    requesting-user-name
1437          */
1438
1439         request = ippNew();
1440
1441         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1442         request->request.op.request_id   = 1;
1443
1444         language = cupsLangDefault();
1445
1446         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1447                      "attributes-charset", NULL, "utf-8");
1448
1449         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1450                      "attributes-natural-language", NULL, language->language);
1451
1452         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1453                 goto out;
1454         }
1455         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1456                  printername);
1457
1458         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1459
1460         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1461                 goto out;
1462         }
1463         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1464                      NULL, username);
1465
1466        /*
1467         * Do the request and get back a response...
1468         */
1469
1470         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1471                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1472                         DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1473                                 ippErrorString(cupsLastError())));
1474                 } else {
1475                         ret = 0;
1476                 }
1477         } else {
1478                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1479                         ippErrorString(cupsLastError())));
1480         }
1481
1482  out:
1483         if (response)
1484                 ippDelete(response);
1485
1486         if (language)
1487                 cupsLangFree(language);
1488
1489         if (http)
1490                 httpClose(http);
1491
1492         TALLOC_FREE(frame);
1493         return ret;
1494 }
1495
1496
1497 /*
1498  * 'cups_queue_resume()' - Restart a print queue.
1499  */
1500
1501 static int cups_queue_resume(int snum)
1502 {
1503         TALLOC_CTX *frame = talloc_stackframe();
1504         int             ret = 1;                /* Return value */
1505         http_t          *http = NULL;           /* HTTP connection to server */
1506         ipp_t           *request = NULL,        /* IPP Request */
1507                         *response = NULL;       /* IPP Response */
1508         cups_lang_t     *language = NULL;       /* Default language */
1509         char *printername = NULL;
1510         char *username = NULL;
1511         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1512         size_t size;
1513
1514         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1515
1516        /*
1517         * Make sure we don't ask for passwords...
1518         */
1519
1520         cupsSetPasswordCB(cups_passwd_cb);
1521
1522        /*
1523         * Try to connect to the server...
1524         */
1525
1526         if ((http = cups_connect(frame)) == NULL) {
1527                 goto out;
1528         }
1529
1530        /*
1531         * Build an IPP_RESUME_PRINTER request, which requires the following
1532         * attributes:
1533         *
1534         *    attributes-charset
1535         *    attributes-natural-language
1536         *    printer-uri
1537         *    requesting-user-name
1538         */
1539
1540         request = ippNew();
1541
1542         request->request.op.operation_id = IPP_RESUME_PRINTER;
1543         request->request.op.request_id   = 1;
1544
1545         language = cupsLangDefault();
1546
1547         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1548                      "attributes-charset", NULL, "utf-8");
1549
1550         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1551                      "attributes-natural-language", NULL, language->language);
1552
1553         if (!push_utf8_talloc(frame, &printername, PRINTERNAME(snum), &size)) {
1554                 goto out;
1555         }
1556         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1557                  printername);
1558
1559         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1560
1561         if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1562                 goto out;
1563         }
1564         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1565                      NULL, username);
1566
1567        /*
1568         * Do the request and get back a response...
1569         */
1570
1571         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1572                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1573                         DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1574                                 ippErrorString(cupsLastError())));
1575                 } else {
1576                         ret = 0;
1577                 }
1578         } else {
1579                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1580                         ippErrorString(cupsLastError())));
1581         }
1582
1583  out:
1584         if (response)
1585                 ippDelete(response);
1586
1587         if (language)
1588                 cupsLangFree(language);
1589
1590         if (http)
1591                 httpClose(http);
1592
1593         TALLOC_FREE(frame);
1594         return ret;
1595 }
1596
1597 /*******************************************************************
1598  * CUPS printing interface definitions...
1599  ******************************************************************/
1600
1601 struct printif  cups_printif =
1602 {
1603         PRINT_CUPS,
1604         cups_queue_get,
1605         cups_queue_pause,
1606         cups_queue_resume,
1607         cups_job_delete,
1608         cups_job_pause,
1609         cups_job_resume,
1610         cups_job_submit,
1611 };
1612
1613 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1614 {
1615         TALLOC_CTX *frame = talloc_stackframe();
1616         http_t          *http = NULL;           /* HTTP connection to server */
1617         ipp_t           *request = NULL,        /* IPP Request */
1618                         *response = NULL;       /* IPP Response */
1619         ipp_attribute_t *attr;          /* Current attribute */
1620         cups_lang_t     *language = NULL;       /* Default language */
1621         char            uri[HTTP_MAX_URI];
1622         char *server = NULL;
1623         char *sharename = NULL;
1624         char *name = NULL;
1625         static const char *requested[] =/* Requested attributes */
1626                         {
1627                           "printer-name",
1628                           "printer-info",
1629                           "printer-location"
1630                         };
1631         bool ret = False;
1632         size_t size;
1633
1634         DEBUG(5, ("pulling %s location\n", printer->sharename));
1635
1636         /*
1637          * Make sure we don't ask for passwords...
1638          */
1639
1640         cupsSetPasswordCB(cups_passwd_cb);
1641
1642         /*
1643          * Try to connect to the server...
1644          */
1645
1646         if ((http = cups_connect(frame)) == NULL) {
1647                 goto out;
1648         }
1649
1650         request = ippNew();
1651
1652         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1653         request->request.op.request_id   = 1;
1654
1655         language = cupsLangDefault();
1656
1657         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1658                      "attributes-charset", NULL, "utf-8");
1659
1660         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1661                      "attributes-natural-language", NULL, language->language);
1662
1663         if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1664                 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1665                         goto out;
1666                 }
1667         } else {
1668                 server = talloc_strdup(frame,cupsServer());
1669         }
1670         if (server) {
1671                 goto out;
1672         }
1673         if (!push_utf8_talloc(frame, &sharename, printer->sharename, &size)) {
1674                 goto out;
1675         }
1676         slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1677                  server, sharename);
1678
1679         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1680                      "printer-uri", NULL, uri);
1681
1682         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1683                       "requested-attributes",
1684                       (sizeof(requested) / sizeof(requested[0])),
1685                       NULL, requested);
1686
1687         /*
1688          * Do the request and get back a response...
1689          */
1690
1691         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1692                 DEBUG(0,("Unable to get printer attributes - %s\n",
1693                          ippErrorString(cupsLastError())));
1694                 goto out;
1695         }
1696
1697         for (attr = response->attrs; attr != NULL;) {
1698                 /*
1699                  * Skip leading attributes until we hit a printer...
1700                  */
1701
1702                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1703                         attr = attr->next;
1704
1705                 if (attr == NULL)
1706                         break;
1707
1708                 /*
1709                  * Pull the needed attributes from this printer...
1710                  */
1711
1712                 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1713                         if (strcmp(attr->name, "printer-name") == 0 &&
1714                             attr->value_tag == IPP_TAG_NAME) {
1715                                 if (!pull_utf8_talloc(frame,
1716                                                 &name,
1717                                                 attr->values[0].string.text,
1718                                                 &size)) {
1719                                         goto out;
1720                                 }
1721                         }
1722
1723                         /* Grab the comment if we don't have one */
1724                         if ( (strcmp(attr->name, "printer-info") == 0)
1725                              && (attr->value_tag == IPP_TAG_TEXT)
1726                              && !strlen(printer->comment) )
1727                         {
1728                                 char *comment = NULL;
1729                                 if (!pull_utf8_talloc(frame,
1730                                                 &comment,
1731                                                 attr->values[0].string.text,
1732                                                 &size)) {
1733                                         goto out;
1734                                 }
1735                                 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1736                                          comment));
1737                                 strlcpy(printer->comment,
1738                                         comment,
1739                                         sizeof(printer->comment));
1740                         }
1741
1742                         /* Grab the location if we don't have one */
1743                         if ( (strcmp(attr->name, "printer-location") == 0)
1744                              && (attr->value_tag == IPP_TAG_TEXT)
1745                              && !strlen(printer->location) )
1746                         {
1747                                 char *location = NULL;
1748                                 if (!pull_utf8_talloc(frame,
1749                                                 &location,
1750                                                 attr->values[0].string.text,
1751                                                 &size)) {
1752                                         goto out;
1753                                 }
1754                                 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1755                                          location));
1756                                 strlcpy(printer->location,
1757                                         location,
1758                                         sizeof(printer->location));
1759                         }
1760
1761                         attr = attr->next;
1762                 }
1763
1764                 /*
1765                  * We have everything needed...
1766                  */
1767
1768                 if (name != NULL)
1769                         break;
1770         }
1771
1772         ret = True;
1773
1774  out:
1775         if (response)
1776                 ippDelete(response);
1777
1778         if (request) {
1779                 ippDelete(request);
1780         }
1781
1782         if (language)
1783                 cupsLangFree(language);
1784
1785         if (http)
1786                 httpClose(http);
1787
1788         TALLOC_FREE(frame);
1789         return ret;
1790 }
1791
1792 #else
1793  /* this keeps fussy compilers happy */
1794  void print_cups_dummy(void);
1795  void print_cups_dummy(void) {}
1796 #endif /* HAVE_CUPS */