]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/ipp-var.c
4bf7977765de04b11f3724a04c312b83f5dc7832
[thirdparty/cups.git] / cgi-bin / ipp-var.c
1 /*
2 * "$Id$"
3 *
4 * CGI <-> IPP variable routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * cgiGetAttributes() - Get the list of attributes that are needed
27 * by the template file.
28 * cgiGetIPPObjects() - Get the objects in an IPP response.
29 * cgiMoveJobs() - Move one or more jobs.
30 * cgiPrintTestPage() - Print a test page.
31 * cgiRewriteURL() - Rewrite a printer URI into a web browser URL...
32 * cgiSetIPPObjectVars() - Set CGI variables from an IPP object.
33 * cgiSetIPPVars() - Set CGI variables from an IPP response.
34 * cgiShowIPPError() - Show the last IPP error message.
35 * cgiShowJobs() - Show print jobs.
36 * cgiText() - Return localized text.
37 */
38
39 /*
40 * Include necessary headers...
41 */
42
43 #include "cgi-private.h"
44
45
46 /*
47 * 'cgiGetAttributes()' - Get the list of attributes that are needed
48 * by the template file.
49 */
50
51 void
52 cgiGetAttributes(ipp_t *request, /* I - IPP request */
53 const char *tmpl) /* I - Base filename */
54 {
55 int num_attrs; /* Number of attributes */
56 char *attrs[1000]; /* Attributes */
57 int i; /* Looping var */
58 char filename[1024], /* Filename */
59 locale[16]; /* Locale name */
60 const char *directory, /* Directory */
61 *lang; /* Language */
62 FILE *in; /* Input file */
63 int ch; /* Character from file */
64 char name[255], /* Name of variable */
65 *nameptr; /* Pointer into name */
66
67
68 /*
69 * Convert the language to a locale name...
70 */
71
72 if ((lang = getenv("LANG")) != NULL)
73 {
74 for (i = 0; lang[i] && i < 15; i ++)
75 if (isalnum(lang[i] & 255))
76 locale[i] = tolower(lang[i]);
77 else
78 locale[i] = '_';
79
80 locale[i] = '\0';
81 }
82 else
83 locale[0] = '\0';
84
85 /*
86 * See if we have a template file for this language...
87 */
88
89 directory = cgiGetTemplateDir();
90
91 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
92 if (access(filename, 0))
93 {
94 locale[2] = '\0';
95
96 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
97 if (access(filename, 0))
98 snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
99 }
100
101 /*
102 * Open the template file...
103 */
104
105 if ((in = fopen(filename, "r")) == NULL)
106 return;
107
108 /*
109 * Loop through the file adding attribute names as needed...
110 */
111
112 num_attrs = 0;
113
114 while ((ch = getc(in)) != EOF)
115 if (ch == '\\')
116 getc(in);
117 else if (ch == '{' && num_attrs < (sizeof(attrs) / sizeof(attrs[0])))
118 {
119 /*
120 * Grab the name...
121 */
122
123 for (nameptr = name; (ch = getc(in)) != EOF;)
124 if (strchr("}]<>=! \t\n", ch))
125 break;
126 else if (nameptr > name && ch == '?')
127 break;
128 else if (nameptr < (name + sizeof(name) - 1))
129 {
130 if (ch == '_')
131 *nameptr++ = '-';
132 else
133 *nameptr++ = ch;
134 }
135
136 *nameptr = '\0';
137
138 if (!strncmp(name, "printer_state_history", 21))
139 strcpy(name, "printer_state_history");
140
141 /*
142 * Possibly add it to the list of attributes...
143 */
144
145 for (i = 0; i < num_attrs; i ++)
146 if (!strcmp(attrs[i], name))
147 break;
148
149 if (i >= num_attrs)
150 {
151 attrs[num_attrs] = strdup(name);
152 num_attrs ++;
153 }
154 }
155
156 /*
157 * If we have attributes, add a requested-attributes attribute to the
158 * request...
159 */
160
161 if (num_attrs > 0)
162 {
163 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
164 "requested-attributes", num_attrs, NULL, (const char **)attrs);
165
166 for (i = 0; i < num_attrs; i ++)
167 free(attrs[i]);
168 }
169 }
170
171
172 /*
173 * 'cgiGetIPPObjects()' - Get the objects in an IPP response.
174 */
175
176 cups_array_t * /* O - Array of objects */
177 cgiGetIPPObjects(ipp_t *response, /* I - IPP response */
178 void *search) /* I - Search filter */
179 {
180 int i; /* Looping var */
181 cups_array_t *objs; /* Array of objects */
182 ipp_attribute_t *attr, /* Current attribute */
183 *first; /* First attribute for object */
184 ipp_tag_t group; /* Current group tag */
185 int add; /* Add this object to the array? */
186
187
188 if (!response)
189 return (0);
190
191 for (add = 0, first = NULL, objs = cupsArrayNew(NULL, NULL),
192 group = IPP_TAG_ZERO, attr = response->attrs;
193 attr;
194 attr = attr->next)
195 {
196 if (attr->group_tag != group)
197 {
198 group = attr->group_tag;
199
200 if (group != IPP_TAG_ZERO && group != IPP_TAG_OPERATION)
201 {
202 first = attr;
203 add = 0;
204 }
205 else if (add && first)
206 {
207 cupsArrayAdd(objs, first);
208
209 add = 0;
210 first = NULL;
211 }
212 }
213
214 if (attr->name && attr->group_tag != IPP_TAG_OPERATION && !add)
215 {
216 if (!search)
217 {
218 /*
219 * Add all objects if there is no search...
220 */
221
222 add = 1;
223 }
224 else
225 {
226 /*
227 * Check the search string against the string and integer values.
228 */
229
230 switch (attr->value_tag)
231 {
232 case IPP_TAG_TEXTLANG :
233 case IPP_TAG_NAMELANG :
234 case IPP_TAG_TEXT :
235 case IPP_TAG_NAME :
236 case IPP_TAG_KEYWORD :
237 case IPP_TAG_URI :
238 case IPP_TAG_MIMETYPE :
239 for (i = 0; !add && i < attr->num_values; i ++)
240 if (cgiDoSearch(search, attr->values[i].string.text))
241 add = 1;
242 break;
243
244 case IPP_TAG_INTEGER :
245 for (i = 0; !add && i < attr->num_values; i ++)
246 {
247 char buf[255]; /* Number buffer */
248
249
250 sprintf(buf, "%d", attr->values[i].integer);
251
252 if (cgiDoSearch(search, buf))
253 add = 1;
254 }
255 break;
256
257 default :
258 break;
259 }
260 }
261 }
262 }
263
264 if (add && first)
265 cupsArrayAdd(objs, first);
266
267 return (objs);
268 }
269
270
271 /*
272 * 'cgiMoveJobs()' - Move one or more jobs.
273 *
274 * At least one of dest or job_id must be non-zero/NULL.
275 */
276
277 void
278 cgiMoveJobs(http_t *http, /* I - Connection to server */
279 const char *dest, /* I - Destination or NULL */
280 int job_id) /* I - Job ID or 0 for all */
281 {
282 int i; /* Looping var */
283 const char *user; /* Username */
284 ipp_t *request, /* IPP request */
285 *response; /* IPP response */
286 ipp_attribute_t *attr; /* Current attribute */
287 const char *name; /* Destination name */
288 const char *job_printer_uri; /* JOB_PRINTER_URI form variable */
289 char current_dest[1024]; /* Current destination */
290
291
292 /*
293 * See who is logged in...
294 */
295
296 if ((user = getenv("REMOTE_USER")) == NULL)
297 user = "guest";
298
299 /*
300 * See if the user has already selected a new destination...
301 */
302
303 if ((job_printer_uri = cgiGetVariable("JOB_PRINTER_URI")) == NULL)
304 {
305 /*
306 * Make sure necessary form variables are set...
307 */
308
309 if (job_id)
310 {
311 char temp[255]; /* Temporary string */
312
313
314 sprintf(temp, "%d", job_id);
315 cgiSetVariable("JOB_ID", temp);
316 }
317
318 if (dest)
319 cgiSetVariable("PRINTER_NAME", dest);
320
321 /*
322 * No new destination specified, show the user what the available
323 * printers/classes are...
324 */
325
326 if (!dest)
327 {
328 /*
329 * Get the current destination for job N...
330 */
331
332 char job_uri[1024]; /* Job URI */
333
334
335 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
336
337 snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", job_id);
338 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
339 NULL, job_uri);
340 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
341 "requested-attributes", NULL, "job-printer-uri");
342
343 if ((response = cupsDoRequest(http, request, "/")) != NULL)
344 {
345 if ((attr = ippFindAttribute(response, "job-printer-uri",
346 IPP_TAG_URI)) != NULL)
347 {
348 /*
349 * Pull the name from the URI...
350 */
351
352 strlcpy(current_dest, strrchr(attr->values[0].string.text, '/') + 1,
353 sizeof(current_dest));
354 dest = current_dest;
355 }
356
357 ippDelete(response);
358 }
359
360 if (!dest)
361 {
362 /*
363 * Couldn't get the current destination...
364 */
365
366 cgiStartHTML(cgiText(_("Move Job")));
367 cgiShowIPPError(_("Unable to find destination for job!"));
368 cgiEndHTML();
369 return;
370 }
371 }
372
373 /*
374 * Get the list of available destinations...
375 */
376
377 request = ippNewRequest(CUPS_GET_PRINTERS);
378
379 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
380 "requested-attributes", NULL, "printer-uri-supported");
381
382 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
383 "requesting-user-name", NULL, user);
384
385 if ((response = cupsDoRequest(http, request, "/")) != NULL)
386 {
387 for (i = 0, attr = ippFindAttribute(response, "printer-uri-supported",
388 IPP_TAG_URI);
389 attr;
390 attr = ippFindNextAttribute(response, "printer-uri-supported",
391 IPP_TAG_URI))
392 {
393 /*
394 * Pull the name from the URI...
395 */
396
397 name = strrchr(attr->values[0].string.text, '/') + 1;
398
399 /*
400 * If the name is not the same as the current destination, add it!
401 */
402
403 if (strcasecmp(name, dest))
404 {
405 cgiSetArray("JOB_PRINTER_URI", i, attr->values[0].string.text);
406 cgiSetArray("JOB_PRINTER_NAME", i, name);
407 i ++;
408 }
409 }
410
411 ippDelete(response);
412 }
413
414 /*
415 * Show the form...
416 */
417
418 if (job_id)
419 cgiStartHTML(cgiText(_("Move Job")));
420 else
421 cgiStartHTML(cgiText(_("Move All Jobs")));
422
423 cgiCopyTemplateLang("job-move.tmpl");
424 }
425 else
426 {
427 /*
428 * Try moving the job or jobs...
429 */
430
431 char uri[1024], /* Job/printer URI */
432 resource[1024], /* Post resource */
433 refresh[1024]; /* Refresh URL */
434 const char *job_printer_name; /* New printer name */
435
436
437 request = ippNewRequest(CUPS_MOVE_JOB);
438
439 if (job_id)
440 {
441 /*
442 * Move 1 job...
443 */
444
445 snprintf(resource, sizeof(resource), "/jobs/%d", job_id);
446
447 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
448 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
449 NULL, uri);
450 }
451 else
452 {
453 /*
454 * Move all active jobs on a destination...
455 */
456
457 snprintf(resource, sizeof(resource), "/%s/%s",
458 cgiGetVariable("SECTION"), dest);
459
460 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
461 "localhost", ippPort(), "/%s/%s",
462 cgiGetVariable("SECTION"), dest);
463 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
464 NULL, uri);
465 }
466
467 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-printer-uri",
468 NULL, job_printer_uri);
469
470 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
471 "requesting-user-name", NULL, user);
472
473 ippDelete(cupsDoRequest(http, request, resource));
474
475 /*
476 * Show the results...
477 */
478
479 job_printer_name = strrchr(job_printer_uri, '/') + 1;
480
481 if (cupsLastError() <= IPP_OK_CONFLICT)
482 {
483 cgiRewriteURL(job_printer_uri, resource, sizeof(resource), NULL);
484 cgiFormEncode(uri, resource, sizeof(uri));
485 snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
486 cgiSetVariable("refresh_page", refresh);
487 }
488
489 if (job_id)
490 cgiStartHTML(cgiText(_("Move Job")));
491 else
492 cgiStartHTML(cgiText(_("Move All Jobs")));
493
494 if (cupsLastError() > IPP_OK_CONFLICT)
495 {
496 if (job_id)
497 cgiShowIPPError(_("Unable to move job"));
498 else
499 cgiShowIPPError(_("Unable to move jobs"));
500 }
501 else
502 {
503 cgiSetVariable("JOB_PRINTER_NAME", job_printer_name);
504 cgiCopyTemplateLang("job-moved.tmpl");
505 }
506 }
507
508 cgiEndHTML();
509 }
510
511
512 /*
513 * 'cgiPrintTestPage()' - Print a test page.
514 */
515
516 void
517 cgiPrintTestPage(http_t *http, /* I - Connection to server */
518 const char *dest) /* I - Destination printer/class */
519 {
520 ipp_t *request, /* IPP request */
521 *response; /* IPP response */
522 char uri[HTTP_MAX_URI], /* Printer URI */
523 resource[1024], /* POST resource path */
524 refresh[1024], /* Refresh URL */
525 filename[1024]; /* Test page filename */
526 const char *datadir; /* CUPS_DATADIR env var */
527 const char *user; /* Username */
528
529
530 /*
531 * See who is logged in...
532 */
533
534 if ((user = getenv("REMOTE_USER")) == NULL)
535 user = "guest";
536
537 /*
538 * Locate the test page file...
539 */
540
541 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
542 datadir = CUPS_DATADIR;
543
544 snprintf(filename, sizeof(filename), "%s/data/testprint.ps", datadir);
545
546 /*
547 * Point to the printer/class...
548 */
549
550 snprintf(resource, sizeof(resource), "/%s/%s", cgiGetVariable("SECTION"),
551 dest);
552
553 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
554 "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
555 dest);
556
557 /*
558 * Build an IPP_PRINT_JOB request, which requires the following
559 * attributes:
560 *
561 * attributes-charset
562 * attributes-natural-language
563 * printer-uri
564 * requesting-user-name
565 * document-format
566 */
567
568 request = ippNewRequest(IPP_PRINT_JOB);
569
570 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
571 NULL, uri);
572
573 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
574 "requesting-user-name", NULL, user);
575
576 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
577 NULL, "Test Page");
578
579 ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
580 NULL, "application/postscript");
581
582 /*
583 * Do the request and get back a response...
584 */
585
586 if ((response = cupsDoFileRequest(http, request, resource,
587 filename)) != NULL)
588 {
589 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
590
591 ippDelete(response);
592 }
593
594 if (cupsLastError() <= IPP_OK_CONFLICT)
595 {
596 /*
597 * Automatically reload the printer status page...
598 */
599
600 cgiFormEncode(uri, resource, sizeof(uri));
601 snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
602 cgiSetVariable("refresh_page", refresh);
603 }
604
605 cgiStartHTML(cgiText(_("Print Test Page")));
606
607 if (cupsLastError() > IPP_OK_CONFLICT)
608 cgiShowIPPError(_("Unable to print test page:"));
609 else
610 {
611 cgiSetVariable("PRINTER_NAME", dest);
612
613 cgiCopyTemplateLang("test-page.tmpl");
614 }
615
616 cgiEndHTML();
617 }
618
619
620 /*
621 * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
622 */
623
624 char * /* O - New URL */
625 cgiRewriteURL(const char *uri, /* I - Current URI */
626 char *url, /* O - New URL */
627 int urlsize, /* I - Size of URL buffer */
628 const char *newresource) /* I - Replacement resource */
629 {
630 char method[HTTP_MAX_URI],
631 userpass[HTTP_MAX_URI],
632 hostname[HTTP_MAX_URI],
633 rawresource[HTTP_MAX_URI],
634 resource[HTTP_MAX_URI],
635 /* URI components... */
636 *rawptr, /* Pointer into rawresource */
637 *resptr; /* Pointer into resource */
638 int port; /* Port number */
639 static int ishttps = -1; /* Using encryption? */
640 static const char *server; /* Name of server */
641 static char servername[1024];
642 /* Local server name */
643 static const char hexchars[] = "0123456789ABCDEF";
644 /* Hexadecimal conversion characters */
645
646
647 /*
648 * Check if we have been called before...
649 */
650
651 if (ishttps < 0)
652 {
653 /*
654 * No, initialize static vars for the conversion...
655 *
656 * First get the server name associated with the client interface as
657 * well as the locally configured hostname. We'll check *both* of
658 * these to see if the printer URL is local...
659 */
660
661 if ((server = getenv("SERVER_NAME")) == NULL)
662 server = "";
663
664 httpGetHostname(NULL, servername, sizeof(servername));
665
666 /*
667 * Then flag whether we are using SSL on this connection...
668 */
669
670 ishttps = getenv("HTTPS") != NULL;
671 }
672
673 /*
674 * Convert the URI to a URL...
675 */
676
677 httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), userpass,
678 sizeof(userpass), hostname, sizeof(hostname), &port,
679 rawresource, sizeof(rawresource));
680
681 if (!strcmp(method, "ipp") ||
682 !strcmp(method, "http") ||
683 !strcmp(method, "https"))
684 {
685 if (newresource)
686 {
687 /*
688 * Force the specified resource name instead of the one in the URL...
689 */
690
691 strlcpy(resource, newresource, sizeof(resource));
692 }
693 else
694 {
695 /*
696 * Rewrite the resource string so it doesn't contain any
697 * illegal chars...
698 */
699
700 for (rawptr = rawresource, resptr = resource; *rawptr; rawptr ++)
701 if ((*rawptr & 128) || *rawptr == '%' || *rawptr == ' ' ||
702 *rawptr == '#' || *rawptr == '?' ||
703 *rawptr == '.') /* For MSIE */
704 {
705 if (resptr < (resource + sizeof(resource) - 3))
706 {
707 *resptr++ = '%';
708 *resptr++ = hexchars[(*rawptr >> 4) & 15];
709 *resptr++ = hexchars[*rawptr & 15];
710 }
711 }
712 else if (resptr < (resource + sizeof(resource) - 1))
713 *resptr++ = *rawptr;
714
715 *resptr = '\0';
716 }
717
718 /*
719 * Map local access to a local URI...
720 */
721
722 if (!strcasecmp(hostname, "localhost") ||
723 !strncasecmp(hostname, "localhost.", 10) ||
724 !strcasecmp(hostname, server) ||
725 !strcasecmp(hostname, servername))
726 {
727 /*
728 * Make URI relative to the current server...
729 */
730
731 strlcpy(url, resource, urlsize);
732 }
733 else
734 {
735 /*
736 * Rewrite URI with HTTP/HTTPS scheme...
737 */
738
739 if (userpass[0])
740 snprintf(url, urlsize, "%s://%s@%s:%d%s",
741 ishttps ? "https" : "http",
742 userpass, hostname, port, resource);
743 else
744 snprintf(url, urlsize, "%s://%s:%d%s",
745 ishttps ? "https" : "http",
746 hostname, port, resource);
747 }
748 }
749 else
750 strlcpy(url, uri, urlsize);
751
752 return (url);
753 }
754
755
756 /*
757 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
758 */
759
760 ipp_attribute_t * /* O - Next object */
761 cgiSetIPPObjectVars(
762 ipp_attribute_t *obj, /* I - Response data to be copied... */
763 const char *prefix, /* I - Prefix for name or NULL */
764 int element) /* I - Parent element number */
765 {
766 ipp_attribute_t *attr; /* Attribute in response... */
767 int i; /* Looping var */
768 char name[1024], /* Name of attribute */
769 *nameptr, /* Pointer into name */
770 value[16384], /* Value(s) */
771 *valptr; /* Pointer into value */
772 struct tm *date; /* Date information */
773
774
775 fprintf(stderr, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
776 "element=%d)\n",
777 obj, prefix ? prefix : "(null)", element);
778
779 /*
780 * Set common CGI template variables...
781 */
782
783 if (!prefix)
784 cgiSetServerVersion();
785
786 /*
787 * Loop through the attributes and set them for the template...
788 */
789
790 for (attr = obj; attr && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
791 {
792 /*
793 * Copy the attribute name, substituting "_" for "-"...
794 */
795
796 if (!attr->name)
797 continue;
798
799 if (prefix)
800 {
801 snprintf(name, sizeof(name), "%s.", prefix);
802 nameptr = name + strlen(name);
803 }
804 else
805 nameptr = name;
806
807 for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++)
808 if (attr->name[i] == '-')
809 *nameptr++ = '_';
810 else
811 *nameptr++ = attr->name[i];
812
813 *nameptr = '\0';
814
815 /*
816 * Add "job_printer_name" variable if we have a "job_printer_uri"
817 * attribute...
818 */
819
820 if (!strcmp(name, "job_printer_uri"))
821 {
822 if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
823 valptr = "unknown";
824 else
825 valptr ++;
826
827 cgiSetArray("job_printer_name", element, valptr);
828 }
829
830 /*
831 * Add "admin_uri" variable if we have a "printer_uri_supported"
832 * attribute...
833 */
834
835 if (!strcmp(name, "printer_uri_supported"))
836 {
837 cgiRewriteURL(attr->values[0].string.text, value, sizeof(value),
838 "/admin/");
839
840 cgiSetArray("admin_uri", element, value);
841 }
842
843 /*
844 * Copy values...
845 */
846
847 value[0] = '\0'; /* Initially an empty string */
848 valptr = value; /* Start at the beginning */
849
850 for (i = 0; i < attr->num_values; i ++)
851 {
852 if (i)
853 strlcat(valptr, ",", sizeof(value) - (valptr - value));
854
855 valptr += strlen(valptr);
856
857 switch (attr->value_tag)
858 {
859 case IPP_TAG_INTEGER :
860 case IPP_TAG_ENUM :
861 if (strncmp(name, "time_at_", 8) == 0)
862 {
863 time_t t; /* Temporary time value */
864
865 t = (time_t)attr->values[i].integer;
866 date = localtime(&t);
867
868 strftime(valptr, sizeof(value) - (valptr - value), "%c", date);
869 }
870 else
871 snprintf(valptr, sizeof(value) - (valptr - value),
872 "%d", attr->values[i].integer);
873 break;
874
875 case IPP_TAG_BOOLEAN :
876 snprintf(valptr, sizeof(value) - (valptr - value),
877 "%d", attr->values[i].boolean);
878 break;
879
880 case IPP_TAG_NOVALUE :
881 strlcat(valptr, "novalue", sizeof(value) - (valptr - value));
882 break;
883
884 case IPP_TAG_RANGE :
885 snprintf(valptr, sizeof(value) - (valptr - value),
886 "%d-%d", attr->values[i].range.lower,
887 attr->values[i].range.upper);
888 break;
889
890 case IPP_TAG_RESOLUTION :
891 snprintf(valptr, sizeof(value) - (valptr - value),
892 "%dx%d%s", attr->values[i].resolution.xres,
893 attr->values[i].resolution.yres,
894 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
895 "dpi" : "dpc");
896 break;
897
898 case IPP_TAG_URI :
899 if (strchr(attr->values[i].string.text, ':') &&
900 strcmp(name, "device_uri"))
901 {
902 /*
903 * Rewrite URIs...
904 */
905
906 if (!strcmp(name, "member_uris"))
907 {
908 char url[1024]; /* URL for class member... */
909
910
911 cgiRewriteURL(attr->values[i].string.text, url,
912 sizeof(url), NULL);
913
914 snprintf(valptr, sizeof(value) - (valptr - value),
915 "<A HREF=\"%s\">%s</A>", url,
916 strrchr(url, '/') + 1);
917 }
918 else
919 cgiRewriteURL(attr->values[i].string.text, valptr,
920 sizeof(value) - (valptr - value), NULL);
921 break;
922 }
923
924 case IPP_TAG_STRING :
925 case IPP_TAG_TEXT :
926 case IPP_TAG_NAME :
927 case IPP_TAG_KEYWORD :
928 case IPP_TAG_CHARSET :
929 case IPP_TAG_LANGUAGE :
930 case IPP_TAG_MIMETYPE :
931 strlcat(valptr, attr->values[i].string.text,
932 sizeof(value) - (valptr - value));
933 break;
934
935 case IPP_TAG_BEGIN_COLLECTION :
936 snprintf(value, sizeof(value), "%s%d", name, i + 1);
937 cgiSetIPPVars(attr->values[i].collection, NULL, NULL, value,
938 element);
939 break;
940
941 default :
942 break; /* anti-compiler-warning-code */
943 }
944 }
945
946 /*
947 * Add the element...
948 */
949
950 if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
951 {
952 cgiSetArray(name, element, value);
953
954 fprintf(stderr, "DEBUG2: %s[%d]=\"%s\"\n", name, element, value);
955 }
956 }
957
958 return (attr ? attr->next : NULL);
959 }
960
961
962 /*
963 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
964 */
965
966 int /* O - Maximum number of elements */
967 cgiSetIPPVars(ipp_t *response, /* I - Response data to be copied... */
968 const char *filter_name, /* I - Filter name */
969 const char *filter_value, /* I - Filter value */
970 const char *prefix, /* I - Prefix for name or NULL */
971 int parent_el) /* I - Parent element number */
972 {
973 int element; /* Element in CGI array */
974 ipp_attribute_t *attr, /* Attribute in response... */
975 *filter; /* Filtering attribute */
976
977
978 fprintf(stderr, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
979 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
980 response, filter_name ? filter_name : "(null)",
981 filter_value ? filter_value : "(null)",
982 prefix ? prefix : "(null)", parent_el);
983
984 /*
985 * Set common CGI template variables...
986 */
987
988 if (!prefix)
989 cgiSetServerVersion();
990
991 /*
992 * Loop through the attributes and set them for the template...
993 */
994
995 attr = response->attrs;
996
997 if (!prefix)
998 while (attr && attr->group_tag == IPP_TAG_OPERATION)
999 attr = attr->next;
1000
1001 for (element = parent_el; attr; element ++)
1002 {
1003 /*
1004 * Copy attributes to a separator...
1005 */
1006
1007 while (attr && attr->group_tag == IPP_TAG_ZERO)
1008 attr= attr->next;
1009
1010 if (!attr)
1011 break;
1012
1013 if (filter_name)
1014 {
1015 for (filter = attr;
1016 filter != NULL && filter->group_tag != IPP_TAG_ZERO;
1017 filter = filter->next)
1018 if (filter->name && !strcmp(filter->name, filter_name) &&
1019 (filter->value_tag == IPP_TAG_STRING ||
1020 (filter->value_tag >= IPP_TAG_TEXTLANG &&
1021 filter->value_tag <= IPP_TAG_MIMETYPE)) &&
1022 filter->values[0].string.text != NULL &&
1023 !strcasecmp(filter->values[0].string.text, filter_value))
1024 break;
1025
1026 if (!filter)
1027 return (element + 1);
1028
1029 if (filter->group_tag == IPP_TAG_ZERO)
1030 {
1031 attr = filter;
1032 element --;
1033 continue;
1034 }
1035 }
1036
1037 attr = cgiSetIPPObjectVars(attr, prefix, element);
1038 }
1039
1040 fprintf(stderr, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element);
1041
1042 return (element);
1043 }
1044
1045
1046 /*
1047 * 'cgiShowIPPError()' - Show the last IPP error message.
1048 *
1049 * The caller must still call cgiStartHTML() and cgiEndHTML().
1050 */
1051
1052 void
1053 cgiShowIPPError(const char *message) /* I - Contextual message */
1054 {
1055 cgiSetVariable("MESSAGE", cgiText(message));
1056 cgiSetVariable("ERROR", cupsLastErrorString());
1057 cgiCopyTemplateLang("error.tmpl");
1058 }
1059
1060
1061 /*
1062 * 'cgiShowJobs()' - Show print jobs.
1063 */
1064
1065 void
1066 cgiShowJobs(http_t *http, /* I - Connection to server */
1067 const char *dest) /* I - Destination name or NULL */
1068 {
1069 int i; /* Looping var */
1070 const char *which_jobs; /* Which jobs to show */
1071 ipp_t *request, /* IPP request */
1072 *response; /* IPP response */
1073 cups_array_t *jobs; /* Array of job objects */
1074 ipp_attribute_t *job; /* Job object */
1075 int ascending, /* Order of jobs (0 = descending) */
1076 first, /* First job to show */
1077 count; /* Number of jobs */
1078 const char *var; /* Form variable */
1079 void *search; /* Search data */
1080 char url[1024], /* URL for prev/next/this */
1081 *urlptr, /* Position in URL */
1082 *urlend; /* End of URL */
1083
1084
1085 /*
1086 * Build an IPP_GET_JOBS request, which requires the following
1087 * attributes:
1088 *
1089 * attributes-charset
1090 * attributes-natural-language
1091 * printer-uri
1092 */
1093
1094 request = ippNewRequest(IPP_GET_JOBS);
1095
1096 if (dest)
1097 {
1098 httpAssembleURIf(HTTP_URI_CODING_ALL, url, sizeof(url), "ipp", NULL,
1099 "localhost", ippPort(), "/printers/%s", dest);
1100 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1101 NULL, url);
1102 }
1103 else
1104 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL,
1105 "ipp://localhost/jobs");
1106
1107 if ((which_jobs = cgiGetVariable("which_jobs")) != NULL)
1108 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
1109 NULL, which_jobs);
1110
1111 cgiGetAttributes(request, "jobs.tmpl");
1112
1113 /*
1114 * Do the request and get back a response...
1115 */
1116
1117 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1118 {
1119 /*
1120 * Get a list of matching job objects.
1121 */
1122
1123 if ((var = cgiGetVariable("QUERY")) != NULL)
1124 search = cgiCompileSearch(var);
1125 else
1126 search = NULL;
1127
1128 jobs = cgiGetIPPObjects(response, search);
1129 count = cupsArrayCount(jobs);
1130
1131 if (search)
1132 cgiFreeSearch(search);
1133
1134 /*
1135 * Figure out which jobs to display...
1136 */
1137
1138 if ((var = cgiGetVariable("FIRST")) != NULL)
1139 first = atoi(var);
1140 else
1141 first = 0;
1142
1143 if (first >= count)
1144 first = count - CUPS_PAGE_MAX;
1145
1146 first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
1147
1148 if (first < 0)
1149 first = 0;
1150
1151 sprintf(url, "%d", count);
1152 cgiSetVariable("TOTAL", url);
1153
1154 if ((var = cgiGetVariable("ORDER")) != NULL)
1155 ascending = !strcasecmp(var, "asc");
1156 else
1157 {
1158 ascending = !which_jobs || !strcasecmp(which_jobs, "not-completed");
1159 cgiSetVariable("ORDER", ascending ? "asc" : "dec");
1160 }
1161
1162 if (ascending)
1163 {
1164 for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, first);
1165 i < CUPS_PAGE_MAX && job;
1166 i ++, job = (ipp_attribute_t *)cupsArrayNext(jobs))
1167 cgiSetIPPObjectVars(job, NULL, i);
1168 }
1169 else
1170 {
1171 for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, count - first - 1);
1172 i < CUPS_PAGE_MAX && job;
1173 i ++, job = (ipp_attribute_t *)cupsArrayPrev(jobs))
1174 cgiSetIPPObjectVars(job, NULL, i);
1175 }
1176
1177 /*
1178 * Save navigation URLs...
1179 */
1180
1181 urlend = url + sizeof(url);
1182
1183 if ((var = cgiGetVariable("QUERY")) != NULL)
1184 {
1185 if (dest)
1186 snprintf(url, sizeof(url), "/%s/%s?QUERY=", cgiGetVariable("SECTION"),
1187 dest);
1188 else
1189 strlcpy(url, "/jobs/?QUERY=", sizeof(url));
1190
1191 urlptr = url + strlen(url);
1192
1193 cgiFormEncode(urlptr, var, urlend - urlptr);
1194 urlptr += strlen(urlptr);
1195
1196 strlcpy(urlptr, "&", urlend - urlptr);
1197 urlptr += strlen(urlptr);
1198 }
1199 else
1200 {
1201 if (dest)
1202 snprintf(url, sizeof(url), "/%s/%s?", cgiGetVariable("SECTION"), dest);
1203 else
1204 strlcpy(url, "/jobs/?", sizeof(url));
1205
1206 urlptr = url + strlen(url);
1207 }
1208
1209 if (which_jobs)
1210 {
1211 strlcpy(urlptr, "WHICH_JOBS=", urlend - urlptr);
1212 urlptr += strlen(urlptr);
1213
1214 cgiFormEncode(urlptr, which_jobs, urlend - urlptr);
1215 urlptr += strlen(urlptr);
1216
1217 strlcpy(urlptr, "&", urlend - urlptr);
1218 urlptr += strlen(urlptr);
1219 }
1220
1221 snprintf(urlptr, urlend - urlptr, "FIRST=%d", first);
1222 cgiSetVariable("THISURL", url);
1223
1224 if (first > 0)
1225 {
1226 snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s",
1227 first - CUPS_PAGE_MAX, ascending ? "asc" : "dec");
1228 cgiSetVariable("PREVURL", url);
1229 }
1230
1231 if ((first + CUPS_PAGE_MAX) < count)
1232 {
1233 snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s",
1234 first + CUPS_PAGE_MAX, ascending ? "asc" : "dec");
1235 cgiSetVariable("NEXTURL", url);
1236 }
1237
1238 /*
1239 * Then show everything...
1240 */
1241
1242 if (dest)
1243 cgiSetVariable("SEARCH_DEST", dest);
1244
1245 cgiCopyTemplateLang("search.tmpl");
1246
1247 cgiCopyTemplateLang("jobs-header.tmpl");
1248
1249 if (count > 0)
1250 cgiCopyTemplateLang("pager.tmpl");
1251
1252 cgiCopyTemplateLang("jobs.tmpl");
1253
1254 if (count > 0)
1255 cgiCopyTemplateLang("pager.tmpl");
1256
1257 cupsArrayDelete(jobs);
1258 ippDelete(response);
1259 }
1260 }
1261
1262
1263 /*
1264 * 'cgiText()' - Return localized text.
1265 */
1266
1267 const char * /* O - Localized message */
1268 cgiText(const char *message) /* I - Message */
1269 {
1270 static cups_lang_t *language = NULL;
1271 /* Language */
1272
1273
1274 if (!language)
1275 language = cupsLangDefault();
1276
1277 return (_cupsLangString(language, message));
1278 }
1279
1280
1281 /*
1282 * End of "$Id$".
1283 */