]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/ipp-var.c
Update copyright notices, addresses, etc.
[thirdparty/cups.git] / cgi-bin / ipp-var.c
1 /*
2 * "$Id$"
3 *
4 * IPP variable routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * ippGetAttributes() - Get the list of attributes that are needed
27 * by the template file.
28 * ippGetTemplateDir() - Get the templates directory...
29 * ippRewriteURL() - Rewrite a printer URI into a web browser URL...
30 * ippSetServerVersion() - Set the server name and CUPS version...
31 * ippSetCGIVars() - Set CGI variables from an IPP response.
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "ipp-var.h"
39
40
41 /*
42 * 'ippGetAttributes()' - Get the list of attributes that are needed
43 * by the template file.
44 */
45
46 void
47 ippGetAttributes(ipp_t *request, /* I - IPP request */
48 const char *directory, /* I - Directory */
49 const char *tmpl, /* I - Base filename */
50 const char *lang) /* I - Language */
51 {
52 int num_attrs; /* Number of attributes */
53 char *attrs[1000]; /* Attributes */
54 int i; /* Looping var */
55 char filename[1024], /* Filename */
56 locale[16]; /* Locale name */
57 FILE *in; /* Input file */
58 int ch; /* Character from file */
59 char name[255], /* Name of variable */
60 *nameptr; /* Pointer into name */
61
62
63 /*
64 * Convert the language to a locale name...
65 */
66
67 if (lang != NULL)
68 {
69 for (i = 0; lang[i] && i < 15; i ++)
70 if (isalnum(lang[i] & 255))
71 locale[i] = tolower(lang[i]);
72 else
73 locale[i] = '_';
74
75 locale[i] = '\0';
76 }
77 else
78 locale[0] = '\0';
79
80 /*
81 * See if we have a template file for this language...
82 */
83
84 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
85 if (access(filename, 0))
86 {
87 locale[2] = '\0';
88
89 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
90 if (access(filename, 0))
91 snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
92 }
93
94 /*
95 * Open the template file...
96 */
97
98 if ((in = fopen(filename, "r")) == NULL)
99 return;
100
101 /*
102 * Loop through the file adding attribute names as needed...
103 */
104
105 num_attrs = 0;
106
107 while ((ch = getc(in)) != EOF)
108 if (ch == '\\')
109 getc(in);
110 else if (ch == '{' && num_attrs < (sizeof(attrs) / sizeof(attrs[0])))
111 {
112 /*
113 * Grab the name...
114 */
115
116 for (nameptr = name; (ch = getc(in)) != EOF;)
117 if (strchr("}]<>=! \t\n", ch))
118 break;
119 else if (nameptr > name && ch == '?')
120 break;
121 else if (nameptr < (name + sizeof(name) - 1))
122 {
123 if (ch == '_')
124 *nameptr++ = '-';
125 else
126 *nameptr++ = ch;
127 }
128
129 *nameptr = '\0';
130
131 if (!strncmp(name, "printer_state_history", 21))
132 strcpy(name, "printer_state_history");
133
134 /*
135 * Possibly add it to the list of attributes...
136 */
137
138 for (i = 0; i < num_attrs; i ++)
139 if (!strcmp(attrs[i], name))
140 break;
141
142 if (i >= num_attrs)
143 {
144 attrs[num_attrs] = strdup(name);
145 num_attrs ++;
146 }
147 }
148
149 /*
150 * If we have attributes, add a requested-attributes attribute to the
151 * request...
152 */
153
154 if (num_attrs > 0)
155 {
156 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
157 "requested-attributes", num_attrs, NULL, (const char **)attrs);
158
159 for (i = 0; i < num_attrs; i ++)
160 free(attrs[i]);
161 }
162 }
163
164
165 /*
166 * 'ippGetTemplateDir()' - Get the templates directory...
167 */
168
169 char * /* O - Template directory */
170 ippGetTemplateDir(void)
171 {
172 const char *datadir; /* CUPS_DATADIR env var */
173 static char templates[1024] = ""; /* Template directory */
174
175
176 if (!templates[0])
177 {
178 /*
179 * Build the template directory pathname...
180 */
181
182 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
183 datadir = CUPS_DATADIR;
184
185 snprintf(templates, sizeof(templates), "%s/templates", datadir);
186 }
187
188 return (templates);
189 }
190
191
192 /*
193 * 'ippRewriteURL()' - Rewrite a printer URI into a web browser URL...
194 */
195
196 char * /* O - New URL */
197 ippRewriteURL(const char *uri, /* I - Current URI */
198 char *url, /* O - New URL */
199 int urlsize, /* I - Size of URL buffer */
200 const char *newresource) /* I - Replacement resource */
201 {
202 char method[HTTP_MAX_URI],
203 userpass[HTTP_MAX_URI],
204 hostname[HTTP_MAX_URI],
205 rawresource[HTTP_MAX_URI],
206 resource[HTTP_MAX_URI],
207 /* URI components... */
208 *rawptr, /* Pointer into rawresource */
209 *resptr; /* Pointer into resource */
210 int port; /* Port number */
211 static int ishttps = -1; /* Using encryption? */
212 static const char *server; /* Name of server */
213 static char servername[1024];
214 /* Local server name */
215 static const char hexchars[] = "0123456789ABCDEF";
216 /* Hexadecimal conversion characters */
217
218
219 /*
220 * Check if we have been called before...
221 */
222
223 if (ishttps < 0)
224 {
225 /*
226 * No, initialize static vars for the conversion...
227 *
228 * First get the server name associated with the client interface as
229 * well as the locally configured hostname. We'll check *both* of
230 * these to see if the printer URL is local...
231 */
232
233 server = getenv("SERVER_NAME");
234 gethostname(servername, sizeof(servername));
235
236 /*
237 * Then flag whether we are using SSL on this connection...
238 */
239
240 ishttps = getenv("HTTPS") != NULL;
241 }
242
243 /*
244 * Convert the URI to a URL...
245 */
246
247 httpSeparate(uri, method, userpass, hostname, &port, rawresource);
248
249 if (strcmp(method, "ipp") == 0 ||
250 strcmp(method, "http") == 0)
251 {
252 if (newresource)
253 {
254 /*
255 * Force the specified resource name instead of the one in the URL...
256 */
257
258 strlcpy(resource, newresource, sizeof(resource));
259 }
260 else
261 {
262 /*
263 * Rewrite the resource string so it doesn't contain any
264 * illegal chars...
265 */
266
267 for (rawptr = rawresource, resptr = resource; *rawptr; rawptr ++)
268 if ((*rawptr & 128) || *rawptr == '%' || *rawptr == ' ' ||
269 *rawptr == '#' || *rawptr == '?' ||
270 *rawptr == '.') /* For MSIE */
271 {
272 if (resptr < (resource + sizeof(resource) - 3))
273 {
274 *resptr++ = '%';
275 *resptr++ = hexchars[(*rawptr >> 4) & 15];
276 *resptr++ = hexchars[*rawptr & 15];
277 }
278 }
279 else if (resptr < (resource + sizeof(resource) - 1))
280 *resptr++ = *rawptr;
281
282 *resptr = '\0';
283 }
284
285 /*
286 * Map local access to a local URI...
287 */
288
289 if (strcasecmp(hostname, server) == 0 ||
290 strcasecmp(hostname, servername) == 0)
291 {
292 /*
293 * Make URI relative to the current server...
294 */
295
296 strlcpy(url, resource, urlsize);
297 }
298 else
299 {
300 /*
301 * Rewrite URI with HTTP/HTTPS scheme...
302 */
303
304 if (userpass[0])
305 snprintf(url, urlsize, "%s://%s@%s:%d%s",
306 ishttps ? "https" : "http",
307 userpass, hostname, port, resource);
308 else
309 snprintf(url, urlsize, "%s://%s:%d%s",
310 ishttps ? "https" : "http",
311 hostname, port, resource);
312 }
313 }
314 else
315 strlcpy(url, uri, urlsize);
316
317 return (url);
318 }
319
320
321 /*
322 * 'ippSetServerVersion()' - Set the server name and CUPS version...
323 */
324
325 void
326 ippSetServerVersion(void)
327 {
328 cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME"));
329 cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER"));
330 cgiSetVariable("CUPS_VERSION", CUPS_SVERSION);
331
332 #ifdef LC_TIME
333 setlocale(LC_TIME, "");
334 #endif /* LC_TIME */
335 }
336
337
338 /*
339 * 'ippSetCGIVars()' - Set CGI variables from an IPP response.
340 */
341
342 void
343 ippSetCGIVars(ipp_t *response, /* I - Response data to be copied... */
344 const char *filter_name, /* I - Filter name */
345 const char *filter_value, /* I - Filter value */
346 const char *prefix, /* I - Prefix for name or NULL */
347 int parent_el) /* I - Parent element number */
348 {
349 int element; /* Element in CGI array */
350 ipp_attribute_t *attr, /* Attribute in response... */
351 *filter; /* Filtering attribute */
352 int i; /* Looping var */
353 char name[1024], /* Name of attribute */
354 *nameptr, /* Pointer into name */
355 value[16384], /* Value(s) */
356 *valptr; /* Pointer into value */
357 struct tm *date; /* Date information */
358
359
360 DEBUG_printf(("<P>ippSetCGIVars(response=%p, filter_name=\"%s\", filter_value=\"%s\", prefix=\"%s\")\n",
361 response, filter_name, filter_value, prefix));
362
363 /*
364 * Set common CGI template variables...
365 */
366
367 if (!prefix)
368 ippSetServerVersion();
369
370 /*
371 * Loop through the attributes and set them for the template...
372 */
373
374 attr = response->attrs;
375
376 if (!prefix)
377 while (attr && attr->group_tag == IPP_TAG_OPERATION)
378 attr = attr->next;
379
380 for (element = parent_el; attr != NULL; attr = attr->next, element ++)
381 {
382 /*
383 * Copy attributes to a separator...
384 */
385
386 if (filter_name)
387 {
388 for (filter = attr;
389 filter != NULL && filter->group_tag != IPP_TAG_ZERO;
390 filter = filter->next)
391 if (filter->name && strcmp(filter->name, filter_name) == 0 &&
392 (filter->value_tag == IPP_TAG_STRING ||
393 (filter->value_tag >= IPP_TAG_TEXTLANG &&
394 filter->value_tag <= IPP_TAG_MIMETYPE)) &&
395 filter->values[0].string.text != NULL &&
396 strcasecmp(filter->values[0].string.text, filter_value) == 0)
397 break;
398
399 if (!filter)
400 return;
401
402 if (filter->group_tag == IPP_TAG_ZERO)
403 {
404 attr = filter;
405 element --;
406 continue;
407 }
408 }
409
410 for (; attr != NULL && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
411 {
412 /*
413 * Copy the attribute name, substituting "_" for "-"...
414 */
415
416 if (attr->name == NULL)
417 continue;
418
419 if (prefix)
420 {
421 snprintf(name, sizeof(name), "%s.", prefix);
422 nameptr = name + strlen(name);
423 }
424 else
425 nameptr = name;
426
427 for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++)
428 if (attr->name[i] == '-')
429 *nameptr++ = '_';
430 else
431 *nameptr++ = attr->name[i];
432
433 *nameptr = '\0';
434
435 /*
436 * Add "job_printer_name" variable if we have a "job_printer_uri"
437 * attribute...
438 */
439
440 if (!strcmp(name, "job_printer_uri"))
441 {
442 if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
443 valptr = "unknown";
444 else
445 valptr ++;
446
447 cgiSetArray("job_printer_name", element, valptr);
448 }
449
450 /*
451 * Add "admin_uri" variable if we have a "printer_uri_supported"
452 * attribute...
453 */
454
455 if (!strcmp(name, "printer_uri_supported"))
456 {
457 ippRewriteURL(attr->values[0].string.text, value, sizeof(value),
458 "/admin/");
459
460 cgiSetArray("admin_uri", element, value);
461 }
462
463 /*
464 * Copy values...
465 */
466
467 value[0] = '\0'; /* Initially an empty string */
468 valptr = value; /* Start at the beginning */
469
470 for (i = 0; i < attr->num_values; i ++)
471 {
472 if (i)
473 strlcat(valptr, ",", sizeof(value) - (valptr - value));
474
475 valptr += strlen(valptr);
476
477 switch (attr->value_tag)
478 {
479 case IPP_TAG_INTEGER :
480 case IPP_TAG_ENUM :
481 if (strncmp(name, "time_at_", 8) == 0)
482 {
483 time_t t; /* Temporary time value */
484
485 t = (time_t)attr->values[i].integer;
486 date = localtime(&t);
487
488 strftime(valptr, sizeof(value) - (valptr - value),
489 CUPS_STRFTIME_FORMAT, date);
490 }
491 else
492 snprintf(valptr, sizeof(value) - (valptr - value),
493 "%d", attr->values[i].integer);
494 break;
495
496 case IPP_TAG_BOOLEAN :
497 snprintf(valptr, sizeof(value) - (valptr - value),
498 "%d", attr->values[i].boolean);
499 break;
500
501 case IPP_TAG_NOVALUE :
502 strlcat(valptr, "novalue", sizeof(value) - (valptr - value));
503 break;
504
505 case IPP_TAG_RANGE :
506 snprintf(valptr, sizeof(value) - (valptr - value),
507 "%d-%d", attr->values[i].range.lower,
508 attr->values[i].range.upper);
509 break;
510
511 case IPP_TAG_RESOLUTION :
512 snprintf(valptr, sizeof(value) - (valptr - value),
513 "%dx%d%s", attr->values[i].resolution.xres,
514 attr->values[i].resolution.yres,
515 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
516 "dpi" : "dpc");
517 break;
518
519 case IPP_TAG_URI :
520 if (strchr(attr->values[i].string.text, ':') != NULL)
521 {
522 /*
523 * Rewrite URIs...
524 */
525
526 ippRewriteURL(attr->values[i].string.text, valptr,
527 sizeof(value) - (valptr - value), NULL);
528 break;
529 }
530
531 case IPP_TAG_STRING :
532 case IPP_TAG_TEXT :
533 case IPP_TAG_NAME :
534 case IPP_TAG_KEYWORD :
535 case IPP_TAG_CHARSET :
536 case IPP_TAG_LANGUAGE :
537 case IPP_TAG_MIMETYPE :
538 strlcat(valptr, attr->values[i].string.text,
539 sizeof(value) - (valptr - value));
540 break;
541
542 case IPP_TAG_BEGIN_COLLECTION :
543 snprintf(value, sizeof(value), "%s%d", name, i + 1);
544 ippSetCGIVars(attr->values[i].collection, filter_name,
545 filter_value, value, element);
546 break;
547
548 default :
549 break; /* anti-compiler-warning-code */
550 }
551 }
552
553 /*
554 * Add the element...
555 */
556
557 if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
558 {
559 cgiSetArray(name, element, value);
560
561 DEBUG_printf(("<P>%s[%d]=\"%s\"\n", name, element, value));
562 }
563 }
564
565 if (attr == NULL)
566 break;
567 }
568
569 DEBUG_puts("<P>Leaving ippSetCGIVars()...");
570 }
571
572
573 /*
574 * End of "$Id$".
575 */