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