]>
Commit | Line | Data |
---|---|---|
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 | ||
52 | int /* O - 0 on success, -1 on failure */ | |
ed486911 | 53 | backendGetDeviceID( |
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 | ||
299 | int /* O - 0 on success, -1 on failure */ | |
ed486911 | 300 | backendGetMakeModel( |
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 | */ |