Remove most of the remaining globals out of lib/util_sock.c.
[ira/wip.git] / source3 / printing / print_cups.c
1 /*
2  * Support code for the Common UNIX Printing System ("CUPS")
3  *
4  * Copyright 1999-2003 by Michael R Sweet.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "printing.h"
22
23 #ifdef HAVE_CUPS
24 #include <cups/cups.h>
25 #include <cups/language.h>
26
27 extern userdom_struct current_user_info;
28
29 /*
30  * 'cups_passwd_cb()' - The CUPS password callback...
31  */
32
33 static const char *                             /* O - Password or NULL */
34 cups_passwd_cb(const char *prompt)      /* I - Prompt */
35 {
36         /*
37          * Always return NULL to indicate that no password is available...
38          */
39
40         return (NULL);
41 }
42
43 static http_t *cups_connect(void)
44 {
45         http_t *http;
46         char *server, *p;
47         int port;
48         
49         if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
50                 server = smb_xstrdup(lp_cups_server());
51         } else {
52                 server = smb_xstrdup(cupsServer());
53         }
54
55         p = strchr(server, ':');
56         if (p) {
57                 port = atoi(p+1);
58                 *p = '\0';
59         } else {
60                 port = ippPort();
61         }
62         
63         DEBUG(10, ("connecting to cups server %s:%d\n",
64                    server, port));
65
66         if ((http = httpConnect(server, port)) == NULL) {
67                 DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n", 
68                          server, port, strerror(errno)));
69                 SAFE_FREE(server);
70                 return NULL;
71         }
72
73         SAFE_FREE(server);
74         return http;
75 }
76
77 bool cups_cache_reload(void)
78 {
79         http_t          *http = NULL;           /* HTTP connection to server */
80         ipp_t           *request = NULL,        /* IPP Request */
81                         *response = NULL;       /* IPP Response */
82         ipp_attribute_t *attr;          /* Current attribute */
83         cups_lang_t     *language = NULL;       /* Default language */
84         char            *name,          /* printer-name attribute */
85                         *info;          /* printer-info attribute */
86         static const char *requested[] =/* Requested attributes */
87                         {
88                           "printer-name",
89                           "printer-info"
90                         };       
91         bool ret = False;
92
93         DEBUG(5, ("reloading cups printcap cache\n"));
94
95        /*
96         * Make sure we don't ask for passwords...
97         */
98
99         cupsSetPasswordCB(cups_passwd_cb);
100
101        /*
102         * Try to connect to the server...
103         */
104
105         if ((http = cups_connect()) == NULL) {
106                 goto out;
107         }
108
109        /*
110         * Build a CUPS_GET_PRINTERS request, which requires the following
111         * attributes:
112         *
113         *    attributes-charset
114         *    attributes-natural-language
115         *    requested-attributes
116         */
117
118         request = ippNew();
119
120         request->request.op.operation_id = CUPS_GET_PRINTERS;
121         request->request.op.request_id   = 1;
122
123         language = cupsLangDefault();
124
125         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
126                      "attributes-charset", NULL, cupsLangEncoding(language));
127
128         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
129                      "attributes-natural-language", NULL, language->language);
130
131         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
132                       "requested-attributes",
133                       (sizeof(requested) / sizeof(requested[0])),
134                       NULL, requested);
135
136        /*
137         * Do the request and get back a response...
138         */
139
140         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
141                 DEBUG(0,("Unable to get printer list - %s\n",
142                          ippErrorString(cupsLastError())));
143                 goto out;
144         }
145
146         for (attr = response->attrs; attr != NULL;) {
147                /*
148                 * Skip leading attributes until we hit a printer...
149                 */
150
151                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
152                         attr = attr->next;
153
154                 if (attr == NULL)
155                         break;
156
157                /*
158                 * Pull the needed attributes from this printer...
159                 */
160
161                 name       = NULL;
162                 info       = NULL;
163
164                 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
165                         if (strcmp(attr->name, "printer-name") == 0 &&
166                             attr->value_tag == IPP_TAG_NAME)
167                                 name = attr->values[0].string.text;
168
169                         if (strcmp(attr->name, "printer-info") == 0 &&
170                             attr->value_tag == IPP_TAG_TEXT)
171                                 info = attr->values[0].string.text;
172
173                         attr = attr->next;
174                 }
175
176                /*
177                 * See if we have everything needed...
178                 */
179
180                 if (name == NULL)
181                         break;
182
183                 if (!pcap_cache_add(name, info)) {
184                         goto out;
185                 }
186         }
187
188         ippDelete(response);
189         response = NULL;
190
191        /*
192         * Build a CUPS_GET_CLASSES request, which requires the following
193         * attributes:
194         *
195         *    attributes-charset
196         *    attributes-natural-language
197         *    requested-attributes
198         */
199
200         request = ippNew();
201
202         request->request.op.operation_id = CUPS_GET_CLASSES;
203         request->request.op.request_id   = 1;
204
205         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
206                      "attributes-charset", NULL, cupsLangEncoding(language));
207
208         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
209                      "attributes-natural-language", NULL, language->language);
210
211         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
212                       "requested-attributes",
213                       (sizeof(requested) / sizeof(requested[0])),
214                       NULL, requested);
215
216        /*
217         * Do the request and get back a response...
218         */
219
220         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
221                 DEBUG(0,("Unable to get printer list - %s\n",
222                          ippErrorString(cupsLastError())));
223                 goto out;
224         }
225
226         for (attr = response->attrs; attr != NULL;) {
227                /*
228                 * Skip leading attributes until we hit a printer...
229                 */
230
231                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
232                         attr = attr->next;
233
234                 if (attr == NULL)
235                         break;
236
237                /*
238                 * Pull the needed attributes from this printer...
239                 */
240
241                 name       = NULL;
242                 info       = NULL;
243
244                 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
245                         if (strcmp(attr->name, "printer-name") == 0 &&
246                             attr->value_tag == IPP_TAG_NAME)
247                                 name = attr->values[0].string.text;
248
249                         if (strcmp(attr->name, "printer-info") == 0 &&
250                             attr->value_tag == IPP_TAG_TEXT)
251                                 info = attr->values[0].string.text;
252
253                         attr = attr->next;
254                 }
255
256                /*
257                 * See if we have everything needed...
258                 */
259
260                 if (name == NULL)
261                         break;
262
263                 if (!pcap_cache_add(name, info)) {
264                         goto out;
265                 }
266         }
267
268         ret = True;
269
270  out:
271         if (response)
272                 ippDelete(response);
273
274         if (language)
275                 cupsLangFree(language);
276
277         if (http)
278                 httpClose(http);
279
280         return ret;
281 }
282
283
284 /*
285  * 'cups_job_delete()' - Delete a job.
286  */
287
288 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
289 {
290         int             ret = 1;                /* Return value */
291         http_t          *http = NULL;           /* HTTP connection to server */
292         ipp_t           *request = NULL,        /* IPP Request */
293                         *response = NULL;       /* IPP Response */
294         cups_lang_t     *language = NULL;       /* Default language */
295         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
296
297
298         DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
299
300        /*
301         * Make sure we don't ask for passwords...
302         */
303
304         cupsSetPasswordCB(cups_passwd_cb);
305
306        /*
307         * Try to connect to the server...
308         */
309
310         if ((http = cups_connect()) == NULL) {
311                 goto out;
312         }
313
314        /*
315         * Build an IPP_CANCEL_JOB request, which requires the following
316         * attributes:
317         *
318         *    attributes-charset
319         *    attributes-natural-language
320         *    job-uri
321         *    requesting-user-name
322         */
323
324         request = ippNew();
325
326         request->request.op.operation_id = IPP_CANCEL_JOB;
327         request->request.op.request_id   = 1;
328
329         language = cupsLangDefault();
330
331         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
332                      "attributes-charset", NULL, cupsLangEncoding(language));
333
334         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
335                      "attributes-natural-language", NULL, language->language);
336
337         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
338
339         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
340
341         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
342                      NULL, pjob->user);
343
344        /*
345         * Do the request and get back a response...
346         */
347
348         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
349                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
350                         DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
351                                 ippErrorString(cupsLastError())));
352                 } else {
353                         ret = 0;
354                 }
355         } else {
356                 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
357                         ippErrorString(cupsLastError())));
358         }
359
360  out:
361         if (response)
362                 ippDelete(response);
363
364         if (language)
365                 cupsLangFree(language);
366
367         if (http)
368                 httpClose(http);
369
370         return ret;
371 }
372
373
374 /*
375  * 'cups_job_pause()' - Pause a job.
376  */
377
378 static int cups_job_pause(int snum, struct printjob *pjob)
379 {
380         int             ret = 1;                /* Return value */
381         http_t          *http = NULL;           /* HTTP connection to server */
382         ipp_t           *request = NULL,        /* IPP Request */
383                         *response = NULL;       /* IPP Response */
384         cups_lang_t     *language = NULL;       /* Default language */
385         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
386
387
388         DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
389
390        /*
391         * Make sure we don't ask for passwords...
392         */
393
394         cupsSetPasswordCB(cups_passwd_cb);
395
396        /*
397         * Try to connect to the server...
398         */
399
400         if ((http = cups_connect()) == NULL) {
401                 goto out;
402         }
403
404        /*
405         * Build an IPP_HOLD_JOB request, which requires the following
406         * attributes:
407         *
408         *    attributes-charset
409         *    attributes-natural-language
410         *    job-uri
411         *    requesting-user-name
412         */
413
414         request = ippNew();
415
416         request->request.op.operation_id = IPP_HOLD_JOB;
417         request->request.op.request_id   = 1;
418
419         language = cupsLangDefault();
420
421         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
422                      "attributes-charset", NULL, cupsLangEncoding(language));
423
424         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
425                      "attributes-natural-language", NULL, language->language);
426
427         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
428
429         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
430
431         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
432                      NULL, pjob->user);
433
434        /*
435         * Do the request and get back a response...
436         */
437
438         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
439                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
440                         DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
441                                 ippErrorString(cupsLastError())));
442                 } else {
443                         ret = 0;
444                 }
445         } else {
446                 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
447                         ippErrorString(cupsLastError())));
448         }
449
450  out:
451         if (response)
452                 ippDelete(response);
453
454         if (language)
455                 cupsLangFree(language);
456
457         if (http)
458                 httpClose(http);
459
460         return ret;
461 }
462
463
464 /*
465  * 'cups_job_resume()' - Resume a paused job.
466  */
467
468 static int cups_job_resume(int snum, struct printjob *pjob)
469 {
470         int             ret = 1;                /* Return value */
471         http_t          *http = NULL;           /* HTTP connection to server */
472         ipp_t           *request = NULL,        /* IPP Request */
473                         *response = NULL;       /* IPP Response */
474         cups_lang_t     *language = NULL;       /* Default language */
475         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
476
477
478         DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
479
480        /*
481         * Make sure we don't ask for passwords...
482         */
483
484         cupsSetPasswordCB(cups_passwd_cb);
485
486        /*
487         * Try to connect to the server...
488         */
489
490         if ((http = cups_connect()) == NULL) {
491                 goto out;
492         }
493
494        /*
495         * Build an IPP_RELEASE_JOB request, which requires the following
496         * attributes:
497         *
498         *    attributes-charset
499         *    attributes-natural-language
500         *    job-uri
501         *    requesting-user-name
502         */
503
504         request = ippNew();
505
506         request->request.op.operation_id = IPP_RELEASE_JOB;
507         request->request.op.request_id   = 1;
508
509         language = cupsLangDefault();
510
511         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
512                      "attributes-charset", NULL, cupsLangEncoding(language));
513
514         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
515                      "attributes-natural-language", NULL, language->language);
516
517         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
518
519         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
520
521         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
522                      NULL, pjob->user);
523
524        /*
525         * Do the request and get back a response...
526         */
527
528         if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
529                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
530                         DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
531                                 ippErrorString(cupsLastError())));
532                 } else {
533                         ret = 0;
534                 }
535         } else {
536                 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
537                         ippErrorString(cupsLastError())));
538         }
539
540  out:
541         if (response)
542                 ippDelete(response);
543
544         if (language)
545                 cupsLangFree(language);
546
547         if (http)
548                 httpClose(http);
549
550         return ret;
551 }
552
553
554 /*
555  * 'cups_job_submit()' - Submit a job for printing.
556  */
557
558 static int cups_job_submit(int snum, struct printjob *pjob)
559 {
560         int             ret = 1;                /* Return value */
561         http_t          *http = NULL;           /* HTTP connection to server */
562         ipp_t           *request = NULL,        /* IPP Request */
563                         *response = NULL;       /* IPP Response */
564         cups_lang_t     *language = NULL;       /* Default language */
565         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
566         const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
567         pstring         new_jobname;
568         int             num_options = 0; 
569         cups_option_t   *options = NULL;
570         char addr[INET6_ADDRSTRLEN];
571
572         DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
573
574        /*
575         * Make sure we don't ask for passwords...
576         */
577
578         cupsSetPasswordCB(cups_passwd_cb);
579
580        /*
581         * Try to connect to the server...
582         */
583
584         if ((http = cups_connect()) == NULL) {
585                 goto out;
586         }
587
588        /*
589         * Build an IPP_PRINT_JOB request, which requires the following
590         * attributes:
591         *
592         *    attributes-charset
593         *    attributes-natural-language
594         *    printer-uri
595         *    requesting-user-name
596         *    [document-data]
597         */
598
599         request = ippNew();
600
601         request->request.op.operation_id = IPP_PRINT_JOB;
602         request->request.op.request_id   = 1;
603
604         language = cupsLangDefault();
605
606         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
607                      "attributes-charset", NULL, cupsLangEncoding(language));
608
609         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
610                      "attributes-natural-language", NULL, language->language);
611
612         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
613                  PRINTERNAME(snum));
614
615         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
616                      "printer-uri", NULL, uri);
617
618         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
619                      NULL, pjob->user);
620
621         clientname = client_name(get_client_fd());
622         if (strcmp(clientname, "UNKNOWN") == 0) {
623                 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
624         }
625
626         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
627                      "job-originating-host-name", NULL,
628                       clientname);
629
630         pstr_sprintf(new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX, 
631                 (unsigned int)pjob->smbjob, pjob->jobname);
632
633         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
634                      new_jobname);
635
636         /* 
637          * add any options defined in smb.conf 
638          */
639
640         num_options = 0;
641         options     = NULL;
642         num_options = cupsParseOptions(lp_cups_options(snum), num_options, &options);
643
644         if ( num_options )
645                 cupsEncodeOptions(request, num_options, options); 
646
647        /*
648         * Do the request and get back a response...
649         */
650
651         slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
652
653         if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
654                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
655                         DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
656                                  ippErrorString(cupsLastError())));
657                 } else {
658                         ret = 0;
659                 }
660         } else {
661                 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
662                          ippErrorString(cupsLastError())));
663         }
664
665         if ( ret == 0 )
666                 unlink(pjob->filename);
667         /* else print_job_end will do it for us */
668
669  out:
670         if (response)
671                 ippDelete(response);
672
673         if (language)
674                 cupsLangFree(language);
675
676         if (http)
677                 httpClose(http);
678
679         return ret;
680 }
681
682 /*
683  * 'cups_queue_get()' - Get all the jobs in the print queue.
684  */
685
686 static int cups_queue_get(const char *sharename,
687                enum printing_types printing_type,
688                char *lpq_command,
689                print_queue_struct **q, 
690                print_status_struct *status)
691 {
692         fstring         printername;
693         http_t          *http = NULL;           /* HTTP connection to server */
694         ipp_t           *request = NULL,        /* IPP Request */
695                         *response = NULL;       /* IPP Response */
696         ipp_attribute_t *attr = NULL;           /* Current attribute */
697         cups_lang_t     *language = NULL;       /* Default language */
698         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
699         int             qcount = 0,             /* Number of active queue entries */
700                         qalloc = 0;             /* Number of queue entries allocated */
701         print_queue_struct *queue = NULL,       /* Queue entries */
702                         *temp;          /* Temporary pointer for queue */
703         const char      *user_name,     /* job-originating-user-name attribute */
704                         *job_name;      /* job-name attribute */
705         int             job_id;         /* job-id attribute */
706         int             job_k_octets;   /* job-k-octets attribute */
707         time_t          job_time;       /* time-at-creation attribute */
708         ipp_jstate_t    job_status;     /* job-status attribute */
709         int             job_priority;   /* job-priority attribute */
710         static const char *jattrs[] =   /* Requested job attributes */
711                         {
712                           "job-id",
713                           "job-k-octets",
714                           "job-name",
715                           "job-originating-user-name",
716                           "job-priority",
717                           "job-state",
718                           "time-at-creation",
719                         };
720         static const char *pattrs[] =   /* Requested printer attributes */
721                         {
722                           "printer-state",
723                           "printer-state-message"
724                         };
725
726         *q = NULL;
727
728         /* HACK ALERT!!!  The problem with support the 'printer name' 
729            option is that we key the tdb off the sharename.  So we will 
730            overload the lpq_command string to pass in the printername 
731            (which is basically what we do for non-cups printers ... using 
732            the lpq_command to get the queue listing). */
733
734         fstrcpy( printername, lpq_command );
735
736         DEBUG(5,("cups_queue_get(%s, %p, %p)\n", printername, q, status));
737
738        /*
739         * Make sure we don't ask for passwords...
740         */
741
742         cupsSetPasswordCB(cups_passwd_cb);
743
744        /*
745         * Try to connect to the server...
746         */
747
748         if ((http = cups_connect()) == NULL) {
749                 goto out;
750         }
751
752        /*
753         * Generate the printer URI...
754         */
755
756         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
757
758        /*
759         * Build an IPP_GET_JOBS request, which requires the following
760         * attributes:
761         *
762         *    attributes-charset
763         *    attributes-natural-language
764         *    requested-attributes
765         *    printer-uri
766         */
767
768         request = ippNew();
769
770         request->request.op.operation_id = IPP_GET_JOBS;
771         request->request.op.request_id   = 1;
772
773         language = cupsLangDefault();
774
775         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
776                      "attributes-charset", NULL, cupsLangEncoding(language));
777
778         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
779                      "attributes-natural-language", NULL, language->language);
780
781         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
782                       "requested-attributes",
783                       (sizeof(jattrs) / sizeof(jattrs[0])),
784                       NULL, jattrs);
785
786         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
787                      "printer-uri", NULL, uri);
788
789        /*
790         * Do the request and get back a response...
791         */
792
793         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
794                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
795                          ippErrorString(cupsLastError())));
796                 goto out;
797         }
798
799         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
800                 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
801                          ippErrorString(response->request.status.status_code)));
802                 goto out;
803         }
804
805        /*
806         * Process the jobs...
807         */
808
809         qcount = 0;
810         qalloc = 0;
811         queue  = NULL;
812
813         for (attr = response->attrs; attr != NULL; attr = attr->next) {
814                /*
815                 * Skip leading attributes until we hit a job...
816                 */
817
818                 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
819                         attr = attr->next;
820
821                 if (attr == NULL)
822                         break;
823
824                /*
825                 * Allocate memory as needed...
826                 */
827                 if (qcount >= qalloc) {
828                         qalloc += 16;
829
830                         queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
831
832                         if (queue == NULL) {
833                                 DEBUG(0,("cups_queue_get: Not enough memory!"));
834                                 qcount = 0;
835                                 goto out;
836                         }
837                 }
838
839                 temp = queue + qcount;
840                 memset(temp, 0, sizeof(print_queue_struct));
841
842                /*
843                 * Pull the needed attributes from this job...
844                 */
845
846                 job_id       = 0;
847                 job_priority = 50;
848                 job_status   = IPP_JOB_PENDING;
849                 job_time     = 0;
850                 job_k_octets = 0;
851                 user_name    = NULL;
852                 job_name     = NULL;
853
854                 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
855                         if (attr->name == NULL) {
856                                 attr = attr->next;
857                                 break;
858                         }
859
860                         if (strcmp(attr->name, "job-id") == 0 &&
861                             attr->value_tag == IPP_TAG_INTEGER)
862                                 job_id = attr->values[0].integer;
863
864                         if (strcmp(attr->name, "job-k-octets") == 0 &&
865                             attr->value_tag == IPP_TAG_INTEGER)
866                                 job_k_octets = attr->values[0].integer;
867
868                         if (strcmp(attr->name, "job-priority") == 0 &&
869                             attr->value_tag == IPP_TAG_INTEGER)
870                                 job_priority = attr->values[0].integer;
871
872                         if (strcmp(attr->name, "job-state") == 0 &&
873                             attr->value_tag == IPP_TAG_ENUM)
874                                 job_status = (ipp_jstate_t)(attr->values[0].integer);
875
876                         if (strcmp(attr->name, "time-at-creation") == 0 &&
877                             attr->value_tag == IPP_TAG_INTEGER)
878                                 job_time = attr->values[0].integer;
879
880                         if (strcmp(attr->name, "job-name") == 0 &&
881                             attr->value_tag == IPP_TAG_NAME)
882                                 job_name = attr->values[0].string.text;
883
884                         if (strcmp(attr->name, "job-originating-user-name") == 0 &&
885                             attr->value_tag == IPP_TAG_NAME)
886                                 user_name = attr->values[0].string.text;
887
888                         attr = attr->next;
889                 }
890
891                /*
892                 * See if we have everything needed...
893                 */
894
895                 if (user_name == NULL || job_name == NULL || job_id == 0) {
896                         if (attr == NULL)
897                                 break;
898                         else
899                                 continue;
900                 }
901
902                 temp->job      = job_id;
903                 temp->size     = job_k_octets * 1024;
904                 temp->status   = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
905                                  job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
906                                  job_status == IPP_JOB_HELD ? LPQ_PAUSED :
907                                  LPQ_PRINTING;
908                 temp->priority = job_priority;
909                 temp->time     = job_time;
910                 strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1);
911                 strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
912
913                 qcount ++;
914
915                 if (attr == NULL)
916                         break;
917         }
918
919         ippDelete(response);
920         response = NULL;
921
922        /*
923         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
924         * following attributes:
925         *
926         *    attributes-charset
927         *    attributes-natural-language
928         *    requested-attributes
929         *    printer-uri
930         */
931
932         request = ippNew();
933
934         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
935         request->request.op.request_id   = 1;
936
937         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
938                      "attributes-charset", NULL, cupsLangEncoding(language));
939
940         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
941                      "attributes-natural-language", NULL, language->language);
942
943         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
944                       "requested-attributes",
945                       (sizeof(pattrs) / sizeof(pattrs[0])),
946                       NULL, pattrs);
947
948         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
949                      "printer-uri", NULL, uri);
950
951        /*
952         * Do the request and get back a response...
953         */
954
955         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
956                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
957                          ippErrorString(cupsLastError())));
958                 *q = queue;
959                 goto out;
960         }
961
962         if (response->request.status.status_code >= IPP_OK_CONFLICT) {
963                 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
964                          ippErrorString(response->request.status.status_code)));
965                 *q = queue;
966                 goto out;
967         }
968
969        /*
970         * Get the current printer status and convert it to the SAMBA values.
971         */
972
973         if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
974                 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
975                         status->status = LPSTAT_STOPPED;
976                 else
977                         status->status = LPSTAT_OK;
978         }
979
980         if ((attr = ippFindAttribute(response, "printer-state-message",
981                                      IPP_TAG_TEXT)) != NULL)
982                 fstrcpy(status->message, attr->values[0].string.text);
983
984        /*
985         * Return the job queue...
986         */
987
988         *q = queue;
989
990  out:
991         if (response)
992                 ippDelete(response);
993
994         if (language)
995                 cupsLangFree(language);
996
997         if (http)
998                 httpClose(http);
999
1000         return qcount;
1001 }
1002
1003
1004 /*
1005  * 'cups_queue_pause()' - Pause a print queue.
1006  */
1007
1008 static int cups_queue_pause(int snum)
1009 {
1010         int             ret = 1;                /* Return value */
1011         http_t          *http = NULL;           /* HTTP connection to server */
1012         ipp_t           *request = NULL,        /* IPP Request */
1013                         *response = NULL;       /* IPP Response */
1014         cups_lang_t     *language = NULL;       /* Default language */
1015         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1016
1017
1018         DEBUG(5,("cups_queue_pause(%d)\n", snum));
1019
1020         /*
1021          * Make sure we don't ask for passwords...
1022          */
1023
1024         cupsSetPasswordCB(cups_passwd_cb);
1025
1026         /*
1027          * Try to connect to the server...
1028          */
1029
1030         if ((http = cups_connect()) == NULL) {
1031                 goto out;
1032         }
1033
1034         /*
1035          * Build an IPP_PAUSE_PRINTER request, which requires the following
1036          * attributes:
1037          *
1038          *    attributes-charset
1039          *    attributes-natural-language
1040          *    printer-uri
1041          *    requesting-user-name
1042          */
1043
1044         request = ippNew();
1045
1046         request->request.op.operation_id = IPP_PAUSE_PRINTER;
1047         request->request.op.request_id   = 1;
1048
1049         language = cupsLangDefault();
1050
1051         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1052                      "attributes-charset", NULL, cupsLangEncoding(language));
1053
1054         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1055                      "attributes-natural-language", NULL, language->language);
1056
1057         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1058                  PRINTERNAME(snum));
1059
1060         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1061
1062         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1063                      NULL, current_user_info.unix_name);
1064
1065        /*
1066         * Do the request and get back a response...
1067         */
1068
1069         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1070                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1071                         DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1072                                 ippErrorString(cupsLastError())));
1073                 } else {
1074                         ret = 0;
1075                 }
1076         } else {
1077                 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1078                         ippErrorString(cupsLastError())));
1079         }
1080
1081  out:
1082         if (response)
1083                 ippDelete(response);
1084
1085         if (language)
1086                 cupsLangFree(language);
1087
1088         if (http)
1089                 httpClose(http);
1090
1091         return ret;
1092 }
1093
1094
1095 /*
1096  * 'cups_queue_resume()' - Restart a print queue.
1097  */
1098
1099 static int cups_queue_resume(int snum)
1100 {
1101         int             ret = 1;                /* Return value */
1102         http_t          *http = NULL;           /* HTTP connection to server */
1103         ipp_t           *request = NULL,        /* IPP Request */
1104                         *response = NULL;       /* IPP Response */
1105         cups_lang_t     *language = NULL;       /* Default language */
1106         char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
1107
1108
1109         DEBUG(5,("cups_queue_resume(%d)\n", snum));
1110
1111        /*
1112         * Make sure we don't ask for passwords...
1113         */
1114
1115         cupsSetPasswordCB(cups_passwd_cb);
1116
1117        /*
1118         * Try to connect to the server...
1119         */
1120
1121         if ((http = cups_connect()) == NULL) {
1122                 goto out;
1123         }
1124
1125        /*
1126         * Build an IPP_RESUME_PRINTER request, which requires the following
1127         * attributes:
1128         *
1129         *    attributes-charset
1130         *    attributes-natural-language
1131         *    printer-uri
1132         *    requesting-user-name
1133         */
1134
1135         request = ippNew();
1136
1137         request->request.op.operation_id = IPP_RESUME_PRINTER;
1138         request->request.op.request_id   = 1;
1139
1140         language = cupsLangDefault();
1141
1142         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1143                      "attributes-charset", NULL, cupsLangEncoding(language));
1144
1145         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1146                      "attributes-natural-language", NULL, language->language);
1147
1148         slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1149                  PRINTERNAME(snum));
1150
1151         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1152
1153         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1154                      NULL, current_user_info.unix_name);
1155
1156        /*
1157         * Do the request and get back a response...
1158         */
1159
1160         if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1161                 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1162                         DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1163                                 ippErrorString(cupsLastError())));
1164                 } else {
1165                         ret = 0;
1166                 }
1167         } else {
1168                 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1169                         ippErrorString(cupsLastError())));
1170         }
1171
1172  out:
1173         if (response)
1174                 ippDelete(response);
1175
1176         if (language)
1177                 cupsLangFree(language);
1178
1179         if (http)
1180                 httpClose(http);
1181
1182         return ret;
1183 }
1184
1185 /*******************************************************************
1186  * CUPS printing interface definitions...
1187  ******************************************************************/
1188
1189 struct printif  cups_printif =
1190 {
1191         PRINT_CUPS,
1192         cups_queue_get,
1193         cups_queue_pause,
1194         cups_queue_resume,
1195         cups_job_delete,
1196         cups_job_pause,
1197         cups_job_resume,
1198         cups_job_submit,
1199 };
1200
1201 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1202 {
1203         http_t          *http = NULL;           /* HTTP connection to server */
1204         ipp_t           *request = NULL,        /* IPP Request */
1205                         *response = NULL;       /* IPP Response */
1206         ipp_attribute_t *attr;          /* Current attribute */
1207         cups_lang_t     *language = NULL;       /* Default language */
1208         char            *name,          /* printer-name attribute */
1209                         *info,          /* printer-info attribute */
1210                         *location;      /* printer-location attribute */
1211         char            uri[HTTP_MAX_URI];
1212         static const char *requested[] =/* Requested attributes */
1213                         {
1214                           "printer-name",
1215                           "printer-info",
1216                           "printer-location"
1217                         };
1218         bool ret = False;
1219
1220         DEBUG(5, ("pulling %s location\n", printer->sharename));
1221
1222         /*
1223          * Make sure we don't ask for passwords...
1224          */
1225
1226         cupsSetPasswordCB(cups_passwd_cb);
1227
1228         /*
1229          * Try to connect to the server...
1230          */
1231
1232         if ((http = cups_connect()) == NULL) {
1233                 goto out;
1234         }
1235
1236         request = ippNew();
1237
1238         request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1239         request->request.op.request_id   = 1;
1240
1241         language = cupsLangDefault();
1242
1243         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1244                      "attributes-charset", NULL, cupsLangEncoding(language));
1245
1246         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1247                      "attributes-natural-language", NULL, language->language);
1248
1249         slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1250                  lp_cups_server(), printer->sharename);
1251
1252         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1253                      "printer-uri", NULL, uri);
1254
1255         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1256                       "requested-attributes",
1257                       (sizeof(requested) / sizeof(requested[0])),
1258                       NULL, requested);
1259
1260         /*
1261          * Do the request and get back a response...
1262          */
1263
1264         if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1265                 DEBUG(0,("Unable to get printer attributes - %s\n",
1266                          ippErrorString(cupsLastError())));
1267                 goto out;
1268         }
1269
1270         for (attr = response->attrs; attr != NULL;) {
1271                 /*
1272                  * Skip leading attributes until we hit a printer...
1273                  */
1274
1275                 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1276                         attr = attr->next;
1277
1278                 if (attr == NULL)
1279                         break;
1280
1281                 /*
1282                  * Pull the needed attributes from this printer...
1283                  */
1284
1285                 name       = NULL;
1286                 info       = NULL;
1287                 location   = NULL;
1288
1289                 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1290                         /* Grab the comment if we don't have one */
1291                         if ( (strcmp(attr->name, "printer-info") == 0)
1292                              && (attr->value_tag == IPP_TAG_TEXT)
1293                              && !strlen(printer->comment) ) 
1294                         {
1295                                 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1296                                          attr->values[0].string.text));                         
1297                                 pstrcpy(printer->comment,attr->values[0].string.text);
1298                         }
1299
1300                         /* Grab the location if we don't have one */ 
1301                         if ( (strcmp(attr->name, "printer-location") == 0)
1302                              && (attr->value_tag == IPP_TAG_TEXT) 
1303                              && !strlen(printer->location) )
1304                         {
1305                                 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1306                                          attr->values[0].string.text));                         
1307                                 fstrcpy(printer->location,attr->values[0].string.text);
1308                         }
1309
1310                         attr = attr->next;
1311                 }
1312
1313                 /*
1314                  * See if we have everything needed...
1315                  */
1316
1317                 if (name == NULL)
1318                         break;
1319
1320         }
1321
1322         ret = True;
1323
1324  out:
1325         if (response)
1326                 ippDelete(response);
1327
1328         if (language)
1329                 cupsLangFree(language);
1330
1331         if (http)
1332                 httpClose(http);
1333
1334         return ret;
1335 }
1336
1337 #else
1338  /* this keeps fussy compilers happy */
1339  void print_cups_dummy(void);
1340  void print_cups_dummy(void) {}
1341 #endif /* HAVE_CUPS */