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