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