2 * "$Id: ipp-var.c 7940 2008-09-16 00:45:16Z mike $"
4 * CGI <-> IPP variable routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
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/".
17 * cgiGetAttributes() - Get the list of attributes that are needed by the
19 * cgiGetIPPObjects() - Get the objects in an IPP response.
20 * cgiMoveJobs() - Move one or more jobs.
21 * cgiPrintCommand() - Print a CUPS command job.
22 * cgiPrintTestPage() - Print a test page.
23 * cgiRewriteURL() - Rewrite a printer URI into a web browser URL...
24 * cgiSetIPPObjectVars() - Set CGI variables from an IPP object.
25 * cgiSetIPPVars() - Set CGI variables from an IPP response.
26 * cgiShowIPPError() - Show the last IPP error message.
27 * cgiShowJobs() - Show print jobs.
28 * cgiText() - Return localized text.
32 * Include necessary headers...
35 #include "cgi-private.h"
39 * 'cgiGetAttributes()' - Get the list of attributes that are needed
40 * by the template file.
44 cgiGetAttributes(ipp_t
*request
, /* I - IPP request */
45 const char *tmpl
) /* I - Base filename */
47 int num_attrs
; /* Number of attributes */
48 char *attrs
[1000]; /* Attributes */
49 int i
; /* Looping var */
50 char filename
[1024], /* Filename */
51 locale
[16]; /* Locale name */
52 const char *directory
, /* Directory */
54 FILE *in
; /* Input file */
55 int ch
; /* Character from file */
56 char name
[255], /* Name of variable */
57 *nameptr
; /* Pointer into name */
61 * Convert the language to a locale name...
64 if ((lang
= getenv("LANG")) != NULL
)
66 for (i
= 0; lang
[i
] && i
< 15; i
++)
67 if (isalnum(lang
[i
] & 255))
68 locale
[i
] = tolower(lang
[i
]);
78 * See if we have a template file for this language...
81 directory
= cgiGetTemplateDir();
83 snprintf(filename
, sizeof(filename
), "%s/%s/%s", directory
, locale
, tmpl
);
84 if (access(filename
, 0))
88 snprintf(filename
, sizeof(filename
), "%s/%s/%s", directory
, locale
, tmpl
);
89 if (access(filename
, 0))
90 snprintf(filename
, sizeof(filename
), "%s/%s", directory
, tmpl
);
94 * Open the template file...
97 if ((in
= fopen(filename
, "r")) == NULL
)
101 * Loop through the file adding attribute names as needed...
105 attrs
[0] = NULL
; /* Eliminate compiler warning */
107 while ((ch
= getc(in
)) != EOF
)
110 else if (ch
== '{' && num_attrs
< (sizeof(attrs
) / sizeof(attrs
[0])))
116 for (nameptr
= name
; (ch
= getc(in
)) != EOF
;)
117 if (strchr("}]<>=!~ \t\n", ch
))
119 else if (nameptr
> name
&& ch
== '?')
121 else if (nameptr
< (name
+ sizeof(name
) - 1))
131 if (!strncmp(name
, "printer_state_history", 21))
132 strcpy(name
, "printer_state_history");
135 * Possibly add it to the list of attributes...
138 for (i
= 0; i
< num_attrs
; i
++)
139 if (!strcmp(attrs
[i
], name
))
144 attrs
[num_attrs
] = strdup(name
);
150 * If we have attributes, add a requested-attributes attribute to the
156 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
157 "requested-attributes", num_attrs
, NULL
, (const char **)attrs
);
159 for (i
= 0; i
< num_attrs
; i
++)
168 * 'cgiGetIPPObjects()' - Get the objects in an IPP response.
171 cups_array_t
* /* O - Array of objects */
172 cgiGetIPPObjects(ipp_t
*response
, /* I - IPP response */
173 void *search
) /* I - Search filter */
175 int i
; /* Looping var */
176 cups_array_t
*objs
; /* Array of objects */
177 ipp_attribute_t
*attr
, /* Current attribute */
178 *first
; /* First attribute for object */
179 ipp_tag_t group
; /* Current group tag */
180 int add
; /* Add this object to the array? */
186 for (add
= 0, first
= NULL
, objs
= cupsArrayNew(NULL
, NULL
),
187 group
= IPP_TAG_ZERO
, attr
= response
->attrs
;
191 if (attr
->group_tag
!= group
)
193 group
= attr
->group_tag
;
195 if (group
!= IPP_TAG_ZERO
&& group
!= IPP_TAG_OPERATION
)
200 else if (add
&& first
)
202 cupsArrayAdd(objs
, first
);
209 if (attr
->name
&& attr
->group_tag
!= IPP_TAG_OPERATION
&& !add
)
214 * Add all objects if there is no search...
222 * Check the search string against the string and integer values.
225 switch (attr
->value_tag
)
227 case IPP_TAG_TEXTLANG
:
228 case IPP_TAG_NAMELANG
:
231 case IPP_TAG_KEYWORD
:
233 case IPP_TAG_MIMETYPE
:
234 for (i
= 0; !add
&& i
< attr
->num_values
; i
++)
235 if (cgiDoSearch(search
, attr
->values
[i
].string
.text
))
239 case IPP_TAG_INTEGER
:
240 for (i
= 0; !add
&& i
< attr
->num_values
; i
++)
242 char buf
[255]; /* Number buffer */
245 sprintf(buf
, "%d", attr
->values
[i
].integer
);
247 if (cgiDoSearch(search
, buf
))
260 cupsArrayAdd(objs
, first
);
267 * 'cgiMoveJobs()' - Move one or more jobs.
269 * At least one of dest or job_id must be non-zero/NULL.
273 cgiMoveJobs(http_t
*http
, /* I - Connection to server */
274 const char *dest
, /* I - Destination or NULL */
275 int job_id
) /* I - Job ID or 0 for all */
277 int i
; /* Looping var */
278 const char *user
; /* Username */
279 ipp_t
*request
, /* IPP request */
280 *response
; /* IPP response */
281 ipp_attribute_t
*attr
; /* Current attribute */
282 const char *name
; /* Destination name */
283 const char *job_printer_uri
; /* JOB_PRINTER_URI form variable */
284 char current_dest
[1024]; /* Current destination */
288 * See who is logged in...
291 user
= getenv("REMOTE_USER");
294 * See if the user has already selected a new destination...
297 if ((job_printer_uri
= cgiGetVariable("JOB_PRINTER_URI")) == NULL
)
300 * Make sure necessary form variables are set...
305 char temp
[255]; /* Temporary string */
308 sprintf(temp
, "%d", job_id
);
309 cgiSetVariable("JOB_ID", temp
);
313 cgiSetVariable("PRINTER_NAME", dest
);
316 * No new destination specified, show the user what the available
317 * printers/classes are...
323 * Get the current destination for job N...
326 char job_uri
[1024]; /* Job URI */
329 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
331 snprintf(job_uri
, sizeof(job_uri
), "ipp://localhost/jobs/%d", job_id
);
332 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
334 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
335 "requested-attributes", NULL
, "job-printer-uri");
337 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
339 if ((attr
= ippFindAttribute(response
, "job-printer-uri",
340 IPP_TAG_URI
)) != NULL
)
343 * Pull the name from the URI...
346 strlcpy(current_dest
, strrchr(attr
->values
[0].string
.text
, '/') + 1,
347 sizeof(current_dest
));
357 * Couldn't get the current destination...
360 cgiStartHTML(cgiText(_("Move Job")));
361 cgiShowIPPError(_("Unable to find destination for job!"));
368 * Get the list of available destinations...
371 request
= ippNewRequest(CUPS_GET_PRINTERS
);
373 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
374 "requested-attributes", NULL
, "printer-uri-supported");
377 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
378 "requesting-user-name", NULL
, user
);
380 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
382 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
383 CUPS_PRINTER_SCANNER
);
385 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
387 for (i
= 0, attr
= ippFindAttribute(response
, "printer-uri-supported",
390 attr
= ippFindNextAttribute(response
, "printer-uri-supported",
394 * Pull the name from the URI...
397 name
= strrchr(attr
->values
[0].string
.text
, '/') + 1;
400 * If the name is not the same as the current destination, add it!
403 if (strcasecmp(name
, dest
))
405 cgiSetArray("JOB_PRINTER_URI", i
, attr
->values
[0].string
.text
);
406 cgiSetArray("JOB_PRINTER_NAME", i
, name
);
419 cgiStartHTML(cgiText(_("Move Job")));
421 cgiStartHTML(cgiText(_("Move All Jobs")));
423 if (cgiGetSize("JOB_PRINTER_NAME") > 0)
424 cgiCopyTemplateLang("job-move.tmpl");
428 cgiSetVariable("MESSAGE", cgiText(_("Unable to move job")));
430 cgiSetVariable("MESSAGE", cgiText(_("Unable to move jobs")));
432 cgiSetVariable("ERROR", cgiText(_("No destinations added.")));
433 cgiCopyTemplateLang("error.tmpl");
439 * Try moving the job or jobs...
442 char uri
[1024], /* Job/printer URI */
443 resource
[1024], /* Post resource */
444 refresh
[1024]; /* Refresh URL */
445 const char *job_printer_name
; /* New printer name */
448 request
= ippNewRequest(CUPS_MOVE_JOB
);
456 snprintf(resource
, sizeof(resource
), "/jobs/%d", job_id
);
458 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
459 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
465 * Move all active jobs on a destination...
468 snprintf(resource
, sizeof(resource
), "/%s/%s",
469 cgiGetVariable("SECTION"), dest
);
471 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
472 "localhost", ippPort(), "/%s/%s",
473 cgiGetVariable("SECTION"), dest
);
474 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
478 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-printer-uri",
479 NULL
, job_printer_uri
);
481 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
482 "requesting-user-name", NULL
, user
);
484 ippDelete(cupsDoRequest(http
, request
, resource
));
487 * Show the results...
490 job_printer_name
= strrchr(job_printer_uri
, '/') + 1;
492 if (cupsLastError() <= IPP_OK_CONFLICT
)
494 const char *path
= strstr(job_printer_uri
, "/printers/");
497 path
= strstr(job_printer_uri
, "/classes/");
498 cgiSetVariable("IS_CLASS", "YES");
503 cgiFormEncode(uri
, path
, sizeof(uri
));
504 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
505 cgiSetVariable("refresh_page", refresh
);
510 cgiStartHTML(cgiText(_("Move Job")));
512 cgiStartHTML(cgiText(_("Move All Jobs")));
514 if (cupsLastError() > IPP_OK_CONFLICT
)
517 cgiShowIPPError(_("Unable to move job"));
519 cgiShowIPPError(_("Unable to move jobs"));
523 cgiSetVariable("JOB_PRINTER_NAME", job_printer_name
);
524 cgiCopyTemplateLang("job-moved.tmpl");
533 * 'cgiPrintCommand()' - Print a CUPS command job.
537 cgiPrintCommand(http_t
*http
, /* I - Connection to server */
538 const char *dest
, /* I - Destination printer */
539 const char *command
, /* I - Command to send */
540 const char *title
) /* I - Page/job title */
542 int job_id
; /* Command file job */
543 char uri
[HTTP_MAX_URI
], /* Job URI */
544 resource
[1024], /* Printer resource path */
545 refresh
[1024], /* Refresh URL */
546 command_file
[1024]; /* Command "file" */
547 http_status_t status
; /* Document status */
548 cups_option_t hold_option
; /* job-hold-until option */
549 const char *user
; /* User name */
550 ipp_t
*request
, /* Get-Job-Attributes request */
551 *response
; /* Get-Job-Attributes response */
552 ipp_attribute_t
*attr
; /* Current job attribute */
553 static const char const *job_attrs
[] =/* Job attributes we want */
556 "job-printer-state-message"
561 * Create the CUPS command file...
564 snprintf(command_file
, sizeof(command_file
), "#CUPS-COMMAND\n%s\n", command
);
570 if (cgiSupportsMultipart())
574 cgiCopyTemplateLang("command.tmpl");
580 * Send the command file job...
583 hold_option
.name
= "job-hold-until";
584 hold_option
.value
= "no-hold";
586 if ((user
= getenv("REMOTE_USER")) != NULL
)
589 cupsSetUser("anonymous");
591 if ((job_id
= cupsCreateJob(http
, dest
, title
,
592 1, &hold_option
)) < 1)
594 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver!")));
595 cgiSetVariable("ERROR", cupsLastErrorString());
597 cgiCopyTemplateLang("error.tmpl");
600 if (cgiSupportsMultipart())
605 status
= cupsStartDocument(http
, dest
, job_id
, NULL
, CUPS_FORMAT_COMMAND
, 1);
606 if (status
== HTTP_CONTINUE
)
607 status
= cupsWriteRequestData(http
, command_file
,
608 strlen(command_file
));
609 if (status
== HTTP_CONTINUE
)
610 cupsFinishDocument(http
, dest
);
612 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE
)
614 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver!")));
615 cgiSetVariable("ERROR", cupsLastErrorString());
617 cgiCopyTemplateLang("error.tmpl");
620 if (cgiSupportsMultipart())
623 cupsCancelJob(dest
, job_id
);
628 * Wait for the job to complete...
631 if (cgiSupportsMultipart())
636 * Get the current job state...
639 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
640 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
641 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
644 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
645 "requesting-user-name", NULL
, user
);
646 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
647 "requested-attributes", 2, NULL
, job_attrs
);
649 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
650 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
652 attr
= ippFindAttribute(response
, "job-state", IPP_TAG_ENUM
);
653 if (!attr
|| attr
->values
[0].integer
>= IPP_JOB_STOPPED
||
654 attr
->values
[0].integer
== IPP_JOB_HELD
)
661 * Job not complete, so update the status...
667 cgiCopyTemplateLang("command.tmpl");
676 * Send the final page that reloads the printer's page...
679 snprintf(resource
, sizeof(resource
), "/printers/%s", dest
);
681 cgiFormEncode(uri
, resource
, sizeof(uri
));
682 snprintf(refresh
, sizeof(refresh
), "5;URL=%s", uri
);
683 cgiSetVariable("refresh_page", refresh
);
686 cgiCopyTemplateLang("command.tmpl");
689 if (cgiSupportsMultipart())
695 * 'cgiPrintTestPage()' - Print a test page.
699 cgiPrintTestPage(http_t
*http
, /* I - Connection to server */
700 const char *dest
) /* I - Destination printer/class */
702 ipp_t
*request
, /* IPP request */
703 *response
; /* IPP response */
704 char uri
[HTTP_MAX_URI
], /* Printer URI */
705 resource
[1024], /* POST resource path */
706 refresh
[1024], /* Refresh URL */
707 filename
[1024]; /* Test page filename */
708 const char *datadir
; /* CUPS_DATADIR env var */
709 const char *user
; /* Username */
713 * See who is logged in...
716 user
= getenv("REMOTE_USER");
719 * Locate the test page file...
722 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
723 datadir
= CUPS_DATADIR
;
725 snprintf(filename
, sizeof(filename
), "%s/data/testprint", datadir
);
728 * Point to the printer/class...
731 snprintf(resource
, sizeof(resource
), "/%s/%s", cgiGetVariable("SECTION"),
734 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
735 "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
739 * Build an IPP_PRINT_JOB request, which requires the following
743 * attributes-natural-language
745 * requesting-user-name
748 request
= ippNewRequest(IPP_PRINT_JOB
);
750 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
754 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
755 "requesting-user-name", NULL
, user
);
757 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name",
761 * Do the request and get back a response...
764 if ((response
= cupsDoFileRequest(http
, request
, resource
,
767 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
772 if (cupsLastError() <= IPP_OK_CONFLICT
)
775 * Automatically reload the printer status page...
778 cgiFormEncode(uri
, resource
, sizeof(uri
));
779 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
780 cgiSetVariable("refresh_page", refresh
);
782 else if (cupsLastError() == IPP_NOT_AUTHORIZED
)
784 puts("Status: 401\n");
788 cgiStartHTML(cgiText(_("Print Test Page")));
790 if (cupsLastError() > IPP_OK_CONFLICT
)
791 cgiShowIPPError(_("Unable to print test page:"));
794 cgiSetVariable("PRINTER_NAME", dest
);
796 cgiCopyTemplateLang("test-page.tmpl");
804 * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
807 char * /* O - New URL */
808 cgiRewriteURL(const char *uri
, /* I - Current URI */
809 char *url
, /* O - New URL */
810 int urlsize
, /* I - Size of URL buffer */
811 const char *newresource
) /* I - Replacement resource */
813 char scheme
[HTTP_MAX_URI
],
814 userpass
[HTTP_MAX_URI
],
815 hostname
[HTTP_MAX_URI
],
816 rawresource
[HTTP_MAX_URI
],
817 resource
[HTTP_MAX_URI
],
818 /* URI components... */
819 *rawptr
, /* Pointer into rawresource */
820 *resptr
; /* Pointer into resource */
821 int port
; /* Port number */
822 static int ishttps
= -1; /* Using encryption? */
823 static const char *server
; /* Name of server */
824 static char servername
[1024];
825 /* Local server name */
826 static const char hexchars
[] = "0123456789ABCDEF";
827 /* Hexadecimal conversion characters */
831 * Check if we have been called before...
837 * No, initialize static vars for the conversion...
839 * First get the server name associated with the client interface as
840 * well as the locally configured hostname. We'll check *both* of
841 * these to see if the printer URL is local...
844 if ((server
= getenv("SERVER_NAME")) == NULL
)
847 httpGetHostname(NULL
, servername
, sizeof(servername
));
850 * Then flag whether we are using SSL on this connection...
853 ishttps
= getenv("HTTPS") != NULL
;
857 * Convert the URI to a URL...
860 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
,
861 sizeof(userpass
), hostname
, sizeof(hostname
), &port
,
862 rawresource
, sizeof(rawresource
));
864 if (!strcmp(scheme
, "ipp") ||
865 !strcmp(scheme
, "http") ||
866 !strcmp(scheme
, "https"))
871 * Force the specified resource name instead of the one in the URL...
874 strlcpy(resource
, newresource
, sizeof(resource
));
879 * Rewrite the resource string so it doesn't contain any
883 for (rawptr
= rawresource
, resptr
= resource
; *rawptr
; rawptr
++)
884 if ((*rawptr
& 128) || *rawptr
== '%' || *rawptr
== ' ' ||
885 *rawptr
== '#' || *rawptr
== '?' ||
886 *rawptr
== '.') /* For MSIE */
888 if (resptr
< (resource
+ sizeof(resource
) - 3))
891 *resptr
++ = hexchars
[(*rawptr
>> 4) & 15];
892 *resptr
++ = hexchars
[*rawptr
& 15];
895 else if (resptr
< (resource
+ sizeof(resource
) - 1))
902 * Map local access to a local URI...
905 if (!strcasecmp(hostname
, "127.0.0.1") ||
906 !strcasecmp(hostname
, "[::1]") ||
907 !strcasecmp(hostname
, "localhost") ||
908 !strncasecmp(hostname
, "localhost.", 10) ||
909 !strcasecmp(hostname
, server
) ||
910 !strcasecmp(hostname
, servername
))
913 * Make URI relative to the current server...
916 strlcpy(url
, resource
, urlsize
);
921 * Rewrite URI with HTTP/HTTPS scheme...
925 snprintf(url
, urlsize
, "%s://%s@%s:%d%s",
926 ishttps
? "https" : "http",
927 userpass
, hostname
, port
, resource
);
929 snprintf(url
, urlsize
, "%s://%s:%d%s",
930 ishttps
? "https" : "http",
931 hostname
, port
, resource
);
935 strlcpy(url
, uri
, urlsize
);
942 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
945 ipp_attribute_t
* /* O - Next object */
947 ipp_attribute_t
*obj
, /* I - Response data to be copied... */
948 const char *prefix
, /* I - Prefix for name or NULL */
949 int element
) /* I - Parent element number */
951 ipp_attribute_t
*attr
; /* Attribute in response... */
952 int i
; /* Looping var */
953 char name
[1024], /* Name of attribute */
954 *nameptr
, /* Pointer into name */
955 value
[16384], /* Value(s) */
956 *valptr
; /* Pointer into value */
957 struct tm
*date
; /* Date information */
960 fprintf(stderr
, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
962 obj
, prefix
? prefix
: "(null)", element
);
965 * Set common CGI template variables...
969 cgiSetServerVersion();
972 * Loop through the attributes and set them for the template...
975 for (attr
= obj
; attr
&& attr
->group_tag
!= IPP_TAG_ZERO
; attr
= attr
->next
)
978 * Copy the attribute name, substituting "_" for "-"...
986 snprintf(name
, sizeof(name
), "%s.", prefix
);
987 nameptr
= name
+ strlen(name
);
992 for (i
= 0; attr
->name
[i
] && nameptr
< (name
+ sizeof(name
) - 1); i
++)
993 if (attr
->name
[i
] == '-')
996 *nameptr
++ = attr
->name
[i
];
1001 * Add "job_printer_name" variable if we have a "job_printer_uri"
1005 if (!strcmp(name
, "job_printer_uri"))
1007 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
1012 cgiSetArray("job_printer_name", element
, valptr
);
1016 * Localize event names in "notify_events" variable...
1019 if (!strcmp(name
, "notify_events"))
1021 size_t remaining
; /* Remaining bytes in buffer */
1027 for (i
= 0; i
< attr
->num_values
; i
++)
1029 if (valptr
>= (value
+ sizeof(value
) - 3))
1038 remaining
= sizeof(value
) - (valptr
- value
);
1040 if (!strcmp(attr
->values
[i
].string
.text
, "printer-stopped"))
1041 strlcpy(valptr
, _("Printer Paused"), remaining
);
1042 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-added"))
1043 strlcpy(valptr
, _("Printer Added"), remaining
);
1044 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-modified"))
1045 strlcpy(valptr
, _("Printer Modified"), remaining
);
1046 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-deleted"))
1047 strlcpy(valptr
, _("Printer Deleted"), remaining
);
1048 else if (!strcmp(attr
->values
[i
].string
.text
, "job-created"))
1049 strlcpy(valptr
, _("Job Created"), remaining
);
1050 else if (!strcmp(attr
->values
[i
].string
.text
, "job-completed"))
1051 strlcpy(valptr
, _("Job Completed"), remaining
);
1052 else if (!strcmp(attr
->values
[i
].string
.text
, "job-stopped"))
1053 strlcpy(valptr
, _("Job Stopped"), remaining
);
1054 else if (!strcmp(attr
->values
[i
].string
.text
, "job-config-changed"))
1055 strlcpy(valptr
, _("Job Options Changed"), remaining
);
1056 else if (!strcmp(attr
->values
[i
].string
.text
, "server-restarted"))
1057 strlcpy(valptr
, _("Server Restarted"), remaining
);
1058 else if (!strcmp(attr
->values
[i
].string
.text
, "server-started"))
1059 strlcpy(valptr
, _("Server Started"), remaining
);
1060 else if (!strcmp(attr
->values
[i
].string
.text
, "server-stopped"))
1061 strlcpy(valptr
, _("Server Stopped"), remaining
);
1062 else if (!strcmp(attr
->values
[i
].string
.text
, "server-audit"))
1063 strlcpy(valptr
, _("Server Security Auditing"), remaining
);
1065 strlcpy(valptr
, attr
->values
[i
].string
.text
, remaining
);
1067 valptr
+= strlen(valptr
);
1070 cgiSetArray("notify_events", element
, value
);
1075 * Add "notify_printer_name" variable if we have a "notify_printer_uri"
1079 if (!strcmp(name
, "notify_printer_uri"))
1081 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
1086 cgiSetArray("notify_printer_name", element
, valptr
);
1090 * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
1091 * attribute, and rewrite recipient URI...
1094 if (!strcmp(name
, "notify_recipient_uri"))
1096 char uri
[1024], /* New URI */
1097 scheme
[32], /* Scheme portion of URI */
1098 userpass
[256], /* Username/password portion of URI */
1099 host
[1024], /* Hostname portion of URI */
1100 resource
[1024], /* Resource portion of URI */
1101 *options
; /* Options in URI */
1102 int port
; /* Port number */
1105 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
1106 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
1107 host
, sizeof(host
), &port
, resource
, sizeof(resource
));
1109 if (!strcmp(scheme
, "rss"))
1112 * RSS notification...
1115 if ((options
= strchr(resource
, '?')) != NULL
)
1121 * Link to remote feed...
1124 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "http",
1125 userpass
, host
, port
, resource
);
1126 strlcpy(name
, uri
, sizeof(name
));
1131 * Link to local feed...
1134 snprintf(uri
, sizeof(uri
), "/rss%s", resource
);
1135 strlcpy(name
, resource
+ 1, sizeof(name
));
1144 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
1145 strlcpy(name
, resource
, sizeof(name
));
1148 cgiSetArray("notify_recipient_uri", element
, uri
);
1149 cgiSetArray("notify_recipient_name", element
, name
);
1154 * Add "admin_uri" variable if we have a "printer_uri_supported"
1158 if (!strcmp(name
, "printer_uri_supported"))
1160 cgiRewriteURL(attr
->values
[0].string
.text
, value
, sizeof(value
),
1163 cgiSetArray("admin_uri", element
, value
);
1170 value
[0] = '\0'; /* Initially an empty string */
1171 valptr
= value
; /* Start at the beginning */
1173 for (i
= 0; i
< attr
->num_values
; i
++)
1176 strlcat(valptr
, ", ", sizeof(value
) - (valptr
- value
));
1178 valptr
+= strlen(valptr
);
1180 switch (attr
->value_tag
)
1182 case IPP_TAG_INTEGER
:
1184 if (strncmp(name
, "time_at_", 8) == 0)
1186 time_t t
; /* Temporary time value */
1188 t
= (time_t)attr
->values
[i
].integer
;
1189 date
= localtime(&t
);
1191 strftime(valptr
, sizeof(value
) - (valptr
- value
), "%c", date
);
1194 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1195 "%d", attr
->values
[i
].integer
);
1198 case IPP_TAG_BOOLEAN
:
1199 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1200 "%d", attr
->values
[i
].boolean
);
1203 case IPP_TAG_NOVALUE
:
1204 strlcat(valptr
, "novalue", sizeof(value
) - (valptr
- value
));
1207 case IPP_TAG_RANGE
:
1208 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1209 "%d-%d", attr
->values
[i
].range
.lower
,
1210 attr
->values
[i
].range
.upper
);
1213 case IPP_TAG_RESOLUTION
:
1214 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1215 "%dx%d%s", attr
->values
[i
].resolution
.xres
,
1216 attr
->values
[i
].resolution
.yres
,
1217 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
1222 if (strchr(attr
->values
[i
].string
.text
, ':') &&
1223 strcmp(name
, "device_uri"))
1229 if (!strcmp(name
, "member_uris"))
1231 char url
[1024]; /* URL for class member... */
1234 cgiRewriteURL(attr
->values
[i
].string
.text
, url
,
1237 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1238 "<A HREF=\"%s\">%s</A>", url
,
1239 strrchr(attr
->values
[i
].string
.text
, '/') + 1);
1242 cgiRewriteURL(attr
->values
[i
].string
.text
, valptr
,
1243 sizeof(value
) - (valptr
- value
), NULL
);
1247 case IPP_TAG_STRING
:
1250 case IPP_TAG_KEYWORD
:
1251 case IPP_TAG_CHARSET
:
1252 case IPP_TAG_LANGUAGE
:
1253 case IPP_TAG_MIMETYPE
:
1254 strlcat(valptr
, attr
->values
[i
].string
.text
,
1255 sizeof(value
) - (valptr
- value
));
1258 case IPP_TAG_BEGIN_COLLECTION
:
1259 snprintf(value
, sizeof(value
), "%s%d", name
, i
+ 1);
1260 cgiSetIPPVars(attr
->values
[i
].collection
, NULL
, NULL
, value
,
1265 break; /* anti-compiler-warning-code */
1270 * Add the element...
1273 if (attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
)
1275 cgiSetArray(name
, element
, value
);
1277 fprintf(stderr
, "DEBUG2: %s[%d]=\"%s\"\n", name
, element
, value
);
1281 return (attr
? attr
->next
: NULL
);
1286 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
1289 int /* O - Maximum number of elements */
1290 cgiSetIPPVars(ipp_t
*response
, /* I - Response data to be copied... */
1291 const char *filter_name
, /* I - Filter name */
1292 const char *filter_value
, /* I - Filter value */
1293 const char *prefix
, /* I - Prefix for name or NULL */
1294 int parent_el
) /* I - Parent element number */
1296 int element
; /* Element in CGI array */
1297 ipp_attribute_t
*attr
, /* Attribute in response... */
1298 *filter
; /* Filtering attribute */
1301 fprintf(stderr
, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
1302 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
1303 response
, filter_name
? filter_name
: "(null)",
1304 filter_value
? filter_value
: "(null)",
1305 prefix
? prefix
: "(null)", parent_el
);
1308 * Set common CGI template variables...
1312 cgiSetServerVersion();
1315 * Loop through the attributes and set them for the template...
1318 attr
= response
->attrs
;
1321 while (attr
&& attr
->group_tag
== IPP_TAG_OPERATION
)
1324 for (element
= parent_el
; attr
; element
++)
1327 * Copy attributes to a separator...
1330 while (attr
&& attr
->group_tag
== IPP_TAG_ZERO
)
1339 filter
!= NULL
&& filter
->group_tag
!= IPP_TAG_ZERO
;
1340 filter
= filter
->next
)
1341 if (filter
->name
&& !strcmp(filter
->name
, filter_name
) &&
1342 (filter
->value_tag
== IPP_TAG_STRING
||
1343 (filter
->value_tag
>= IPP_TAG_TEXTLANG
&&
1344 filter
->value_tag
<= IPP_TAG_MIMETYPE
)) &&
1345 filter
->values
[0].string
.text
!= NULL
&&
1346 !strcasecmp(filter
->values
[0].string
.text
, filter_value
))
1350 return (element
+ 1);
1352 if (filter
->group_tag
== IPP_TAG_ZERO
)
1360 attr
= cgiSetIPPObjectVars(attr
, prefix
, element
);
1363 fprintf(stderr
, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element
);
1370 * 'cgiShowIPPError()' - Show the last IPP error message.
1372 * The caller must still call cgiStartHTML() and cgiEndHTML().
1376 cgiShowIPPError(const char *message
) /* I - Contextual message */
1378 cgiSetVariable("MESSAGE", cgiText(message
));
1379 cgiSetVariable("ERROR", cupsLastErrorString());
1380 cgiCopyTemplateLang("error.tmpl");
1385 * 'cgiShowJobs()' - Show print jobs.
1389 cgiShowJobs(http_t
*http
, /* I - Connection to server */
1390 const char *dest
) /* I - Destination name or NULL */
1392 int i
; /* Looping var */
1393 const char *which_jobs
; /* Which jobs to show */
1394 ipp_t
*request
, /* IPP request */
1395 *response
; /* IPP response */
1396 cups_array_t
*jobs
; /* Array of job objects */
1397 ipp_attribute_t
*job
; /* Job object */
1398 int ascending
, /* Order of jobs (0 = descending) */
1399 first
, /* First job to show */
1400 count
; /* Number of jobs */
1401 const char *var
; /* Form variable */
1402 void *search
; /* Search data */
1403 char url
[1024], /* Printer URI */
1404 val
[1024]; /* Form variable */
1408 * Build an IPP_GET_JOBS request, which requires the following
1411 * attributes-charset
1412 * attributes-natural-language
1416 request
= ippNewRequest(IPP_GET_JOBS
);
1420 httpAssembleURIf(HTTP_URI_CODING_ALL
, url
, sizeof(url
), "ipp", NULL
,
1421 "localhost", ippPort(), "/printers/%s", dest
);
1422 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1426 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
1427 "ipp://localhost/");
1429 if ((which_jobs
= cgiGetVariable("which_jobs")) != NULL
)
1430 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "which-jobs",
1433 cgiGetAttributes(request
, "jobs.tmpl");
1436 * Do the request and get back a response...
1439 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1442 * Get a list of matching job objects.
1445 if ((var
= cgiGetVariable("QUERY")) != NULL
&&
1446 !cgiGetVariable("CLEAR"))
1447 search
= cgiCompileSearch(var
);
1451 jobs
= cgiGetIPPObjects(response
, search
);
1452 count
= cupsArrayCount(jobs
);
1455 cgiFreeSearch(search
);
1458 * Figure out which jobs to display...
1461 if ((var
= cgiGetVariable("FIRST")) != NULL
)
1467 first
= count
- CUPS_PAGE_MAX
;
1469 first
= (first
/ CUPS_PAGE_MAX
) * CUPS_PAGE_MAX
;
1474 sprintf(val
, "%d", count
);
1475 cgiSetVariable("TOTAL", val
);
1477 if ((var
= cgiGetVariable("ORDER")) != NULL
)
1478 ascending
= !strcasecmp(var
, "asc");
1481 ascending
= !which_jobs
|| !strcasecmp(which_jobs
, "not-completed");
1482 cgiSetVariable("ORDER", ascending
? "asc" : "dec");
1487 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayIndex(jobs
, first
);
1488 i
< CUPS_PAGE_MAX
&& job
;
1489 i
++, job
= (ipp_attribute_t
*)cupsArrayNext(jobs
))
1490 cgiSetIPPObjectVars(job
, NULL
, i
);
1494 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayIndex(jobs
, count
- first
- 1);
1495 i
< CUPS_PAGE_MAX
&& job
;
1496 i
++, job
= (ipp_attribute_t
*)cupsArrayPrev(jobs
))
1497 cgiSetIPPObjectVars(job
, NULL
, i
);
1501 * Save navigation URLs...
1505 snprintf(val
, sizeof(val
), "/%s/%s", cgiGetVariable("SECTION"), dest
);
1507 strlcpy(val
, "/jobs/", sizeof(val
));
1509 cgiSetVariable("THISURL", val
);
1513 sprintf(val
, "%d", first
- CUPS_PAGE_MAX
);
1514 cgiSetVariable("PREV", val
);
1517 if ((first
+ CUPS_PAGE_MAX
) < count
)
1519 sprintf(val
, "%d", first
+ CUPS_PAGE_MAX
);
1520 cgiSetVariable("NEXT", val
);
1524 * Then show everything...
1528 cgiSetVariable("SEARCH_DEST", dest
);
1530 cgiCopyTemplateLang("search.tmpl");
1532 cgiCopyTemplateLang("jobs-header.tmpl");
1534 if (count
> CUPS_PAGE_MAX
)
1535 cgiCopyTemplateLang("pager.tmpl");
1537 cgiCopyTemplateLang("jobs.tmpl");
1539 if (count
> CUPS_PAGE_MAX
)
1540 cgiCopyTemplateLang("pager.tmpl");
1542 cupsArrayDelete(jobs
);
1543 ippDelete(response
);
1549 * 'cgiText()' - Return localized text.
1552 const char * /* O - Localized message */
1553 cgiText(const char *message
) /* I - Message */
1555 static cups_lang_t
*language
= NULL
;
1560 language
= cupsLangDefault();
1562 return (_cupsLangString(language
, message
));
1567 * End of "$Id: ipp-var.c 7940 2008-09-16 00:45:16Z mike $".