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