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