Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/backend/ieee1284.c
1090 views
1
/*
2
* IEEE-1284 support functions for CUPS.
3
*
4
* Copyright © 2007-2015 by Apple Inc.
5
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6
*
7
* Licensed under Apache License v2.0. See the file "LICENSE" for more
8
* information.
9
*/
10
11
/*
12
* Include necessary headers.
13
*/
14
15
#include "backend-private.h"
16
#include <cups/ppd-private.h>
17
18
19
/*
20
* 'backendGetDeviceID()' - Get the IEEE-1284 device ID string and
21
* corresponding URI.
22
*/
23
24
int /* O - 0 on success, -1 on failure */
25
backendGetDeviceID(
26
int fd, /* I - File descriptor */
27
char *device_id, /* O - 1284 device ID */
28
int device_id_size, /* I - Size of buffer */
29
char *make_model, /* O - Make/model */
30
int make_model_size, /* I - Size of buffer */
31
const char *scheme, /* I - URI scheme */
32
char *uri, /* O - Device URI */
33
int uri_size) /* I - Size of buffer */
34
{
35
#ifdef __APPLE__ /* This function is a no-op */
36
(void)fd;
37
(void)device_id;
38
(void)device_id_size;
39
(void)make_model;
40
(void)make_model_size;
41
(void)scheme;
42
(void)uri;
43
(void)uri_size;
44
45
return (-1);
46
47
#else /* Get the device ID from the specified file descriptor... */
48
# ifdef __linux
49
int length; /* Length of device ID info */
50
int got_id = 0;
51
# endif /* __linux */
52
# if defined(__sun) && defined(ECPPIOC_GETDEVID)
53
struct ecpp_device_id did; /* Device ID buffer */
54
# endif /* __sun && ECPPIOC_GETDEVID */
55
char *ptr; /* Pointer into device ID */
56
57
58
/*
59
* Range check input...
60
*/
61
62
if (!device_id || device_id_size < 32)
63
{
64
return (-1);
65
}
66
67
if (make_model)
68
*make_model = '\0';
69
70
if (fd >= 0)
71
{
72
/*
73
* Get the device ID string...
74
*/
75
76
*device_id = '\0';
77
78
# ifdef __linux
79
if (ioctl(fd, LPIOC_GET_DEVICE_ID((unsigned)device_id_size), device_id))
80
{
81
/*
82
* Linux has to implement things differently for every device it seems.
83
* Since the standard parallel port driver does not provide a simple
84
* ioctl() to get the 1284 device ID, we have to open the "raw" parallel
85
* device corresponding to this port and do some negotiation trickery
86
* to get the current device ID.
87
*/
88
89
if (uri && !strncmp(uri, "parallel:/dev/", 14))
90
{
91
char devparport[16]; /* /dev/parportN */
92
int devparportfd, /* File descriptor for raw device */
93
mode; /* Port mode */
94
95
96
/*
97
* Since the Linux parallel backend only supports 4 parallel port
98
* devices, just grab the trailing digit and use it to construct a
99
* /dev/parportN filename...
100
*/
101
102
snprintf(devparport, sizeof(devparport), "/dev/parport%s",
103
uri + strlen(uri) - 1);
104
105
if ((devparportfd = open(devparport, O_RDWR | O_NOCTTY)) != -1)
106
{
107
/*
108
* Claim the device...
109
*/
110
111
if (!ioctl(devparportfd, PPCLAIM))
112
{
113
fcntl(devparportfd, F_SETFL, fcntl(devparportfd, F_GETFL) | O_NONBLOCK);
114
115
mode = IEEE1284_MODE_COMPAT;
116
117
if (!ioctl(devparportfd, PPNEGOT, &mode))
118
{
119
/*
120
* Put the device into Device ID mode...
121
*/
122
123
mode = IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID;
124
125
if (!ioctl(devparportfd, PPNEGOT, &mode))
126
{
127
/*
128
* Read the 1284 device ID...
129
*/
130
131
if ((length = read(devparportfd, device_id, (size_t)device_id_size - 1)) >= 2)
132
{
133
device_id[length] = '\0';
134
got_id = 1;
135
}
136
}
137
}
138
139
/*
140
* Release the device...
141
*/
142
143
ioctl(devparportfd, PPRELEASE);
144
}
145
146
close(devparportfd);
147
}
148
}
149
}
150
else
151
got_id = 1;
152
153
if (got_id)
154
{
155
/*
156
* Extract the length of the device ID string from the first two
157
* bytes. The 1284 spec says the length is stored MSB first...
158
*/
159
160
length = (int)((((unsigned)device_id[0] & 255) << 8) + ((unsigned)device_id[1] & 255));
161
162
/*
163
* Check to see if the length is larger than our buffer; first
164
* assume that the vendor incorrectly implemented the 1284 spec,
165
* and then limit the length to the size of our buffer...
166
*/
167
168
if (length > device_id_size || length < 14)
169
length = (int)((((unsigned)device_id[1] & 255) << 8) + ((unsigned)device_id[0] & 255));
170
171
if (length > device_id_size)
172
length = device_id_size;
173
174
/*
175
* The length field counts the number of bytes in the string
176
* including the length field itself (2 bytes). The minimum
177
* length for a valid/usable device ID is 14 bytes:
178
*
179
* <LENGTH> MFG: <MFG> ;MDL: <MDL> ;
180
* 2 + 4 + 1 + 5 + 1 + 1
181
*/
182
183
if (length < 14)
184
{
185
/*
186
* Can't use this device ID, so don't try to copy it...
187
*/
188
189
device_id[0] = '\0';
190
got_id = 0;
191
}
192
else
193
{
194
/*
195
* Copy the device ID text to the beginning of the buffer and
196
* nul-terminate.
197
*/
198
199
length -= 2;
200
201
memmove(device_id, device_id + 2, (size_t)length);
202
device_id[length] = '\0';
203
}
204
}
205
else
206
{
207
*device_id = '\0';
208
}
209
# endif /* __linux */
210
211
# if defined(__sun) && defined(ECPPIOC_GETDEVID)
212
did.mode = ECPP_CENTRONICS;
213
did.len = device_id_size - 1;
214
did.rlen = 0;
215
did.addr = device_id;
216
217
if (!ioctl(fd, ECPPIOC_GETDEVID, &did))
218
{
219
/*
220
* Nul-terminate the device ID text.
221
*/
222
223
if (did.rlen < (device_id_size - 1))
224
device_id[did.rlen] = '\0';
225
else
226
device_id[device_id_size - 1] = '\0';
227
}
228
# endif /* __sun && ECPPIOC_GETDEVID */
229
}
230
231
/*
232
* Check whether device ID is valid. Turn line breaks and tabs to spaces and
233
* reject device IDs with non-printable characters.
234
*/
235
236
for (ptr = device_id; *ptr; ptr ++)
237
if (_cups_isspace(*ptr))
238
*ptr = ' ';
239
else if ((*ptr & 255) < ' ' || *ptr == 127)
240
{
241
*device_id = '\0';
242
break;
243
}
244
245
if (scheme && uri)
246
*uri = '\0';
247
248
if (!*device_id)
249
return (-1);
250
251
/*
252
* Get the make and model...
253
*/
254
255
if (make_model)
256
backendGetMakeModel(device_id, make_model, (size_t)make_model_size);
257
258
/*
259
* Then generate a device URI...
260
*/
261
262
if (scheme && uri && uri_size > 32)
263
{
264
int num_values; /* Number of keys and values */
265
cups_option_t *values; /* Keys and values in device ID */
266
const char *mfg, /* Manufacturer */
267
*mdl, /* Model */
268
*sern; /* Serial number */
269
char temp[256], /* Temporary manufacturer string */
270
*tempptr; /* Pointer into temp string */
271
272
273
/*
274
* Get the make, model, and serial numbers...
275
*/
276
277
num_values = _cupsGet1284Values(device_id, &values);
278
279
if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
280
if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
281
sern = cupsGetOption("SN", num_values, values);
282
283
if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
284
mfg = cupsGetOption("MFG", num_values, values);
285
286
if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
287
mdl = cupsGetOption("MDL", num_values, values);
288
289
if (mfg)
290
{
291
if (!_cups_strcasecmp(mfg, "Hewlett-Packard"))
292
mfg = "HP";
293
else if (!_cups_strcasecmp(mfg, "Lexmark International"))
294
mfg = "Lexmark";
295
}
296
else
297
{
298
strlcpy(temp, make_model, sizeof(temp));
299
300
if ((tempptr = strchr(temp, ' ')) != NULL)
301
*tempptr = '\0';
302
303
mfg = temp;
304
}
305
306
if (!mdl)
307
mdl = "";
308
309
if (!_cups_strncasecmp(mdl, mfg, strlen(mfg)))
310
{
311
mdl += strlen(mfg);
312
313
while (isspace(*mdl & 255))
314
mdl ++;
315
}
316
317
/*
318
* Generate the device URI from the manufacturer, make_model, and
319
* serial number strings.
320
*/
321
322
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, scheme, NULL, mfg, 0,
323
"/%s%s%s", mdl, sern ? "?serial=" : "", sern ? sern : "");
324
325
cupsFreeOptions(num_values, values);
326
}
327
328
return (0);
329
#endif /* __APPLE__ */
330
}
331
332
333
/*
334
* 'backendGetMakeModel()' - Get the make and model string from the device ID.
335
*/
336
337
int /* O - 0 on success, -1 on failure */
338
backendGetMakeModel(
339
const char *device_id, /* O - 1284 device ID */
340
char *make_model, /* O - Make/model */
341
size_t make_model_size) /* I - Size of buffer */
342
{
343
int num_values; /* Number of keys and values */
344
cups_option_t *values; /* Keys and values */
345
const char *mfg, /* Manufacturer string */
346
*mdl, /* Model string */
347
*des; /* Description string */
348
349
350
/*
351
* Range check input...
352
*/
353
354
if (!device_id || !*device_id || !make_model || make_model_size < 32)
355
return (-1);
356
357
*make_model = '\0';
358
359
/*
360
* Look for the description field...
361
*/
362
363
num_values = _cupsGet1284Values(device_id, &values);
364
365
if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
366
mdl = cupsGetOption("MDL", num_values, values);
367
368
if (mdl)
369
{
370
/*
371
* Build a make-model string from the manufacturer and model attributes...
372
*/
373
374
if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
375
mfg = cupsGetOption("MFG", num_values, values);
376
377
if (!mfg || !_cups_strncasecmp(mdl, mfg, strlen(mfg)))
378
{
379
/*
380
* Just copy the model string, since it has the manufacturer...
381
*/
382
383
_ppdNormalizeMakeAndModel(mdl, make_model, make_model_size);
384
}
385
else
386
{
387
/*
388
* Concatenate the make and model...
389
*/
390
391
char temp[1024]; /* Temporary make and model */
392
393
snprintf(temp, sizeof(temp), "%s %s", mfg, mdl);
394
395
_ppdNormalizeMakeAndModel(temp, make_model, make_model_size);
396
}
397
}
398
else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
399
(des = cupsGetOption("DES", num_values, values)) != NULL)
400
{
401
/*
402
* Make sure the description contains something useful, since some
403
* printer manufacturers (HP) apparently don't follow the standards
404
* they helped to define...
405
*
406
* Here we require the description to be 8 or more characters in length,
407
* containing at least one space and one letter.
408
*/
409
410
if (strlen(des) >= 8)
411
{
412
const char *ptr; /* Pointer into description */
413
int letters, /* Number of letters seen */
414
spaces; /* Number of spaces seen */
415
416
417
for (ptr = des, letters = 0, spaces = 0; *ptr; ptr ++)
418
{
419
if (isspace(*ptr & 255))
420
spaces ++;
421
else if (isalpha(*ptr & 255))
422
letters ++;
423
424
if (spaces && letters)
425
break;
426
}
427
428
if (spaces && letters)
429
_ppdNormalizeMakeAndModel(des, make_model, make_model_size);
430
}
431
}
432
433
if (!make_model[0])
434
{
435
/*
436
* Use "Unknown" as the printer make and model...
437
*/
438
439
strlcpy(make_model, "Unknown", make_model_size);
440
}
441
442
cupsFreeOptions(num_values, values);
443
444
return (0);
445
}
446
447