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