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