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