]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
2 | * "$Id: ieee1284.c 4903 2006-01-10 20:02:46Z mike $" | |
3 | * | |
4 | * IEEE-1284 support functions for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. | |
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" 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 | * This file is subject to the Apple OS-Developed Software exception. | |
25 | * | |
26 | * Contents: | |
27 | * | |
28 | * get_device_id() - Get the IEEE-1284 device ID string and corresponding | |
29 | * URI. | |
30 | */ | |
31 | ||
32 | /* | |
33 | * Include necessary headers. | |
34 | */ | |
35 | ||
36 | #include <cups/debug.h> | |
37 | #ifdef __linux | |
38 | # include <sys/ioctl.h> | |
39 | # include <linux/lp.h> | |
40 | # define IOCNR_GET_DEVICE_ID 1 | |
41 | # define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) | |
42 | #endif /* __linux */ | |
43 | ||
44 | #ifdef __sun | |
45 | # ifdef __sparc | |
46 | # include <sys/ecppio.h> | |
47 | # else | |
48 | # include <sys/ioccom.h> | |
49 | # include <sys/ecppsys.h> | |
50 | # endif /* __sparc */ | |
51 | #endif /* __sun */ | |
52 | ||
53 | ||
54 | /* | |
55 | * 'get_device_id()' - Get the IEEE-1284 device ID string and | |
56 | * corresponding URI. | |
57 | */ | |
58 | ||
59 | int /* O - 0 on success, -1 on failure */ | |
60 | get_device_id( | |
61 | int fd, /* I - File descriptor */ | |
62 | char *device_id, /* O - 1284 device ID */ | |
63 | int device_id_size, /* I - Size of buffer */ | |
64 | char *make_model, /* O - Make/model */ | |
65 | int make_model_size, /* I - Size of buffer */ | |
66 | const char *scheme, /* I - URI scheme */ | |
67 | char *uri, /* O - Device URI */ | |
68 | int uri_size) /* I - Size of buffer */ | |
69 | { | |
70 | char *attr, /* 1284 attribute */ | |
71 | *delim, /* 1284 delimiter */ | |
72 | *uriptr, /* Pointer into URI */ | |
73 | *mfg, /* Manufacturer string */ | |
74 | *mdl, /* Model string */ | |
75 | serial_number[1024]; /* Serial number string */ | |
76 | #ifdef __linux | |
77 | int length; /* Length of device ID info */ | |
78 | #endif /* __linux */ | |
79 | #ifdef __sun | |
80 | struct ecpp_device_id did; /* Device ID buffer */ | |
81 | #endif /* __sun */ | |
82 | ||
83 | DEBUG_printf(("get_device_id(fd=%d, device_id=%p, device_id_size=%d, " | |
84 | "make_model=%p, make_model_size=%d, scheme=\"%s\", " | |
85 | "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size, | |
86 | make_model, make_model_size, scheme ? scheme : "(null)", | |
87 | uri, uri_size)); | |
88 | ||
89 | /* | |
90 | * Range check input... | |
91 | */ | |
92 | ||
93 | if (fd < 0 || | |
94 | !device_id || device_id_size < 32 || | |
95 | !make_model || make_model_size < 32) | |
96 | { | |
97 | DEBUG_puts("get_device_id: Bad args!"); | |
98 | return (-1); | |
99 | } | |
100 | ||
101 | *device_id = '\0'; | |
102 | *make_model = '\0'; | |
103 | ||
104 | if (uri) | |
105 | *uri = '\0'; | |
106 | ||
107 | /* | |
108 | * Get the device ID string... | |
109 | */ | |
110 | ||
111 | #ifdef __linux | |
112 | if (!ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id)) | |
113 | { | |
114 | /* | |
115 | * Extract the length of the device ID string from the first two | |
116 | * bytes. The 1284 spec says the length is stored MSB first... | |
117 | */ | |
118 | ||
119 | length = (((unsigned)device_id[0] & 255) << 8) + | |
120 | ((unsigned)device_id[1] & 255); | |
121 | ||
122 | /* | |
123 | * Check to see if the length is larger than our buffer; first | |
124 | * assume that the vendor incorrectly implemented the 1284 spec, | |
125 | * and then limit the length to the size of our buffer... | |
126 | */ | |
127 | ||
128 | if (length > (device_id_size - 2)) | |
129 | length = (((unsigned)device_id[1] & 255) << 8) + | |
130 | ((unsigned)device_id[0] & 255); | |
131 | ||
132 | if (length > (device_id_size - 2)) | |
133 | length = device_id_size - 2; | |
134 | ||
135 | /* | |
136 | * Copy the device ID text to the beginning of the buffer and | |
137 | * nul-terminate. | |
138 | */ | |
139 | ||
140 | memmove(device_id, device_id + 2, length); | |
141 | device_id[length] = '\0'; | |
142 | } | |
143 | # ifdef DEBUG | |
144 | else | |
145 | printf("get_device_id: ioctl failed - %s\n", strerror(errno)); | |
146 | # endif /* DEBUG */ | |
147 | #endif /* __linux */ | |
148 | ||
149 | #if defined(__sun) && defined(ECPPIOC_GETDEVID) | |
150 | did.mode = ECPP_CENTRONICS; | |
151 | did.len = device_id_size - 1; | |
152 | did.rlen = 0; | |
153 | did.addr = device_id; | |
154 | ||
155 | if (!ioctl(fd, ECPPIOC_GETDEVID, &did)) | |
156 | { | |
157 | /* | |
158 | * Nul-terminate the device ID text. | |
159 | */ | |
160 | ||
161 | if (did.rlen < (device_id_size - 1)) | |
162 | device_id[did.rlen] = '\0'; | |
163 | else | |
164 | device_id[device_id_size - 1] = '\0'; | |
165 | } | |
166 | # ifdef DEBUG | |
167 | else | |
168 | printf("get_device_id: ioctl failed - %s\n", strerror(errno)); | |
169 | # endif /* DEBUG */ | |
170 | #endif /* __sun && ECPPIOC_GETDEVID */ | |
171 | ||
172 | DEBUG_printf(("get_device_id: device_id=\"%s\"\n", device_id)); | |
173 | ||
174 | if (!*device_id) | |
175 | return (-1); | |
176 | ||
177 | /* | |
178 | * Look for the description field... | |
179 | */ | |
180 | ||
181 | if ((attr = strstr(device_id, "DES:")) != NULL) | |
182 | attr += 4; | |
183 | else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL) | |
184 | attr += 12; | |
185 | ||
186 | if (attr) | |
187 | { | |
188 | /* | |
189 | * Make sure the description contains something useful, since some | |
190 | * printer manufacturers (HP) apparently don't follow the standards | |
191 | * they helped to define... | |
192 | * | |
193 | * Here we require the description to be 8 or more characters in length, | |
194 | * containing at least one space and one letter. | |
195 | */ | |
196 | ||
197 | if ((delim = strchr(attr, ';')) == NULL) | |
198 | delim = attr + strlen(attr); | |
199 | ||
200 | if ((delim - attr) < 8) | |
201 | attr = NULL; | |
202 | else | |
203 | { | |
204 | char *ptr; /* Pointer into description */ | |
205 | int letters, /* Number of letters seen */ | |
206 | spaces; /* Number of spaces seen */ | |
207 | ||
208 | ||
209 | for (ptr = attr, letters = 0, spaces = 0; ptr < delim; ptr ++) | |
210 | { | |
211 | if (isspace(*ptr & 255)) | |
212 | spaces ++; | |
213 | else if (isalpha(*ptr & 255)) | |
214 | letters ++; | |
215 | ||
216 | if (spaces && letters) | |
217 | break; | |
218 | } | |
219 | ||
220 | if (!spaces || !letters) | |
221 | attr = NULL; | |
222 | } | |
223 | } | |
224 | ||
225 | if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL) | |
226 | mfg += 13; | |
227 | else if ((mfg = strstr(device_id, "MFG:")) != NULL) | |
228 | mfg += 4; | |
229 | ||
230 | if ((mdl = strstr(device_id, "MODEL:")) != NULL) | |
231 | mdl += 6; | |
232 | else if ((mdl = strstr(device_id, "MDL:")) != NULL) | |
233 | mdl += 4; | |
234 | ||
235 | if (attr) | |
236 | { | |
237 | /* | |
238 | * Use description... | |
239 | */ | |
240 | ||
241 | if (!strncasecmp(attr, "Hewlett-Packard hp ", 19)) | |
242 | { | |
243 | /* | |
244 | * Check for a common HP bug... | |
245 | */ | |
246 | ||
247 | strlcpy(make_model, "HP ", make_model_size); | |
248 | strlcpy(make_model + 3, attr + 19, make_model_size - 3); | |
249 | } | |
250 | else if (!strncasecmp(attr, "Hewlett-Packard ", 16)) | |
251 | { | |
252 | strlcpy(make_model, "HP ", make_model_size); | |
253 | strlcpy(make_model + 3, attr + 16, make_model_size - 3); | |
254 | } | |
255 | else | |
256 | { | |
257 | strlcpy(make_model, attr, make_model_size); | |
258 | } | |
259 | } | |
260 | else if (mfg && mdl) | |
261 | { | |
262 | /* | |
263 | * Build a make-model string from the manufacturer and model attributes... | |
264 | */ | |
265 | ||
266 | if (!strncasecmp(mfg, "Hewlett-Packard", 15)) | |
267 | strlcpy(make_model, "HP", make_model_size); | |
268 | else | |
269 | strlcpy(make_model, mfg, make_model_size); | |
270 | ||
271 | if ((delim = strchr(make_model, ';')) != NULL) | |
272 | *delim = '\0'; | |
273 | ||
274 | if (!strncasecmp(make_model, mdl, strlen(make_model))) | |
275 | { | |
276 | /* | |
277 | * Just copy model string, since it has the manufacturer... | |
278 | */ | |
279 | ||
280 | strlcpy(make_model, mdl, make_model_size); | |
281 | } | |
282 | else | |
283 | { | |
284 | /* | |
285 | * Concatenate the make and model... | |
286 | */ | |
287 | ||
288 | strlcat(make_model, " ", make_model_size); | |
289 | strlcat(make_model, mdl, make_model_size); | |
290 | } | |
291 | } | |
292 | else | |
293 | { | |
294 | /* | |
295 | * Use "Unknown" as the printer make and model... | |
296 | */ | |
297 | ||
298 | strlcpy(make_model, "Unknown", make_model_size); | |
299 | } | |
300 | ||
301 | if ((delim = strchr(make_model, ';')) != NULL) | |
302 | *delim = '\0'; | |
303 | ||
304 | if (scheme && uri && uri_size > 32) | |
305 | { | |
306 | /* | |
307 | * Look for the serial number field... | |
308 | */ | |
309 | ||
310 | if ((attr = strstr(device_id, "SERN:")) != NULL) | |
311 | attr += 5; | |
312 | else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL) | |
313 | attr += 13; | |
314 | else if ((attr = strstr(device_id, ";SN:")) != NULL) | |
315 | attr += 4; | |
316 | ||
317 | if (attr) | |
318 | { | |
319 | strlcpy(serial_number, attr, sizeof(serial_number)); | |
320 | ||
321 | if ((delim = strchr(serial_number, ';')) != NULL) | |
322 | *delim = '\0'; | |
323 | } | |
324 | else | |
325 | serial_number[0] = '\0'; | |
326 | ||
327 | /* | |
328 | * Generate the device URI from the make_model and serial number strings. | |
329 | */ | |
330 | ||
331 | snprintf(uri, uri_size, "%s://", scheme); | |
332 | for (uriptr = uri + strlen(uri), delim = make_model; | |
333 | *delim && uriptr < (uri + uri_size - 1); | |
334 | delim ++) | |
335 | if (*delim == ' ') | |
336 | { | |
337 | delim ++; | |
338 | *uriptr++ = '/'; | |
339 | break; | |
340 | } | |
341 | else | |
342 | *uriptr++ = *delim; | |
343 | ||
344 | for (; *delim && uriptr < (uri + uri_size - 3); delim ++) | |
345 | if (*delim == ' ') | |
346 | { | |
347 | *uriptr++ = '%'; | |
348 | *uriptr++ = '2'; | |
349 | *uriptr++ = '0'; | |
350 | } | |
351 | else | |
352 | *uriptr++ = *delim; | |
353 | ||
354 | *uriptr = '\0'; | |
355 | ||
356 | if (serial_number[0]) | |
357 | { | |
358 | /* | |
359 | * Add the serial number to the URI... | |
360 | */ | |
361 | ||
362 | strlcat(uri, "?serial=", uri_size); | |
363 | strlcat(uri, serial_number, uri_size); | |
364 | } | |
365 | } | |
366 | ||
367 | return (0); | |
368 | } | |
369 | ||
370 | ||
371 | /* | |
372 | * End of "$Id: ieee1284.c 4903 2006-01-10 20:02:46Z mike $". | |
373 | */ |