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-2008 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 if ((user
= getenv("REMOTE_USER")) == NULL
)
295 * See if the user has already selected a new destination...
298 if ((job_printer_uri
= cgiGetVariable("JOB_PRINTER_URI")) == NULL
)
301 * Make sure necessary form variables are set...
306 char temp
[255]; /* Temporary string */
309 sprintf(temp
, "%d", job_id
);
310 cgiSetVariable("JOB_ID", temp
);
314 cgiSetVariable("PRINTER_NAME", dest
);
317 * No new destination specified, show the user what the available
318 * printers/classes are...
324 * Get the current destination for job N...
327 char job_uri
[1024]; /* Job URI */
330 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
332 snprintf(job_uri
, sizeof(job_uri
), "ipp://localhost/jobs/%d", job_id
);
333 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
335 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
336 "requested-attributes", NULL
, "job-printer-uri");
338 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
340 if ((attr
= ippFindAttribute(response
, "job-printer-uri",
341 IPP_TAG_URI
)) != NULL
)
344 * Pull the name from the URI...
347 strlcpy(current_dest
, strrchr(attr
->values
[0].string
.text
, '/') + 1,
348 sizeof(current_dest
));
358 * Couldn't get the current destination...
361 cgiStartHTML(cgiText(_("Move Job")));
362 cgiShowIPPError(_("Unable to find destination for job!"));
369 * Get the list of available destinations...
372 request
= ippNewRequest(CUPS_GET_PRINTERS
);
374 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
375 "requested-attributes", NULL
, "printer-uri-supported");
377 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
378 "requesting-user-name", NULL
, user
);
380 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
382 for (i
= 0, attr
= ippFindAttribute(response
, "printer-uri-supported",
385 attr
= ippFindNextAttribute(response
, "printer-uri-supported",
389 * Pull the name from the URI...
392 name
= strrchr(attr
->values
[0].string
.text
, '/') + 1;
395 * If the name is not the same as the current destination, add it!
398 if (strcasecmp(name
, dest
))
400 cgiSetArray("JOB_PRINTER_URI", i
, attr
->values
[0].string
.text
);
401 cgiSetArray("JOB_PRINTER_NAME", i
, name
);
414 cgiStartHTML(cgiText(_("Move Job")));
416 cgiStartHTML(cgiText(_("Move All Jobs")));
418 cgiCopyTemplateLang("job-move.tmpl");
423 * Try moving the job or jobs...
426 char uri
[1024], /* Job/printer URI */
427 resource
[1024], /* Post resource */
428 refresh
[1024]; /* Refresh URL */
429 const char *job_printer_name
; /* New printer name */
432 request
= ippNewRequest(CUPS_MOVE_JOB
);
440 snprintf(resource
, sizeof(resource
), "/jobs/%d", job_id
);
442 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
443 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
449 * Move all active jobs on a destination...
452 snprintf(resource
, sizeof(resource
), "/%s/%s",
453 cgiGetVariable("SECTION"), dest
);
455 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
456 "localhost", ippPort(), "/%s/%s",
457 cgiGetVariable("SECTION"), dest
);
458 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
462 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-printer-uri",
463 NULL
, job_printer_uri
);
465 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
466 "requesting-user-name", NULL
, user
);
468 ippDelete(cupsDoRequest(http
, request
, resource
));
471 * Show the results...
474 job_printer_name
= strrchr(job_printer_uri
, '/') + 1;
476 if (cupsLastError() <= IPP_OK_CONFLICT
)
478 const char *path
= strstr(job_printer_uri
, "/printers/");
480 path
= strstr(job_printer_uri
, "/classes/");
484 cgiFormEncode(uri
, path
, sizeof(uri
));
485 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
486 cgiSetVariable("refresh_page", refresh
);
491 cgiStartHTML(cgiText(_("Move Job")));
493 cgiStartHTML(cgiText(_("Move All Jobs")));
495 if (cupsLastError() > IPP_OK_CONFLICT
)
498 cgiShowIPPError(_("Unable to move job"));
500 cgiShowIPPError(_("Unable to move jobs"));
504 cgiSetVariable("JOB_PRINTER_NAME", job_printer_name
);
505 cgiCopyTemplateLang("job-moved.tmpl");
514 * 'cgiPrintCommand()' - Print a CUPS command job.
518 cgiPrintCommand(http_t
*http
, /* I - Connection to server */
519 const char *dest
, /* I - Destination printer */
520 const char *command
, /* I - Command to send */
521 const char *title
) /* I - Page/job title */
523 int job_id
; /* Command file job */
524 char uri
[HTTP_MAX_URI
], /* Job URI */
525 resource
[1024], /* Printer resource path */
526 refresh
[1024], /* Refresh URL */
527 command_file
[1024]; /* Command "file" */
528 http_status_t status
; /* Document status */
529 cups_option_t hold_option
; /* job-hold-until option */
530 const char *user
; /* User name */
531 ipp_t
*request
, /* Get-Job-Attributes request */
532 *response
; /* Get-Job-Attributes response */
533 ipp_attribute_t
*attr
; /* Current job attribute */
534 static const char const *job_attrs
[] =/* Job attributes we want */
537 "job-printer-state-message"
542 * Create the CUPS command file...
545 snprintf(command_file
, sizeof(command_file
), "#CUPS-COMMAND\n%s\n", command
);
553 cgiCopyTemplateLang("command.tmpl");
558 * Send the command file job...
561 hold_option
.name
= "job-hold-until";
562 hold_option
.value
= "no-hold";
564 if ((user
= getenv("REMOTE_USER")) != NULL
)
567 cupsSetUser("anonymous");
569 if ((job_id
= cupsCreateJob(http
, dest
, title
,
570 1, &hold_option
)) < 1)
572 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver!")));
573 cgiSetVariable("ERROR", cupsLastErrorString());
575 cgiCopyTemplateLang("error.tmpl");
581 status
= cupsStartDocument(http
, dest
, job_id
, NULL
, CUPS_FORMAT_COMMAND
, 1);
582 if (status
== HTTP_CONTINUE
)
583 status
= cupsWriteRequestData(http
, command_file
,
584 strlen(command_file
));
585 if (status
== HTTP_CONTINUE
)
586 cupsFinishDocument(http
, dest
);
588 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE
)
590 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver!")));
591 cgiSetVariable("ERROR", cupsLastErrorString());
593 cgiCopyTemplateLang("error.tmpl");
597 cupsCancelJob(dest
, job_id
);
602 * Wait for the job to complete...
608 * Get the current job state...
611 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
612 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
613 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
616 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
617 "requesting-user-name", NULL
, user
);
618 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
619 "requested-attributes", 2, NULL
, job_attrs
);
621 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
622 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
624 attr
= ippFindAttribute(response
, "job-state", IPP_TAG_ENUM
);
625 if (!attr
|| attr
->values
[0].integer
>= IPP_JOB_STOPPED
)
632 * Job not complete, so update the status...
638 cgiCopyTemplateLang("command.tmpl");
646 * Send the final page that reloads the printer's page...
649 snprintf(resource
, sizeof(resource
), "/printers/%s", dest
);
651 cgiFormEncode(uri
, resource
, sizeof(uri
));
652 snprintf(refresh
, sizeof(refresh
), "5;URL=%s", uri
);
653 cgiSetVariable("refresh_page", refresh
);
656 cgiCopyTemplateLang("command.tmpl");
663 * 'cgiPrintTestPage()' - Print a test page.
667 cgiPrintTestPage(http_t
*http
, /* I - Connection to server */
668 const char *dest
) /* I - Destination printer/class */
670 ipp_t
*request
, /* IPP request */
671 *response
; /* IPP response */
672 char uri
[HTTP_MAX_URI
], /* Printer URI */
673 resource
[1024], /* POST resource path */
674 refresh
[1024], /* Refresh URL */
675 filename
[1024]; /* Test page filename */
676 const char *datadir
; /* CUPS_DATADIR env var */
677 const char *user
; /* Username */
681 * See who is logged in...
684 user
= getenv("REMOTE_USER");
687 * Locate the test page file...
690 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
691 datadir
= CUPS_DATADIR
;
693 snprintf(filename
, sizeof(filename
), "%s/data/testprint", datadir
);
696 * Point to the printer/class...
699 snprintf(resource
, sizeof(resource
), "/%s/%s", cgiGetVariable("SECTION"),
702 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
703 "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
707 * Build an IPP_PRINT_JOB request, which requires the following
711 * attributes-natural-language
713 * requesting-user-name
716 request
= ippNewRequest(IPP_PRINT_JOB
);
718 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
722 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
723 "requesting-user-name", NULL
, user
);
725 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name",
729 * Do the request and get back a response...
732 if ((response
= cupsDoFileRequest(http
, request
, resource
,
735 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
740 if (cupsLastError() <= IPP_OK_CONFLICT
)
743 * Automatically reload the printer status page...
746 cgiFormEncode(uri
, resource
, sizeof(uri
));
747 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
748 cgiSetVariable("refresh_page", refresh
);
750 else if (cupsLastError() == IPP_NOT_AUTHORIZED
)
752 puts("Status: 401\n");
756 cgiStartHTML(cgiText(_("Print Test Page")));
758 if (cupsLastError() > IPP_OK_CONFLICT
)
759 cgiShowIPPError(_("Unable to print test page:"));
762 cgiSetVariable("PRINTER_NAME", dest
);
764 cgiCopyTemplateLang("test-page.tmpl");
772 * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
775 char * /* O - New URL */
776 cgiRewriteURL(const char *uri
, /* I - Current URI */
777 char *url
, /* O - New URL */
778 int urlsize
, /* I - Size of URL buffer */
779 const char *newresource
) /* I - Replacement resource */
781 char method
[HTTP_MAX_URI
],
782 userpass
[HTTP_MAX_URI
],
783 hostname
[HTTP_MAX_URI
],
784 rawresource
[HTTP_MAX_URI
],
785 resource
[HTTP_MAX_URI
],
786 /* URI components... */
787 *rawptr
, /* Pointer into rawresource */
788 *resptr
; /* Pointer into resource */
789 int port
; /* Port number */
790 static int ishttps
= -1; /* Using encryption? */
791 static const char *server
; /* Name of server */
792 static char servername
[1024];
793 /* Local server name */
794 static const char hexchars
[] = "0123456789ABCDEF";
795 /* Hexadecimal conversion characters */
799 * Check if we have been called before...
805 * No, initialize static vars for the conversion...
807 * First get the server name associated with the client interface as
808 * well as the locally configured hostname. We'll check *both* of
809 * these to see if the printer URL is local...
812 if ((server
= getenv("SERVER_NAME")) == NULL
)
815 httpGetHostname(NULL
, servername
, sizeof(servername
));
818 * Then flag whether we are using SSL on this connection...
821 ishttps
= getenv("HTTPS") != NULL
;
825 * Convert the URI to a URL...
828 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, method
, sizeof(method
), userpass
,
829 sizeof(userpass
), hostname
, sizeof(hostname
), &port
,
830 rawresource
, sizeof(rawresource
));
832 if (!strcmp(method
, "ipp") ||
833 !strcmp(method
, "http") ||
834 !strcmp(method
, "https"))
839 * Force the specified resource name instead of the one in the URL...
842 strlcpy(resource
, newresource
, sizeof(resource
));
847 * Rewrite the resource string so it doesn't contain any
851 for (rawptr
= rawresource
, resptr
= resource
; *rawptr
; rawptr
++)
852 if ((*rawptr
& 128) || *rawptr
== '%' || *rawptr
== ' ' ||
853 *rawptr
== '#' || *rawptr
== '?' ||
854 *rawptr
== '.') /* For MSIE */
856 if (resptr
< (resource
+ sizeof(resource
) - 3))
859 *resptr
++ = hexchars
[(*rawptr
>> 4) & 15];
860 *resptr
++ = hexchars
[*rawptr
& 15];
863 else if (resptr
< (resource
+ sizeof(resource
) - 1))
870 * Map local access to a local URI...
873 if (!strcasecmp(hostname
, "localhost") ||
874 !strncasecmp(hostname
, "localhost.", 10) ||
875 !strcasecmp(hostname
, server
) ||
876 !strcasecmp(hostname
, servername
))
879 * Make URI relative to the current server...
882 strlcpy(url
, resource
, urlsize
);
887 * Rewrite URI with HTTP/HTTPS scheme...
891 snprintf(url
, urlsize
, "%s://%s@%s:%d%s",
892 ishttps
? "https" : "http",
893 userpass
, hostname
, port
, resource
);
895 snprintf(url
, urlsize
, "%s://%s:%d%s",
896 ishttps
? "https" : "http",
897 hostname
, port
, resource
);
901 strlcpy(url
, uri
, urlsize
);
908 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
911 ipp_attribute_t
* /* O - Next object */
913 ipp_attribute_t
*obj
, /* I - Response data to be copied... */
914 const char *prefix
, /* I - Prefix for name or NULL */
915 int element
) /* I - Parent element number */
917 ipp_attribute_t
*attr
; /* Attribute in response... */
918 int i
; /* Looping var */
919 char name
[1024], /* Name of attribute */
920 *nameptr
, /* Pointer into name */
921 value
[16384], /* Value(s) */
922 *valptr
; /* Pointer into value */
923 struct tm
*date
; /* Date information */
926 fprintf(stderr
, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
928 obj
, prefix
? prefix
: "(null)", element
);
931 * Set common CGI template variables...
935 cgiSetServerVersion();
938 * Loop through the attributes and set them for the template...
941 for (attr
= obj
; attr
&& attr
->group_tag
!= IPP_TAG_ZERO
; attr
= attr
->next
)
944 * Copy the attribute name, substituting "_" for "-"...
952 snprintf(name
, sizeof(name
), "%s.", prefix
);
953 nameptr
= name
+ strlen(name
);
958 for (i
= 0; attr
->name
[i
] && nameptr
< (name
+ sizeof(name
) - 1); i
++)
959 if (attr
->name
[i
] == '-')
962 *nameptr
++ = attr
->name
[i
];
967 * Add "job_printer_name" variable if we have a "job_printer_uri"
971 if (!strcmp(name
, "job_printer_uri"))
973 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
978 cgiSetArray("job_printer_name", element
, valptr
);
982 * Localize event names in "notify_events" variable...
985 if (!strcmp(name
, "notify_events"))
987 size_t remaining
; /* Remaining bytes in buffer */
993 for (i
= 0; i
< attr
->num_values
; i
++)
995 if (valptr
>= (value
+ sizeof(value
) - 3))
1004 remaining
= sizeof(value
) - (valptr
- value
);
1006 if (!strcmp(attr
->values
[i
].string
.text
, "printer-stopped"))
1007 strlcpy(valptr
, _("Printer Paused"), remaining
);
1008 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-added"))
1009 strlcpy(valptr
, _("Printer Added"), remaining
);
1010 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-modified"))
1011 strlcpy(valptr
, _("Printer Modified"), remaining
);
1012 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-deleted"))
1013 strlcpy(valptr
, _("Printer Deleted"), remaining
);
1014 else if (!strcmp(attr
->values
[i
].string
.text
, "job-created"))
1015 strlcpy(valptr
, _("Job Created"), remaining
);
1016 else if (!strcmp(attr
->values
[i
].string
.text
, "job-completed"))
1017 strlcpy(valptr
, _("Job Completed"), remaining
);
1018 else if (!strcmp(attr
->values
[i
].string
.text
, "job-stopped"))
1019 strlcpy(valptr
, _("Job Stopped"), remaining
);
1020 else if (!strcmp(attr
->values
[i
].string
.text
, "job-config-changed"))
1021 strlcpy(valptr
, _("Job Options Changed"), remaining
);
1022 else if (!strcmp(attr
->values
[i
].string
.text
, "server-restarted"))
1023 strlcpy(valptr
, _("Server Restarted"), remaining
);
1024 else if (!strcmp(attr
->values
[i
].string
.text
, "server-started"))
1025 strlcpy(valptr
, _("Server Started"), remaining
);
1026 else if (!strcmp(attr
->values
[i
].string
.text
, "server-stopped"))
1027 strlcpy(valptr
, _("Server Stopped"), remaining
);
1028 else if (!strcmp(attr
->values
[i
].string
.text
, "server-audit"))
1029 strlcpy(valptr
, _("Server Security Auditing"), remaining
);
1031 strlcpy(valptr
, attr
->values
[i
].string
.text
, remaining
);
1033 valptr
+= strlen(valptr
);
1036 cgiSetArray("notify_events", element
, value
);
1041 * Add "notify_printer_name" variable if we have a "notify_printer_uri"
1045 if (!strcmp(name
, "notify_printer_uri"))
1047 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
1052 cgiSetArray("notify_printer_name", element
, valptr
);
1056 * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
1057 * attribute, and rewrite recipient URI...
1060 if (!strcmp(name
, "notify_recipient_uri"))
1062 char uri
[1024], /* New URI */
1063 scheme
[32], /* Scheme portion of URI */
1064 userpass
[256], /* Username/password portion of URI */
1065 host
[1024], /* Hostname portion of URI */
1066 resource
[1024], /* Resource portion of URI */
1067 *options
; /* Options in URI */
1068 int port
; /* Port number */
1071 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
1072 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
1073 host
, sizeof(host
), &port
, resource
, sizeof(resource
));
1075 if (!strcmp(scheme
, "rss"))
1078 * RSS notification...
1081 if ((options
= strchr(resource
, '?')) != NULL
)
1087 * Link to remote feed...
1090 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "http",
1091 userpass
, host
, port
, resource
);
1092 strlcpy(name
, uri
, sizeof(name
));
1097 * Link to local feed...
1100 snprintf(uri
, sizeof(uri
), "/rss%s", resource
);
1101 strlcpy(name
, resource
+ 1, sizeof(name
));
1110 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
1111 strlcpy(name
, resource
, sizeof(name
));
1114 cgiSetArray("notify_recipient_uri", element
, uri
);
1115 cgiSetArray("notify_recipient_name", element
, name
);
1120 * Add "admin_uri" variable if we have a "printer_uri_supported"
1124 if (!strcmp(name
, "printer_uri_supported"))
1126 cgiRewriteURL(attr
->values
[0].string
.text
, value
, sizeof(value
),
1129 cgiSetArray("admin_uri", element
, value
);
1136 value
[0] = '\0'; /* Initially an empty string */
1137 valptr
= value
; /* Start at the beginning */
1139 for (i
= 0; i
< attr
->num_values
; i
++)
1142 strlcat(valptr
, ", ", sizeof(value
) - (valptr
- value
));
1144 valptr
+= strlen(valptr
);
1146 switch (attr
->value_tag
)
1148 case IPP_TAG_INTEGER
:
1150 if (strncmp(name
, "time_at_", 8) == 0)
1152 time_t t
; /* Temporary time value */
1154 t
= (time_t)attr
->values
[i
].integer
;
1155 date
= localtime(&t
);
1157 strftime(valptr
, sizeof(value
) - (valptr
- value
), "%c", date
);
1160 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1161 "%d", attr
->values
[i
].integer
);
1164 case IPP_TAG_BOOLEAN
:
1165 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1166 "%d", attr
->values
[i
].boolean
);
1169 case IPP_TAG_NOVALUE
:
1170 strlcat(valptr
, "novalue", sizeof(value
) - (valptr
- value
));
1173 case IPP_TAG_RANGE
:
1174 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1175 "%d-%d", attr
->values
[i
].range
.lower
,
1176 attr
->values
[i
].range
.upper
);
1179 case IPP_TAG_RESOLUTION
:
1180 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1181 "%dx%d%s", attr
->values
[i
].resolution
.xres
,
1182 attr
->values
[i
].resolution
.yres
,
1183 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
1188 if (strchr(attr
->values
[i
].string
.text
, ':') &&
1189 strcmp(name
, "device_uri"))
1195 if (!strcmp(name
, "member_uris"))
1197 char url
[1024]; /* URL for class member... */
1200 cgiRewriteURL(attr
->values
[i
].string
.text
, url
,
1203 snprintf(valptr
, sizeof(value
) - (valptr
- value
),
1204 "<A HREF=\"%s\">%s</A>", url
,
1205 strrchr(attr
->values
[i
].string
.text
, '/') + 1);
1208 cgiRewriteURL(attr
->values
[i
].string
.text
, valptr
,
1209 sizeof(value
) - (valptr
- value
), NULL
);
1213 case IPP_TAG_STRING
:
1216 case IPP_TAG_KEYWORD
:
1217 case IPP_TAG_CHARSET
:
1218 case IPP_TAG_LANGUAGE
:
1219 case IPP_TAG_MIMETYPE
:
1220 strlcat(valptr
, attr
->values
[i
].string
.text
,
1221 sizeof(value
) - (valptr
- value
));
1224 case IPP_TAG_BEGIN_COLLECTION
:
1225 snprintf(value
, sizeof(value
), "%s%d", name
, i
+ 1);
1226 cgiSetIPPVars(attr
->values
[i
].collection
, NULL
, NULL
, value
,
1231 break; /* anti-compiler-warning-code */
1236 * Add the element...
1239 if (attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
)
1241 cgiSetArray(name
, element
, value
);
1243 fprintf(stderr
, "DEBUG2: %s[%d]=\"%s\"\n", name
, element
, value
);
1247 return (attr
? attr
->next
: NULL
);
1252 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
1255 int /* O - Maximum number of elements */
1256 cgiSetIPPVars(ipp_t
*response
, /* I - Response data to be copied... */
1257 const char *filter_name
, /* I - Filter name */
1258 const char *filter_value
, /* I - Filter value */
1259 const char *prefix
, /* I - Prefix for name or NULL */
1260 int parent_el
) /* I - Parent element number */
1262 int element
; /* Element in CGI array */
1263 ipp_attribute_t
*attr
, /* Attribute in response... */
1264 *filter
; /* Filtering attribute */
1267 fprintf(stderr
, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
1268 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
1269 response
, filter_name
? filter_name
: "(null)",
1270 filter_value
? filter_value
: "(null)",
1271 prefix
? prefix
: "(null)", parent_el
);
1274 * Set common CGI template variables...
1278 cgiSetServerVersion();
1281 * Loop through the attributes and set them for the template...
1284 attr
= response
->attrs
;
1287 while (attr
&& attr
->group_tag
== IPP_TAG_OPERATION
)
1290 for (element
= parent_el
; attr
; element
++)
1293 * Copy attributes to a separator...
1296 while (attr
&& attr
->group_tag
== IPP_TAG_ZERO
)
1305 filter
!= NULL
&& filter
->group_tag
!= IPP_TAG_ZERO
;
1306 filter
= filter
->next
)
1307 if (filter
->name
&& !strcmp(filter
->name
, filter_name
) &&
1308 (filter
->value_tag
== IPP_TAG_STRING
||
1309 (filter
->value_tag
>= IPP_TAG_TEXTLANG
&&
1310 filter
->value_tag
<= IPP_TAG_MIMETYPE
)) &&
1311 filter
->values
[0].string
.text
!= NULL
&&
1312 !strcasecmp(filter
->values
[0].string
.text
, filter_value
))
1316 return (element
+ 1);
1318 if (filter
->group_tag
== IPP_TAG_ZERO
)
1326 attr
= cgiSetIPPObjectVars(attr
, prefix
, element
);
1329 fprintf(stderr
, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element
);
1336 * 'cgiShowIPPError()' - Show the last IPP error message.
1338 * The caller must still call cgiStartHTML() and cgiEndHTML().
1342 cgiShowIPPError(const char *message
) /* I - Contextual message */
1344 cgiSetVariable("MESSAGE", cgiText(message
));
1345 cgiSetVariable("ERROR", cupsLastErrorString());
1346 cgiCopyTemplateLang("error.tmpl");
1351 * 'cgiShowJobs()' - Show print jobs.
1355 cgiShowJobs(http_t
*http
, /* I - Connection to server */
1356 const char *dest
) /* I - Destination name or NULL */
1358 int i
; /* Looping var */
1359 const char *which_jobs
; /* Which jobs to show */
1360 ipp_t
*request
, /* IPP request */
1361 *response
; /* IPP response */
1362 cups_array_t
*jobs
; /* Array of job objects */
1363 ipp_attribute_t
*job
; /* Job object */
1364 int ascending
, /* Order of jobs (0 = descending) */
1365 first
, /* First job to show */
1366 count
; /* Number of jobs */
1367 const char *var
; /* Form variable */
1368 void *search
; /* Search data */
1369 char url
[1024], /* Printer URI */
1370 val
[1024]; /* Form variable */
1374 * Build an IPP_GET_JOBS request, which requires the following
1377 * attributes-charset
1378 * attributes-natural-language
1382 request
= ippNewRequest(IPP_GET_JOBS
);
1386 httpAssembleURIf(HTTP_URI_CODING_ALL
, url
, sizeof(url
), "ipp", NULL
,
1387 "localhost", ippPort(), "/printers/%s", dest
);
1388 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1392 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
,
1393 "ipp://localhost/jobs");
1395 if ((which_jobs
= cgiGetVariable("which_jobs")) != NULL
)
1396 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "which-jobs",
1399 cgiGetAttributes(request
, "jobs.tmpl");
1402 * Do the request and get back a response...
1405 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1408 * Get a list of matching job objects.
1411 if ((var
= cgiGetVariable("QUERY")) != NULL
&&
1412 !cgiGetVariable("CLEAR"))
1413 search
= cgiCompileSearch(var
);
1417 jobs
= cgiGetIPPObjects(response
, search
);
1418 count
= cupsArrayCount(jobs
);
1421 cgiFreeSearch(search
);
1424 * Figure out which jobs to display...
1427 if ((var
= cgiGetVariable("FIRST")) != NULL
)
1433 first
= count
- CUPS_PAGE_MAX
;
1435 first
= (first
/ CUPS_PAGE_MAX
) * CUPS_PAGE_MAX
;
1440 sprintf(val
, "%d", count
);
1441 cgiSetVariable("TOTAL", val
);
1443 if ((var
= cgiGetVariable("ORDER")) != NULL
)
1444 ascending
= !strcasecmp(var
, "asc");
1447 ascending
= !which_jobs
|| !strcasecmp(which_jobs
, "not-completed");
1448 cgiSetVariable("ORDER", ascending
? "asc" : "dec");
1453 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayIndex(jobs
, first
);
1454 i
< CUPS_PAGE_MAX
&& job
;
1455 i
++, job
= (ipp_attribute_t
*)cupsArrayNext(jobs
))
1456 cgiSetIPPObjectVars(job
, NULL
, i
);
1460 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayIndex(jobs
, count
- first
- 1);
1461 i
< CUPS_PAGE_MAX
&& job
;
1462 i
++, job
= (ipp_attribute_t
*)cupsArrayPrev(jobs
))
1463 cgiSetIPPObjectVars(job
, NULL
, i
);
1467 * Save navigation URLs...
1471 snprintf(val
, sizeof(val
), "/%s/%s", cgiGetVariable("SECTION"), dest
);
1473 strlcpy(val
, "/jobs/", sizeof(val
));
1475 cgiSetVariable("THISURL", val
);
1479 sprintf(val
, "%d", first
- CUPS_PAGE_MAX
);
1480 cgiSetVariable("PREV", val
);
1483 if ((first
+ CUPS_PAGE_MAX
) < count
)
1485 sprintf(val
, "%d", first
+ CUPS_PAGE_MAX
);
1486 cgiSetVariable("NEXT", val
);
1490 * Then show everything...
1494 cgiSetVariable("SEARCH_DEST", dest
);
1496 cgiCopyTemplateLang("search.tmpl");
1498 cgiCopyTemplateLang("jobs-header.tmpl");
1500 if (count
> CUPS_PAGE_MAX
)
1501 cgiCopyTemplateLang("pager.tmpl");
1503 cgiCopyTemplateLang("jobs.tmpl");
1505 if (count
> CUPS_PAGE_MAX
)
1506 cgiCopyTemplateLang("pager.tmpl");
1508 cupsArrayDelete(jobs
);
1509 ippDelete(response
);
1515 * 'cgiText()' - Return localized text.
1518 const char * /* O - Localized message */
1519 cgiText(const char *message
) /* I - Message */
1521 static cups_lang_t
*language
= NULL
;
1526 language
= cupsLangDefault();
1528 return (_cupsLangString(language
, message
));
1533 * End of "$Id: ipp-var.c 7940 2008-09-16 00:45:16Z mike $".