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