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