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