]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/ipp-var.c
Merge changes from CUPS 1.4svn-r8305.
[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)
480 path = strstr(job_printer_uri, "/classes/");
481
482 if (path)
483 {
484 cgiFormEncode(uri, path, sizeof(uri));
485 snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
486 cgiSetVariable("refresh_page", refresh);
487 }
fa73b229 488 }
489
490 if (job_id)
491 cgiStartHTML(cgiText(_("Move Job")));
492 else
493 cgiStartHTML(cgiText(_("Move All Jobs")));
494
495 if (cupsLastError() > IPP_OK_CONFLICT)
496 {
497 if (job_id)
498 cgiShowIPPError(_("Unable to move job"));
499 else
500 cgiShowIPPError(_("Unable to move jobs"));
501 }
502 else
503 {
504 cgiSetVariable("JOB_PRINTER_NAME", job_printer_name);
505 cgiCopyTemplateLang("job-moved.tmpl");
506 }
507 }
508
509 cgiEndHTML();
510}
511
512
58dc1933
MS
513/*
514 * 'cgiPrintCommand()' - Print a CUPS command job.
515 */
516
517void
518cgiPrintCommand(http_t *http, /* I - Connection to server */
519 const char *dest, /* I - Destination printer */
520 const char *command, /* I - Command to send */
521 const char *title) /* I - Page/job title */
522{
523 int job_id; /* Command file job */
524 char uri[HTTP_MAX_URI], /* Job URI */
525 resource[1024], /* Printer resource path */
526 refresh[1024], /* Refresh URL */
527 command_file[1024]; /* Command "file" */
528 http_status_t status; /* Document status */
529 cups_option_t hold_option; /* job-hold-until option */
530 const char *user; /* User name */
531 ipp_t *request, /* Get-Job-Attributes request */
532 *response; /* Get-Job-Attributes response */
533 ipp_attribute_t *attr; /* Current job attribute */
534 static const char const *job_attrs[] =/* Job attributes we want */
535 {
536 "job-state",
537 "job-printer-state-message"
538 };
539
540
541 /*
542 * Create the CUPS command file...
543 */
544
545 snprintf(command_file, sizeof(command_file), "#CUPS-COMMAND\n%s\n", command);
546
547 /*
548 * Show status...
549 */
550
d2354e63
MS
551 if (cgiSupportsMultipart())
552 {
553 cgiStartMultipart();
554 cgiStartHTML(title);
555 cgiCopyTemplateLang("command.tmpl");
556 cgiEndHTML();
557 fflush(stdout);
558 }
58dc1933
MS
559
560 /*
561 * Send the command file job...
562 */
563
564 hold_option.name = "job-hold-until";
565 hold_option.value = "no-hold";
566
567 if ((user = getenv("REMOTE_USER")) != NULL)
568 cupsSetUser(user);
569 else
570 cupsSetUser("anonymous");
571
572 if ((job_id = cupsCreateJob(http, dest, title,
573 1, &hold_option)) < 1)
574 {
575 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver!")));
576 cgiSetVariable("ERROR", cupsLastErrorString());
577 cgiStartHTML(title);
578 cgiCopyTemplateLang("error.tmpl");
579 cgiEndHTML();
d2354e63
MS
580
581 if (cgiSupportsMultipart())
582 cgiEndMultipart();
58dc1933
MS
583 return;
584 }
585
586 status = cupsStartDocument(http, dest, job_id, NULL, CUPS_FORMAT_COMMAND, 1);
587 if (status == HTTP_CONTINUE)
588 status = cupsWriteRequestData(http, command_file,
589 strlen(command_file));
590 if (status == HTTP_CONTINUE)
591 cupsFinishDocument(http, dest);
592
593 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
594 {
595 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver!")));
596 cgiSetVariable("ERROR", cupsLastErrorString());
597 cgiStartHTML(title);
598 cgiCopyTemplateLang("error.tmpl");
599 cgiEndHTML();
d2354e63
MS
600
601 if (cgiSupportsMultipart())
602 cgiEndMultipart();
58dc1933
MS
603
604 cupsCancelJob(dest, job_id);
605 return;
606 }
607
608 /*
609 * Wait for the job to complete...
610 */
611
d2354e63 612 if (cgiSupportsMultipart())
58dc1933 613 {
d2354e63
MS
614 for (;;)
615 {
616 /*
617 * Get the current job state...
618 */
58dc1933 619
d2354e63
MS
620 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
621 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
622 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
623 NULL, uri);
624 if (user)
625 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
626 "requesting-user-name", NULL, user);
627 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
628 "requested-attributes", 2, NULL, job_attrs);
58dc1933 629
d2354e63
MS
630 if ((response = cupsDoRequest(http, request, "/")) != NULL)
631 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
58dc1933 632
d2354e63
MS
633 attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM);
634 if (!attr || attr->values[0].integer >= IPP_JOB_STOPPED)
635 {
636 ippDelete(response);
637 break;
638 }
58dc1933 639
d2354e63
MS
640 /*
641 * Job not complete, so update the status...
642 */
58dc1933 643
d2354e63 644 ippDelete(response);
58dc1933 645
d2354e63
MS
646 cgiStartHTML(title);
647 cgiCopyTemplateLang("command.tmpl");
648 cgiEndHTML();
649 fflush(stdout);
58dc1933 650
d2354e63
MS
651 sleep(5);
652 }
58dc1933
MS
653 }
654
655 /*
656 * Send the final page that reloads the printer's page...
657 */
658
659 snprintf(resource, sizeof(resource), "/printers/%s", dest);
660
661 cgiFormEncode(uri, resource, sizeof(uri));
662 snprintf(refresh, sizeof(refresh), "5;URL=%s", uri);
663 cgiSetVariable("refresh_page", refresh);
664
665 cgiStartHTML(title);
666 cgiCopyTemplateLang("command.tmpl");
667 cgiEndHTML();
d2354e63
MS
668
669 if (cgiSupportsMultipart())
670 cgiEndMultipart();
58dc1933
MS
671}
672
673
fa73b229 674/*
675 * 'cgiPrintTestPage()' - Print a test page.
676 */
677
678void
679cgiPrintTestPage(http_t *http, /* I - Connection to server */
680 const char *dest) /* I - Destination printer/class */
681{
682 ipp_t *request, /* IPP request */
683 *response; /* IPP response */
684 char uri[HTTP_MAX_URI], /* Printer URI */
685 resource[1024], /* POST resource path */
686 refresh[1024], /* Refresh URL */
687 filename[1024]; /* Test page filename */
688 const char *datadir; /* CUPS_DATADIR env var */
689 const char *user; /* Username */
690
691
692 /*
693 * See who is logged in...
694 */
695
5a738aea 696 user = getenv("REMOTE_USER");
fa73b229 697
698 /*
699 * Locate the test page file...
700 */
701
702 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
703 datadir = CUPS_DATADIR;
704
6e8b116d 705 snprintf(filename, sizeof(filename), "%s/data/testprint", datadir);
fa73b229 706
707 /*
708 * Point to the printer/class...
709 */
710
711 snprintf(resource, sizeof(resource), "/%s/%s", cgiGetVariable("SECTION"),
712 dest);
713
a4d04587 714 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
715 "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
716 dest);
fa73b229 717
718 /*
719 * Build an IPP_PRINT_JOB request, which requires the following
720 * attributes:
721 *
722 * attributes-charset
723 * attributes-natural-language
724 * printer-uri
725 * requesting-user-name
fa73b229 726 */
727
728 request = ippNewRequest(IPP_PRINT_JOB);
729
730 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
731 NULL, uri);
732
5a738aea
MS
733 if (user)
734 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
735 "requesting-user-name", NULL, user);
fa73b229 736
737 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
738 NULL, "Test Page");
739
fa73b229 740 /*
741 * Do the request and get back a response...
742 */
743
744 if ((response = cupsDoFileRequest(http, request, resource,
745 filename)) != NULL)
746 {
747 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
748
749 ippDelete(response);
750 }
751
752 if (cupsLastError() <= IPP_OK_CONFLICT)
753 {
754 /*
755 * Automatically reload the printer status page...
756 */
757
758 cgiFormEncode(uri, resource, sizeof(uri));
f301802f 759 snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
fa73b229 760 cgiSetVariable("refresh_page", refresh);
761 }
5bd77a73
MS
762 else if (cupsLastError() == IPP_NOT_AUTHORIZED)
763 {
764 puts("Status: 401\n");
765 exit(0);
766 }
fa73b229 767
768 cgiStartHTML(cgiText(_("Print Test Page")));
769
770 if (cupsLastError() > IPP_OK_CONFLICT)
771 cgiShowIPPError(_("Unable to print test page:"));
772 else
773 {
774 cgiSetVariable("PRINTER_NAME", dest);
775
776 cgiCopyTemplateLang("test-page.tmpl");
777 }
778
779 cgiEndHTML();
780}
781
782
ef416fc2 783/*
784 * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
785 */
786
787char * /* O - New URL */
788cgiRewriteURL(const char *uri, /* I - Current URI */
789 char *url, /* O - New URL */
790 int urlsize, /* I - Size of URL buffer */
791 const char *newresource) /* I - Replacement resource */
792{
c168a833 793 char scheme[HTTP_MAX_URI],
ef416fc2 794 userpass[HTTP_MAX_URI],
795 hostname[HTTP_MAX_URI],
796 rawresource[HTTP_MAX_URI],
797 resource[HTTP_MAX_URI],
798 /* URI components... */
799 *rawptr, /* Pointer into rawresource */
800 *resptr; /* Pointer into resource */
801 int port; /* Port number */
802 static int ishttps = -1; /* Using encryption? */
803 static const char *server; /* Name of server */
804 static char servername[1024];
805 /* Local server name */
806 static const char hexchars[] = "0123456789ABCDEF";
807 /* Hexadecimal conversion characters */
808
809
810 /*
811 * Check if we have been called before...
812 */
813
814 if (ishttps < 0)
815 {
816 /*
817 * No, initialize static vars for the conversion...
818 *
819 * First get the server name associated with the client interface as
820 * well as the locally configured hostname. We'll check *both* of
821 * these to see if the printer URL is local...
822 */
823
824 if ((server = getenv("SERVER_NAME")) == NULL)
825 server = "";
826
757d2cad 827 httpGetHostname(NULL, servername, sizeof(servername));
ef416fc2 828
829 /*
830 * Then flag whether we are using SSL on this connection...
831 */
832
833 ishttps = getenv("HTTPS") != NULL;
834 }
835
836 /*
837 * Convert the URI to a URL...
838 */
839
c168a833 840 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
a4d04587 841 sizeof(userpass), hostname, sizeof(hostname), &port,
ef416fc2 842 rawresource, sizeof(rawresource));
843
c168a833
MS
844 if (!strcmp(scheme, "ipp") ||
845 !strcmp(scheme, "http") ||
846 !strcmp(scheme, "https"))
ef416fc2 847 {
848 if (newresource)
849 {
850 /*
851 * Force the specified resource name instead of the one in the URL...
852 */
853
854 strlcpy(resource, newresource, sizeof(resource));
855 }
856 else
857 {
858 /*
859 * Rewrite the resource string so it doesn't contain any
860 * illegal chars...
861 */
862
863 for (rawptr = rawresource, resptr = resource; *rawptr; rawptr ++)
864 if ((*rawptr & 128) || *rawptr == '%' || *rawptr == ' ' ||
865 *rawptr == '#' || *rawptr == '?' ||
866 *rawptr == '.') /* For MSIE */
867 {
868 if (resptr < (resource + sizeof(resource) - 3))
869 {
870 *resptr++ = '%';
871 *resptr++ = hexchars[(*rawptr >> 4) & 15];
872 *resptr++ = hexchars[*rawptr & 15];
873 }
874 }
875 else if (resptr < (resource + sizeof(resource) - 1))
876 *resptr++ = *rawptr;
877
878 *resptr = '\0';
879 }
880
881 /*
882 * Map local access to a local URI...
883 */
884
c168a833
MS
885 if (!strcasecmp(hostname, "127.0.0.1") ||
886 !strcasecmp(hostname, "[::1]") ||
887 !strcasecmp(hostname, "localhost") ||
ef416fc2 888 !strncasecmp(hostname, "localhost.", 10) ||
889 !strcasecmp(hostname, server) ||
890 !strcasecmp(hostname, servername))
891 {
892 /*
893 * Make URI relative to the current server...
894 */
895
896 strlcpy(url, resource, urlsize);
897 }
898 else
899 {
900 /*
901 * Rewrite URI with HTTP/HTTPS scheme...
902 */
903
904 if (userpass[0])
905 snprintf(url, urlsize, "%s://%s@%s:%d%s",
906 ishttps ? "https" : "http",
907 userpass, hostname, port, resource);
908 else
909 snprintf(url, urlsize, "%s://%s:%d%s",
910 ishttps ? "https" : "http",
911 hostname, port, resource);
912 }
913 }
914 else
915 strlcpy(url, uri, urlsize);
916
917 return (url);
918}
919
920
921/*
922 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
923 */
924
925ipp_attribute_t * /* O - Next object */
926cgiSetIPPObjectVars(
927 ipp_attribute_t *obj, /* I - Response data to be copied... */
928 const char *prefix, /* I - Prefix for name or NULL */
929 int element) /* I - Parent element number */
930{
931 ipp_attribute_t *attr; /* Attribute in response... */
932 int i; /* Looping var */
933 char name[1024], /* Name of attribute */
934 *nameptr, /* Pointer into name */
935 value[16384], /* Value(s) */
936 *valptr; /* Pointer into value */
937 struct tm *date; /* Date information */
938
939
940 fprintf(stderr, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
941 "element=%d)\n",
f301802f 942 obj, prefix ? prefix : "(null)", element);
ef416fc2 943
944 /*
945 * Set common CGI template variables...
946 */
947
948 if (!prefix)
949 cgiSetServerVersion();
950
951 /*
952 * Loop through the attributes and set them for the template...
953 */
954
955 for (attr = obj; attr && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
956 {
957 /*
958 * Copy the attribute name, substituting "_" for "-"...
959 */
960
961 if (!attr->name)
962 continue;
963
964 if (prefix)
965 {
966 snprintf(name, sizeof(name), "%s.", prefix);
967 nameptr = name + strlen(name);
968 }
969 else
970 nameptr = name;
971
972 for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++)
973 if (attr->name[i] == '-')
974 *nameptr++ = '_';
975 else
976 *nameptr++ = attr->name[i];
977
978 *nameptr = '\0';
979
980 /*
981 * Add "job_printer_name" variable if we have a "job_printer_uri"
982 * attribute...
983 */
984
985 if (!strcmp(name, "job_printer_uri"))
986 {
987 if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
988 valptr = "unknown";
989 else
990 valptr ++;
991
992 cgiSetArray("job_printer_name", element, valptr);
993 }
994
f7deaa1a 995 /*
996 * Localize event names in "notify_events" variable...
997 */
998
999 if (!strcmp(name, "notify_events"))
1000 {
1001 size_t remaining; /* Remaining bytes in buffer */
1002
1003
1004 value[0] = '\0';
1005 valptr = value;
1006
1007 for (i = 0; i < attr->num_values; i ++)
1008 {
1009 if (valptr >= (value + sizeof(value) - 3))
1010 break;
1011
1012 if (i)
1013 {
1014 *valptr++ = ',';
1015 *valptr++ = ' ';
1016 }
1017
1018 remaining = sizeof(value) - (valptr - value);
1019
1020 if (!strcmp(attr->values[i].string.text, "printer-stopped"))
080811b1 1021 strlcpy(valptr, _("Printer Paused"), remaining);
f7deaa1a 1022 else if (!strcmp(attr->values[i].string.text, "printer-added"))
1023 strlcpy(valptr, _("Printer Added"), remaining);
1024 else if (!strcmp(attr->values[i].string.text, "printer-modified"))
1025 strlcpy(valptr, _("Printer Modified"), remaining);
1026 else if (!strcmp(attr->values[i].string.text, "printer-deleted"))
1027 strlcpy(valptr, _("Printer Deleted"), remaining);
1028 else if (!strcmp(attr->values[i].string.text, "job-created"))
1029 strlcpy(valptr, _("Job Created"), remaining);
1030 else if (!strcmp(attr->values[i].string.text, "job-completed"))
1031 strlcpy(valptr, _("Job Completed"), remaining);
1032 else if (!strcmp(attr->values[i].string.text, "job-stopped"))
1033 strlcpy(valptr, _("Job Stopped"), remaining);
1034 else if (!strcmp(attr->values[i].string.text, "job-config-changed"))
1035 strlcpy(valptr, _("Job Options Changed"), remaining);
1036 else if (!strcmp(attr->values[i].string.text, "server-restarted"))
1037 strlcpy(valptr, _("Server Restarted"), remaining);
1038 else if (!strcmp(attr->values[i].string.text, "server-started"))
1039 strlcpy(valptr, _("Server Started"), remaining);
1040 else if (!strcmp(attr->values[i].string.text, "server-stopped"))
1041 strlcpy(valptr, _("Server Stopped"), remaining);
1042 else if (!strcmp(attr->values[i].string.text, "server-audit"))
1043 strlcpy(valptr, _("Server Security Auditing"), remaining);
1044 else
1045 strlcpy(valptr, attr->values[i].string.text, remaining);
1046
1047 valptr += strlen(valptr);
1048 }
1049
1050 cgiSetArray("notify_events", element, value);
1051 continue;
1052 }
1053
1054 /*
1055 * Add "notify_printer_name" variable if we have a "notify_printer_uri"
1056 * attribute...
1057 */
1058
1059 if (!strcmp(name, "notify_printer_uri"))
1060 {
1061 if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
1062 valptr = "unknown";
1063 else
1064 valptr ++;
1065
1066 cgiSetArray("notify_printer_name", element, valptr);
1067 }
1068
1069 /*
1070 * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
1071 * attribute, and rewrite recipient URI...
1072 */
1073
1074 if (!strcmp(name, "notify_recipient_uri"))
1075 {
1076 char uri[1024], /* New URI */
1077 scheme[32], /* Scheme portion of URI */
1078 userpass[256], /* Username/password portion of URI */
1079 host[1024], /* Hostname portion of URI */
1080 resource[1024], /* Resource portion of URI */
1081 *options; /* Options in URI */
1082 int port; /* Port number */
1083
1084
1085 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
1086 scheme, sizeof(scheme), userpass, sizeof(userpass),
1087 host, sizeof(host), &port, resource, sizeof(resource));
1088
1089 if (!strcmp(scheme, "rss"))
1090 {
1091 /*
1092 * RSS notification...
1093 */
1094
1095 if ((options = strchr(resource, '?')) != NULL)
1096 *options = '\0';
1097
1098 if (host[0])
1099 {
1100 /*
1101 * Link to remote feed...
1102 */
1103
1104 httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http",
1105 userpass, host, port, resource);
1106 strlcpy(name, uri, sizeof(name));
1107 }
1108 else
1109 {
1110 /*
1111 * Link to local feed...
1112 */
1113
1114 snprintf(uri, sizeof(uri), "/rss%s", resource);
1115 strlcpy(name, resource + 1, sizeof(name));
1116 }
1117 }
1118 else
1119 {
1120 /*
1121 * Other...
1122 */
1123
1124 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
1125 strlcpy(name, resource, sizeof(name));
1126 }
1127
1128 cgiSetArray("notify_recipient_uri", element, uri);
1129 cgiSetArray("notify_recipient_name", element, name);
1130 continue;
1131 }
1132
ef416fc2 1133 /*
1134 * Add "admin_uri" variable if we have a "printer_uri_supported"
1135 * attribute...
1136 */
1137
1138 if (!strcmp(name, "printer_uri_supported"))
1139 {
1140 cgiRewriteURL(attr->values[0].string.text, value, sizeof(value),
1141 "/admin/");
1142
1143 cgiSetArray("admin_uri", element, value);
1144 }
1145
1146 /*
1147 * Copy values...
1148 */
1149
1150 value[0] = '\0'; /* Initially an empty string */
1151 valptr = value; /* Start at the beginning */
1152
1153 for (i = 0; i < attr->num_values; i ++)
1154 {
1155 if (i)
2e4ff8af 1156 strlcat(valptr, ", ", sizeof(value) - (valptr - value));
ef416fc2 1157
1158 valptr += strlen(valptr);
1159
1160 switch (attr->value_tag)
1161 {
1162 case IPP_TAG_INTEGER :
1163 case IPP_TAG_ENUM :
1164 if (strncmp(name, "time_at_", 8) == 0)
1165 {
1166 time_t t; /* Temporary time value */
1167
1168 t = (time_t)attr->values[i].integer;
1169 date = localtime(&t);
1170
1171 strftime(valptr, sizeof(value) - (valptr - value), "%c", date);
1172 }
1173 else
1174 snprintf(valptr, sizeof(value) - (valptr - value),
1175 "%d", attr->values[i].integer);
1176 break;
1177
1178 case IPP_TAG_BOOLEAN :
1179 snprintf(valptr, sizeof(value) - (valptr - value),
1180 "%d", attr->values[i].boolean);
1181 break;
1182
1183 case IPP_TAG_NOVALUE :
1184 strlcat(valptr, "novalue", sizeof(value) - (valptr - value));
1185 break;
1186
1187 case IPP_TAG_RANGE :
1188 snprintf(valptr, sizeof(value) - (valptr - value),
1189 "%d-%d", attr->values[i].range.lower,
1190 attr->values[i].range.upper);
1191 break;
1192
1193 case IPP_TAG_RESOLUTION :
1194 snprintf(valptr, sizeof(value) - (valptr - value),
1195 "%dx%d%s", attr->values[i].resolution.xres,
1196 attr->values[i].resolution.yres,
1197 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
1198 "dpi" : "dpc");
1199 break;
1200
1201 case IPP_TAG_URI :
b423cd4c 1202 if (strchr(attr->values[i].string.text, ':') &&
1203 strcmp(name, "device_uri"))
ef416fc2 1204 {
1205 /*
1206 * Rewrite URIs...
1207 */
1208
1209 if (!strcmp(name, "member_uris"))
1210 {
1211 char url[1024]; /* URL for class member... */
1212
1213
1214 cgiRewriteURL(attr->values[i].string.text, url,
1215 sizeof(url), NULL);
1216
1217 snprintf(valptr, sizeof(value) - (valptr - value),
1218 "<A HREF=\"%s\">%s</A>", url,
b86bc4cf 1219 strrchr(attr->values[i].string.text, '/') + 1);
ef416fc2 1220 }
1221 else
1222 cgiRewriteURL(attr->values[i].string.text, valptr,
1223 sizeof(value) - (valptr - value), NULL);
1224 break;
1225 }
1226
1227 case IPP_TAG_STRING :
1228 case IPP_TAG_TEXT :
1229 case IPP_TAG_NAME :
1230 case IPP_TAG_KEYWORD :
1231 case IPP_TAG_CHARSET :
1232 case IPP_TAG_LANGUAGE :
1233 case IPP_TAG_MIMETYPE :
1234 strlcat(valptr, attr->values[i].string.text,
1235 sizeof(value) - (valptr - value));
1236 break;
1237
1238 case IPP_TAG_BEGIN_COLLECTION :
1239 snprintf(value, sizeof(value), "%s%d", name, i + 1);
1240 cgiSetIPPVars(attr->values[i].collection, NULL, NULL, value,
1241 element);
1242 break;
1243
1244 default :
1245 break; /* anti-compiler-warning-code */
1246 }
1247 }
1248
1249 /*
1250 * Add the element...
1251 */
1252
1253 if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
1254 {
1255 cgiSetArray(name, element, value);
1256
1257 fprintf(stderr, "DEBUG2: %s[%d]=\"%s\"\n", name, element, value);
1258 }
1259 }
1260
1261 return (attr ? attr->next : NULL);
1262}
1263
1264
1265/*
1266 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
1267 */
1268
1269int /* O - Maximum number of elements */
1270cgiSetIPPVars(ipp_t *response, /* I - Response data to be copied... */
1271 const char *filter_name, /* I - Filter name */
1272 const char *filter_value, /* I - Filter value */
1273 const char *prefix, /* I - Prefix for name or NULL */
1274 int parent_el) /* I - Parent element number */
1275{
1276 int element; /* Element in CGI array */
1277 ipp_attribute_t *attr, /* Attribute in response... */
1278 *filter; /* Filtering attribute */
1279
1280
1281 fprintf(stderr, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
1282 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
f301802f 1283 response, filter_name ? filter_name : "(null)",
1284 filter_value ? filter_value : "(null)",
1285 prefix ? prefix : "(null)", parent_el);
ef416fc2 1286
1287 /*
1288 * Set common CGI template variables...
1289 */
1290
1291 if (!prefix)
1292 cgiSetServerVersion();
1293
1294 /*
1295 * Loop through the attributes and set them for the template...
1296 */
1297
1298 attr = response->attrs;
1299
1300 if (!prefix)
1301 while (attr && attr->group_tag == IPP_TAG_OPERATION)
1302 attr = attr->next;
1303
1304 for (element = parent_el; attr; element ++)
1305 {
1306 /*
1307 * Copy attributes to a separator...
1308 */
1309
1310 while (attr && attr->group_tag == IPP_TAG_ZERO)
1311 attr= attr->next;
1312
1313 if (!attr)
1314 break;
1315
1316 if (filter_name)
1317 {
1318 for (filter = attr;
1319 filter != NULL && filter->group_tag != IPP_TAG_ZERO;
1320 filter = filter->next)
1321 if (filter->name && !strcmp(filter->name, filter_name) &&
1322 (filter->value_tag == IPP_TAG_STRING ||
1323 (filter->value_tag >= IPP_TAG_TEXTLANG &&
1324 filter->value_tag <= IPP_TAG_MIMETYPE)) &&
1325 filter->values[0].string.text != NULL &&
1326 !strcasecmp(filter->values[0].string.text, filter_value))
1327 break;
1328
1329 if (!filter)
1330 return (element + 1);
1331
1332 if (filter->group_tag == IPP_TAG_ZERO)
1333 {
1334 attr = filter;
1335 element --;
1336 continue;
1337 }
1338 }
1339
1340 attr = cgiSetIPPObjectVars(attr, prefix, element);
1341 }
1342
89d46774 1343 fprintf(stderr, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element);
ef416fc2 1344
89d46774 1345 return (element);
ef416fc2 1346}
1347
1348
fa73b229 1349/*
1350 * 'cgiShowIPPError()' - Show the last IPP error message.
1351 *
1352 * The caller must still call cgiStartHTML() and cgiEndHTML().
1353 */
1354
1355void
1356cgiShowIPPError(const char *message) /* I - Contextual message */
1357{
1358 cgiSetVariable("MESSAGE", cgiText(message));
1359 cgiSetVariable("ERROR", cupsLastErrorString());
1360 cgiCopyTemplateLang("error.tmpl");
1361}
1362
1363
ef416fc2 1364/*
1365 * 'cgiShowJobs()' - Show print jobs.
1366 */
1367
1368void
1369cgiShowJobs(http_t *http, /* I - Connection to server */
1370 const char *dest) /* I - Destination name or NULL */
1371{
1372 int i; /* Looping var */
1373 const char *which_jobs; /* Which jobs to show */
1374 ipp_t *request, /* IPP request */
1375 *response; /* IPP response */
1376 cups_array_t *jobs; /* Array of job objects */
1377 ipp_attribute_t *job; /* Job object */
1378 int ascending, /* Order of jobs (0 = descending) */
1379 first, /* First job to show */
1380 count; /* Number of jobs */
1381 const char *var; /* Form variable */
1382 void *search; /* Search data */
2e4ff8af
MS
1383 char url[1024], /* Printer URI */
1384 val[1024]; /* Form variable */
ef416fc2 1385
1386
1387 /*
1388 * Build an IPP_GET_JOBS request, which requires the following
1389 * attributes:
1390 *
1391 * attributes-charset
1392 * attributes-natural-language
1393 * printer-uri
1394 */
1395
fa73b229 1396 request = ippNewRequest(IPP_GET_JOBS);
ef416fc2 1397
1398 if (dest)
1399 {
a4d04587 1400 httpAssembleURIf(HTTP_URI_CODING_ALL, url, sizeof(url), "ipp", NULL,
1401 "localhost", ippPort(), "/printers/%s", dest);
ef416fc2 1402 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1403 NULL, url);
1404 }
1405 else
1406 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL,
1407 "ipp://localhost/jobs");
1408
1409 if ((which_jobs = cgiGetVariable("which_jobs")) != NULL)
1410 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
1411 NULL, which_jobs);
1412
1413 cgiGetAttributes(request, "jobs.tmpl");
1414
1415 /*
1416 * Do the request and get back a response...
1417 */
1418
1419 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1420 {
1421 /*
1422 * Get a list of matching job objects.
1423 */
1424
2e4ff8af
MS
1425 if ((var = cgiGetVariable("QUERY")) != NULL &&
1426 !cgiGetVariable("CLEAR"))
ef416fc2 1427 search = cgiCompileSearch(var);
1428 else
1429 search = NULL;
1430
1431 jobs = cgiGetIPPObjects(response, search);
1432 count = cupsArrayCount(jobs);
1433
1434 if (search)
1435 cgiFreeSearch(search);
1436
1437 /*
1438 * Figure out which jobs to display...
1439 */
1440
1441 if ((var = cgiGetVariable("FIRST")) != NULL)
1442 first = atoi(var);
1443 else
1444 first = 0;
1445
1446 if (first >= count)
1447 first = count - CUPS_PAGE_MAX;
1448
1449 first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
1450
1451 if (first < 0)
1452 first = 0;
1453
2e4ff8af
MS
1454 sprintf(val, "%d", count);
1455 cgiSetVariable("TOTAL", val);
ef416fc2 1456
1457 if ((var = cgiGetVariable("ORDER")) != NULL)
1458 ascending = !strcasecmp(var, "asc");
1459 else
b423cd4c 1460 {
1461 ascending = !which_jobs || !strcasecmp(which_jobs, "not-completed");
1462 cgiSetVariable("ORDER", ascending ? "asc" : "dec");
1463 }
ef416fc2 1464
1465 if (ascending)
1466 {
1467 for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, first);
1468 i < CUPS_PAGE_MAX && job;
1469 i ++, job = (ipp_attribute_t *)cupsArrayNext(jobs))
1470 cgiSetIPPObjectVars(job, NULL, i);
1471 }
1472 else
1473 {
1474 for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, count - first - 1);
1475 i < CUPS_PAGE_MAX && job;
1476 i ++, job = (ipp_attribute_t *)cupsArrayPrev(jobs))
1477 cgiSetIPPObjectVars(job, NULL, i);
1478 }
1479
1480 /*
1481 * Save navigation URLs...
1482 */
1483
2e4ff8af
MS
1484 if (dest)
1485 snprintf(val, sizeof(val), "/%s/%s", cgiGetVariable("SECTION"), dest);
ef416fc2 1486 else
2e4ff8af 1487 strlcpy(val, "/jobs/", sizeof(val));
ef416fc2 1488
2e4ff8af 1489 cgiSetVariable("THISURL", val);
ef416fc2 1490
1491 if (first > 0)
1492 {
2e4ff8af
MS
1493 sprintf(val, "%d", first - CUPS_PAGE_MAX);
1494 cgiSetVariable("PREV", val);
ef416fc2 1495 }
1496
1497 if ((first + CUPS_PAGE_MAX) < count)
1498 {
2e4ff8af
MS
1499 sprintf(val, "%d", first + CUPS_PAGE_MAX);
1500 cgiSetVariable("NEXT", val);
ef416fc2 1501 }
1502
1503 /*
1504 * Then show everything...
1505 */
1506
fa73b229 1507 if (dest)
1508 cgiSetVariable("SEARCH_DEST", dest);
1509
1510 cgiCopyTemplateLang("search.tmpl");
ef416fc2 1511
1512 cgiCopyTemplateLang("jobs-header.tmpl");
1513
b19ccc9e 1514 if (count > CUPS_PAGE_MAX)
fa73b229 1515 cgiCopyTemplateLang("pager.tmpl");
ef416fc2 1516
1517 cgiCopyTemplateLang("jobs.tmpl");
1518
b19ccc9e 1519 if (count > CUPS_PAGE_MAX)
fa73b229 1520 cgiCopyTemplateLang("pager.tmpl");
ef416fc2 1521
bd7854cb 1522 cupsArrayDelete(jobs);
ef416fc2 1523 ippDelete(response);
1524 }
1525}
1526
1527
fa73b229 1528/*
1529 * 'cgiText()' - Return localized text.
1530 */
1531
1532const char * /* O - Localized message */
1533cgiText(const char *message) /* I - Message */
1534{
1535 static cups_lang_t *language = NULL;
1536 /* Language */
1537
1538
1539 if (!language)
1540 language = cupsLangDefault();
1541
1542 return (_cupsLangString(language, message));
1543}
1544
ef416fc2 1545
1546/*
b19ccc9e 1547 * End of "$Id: ipp-var.c 7940 2008-09-16 00:45:16Z mike $".
ef416fc2 1548 */