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