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