]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/ipp-var.c
Fix build errors on Fedora.
[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, (size_t)urlsize);
906 }
907 else
908 {
909 /*
910 * Rewrite URI with HTTP/HTTPS scheme...
911 */
912
913 if (userpass[0])
914 snprintf(url, (size_t)urlsize, "%s://%s@%s:%d%s", ishttps ? "https" : "http", userpass, hostname, port, resource);
915 else
916 snprintf(url, (size_t)urlsize, "%s://%s:%d%s", ishttps ? "https" : "http", hostname, port, resource);
917 }
918 }
919 else
920 strlcpy(url, uri, (size_t)urlsize);
921
922 return (url);
923 }
924
925
926 /*
927 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
928 */
929
930 ipp_attribute_t * /* O - Next object */
931 cgiSetIPPObjectVars(
932 ipp_attribute_t *obj, /* I - Response data to be copied... */
933 const char *prefix, /* I - Prefix for name or NULL */
934 int element) /* I - Parent element number */
935 {
936 ipp_attribute_t *attr; /* Attribute in response... */
937 int i; /* Looping var */
938 char name[1024], /* Name of attribute */
939 *nameptr, /* Pointer into name */
940 value[16384], /* Value(s) */
941 *valptr; /* Pointer into value */
942 struct tm *date; /* Date information */
943
944
945 fprintf(stderr, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
946 "element=%d)\n",
947 obj, prefix ? prefix : "(null)", element);
948
949 /*
950 * Set common CGI template variables...
951 */
952
953 if (!prefix)
954 cgiSetServerVersion();
955
956 /*
957 * Loop through the attributes and set them for the template...
958 */
959
960 for (attr = obj; attr && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
961 {
962 /*
963 * Copy the attribute name, substituting "_" for "-"...
964 */
965
966 if (!attr->name)
967 continue;
968
969 if (prefix)
970 {
971 snprintf(name, sizeof(name), "%s.", prefix);
972 nameptr = name + strlen(name);
973 }
974 else
975 nameptr = name;
976
977 for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++)
978 if (attr->name[i] == '-')
979 *nameptr++ = '_';
980 else
981 *nameptr++ = attr->name[i];
982
983 *nameptr = '\0';
984
985 /*
986 * Add "job_printer_name" variable if we have a "job_printer_uri"
987 * attribute...
988 */
989
990 if (!strcmp(name, "job_printer_uri"))
991 {
992 if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
993 valptr = "unknown";
994 else
995 valptr ++;
996
997 cgiSetArray("job_printer_name", element, valptr);
998 }
999
1000 /*
1001 * Localize event names in "notify_events" variable...
1002 */
1003
1004 if (!strcmp(name, "notify_events"))
1005 {
1006 size_t remaining; /* Remaining bytes in buffer */
1007
1008
1009 value[0] = '\0';
1010 valptr = value;
1011
1012 for (i = 0; i < attr->num_values; i ++)
1013 {
1014 if (valptr >= (value + sizeof(value) - 3))
1015 break;
1016
1017 if (i)
1018 {
1019 *valptr++ = ',';
1020 *valptr++ = ' ';
1021 }
1022
1023 remaining = sizeof(value) - (size_t)(valptr - value);
1024
1025 if (!strcmp(attr->values[i].string.text, "printer-stopped"))
1026 strlcpy(valptr, _("Printer Paused"), remaining);
1027 else if (!strcmp(attr->values[i].string.text, "printer-added"))
1028 strlcpy(valptr, _("Printer Added"), remaining);
1029 else if (!strcmp(attr->values[i].string.text, "printer-modified"))
1030 strlcpy(valptr, _("Printer Modified"), remaining);
1031 else if (!strcmp(attr->values[i].string.text, "printer-deleted"))
1032 strlcpy(valptr, _("Printer Deleted"), remaining);
1033 else if (!strcmp(attr->values[i].string.text, "job-created"))
1034 strlcpy(valptr, _("Job Created"), remaining);
1035 else if (!strcmp(attr->values[i].string.text, "job-completed"))
1036 strlcpy(valptr, _("Job Completed"), remaining);
1037 else if (!strcmp(attr->values[i].string.text, "job-stopped"))
1038 strlcpy(valptr, _("Job Stopped"), remaining);
1039 else if (!strcmp(attr->values[i].string.text, "job-config-changed"))
1040 strlcpy(valptr, _("Job Options Changed"), remaining);
1041 else if (!strcmp(attr->values[i].string.text, "server-restarted"))
1042 strlcpy(valptr, _("Server Restarted"), remaining);
1043 else if (!strcmp(attr->values[i].string.text, "server-started"))
1044 strlcpy(valptr, _("Server Started"), remaining);
1045 else if (!strcmp(attr->values[i].string.text, "server-stopped"))
1046 strlcpy(valptr, _("Server Stopped"), remaining);
1047 else if (!strcmp(attr->values[i].string.text, "server-audit"))
1048 strlcpy(valptr, _("Server Security Auditing"), remaining);
1049 else
1050 strlcpy(valptr, attr->values[i].string.text, remaining);
1051
1052 valptr += strlen(valptr);
1053 }
1054
1055 cgiSetArray("notify_events", element, value);
1056 continue;
1057 }
1058
1059 /*
1060 * Add "notify_printer_name" variable if we have a "notify_printer_uri"
1061 * attribute...
1062 */
1063
1064 if (!strcmp(name, "notify_printer_uri"))
1065 {
1066 if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
1067 valptr = "unknown";
1068 else
1069 valptr ++;
1070
1071 cgiSetArray("notify_printer_name", element, valptr);
1072 }
1073
1074 /*
1075 * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
1076 * attribute, and rewrite recipient URI...
1077 */
1078
1079 if (!strcmp(name, "notify_recipient_uri"))
1080 {
1081 char uri[1024], /* New URI */
1082 scheme[32], /* Scheme portion of URI */
1083 userpass[256], /* Username/password portion of URI */
1084 host[1024], /* Hostname portion of URI */
1085 resource[1024], /* Resource portion of URI */
1086 *options; /* Options in URI */
1087 int port; /* Port number */
1088
1089
1090 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
1091 scheme, sizeof(scheme), userpass, sizeof(userpass),
1092 host, sizeof(host), &port, resource, sizeof(resource));
1093
1094 if (!strcmp(scheme, "rss"))
1095 {
1096 /*
1097 * RSS notification...
1098 */
1099
1100 if ((options = strchr(resource, '?')) != NULL)
1101 *options = '\0';
1102
1103 if (host[0])
1104 {
1105 /*
1106 * Link to remote feed...
1107 */
1108
1109 httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http",
1110 userpass, host, port, resource);
1111 strlcpy(name, uri, sizeof(name));
1112 }
1113 else
1114 {
1115 /*
1116 * Link to local feed...
1117 */
1118
1119 snprintf(uri, sizeof(uri), "/rss%s", resource);
1120 strlcpy(name, resource + 1, sizeof(name));
1121 }
1122 }
1123 else
1124 {
1125 /*
1126 * Other...
1127 */
1128
1129 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
1130 strlcpy(name, resource, sizeof(name));
1131 }
1132
1133 cgiSetArray("notify_recipient_uri", element, uri);
1134 cgiSetArray("notify_recipient_name", element, name);
1135 continue;
1136 }
1137
1138 /*
1139 * Add "admin_uri" variable if we have a "printer_uri_supported"
1140 * attribute...
1141 */
1142
1143 if (!strcmp(name, "printer_uri_supported"))
1144 {
1145 cgiRewriteURL(attr->values[0].string.text, value, sizeof(value),
1146 "/admin/");
1147
1148 cgiSetArray("admin_uri", element, value);
1149 }
1150
1151 /*
1152 * Copy values...
1153 */
1154
1155 value[0] = '\0'; /* Initially an empty string */
1156 valptr = value; /* Start at the beginning */
1157
1158 for (i = 0; i < attr->num_values; i ++)
1159 {
1160 if (i)
1161 strlcat(valptr, ", ", sizeof(value) - (size_t)(valptr - value));
1162
1163 valptr += strlen(valptr);
1164
1165 switch (attr->value_tag)
1166 {
1167 case IPP_TAG_INTEGER :
1168 case IPP_TAG_ENUM :
1169 if (strncmp(name, "time_at_", 8) == 0)
1170 {
1171 time_t t; /* Temporary time value */
1172
1173 t = (time_t)attr->values[i].integer;
1174 date = localtime(&t);
1175
1176 strftime(valptr, sizeof(value) - (size_t)(valptr - value), "%c", date);
1177 }
1178 else
1179 snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
1180 "%d", attr->values[i].integer);
1181 break;
1182
1183 case IPP_TAG_BOOLEAN :
1184 snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
1185 "%d", attr->values[i].boolean);
1186 break;
1187
1188 case IPP_TAG_NOVALUE :
1189 strlcat(valptr, "novalue", sizeof(value) - (size_t)(valptr - value));
1190 break;
1191
1192 case IPP_TAG_RANGE :
1193 snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
1194 "%d-%d", attr->values[i].range.lower,
1195 attr->values[i].range.upper);
1196 break;
1197
1198 case IPP_TAG_RESOLUTION :
1199 snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
1200 "%dx%d%s", attr->values[i].resolution.xres,
1201 attr->values[i].resolution.yres,
1202 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
1203 "dpi" : "dpcm");
1204 break;
1205
1206 case IPP_TAG_URI :
1207 if (strchr(attr->values[i].string.text, ':') &&
1208 strcmp(name, "device_uri"))
1209 {
1210 /*
1211 * Rewrite URIs...
1212 */
1213
1214 if (!strcmp(name, "member_uris"))
1215 {
1216 char url[1024]; /* URL for class member... */
1217
1218
1219 cgiRewriteURL(attr->values[i].string.text, url,
1220 sizeof(url), NULL);
1221
1222 snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
1223 "<A HREF=\"%s\">%s</A>", url,
1224 strrchr(attr->values[i].string.text, '/') + 1);
1225 }
1226 else
1227 cgiRewriteURL(attr->values[i].string.text, valptr,
1228 (int)(sizeof(value) - (size_t)(valptr - value)), NULL);
1229 break;
1230 }
1231
1232 case IPP_TAG_STRING :
1233 case IPP_TAG_TEXT :
1234 case IPP_TAG_NAME :
1235 case IPP_TAG_KEYWORD :
1236 case IPP_TAG_CHARSET :
1237 case IPP_TAG_LANGUAGE :
1238 case IPP_TAG_MIMETYPE :
1239 strlcat(valptr, attr->values[i].string.text,
1240 sizeof(value) - (size_t)(valptr - value));
1241 break;
1242
1243 case IPP_TAG_BEGIN_COLLECTION :
1244 snprintf(value, sizeof(value), "%s%d", name, i + 1);
1245 cgiSetIPPVars(attr->values[i].collection, NULL, NULL, value,
1246 element);
1247 break;
1248
1249 default :
1250 break; /* anti-compiler-warning-code */
1251 }
1252 }
1253
1254 /*
1255 * Add the element...
1256 */
1257
1258 if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
1259 {
1260 cgiSetArray(name, element, value);
1261
1262 fprintf(stderr, "DEBUG2: %s[%d]=\"%s\"\n", name, element, value);
1263 }
1264 }
1265
1266 return (attr ? attr->next : NULL);
1267 }
1268
1269
1270 /*
1271 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
1272 */
1273
1274 int /* O - Maximum number of elements */
1275 cgiSetIPPVars(ipp_t *response, /* I - Response data to be copied... */
1276 const char *filter_name, /* I - Filter name */
1277 const char *filter_value, /* I - Filter value */
1278 const char *prefix, /* I - Prefix for name or NULL */
1279 int parent_el) /* I - Parent element number */
1280 {
1281 int element; /* Element in CGI array */
1282 ipp_attribute_t *attr, /* Attribute in response... */
1283 *filter; /* Filtering attribute */
1284
1285
1286 fprintf(stderr, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
1287 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
1288 response, filter_name ? filter_name : "(null)",
1289 filter_value ? filter_value : "(null)",
1290 prefix ? prefix : "(null)", parent_el);
1291
1292 /*
1293 * Set common CGI template variables...
1294 */
1295
1296 if (!prefix)
1297 cgiSetServerVersion();
1298
1299 /*
1300 * Loop through the attributes and set them for the template...
1301 */
1302
1303 attr = response->attrs;
1304
1305 if (!prefix)
1306 while (attr && attr->group_tag == IPP_TAG_OPERATION)
1307 attr = attr->next;
1308
1309 for (element = parent_el; attr; element ++)
1310 {
1311 /*
1312 * Copy attributes to a separator...
1313 */
1314
1315 while (attr && attr->group_tag == IPP_TAG_ZERO)
1316 attr= attr->next;
1317
1318 if (!attr)
1319 break;
1320
1321 if (filter_name)
1322 {
1323 for (filter = attr;
1324 filter != NULL && filter->group_tag != IPP_TAG_ZERO;
1325 filter = filter->next)
1326 if (filter->name && !strcmp(filter->name, filter_name) &&
1327 (filter->value_tag == IPP_TAG_STRING ||
1328 (filter->value_tag >= IPP_TAG_TEXTLANG &&
1329 filter->value_tag <= IPP_TAG_MIMETYPE)) &&
1330 filter->values[0].string.text != NULL &&
1331 !_cups_strcasecmp(filter->values[0].string.text, filter_value))
1332 break;
1333
1334 if (!filter)
1335 return (element + 1);
1336
1337 if (filter->group_tag == IPP_TAG_ZERO)
1338 {
1339 attr = filter;
1340 element --;
1341 continue;
1342 }
1343 }
1344
1345 attr = cgiSetIPPObjectVars(attr, prefix, element);
1346 }
1347
1348 fprintf(stderr, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element);
1349
1350 return (element);
1351 }
1352
1353
1354 /*
1355 * 'cgiShowIPPError()' - Show the last IPP error message.
1356 *
1357 * The caller must still call cgiStartHTML() and cgiEndHTML().
1358 */
1359
1360 void
1361 cgiShowIPPError(const char *message) /* I - Contextual message */
1362 {
1363 cgiSetVariable("MESSAGE", cgiText(message));
1364 cgiSetVariable("ERROR", cupsLastErrorString());
1365 cgiCopyTemplateLang("error.tmpl");
1366 }
1367
1368
1369 /*
1370 * 'cgiShowJobs()' - Show print jobs.
1371 */
1372
1373 void
1374 cgiShowJobs(http_t *http, /* I - Connection to server */
1375 const char *dest) /* I - Destination name or NULL */
1376 {
1377 int i; /* Looping var */
1378 const char *which_jobs; /* Which jobs to show */
1379 ipp_t *request, /* IPP request */
1380 *response; /* IPP response */
1381 cups_array_t *jobs; /* Array of job objects */
1382 ipp_attribute_t *job; /* Job object */
1383 int ascending, /* Order of jobs (0 = descending) */
1384 first, /* First job to show */
1385 count; /* Number of jobs */
1386 const char *var, /* Form variable */
1387 *query, /* Query string */
1388 *section; /* Section in web interface */
1389 void *search; /* Search data */
1390 char url[1024], /* Printer URI */
1391 val[1024]; /* Form variable */
1392
1393
1394 /*
1395 * Build an IPP_GET_JOBS request, which requires the following
1396 * attributes:
1397 *
1398 * attributes-charset
1399 * attributes-natural-language
1400 * printer-uri
1401 */
1402
1403 request = ippNewRequest(IPP_GET_JOBS);
1404
1405 if (dest)
1406 {
1407 httpAssembleURIf(HTTP_URI_CODING_ALL, url, sizeof(url), "ipp", NULL,
1408 "localhost", ippPort(), "/printers/%s", dest);
1409 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1410 NULL, url);
1411 }
1412 else
1413 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
1414 "ipp://localhost/");
1415
1416 if ((which_jobs = cgiGetVariable("which_jobs")) != NULL && *which_jobs)
1417 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
1418 NULL, which_jobs);
1419
1420 cgiGetAttributes(request, "jobs.tmpl");
1421
1422 /*
1423 * Do the request and get back a response...
1424 */
1425
1426 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1427 {
1428 /*
1429 * Get a list of matching job objects.
1430 */
1431
1432 if ((query = cgiGetVariable("QUERY")) != NULL &&
1433 !cgiGetVariable("CLEAR"))
1434 search = cgiCompileSearch(query);
1435 else
1436 {
1437 query = NULL;
1438 search = NULL;
1439 }
1440
1441 jobs = cgiGetIPPObjects(response, search);
1442 count = cupsArrayCount(jobs);
1443
1444 if (search)
1445 cgiFreeSearch(search);
1446
1447 /*
1448 * Figure out which jobs to display...
1449 */
1450
1451 if ((var = cgiGetVariable("FIRST")) != NULL)
1452 first = atoi(var);
1453 else
1454 first = 0;
1455
1456 if (first >= count)
1457 first = count - CUPS_PAGE_MAX;
1458
1459 first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
1460
1461 if (first < 0)
1462 first = 0;
1463
1464 if ((var = cgiGetVariable("ORDER")) != NULL && *var)
1465 ascending = !_cups_strcasecmp(var, "asc");
1466 else
1467 ascending = !which_jobs || !*which_jobs ||
1468 !_cups_strcasecmp(which_jobs, "not-completed");
1469
1470 section = cgiGetVariable("SECTION");
1471
1472 cgiClearVariables();
1473
1474 if (query)
1475 cgiSetVariable("QUERY", query);
1476
1477 cgiSetVariable("ORDER", ascending ? "asc" : "dec");
1478
1479 cgiSetVariable("SECTION", section);
1480
1481 sprintf(val, "%d", count);
1482 cgiSetVariable("TOTAL", val);
1483
1484 if (which_jobs)
1485 cgiSetVariable("WHICH_JOBS", which_jobs);
1486
1487 if (ascending)
1488 {
1489 for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, first);
1490 i < CUPS_PAGE_MAX && job;
1491 i ++, job = (ipp_attribute_t *)cupsArrayNext(jobs))
1492 cgiSetIPPObjectVars(job, NULL, i);
1493 }
1494 else
1495 {
1496 for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, count - first - 1);
1497 i < CUPS_PAGE_MAX && job;
1498 i ++, job = (ipp_attribute_t *)cupsArrayPrev(jobs))
1499 cgiSetIPPObjectVars(job, NULL, i);
1500 }
1501
1502 /*
1503 * Save navigation URLs...
1504 */
1505
1506 if (dest)
1507 {
1508 snprintf(val, sizeof(val), "/%s/%s", section, dest);
1509 cgiSetVariable("PRINTER_NAME", dest);
1510 cgiSetVariable("PRINTER_URI_SUPPORTED", val);
1511 }
1512 else
1513 strlcpy(val, "/jobs/", sizeof(val));
1514
1515 cgiSetVariable("THISURL", val);
1516
1517 if (first > 0)
1518 {
1519 sprintf(val, "%d", first - CUPS_PAGE_MAX);
1520 cgiSetVariable("PREV", val);
1521 }
1522
1523 if ((first + CUPS_PAGE_MAX) < count)
1524 {
1525 sprintf(val, "%d", first + CUPS_PAGE_MAX);
1526 cgiSetVariable("NEXT", val);
1527 }
1528
1529 /*
1530 * Then show everything...
1531 */
1532
1533 if (dest)
1534 cgiSetVariable("SEARCH_DEST", dest);
1535
1536 cgiCopyTemplateLang("search.tmpl");
1537
1538 cgiCopyTemplateLang("jobs-header.tmpl");
1539
1540 if (count > CUPS_PAGE_MAX)
1541 cgiCopyTemplateLang("pager.tmpl");
1542
1543 cgiCopyTemplateLang("jobs.tmpl");
1544
1545 if (count > CUPS_PAGE_MAX)
1546 cgiCopyTemplateLang("pager.tmpl");
1547
1548 cupsArrayDelete(jobs);
1549 ippDelete(response);
1550 }
1551 }
1552
1553
1554 /*
1555 * 'cgiText()' - Return localized text.
1556 */
1557
1558 const char * /* O - Localized message */
1559 cgiText(const char *message) /* I - Message */
1560 {
1561 static cups_lang_t *language = NULL;
1562 /* Language */
1563
1564
1565 if (!language)
1566 language = cupsLangDefault();
1567
1568 return (_cupsLangString(language, message));
1569 }
1570
1571
1572 /*
1573 * End of "$Id$".
1574 */