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