]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ieee1284.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / ieee1284.c
CommitLineData
ef416fc2 1/*
bc44d920 2 * "$Id: ieee1284.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * IEEE-1284 support functions for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 by Apple Inc.
f7deaa1a 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
ef416fc2 12 * "LICENSE" which should have been included with this file. If this
bc44d920 13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
ed486911 19 * backendGetDeviceID() - Get the IEEE-1284 device ID string and
20 * corresponding URI.
21 * backendGetMakeModel() - Get the make and model string from the device ID.
ef416fc2 22 */
23
24/*
25 * Include necessary headers.
26 */
27
ed486911 28#include "backend-private.h"
ef416fc2 29
ed486911 30#ifdef __linux
31# include <sys/ioctl.h>
32# include <linux/lp.h>
33# define IOCNR_GET_DEVICE_ID 1
34# define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
35#endif /* __linux */
89d46774 36
ed486911 37#ifdef __sun
38# ifdef __sparc
39# include <sys/ecppio.h>
40# else
41# include <sys/ioccom.h>
42# include <sys/ecppsys.h>
43# endif /* __sparc */
44#endif /* __sun */
ef416fc2 45
46
47/*
ed486911 48 * 'backendGetDeviceID()' - Get the IEEE-1284 device ID string and
49 * corresponding URI.
ef416fc2 50 */
51
52int /* O - 0 on success, -1 on failure */
ed486911 53backendGetDeviceID(
ef416fc2 54 int fd, /* I - File descriptor */
55 char *device_id, /* O - 1284 device ID */
56 int device_id_size, /* I - Size of buffer */
57 char *make_model, /* O - Make/model */
58 int make_model_size, /* I - Size of buffer */
59 const char *scheme, /* I - URI scheme */
60 char *uri, /* O - Device URI */
61 int uri_size) /* I - Size of buffer */
62{
63 char *attr, /* 1284 attribute */
64 *delim, /* 1284 delimiter */
65 *uriptr, /* Pointer into URI */
89d46774 66 manufacturer[256], /* Manufacturer string */
ef416fc2 67 serial_number[1024]; /* Serial number string */
89d46774 68 int manulen; /* Length of manufacturer string */
ef416fc2 69#ifdef __linux
70 int length; /* Length of device ID info */
71#endif /* __linux */
b423cd4c 72#if defined(__sun) && defined(ECPPIOC_GETDEVID)
ef416fc2 73 struct ecpp_device_id did; /* Device ID buffer */
b423cd4c 74#endif /* __sun && ECPPIOC_GETDEVID */
ef416fc2 75
89d46774 76
ed486911 77 DEBUG_printf(("backendGetDeviceID(fd=%d, device_id=%p, device_id_size=%d, "
ef416fc2 78 "make_model=%p, make_model_size=%d, scheme=\"%s\", "
79 "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size,
80 make_model, make_model_size, scheme ? scheme : "(null)",
81 uri, uri_size));
82
83 /*
84 * Range check input...
85 */
86
f7deaa1a 87 if (!device_id || device_id_size < 32)
ef416fc2 88 {
ed486911 89 DEBUG_puts("backendGetDeviceID: Bad args!");
ef416fc2 90 return (-1);
91 }
92
f7deaa1a 93 if (make_model)
94 *make_model = '\0';
ef416fc2 95
96 if (uri)
97 *uri = '\0';
98
f7deaa1a 99 if (fd >= 0)
ef416fc2 100 {
101 /*
f7deaa1a 102 * Get the device ID string...
ef416fc2 103 */
104
f7deaa1a 105 *device_id = '\0';
ef416fc2 106
f7deaa1a 107#ifdef __linux
108 if (!ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
109 {
110 /*
111 * Extract the length of the device ID string from the first two
112 * bytes. The 1284 spec says the length is stored MSB first...
113 */
ef416fc2 114
f7deaa1a 115 length = (((unsigned)device_id[0] & 255) << 8) +
116 ((unsigned)device_id[1] & 255);
ef416fc2 117
f7deaa1a 118 /*
119 * Check to see if the length is larger than our buffer; first
120 * assume that the vendor incorrectly implemented the 1284 spec,
121 * and then limit the length to the size of our buffer...
122 */
ef416fc2 123
f7deaa1a 124 if (length > (device_id_size - 2))
125 length = (((unsigned)device_id[1] & 255) << 8) +
126 ((unsigned)device_id[0] & 255);
ef416fc2 127
f7deaa1a 128 if (length > (device_id_size - 2))
129 length = device_id_size - 2;
130
131 /*
132 * Copy the device ID text to the beginning of the buffer and
133 * nul-terminate.
134 */
135
136 memmove(device_id, device_id + 2, length);
137 device_id[length] = '\0';
138 }
ef416fc2 139# ifdef DEBUG
f7deaa1a 140 else
141 printf("backendGetDeviceID: ioctl failed - %s\n", strerror(errno));
ef416fc2 142# endif /* DEBUG */
143#endif /* __linux */
144
145#if defined(__sun) && defined(ECPPIOC_GETDEVID)
f7deaa1a 146 did.mode = ECPP_CENTRONICS;
147 did.len = device_id_size - 1;
148 did.rlen = 0;
149 did.addr = device_id;
ef416fc2 150
f7deaa1a 151 if (!ioctl(fd, ECPPIOC_GETDEVID, &did))
152 {
153 /*
154 * Nul-terminate the device ID text.
155 */
ef416fc2 156
f7deaa1a 157 if (did.rlen < (device_id_size - 1))
158 device_id[did.rlen] = '\0';
159 else
160 device_id[device_id_size - 1] = '\0';
161 }
ef416fc2 162# ifdef DEBUG
f7deaa1a 163 else
164 printf("backendGetDeviceID: ioctl failed - %s\n", strerror(errno));
ef416fc2 165# endif /* DEBUG */
166#endif /* __sun && ECPPIOC_GETDEVID */
f7deaa1a 167 }
ef416fc2 168
ed486911 169 DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id));
ef416fc2 170
171 if (!*device_id)
172 return (-1);
173
89d46774 174 /*
175 * Get the make and model...
176 */
177
f7deaa1a 178 if (make_model)
179 backendGetMakeModel(device_id, make_model, make_model_size);
89d46774 180
181 /*
182 * Then generate a device URI...
183 */
184
185 if (scheme && uri && uri_size > 32)
186 {
187 /*
188 * Look for the serial number field...
189 */
190
191 if ((attr = strstr(device_id, "SERN:")) != NULL)
192 attr += 5;
193 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
194 attr += 13;
195 else if ((attr = strstr(device_id, ";SN:")) != NULL)
196 attr += 4;
197
198 if (attr)
199 {
200 strlcpy(serial_number, attr, sizeof(serial_number));
201
202 if ((delim = strchr(serial_number, ';')) != NULL)
203 *delim = '\0';
204 }
205 else
206 serial_number[0] = '\0';
207
208 /*
209 * Generate the device URI from the manufacturer, make_model, and
210 * serial number strings.
211 */
212
213 snprintf(uri, uri_size, "%s://", scheme);
214
215 if ((attr = strstr(device_id, "MANUFACTURER:")) != NULL)
216 attr += 13;
217 else if ((attr = strstr(device_id, "Manufacturer:")) != NULL)
218 attr += 13;
219 else if ((attr = strstr(device_id, "MFG:")) != NULL)
220 attr += 4;
221
222 if (attr)
223 {
224 strlcpy(manufacturer, attr, sizeof(manufacturer));
225
226 if ((delim = strchr(manufacturer, ';')) != NULL)
227 *delim = '\0';
228
229 if (!strcasecmp(manufacturer, "Hewlett-Packard"))
230 strcpy(manufacturer, "HP");
d09495fa 231 else if (!strcasecmp(manufacturer, "Lexmark International"))
232 strcpy(manufacturer, "Lexmark");
89d46774 233 }
234 else
235 {
236 strlcpy(manufacturer, make_model, sizeof(manufacturer));
237
238 if ((delim = strchr(manufacturer, ' ')) != NULL)
239 *delim = '\0';
240 }
241
242 manulen = strlen(manufacturer);
243
244 for (uriptr = uri + strlen(uri), delim = manufacturer;
245 *delim && uriptr < (uri + uri_size - 3);
246 delim ++)
247 if (*delim == ' ')
248 {
249 *uriptr++ = '%';
250 *uriptr++ = '2';
251 *uriptr++ = '0';
252 }
253 else
254 *uriptr++ = *delim;
255
256 *uriptr++ = '/';
257
258 if (!strncasecmp(make_model, manufacturer, manulen))
259 {
260 delim = make_model + manulen;
261
262 while (isspace(*delim & 255))
263 delim ++;
264 }
265 else
266 delim = make_model;
267
268 for (; *delim && uriptr < (uri + uri_size - 3); delim ++)
269 if (*delim == ' ')
270 {
271 *uriptr++ = '%';
272 *uriptr++ = '2';
273 *uriptr++ = '0';
274 }
275 else
276 *uriptr++ = *delim;
277
278 if (serial_number[0])
279 {
280 /*
281 * Add the serial number to the URI...
282 */
283
284 strlcpy(uriptr, "?serial=", uri_size - (uriptr - uri));
285 strlcat(uriptr, serial_number, uri_size - (uriptr - uri));
286 }
287 else
288 *uriptr = '\0';
289 }
290
291 return (0);
292}
89d46774 293
294
295/*
ed486911 296 * 'backendGetMakeModel()' - Get the make and model string from the device ID.
89d46774 297 */
298
299int /* O - 0 on success, -1 on failure */
ed486911 300backendGetMakeModel(
89d46774 301 const char *device_id, /* O - 1284 device ID */
302 char *make_model, /* O - Make/model */
303 int make_model_size) /* I - Size of buffer */
304{
305 char *attr, /* 1284 attribute */
306 *delim, /* 1284 delimiter */
307 *mfg, /* Manufacturer string */
308 *mdl; /* Model string */
309
310
ed486911 311 DEBUG_printf(("backendGetMakeModel(device_id=\"%s\", "
89d46774 312 "make_model=%p, make_model_size=%d)\n", device_id,
313 make_model, make_model_size));
314
315 /*
316 * Range check input...
317 */
318
319 if (!device_id || !*device_id || !make_model || make_model_size < 32)
320 {
ed486911 321 DEBUG_puts("backendGetMakeModel: Bad args!");
89d46774 322 return (-1);
323 }
324
325 *make_model = '\0';
326
ef416fc2 327 /*
328 * Look for the description field...
329 */
330
331 if ((attr = strstr(device_id, "DES:")) != NULL)
332 attr += 4;
333 else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
334 attr += 12;
335
336 if (attr)
337 {
338 /*
339 * Make sure the description contains something useful, since some
340 * printer manufacturers (HP) apparently don't follow the standards
341 * they helped to define...
342 *
343 * Here we require the description to be 8 or more characters in length,
344 * containing at least one space and one letter.
345 */
346
347 if ((delim = strchr(attr, ';')) == NULL)
348 delim = attr + strlen(attr);
349
350 if ((delim - attr) < 8)
351 attr = NULL;
352 else
353 {
354 char *ptr; /* Pointer into description */
355 int letters, /* Number of letters seen */
356 spaces; /* Number of spaces seen */
357
358
359 for (ptr = attr, letters = 0, spaces = 0; ptr < delim; ptr ++)
360 {
361 if (isspace(*ptr & 255))
362 spaces ++;
363 else if (isalpha(*ptr & 255))
364 letters ++;
365
366 if (spaces && letters)
367 break;
368 }
369
370 if (!spaces || !letters)
371 attr = NULL;
372 }
373 }
374
375 if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
376 mfg += 13;
89d46774 377 else if ((mfg = strstr(device_id, "Manufacturer:")) != NULL)
378 mfg += 13;
ef416fc2 379 else if ((mfg = strstr(device_id, "MFG:")) != NULL)
380 mfg += 4;
381
382 if ((mdl = strstr(device_id, "MODEL:")) != NULL)
383 mdl += 6;
89d46774 384 else if ((mdl = strstr(device_id, "Model:")) != NULL)
385 mdl += 6;
ef416fc2 386 else if ((mdl = strstr(device_id, "MDL:")) != NULL)
387 mdl += 4;
388
89d46774 389 if (mdl)
ef416fc2 390 {
391 /*
89d46774 392 * Build a make-model string from the manufacturer and model attributes...
ef416fc2 393 */
394
89d46774 395 if (mfg)
ef416fc2 396 {
89d46774 397 if (!strncasecmp(mfg, "Hewlett-Packard", 15))
398 strlcpy(make_model, "HP", make_model_size);
d09495fa 399 else if (!strncasecmp(mfg, "Lexmark International", 21))
400 strlcpy(make_model, "Lexmark", make_model_size);
89d46774 401 else
402 strlcpy(make_model, mfg, make_model_size);
ef416fc2 403
89d46774 404 if ((delim = strchr(make_model, ';')) != NULL)
405 *delim = '\0';
406
407 if (!strncasecmp(make_model, mdl, strlen(make_model)))
408 {
409 /*
410 * Just copy model string, since it has the manufacturer...
411 */
412
413 strlcpy(make_model, mdl, make_model_size);
414 }
415 else
416 {
417 /*
418 * Concatenate the make and model...
419 */
420
421 strlcat(make_model, " ", make_model_size);
422 strlcat(make_model, mdl, make_model_size);
423 }
ef416fc2 424 }
425 else
426 {
89d46774 427 /*
428 * Just copy model string, since it has the manufacturer...
429 */
430
431 strlcpy(make_model, mdl, make_model_size);
ef416fc2 432 }
433 }
89d46774 434 else if (attr)
ef416fc2 435 {
436 /*
89d46774 437 * Use description...
ef416fc2 438 */
439
89d46774 440 if (!strncasecmp(attr, "Hewlett-Packard hp ", 19))
ef416fc2 441 {
442 /*
89d46774 443 * Check for a common HP bug...
ef416fc2 444 */
445
89d46774 446 strlcpy(make_model, "HP ", make_model_size);
447 strlcpy(make_model + 3, attr + 19, make_model_size - 3);
448 }
449 else if (!strncasecmp(attr, "Hewlett-Packard ", 16))
450 {
451 strlcpy(make_model, "HP ", make_model_size);
452 strlcpy(make_model + 3, attr + 16, make_model_size - 3);
ef416fc2 453 }
454 else
455 {
89d46774 456 strlcpy(make_model, attr, make_model_size);
ef416fc2 457 }
458 }
459 else
460 {
461 /*
462 * Use "Unknown" as the printer make and model...
463 */
464
465 strlcpy(make_model, "Unknown", make_model_size);
466 }
467
89d46774 468 /*
469 * Strip trailing data...
470 */
471
ef416fc2 472 if ((delim = strchr(make_model, ';')) != NULL)
473 *delim = '\0';
474
89d46774 475 /*
476 * Strip trailing whitespace...
477 */
ef416fc2 478
89d46774 479 for (delim = make_model + strlen(make_model) - 1; delim >= make_model; delim --)
480 if (isspace(*delim & 255))
481 *delim = '\0';
ef416fc2 482 else
89d46774 483 break;
ef416fc2 484
89d46774 485 /*
486 * Return...
487 */
ef416fc2 488
89d46774 489 if (make_model[0])
490 return (0);
491 else
492 return (-1);
ef416fc2 493}
494
495
496/*
bc44d920 497 * End of "$Id: ieee1284.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 498 */