Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/berkeley/lpq.c
1090 views
1
/*
2
* "lpq" command for CUPS.
3
*
4
* Copyright © 2021-2022 by OpenPrinting.
5
* Copyright © 2007-2018 by Apple Inc.
6
* Copyright © 1997-2006 by Easy Software Products.
7
*
8
* Licensed under Apache License v2.0. See the file "LICENSE" for more
9
* information.
10
*/
11
12
/*
13
* Include necessary headers...
14
*/
15
16
#include <cups/cups-private.h>
17
18
19
/*
20
* Local functions...
21
*/
22
23
static http_t *connect_server(const char *, http_t *);
24
static int show_jobs(const char *, http_t *, const char *,
25
const char *, const int, const int);
26
static void show_printer(const char *, http_t *, const char *);
27
static void usage(void) _CUPS_NORETURN;
28
29
30
/*
31
* 'main()' - Parse options and commands.
32
*/
33
34
int
35
main(int argc, /* I - Number of command-line arguments */
36
char *argv[]) /* I - Command-line arguments */
37
{
38
int i; /* Looping var */
39
http_t *http; /* Connection to server */
40
const char *opt, /* Option pointer */
41
*dest, /* Desired printer */
42
*user, /* Desired user */
43
*val; /* Environment variable name */
44
char *instance; /* Printer instance */
45
int id, /* Desired job ID */
46
all, /* All printers */
47
interval, /* Reporting interval */
48
longstatus; /* Show file details */
49
cups_dest_t *named_dest; /* Named destination */
50
51
52
_cupsSetLocale(argv);
53
54
/*
55
* Check for command-line options...
56
*/
57
58
http = NULL;
59
dest = NULL;
60
user = NULL;
61
id = 0;
62
interval = 0;
63
longstatus = 0;
64
all = 0;
65
66
for (i = 1; i < argc; i ++)
67
{
68
if (argv[i][0] == '+')
69
{
70
interval = atoi(argv[i] + 1);
71
}
72
else if (!strcmp(argv[i], "--help"))
73
usage();
74
else if (argv[i][0] == '-')
75
{
76
for (opt = argv[i] + 1; *opt; opt ++)
77
{
78
switch (*opt)
79
{
80
case 'E' : /* Encrypt */
81
#ifdef HAVE_TLS
82
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
83
84
if (http)
85
httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
86
#else
87
_cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
88
#endif /* HAVE_TLS */
89
break;
90
91
case 'U' : /* Username */
92
if (opt[1] != '\0')
93
{
94
cupsSetUser(opt + 1);
95
opt += strlen(opt) - 1;
96
}
97
else
98
{
99
i ++;
100
if (i >= argc)
101
{
102
_cupsLangPrintf(stderr, _("%s: Error - expected username after \"-U\" option."), argv[0]);
103
return (1);
104
}
105
106
cupsSetUser(argv[i]);
107
}
108
break;
109
110
case 'P' : /* Printer */
111
if (opt[1] != '\0')
112
{
113
dest = opt + 1;
114
opt += strlen(opt) - 1;
115
}
116
else
117
{
118
i ++;
119
120
if (i >= argc)
121
{
122
httpClose(http);
123
124
usage();
125
}
126
127
dest = argv[i];
128
}
129
130
if ((instance = strchr(dest, '/')) != NULL)
131
*instance++ = '\0';
132
133
http = connect_server(argv[0], http);
134
135
if ((named_dest = cupsGetNamedDest(http, dest, instance)) == NULL)
136
{
137
if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
138
cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
139
_cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
140
else if (instance)
141
_cupsLangPrintf(stderr, _("%s: Error - unknown destination \"%s/%s\"."), argv[0], dest, instance);
142
else
143
_cupsLangPrintf(stderr, _("%s: Unknown destination \"%s\"."), argv[0], dest);
144
145
return (1);
146
}
147
148
cupsFreeDests(1, named_dest);
149
break;
150
151
case 'a' : /* All printers */
152
all = 1;
153
break;
154
155
case 'h' : /* Connect to host */
156
if (http)
157
{
158
httpClose(http);
159
http = NULL;
160
}
161
162
if (opt[1] != '\0')
163
{
164
cupsSetServer(opt + 1);
165
opt += strlen(opt) - 1;
166
}
167
else
168
{
169
i ++;
170
171
if (i >= argc)
172
{
173
_cupsLangPrintf(stderr, _("%s: Error - expected hostname after \"-h\" option."), argv[0]);
174
return (1);
175
}
176
else
177
cupsSetServer(argv[i]);
178
}
179
break;
180
181
case 'l' : /* Long status */
182
longstatus = 1;
183
break;
184
185
default :
186
httpClose(http);
187
188
usage();
189
}
190
}
191
}
192
else if (isdigit(argv[i][0] & 255))
193
{
194
id = atoi(argv[i]);
195
}
196
else
197
{
198
user = argv[i];
199
}
200
}
201
202
http = connect_server(argv[0], http);
203
204
if (dest == NULL && !all)
205
{
206
if ((named_dest = cupsGetNamedDest(http, NULL, NULL)) == NULL)
207
{
208
if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
209
cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
210
{
211
_cupsLangPrintf(stderr,
212
_("%s: Error - add '/version=1.1' to server name."),
213
argv[0]);
214
return (1);
215
}
216
217
val = NULL;
218
219
if ((dest = getenv("LPDEST")) == NULL)
220
{
221
if ((dest = getenv("PRINTER")) != NULL)
222
{
223
if (!strcmp(dest, "lp"))
224
dest = NULL;
225
else
226
val = "PRINTER";
227
}
228
}
229
else
230
val = "LPDEST";
231
232
if (dest && val)
233
_cupsLangPrintf(stderr,
234
_("%s: Error - %s environment variable names "
235
"non-existent destination \"%s\"."), argv[0], val,
236
dest);
237
else
238
_cupsLangPrintf(stderr,
239
_("%s: Error - no default destination available."),
240
argv[0]);
241
httpClose(http);
242
return (1);
243
}
244
245
dest = named_dest->name;
246
}
247
248
/*
249
* Show the status in a loop...
250
*/
251
252
for (;;)
253
{
254
if (dest)
255
show_printer(argv[0], http, dest);
256
257
i = show_jobs(argv[0], http, dest, user, id, longstatus);
258
259
if (i && interval)
260
{
261
fflush(stdout);
262
sleep((unsigned)interval);
263
}
264
else
265
break;
266
}
267
268
/*
269
* Close the connection to the server and return...
270
*/
271
272
httpClose(http);
273
274
return (0);
275
}
276
277
278
/*
279
* 'connect_server()' - Connect to the server as necessary...
280
*/
281
282
static http_t * /* O - New HTTP connection */
283
connect_server(const char *command, /* I - Command name */
284
http_t *http) /* I - Current HTTP connection */
285
{
286
if (!http)
287
{
288
http = httpConnectEncrypt(cupsServer(), ippPort(),
289
cupsEncryption());
290
291
if (http == NULL)
292
{
293
_cupsLangPrintf(stderr, _("%s: Unable to connect to server."), command);
294
exit(1);
295
}
296
}
297
298
return (http);
299
}
300
301
302
/*
303
* 'show_jobs()' - Show jobs.
304
*/
305
306
static int /* O - Number of jobs in queue */
307
show_jobs(const char *command, /* I - Command name */
308
http_t *http, /* I - HTTP connection to server */
309
const char *dest, /* I - Destination */
310
const char *user, /* I - User */
311
const int id, /* I - Job ID */
312
const int longstatus) /* I - 1 if long report desired */
313
{
314
ipp_t *request, /* IPP Request */
315
*response; /* IPP Response */
316
ipp_attribute_t *attr; /* Current attribute */
317
const char *jobdest, /* Pointer into job-printer-uri */
318
*jobuser, /* Pointer to job-originating-user-name */
319
*jobname; /* Pointer to job-name */
320
ipp_jstate_t jobstate; /* job-state */
321
int jobid, /* job-id */
322
jobsize, /* job-k-octets */
323
jobcount, /* Number of jobs */
324
jobcopies, /* Number of copies */
325
rank; /* Rank of job */
326
char resource[1024]; /* Resource string */
327
char rankstr[255]; /* Rank string */
328
char namestr[1024]; /* Job name string */
329
static const char * const jobattrs[] =/* Job attributes we want to see */
330
{
331
"copies",
332
"job-id",
333
"job-k-octets",
334
"job-name",
335
"job-originating-user-name",
336
"job-printer-uri",
337
"job-priority",
338
"job-state"
339
};
340
static const char * const ranks[10] = /* Ranking strings */
341
{
342
"th",
343
"st",
344
"nd",
345
"rd",
346
"th",
347
"th",
348
"th",
349
"th",
350
"th",
351
"th"
352
};
353
354
355
if (http == NULL)
356
return (0);
357
358
/*
359
* Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
360
* the following attributes:
361
*
362
* attributes-charset
363
* attributes-natural-language
364
* job-uri or printer-uri
365
* requested-attributes
366
* requesting-user-name
367
*/
368
369
request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
370
371
if (id)
372
{
373
snprintf(resource, sizeof(resource), "ipp://localhost/jobs/%d", id);
374
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
375
NULL, resource);
376
}
377
else if (dest)
378
{
379
httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
380
NULL, "localhost", 0, "/printers/%s", dest);
381
382
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
383
NULL, resource);
384
}
385
else
386
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
387
NULL, "ipp://localhost/");
388
389
if (user)
390
{
391
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
392
"requesting-user-name", NULL, user);
393
ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
394
}
395
else
396
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
397
"requesting-user-name", NULL, cupsUser());
398
399
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
400
"requested-attributes",
401
(int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
402
403
/*
404
* Do the request and get back a response...
405
*/
406
407
jobcount = 0;
408
409
if ((response = cupsDoRequest(http, request, "/")) != NULL)
410
{
411
if (response->request.status.status_code > IPP_OK_CONFLICT)
412
{
413
_cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
414
ippDelete(response);
415
return (0);
416
}
417
418
rank = 1;
419
420
/*
421
* Loop through the job list and display them...
422
*/
423
424
for (attr = response->attrs; attr != NULL; attr = attr->next)
425
{
426
/*
427
* Skip leading attributes until we hit a job...
428
*/
429
430
while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
431
attr = attr->next;
432
433
if (attr == NULL)
434
break;
435
436
/*
437
* Pull the needed attributes from this job...
438
*/
439
440
jobid = 0;
441
jobsize = 0;
442
jobstate = IPP_JOB_PENDING;
443
jobname = "unknown";
444
jobuser = "unknown";
445
jobdest = NULL;
446
jobcopies = 1;
447
448
while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
449
{
450
if (!strcmp(attr->name, "job-id") &&
451
attr->value_tag == IPP_TAG_INTEGER)
452
jobid = attr->values[0].integer;
453
454
if (!strcmp(attr->name, "job-k-octets") &&
455
attr->value_tag == IPP_TAG_INTEGER)
456
jobsize = attr->values[0].integer;
457
458
if (!strcmp(attr->name, "job-state") &&
459
attr->value_tag == IPP_TAG_ENUM)
460
jobstate = (ipp_jstate_t)attr->values[0].integer;
461
462
if (!strcmp(attr->name, "job-printer-uri") &&
463
attr->value_tag == IPP_TAG_URI)
464
if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
465
jobdest ++;
466
467
if (!strcmp(attr->name, "job-originating-user-name") &&
468
attr->value_tag == IPP_TAG_NAME)
469
jobuser = attr->values[0].string.text;
470
471
if (!strcmp(attr->name, "job-name") &&
472
attr->value_tag == IPP_TAG_NAME)
473
jobname = attr->values[0].string.text;
474
475
if (!strcmp(attr->name, "copies") &&
476
attr->value_tag == IPP_TAG_INTEGER)
477
jobcopies = attr->values[0].integer;
478
479
attr = attr->next;
480
}
481
482
/*
483
* See if we have everything needed...
484
*/
485
486
if (jobdest == NULL || jobid == 0)
487
{
488
if (attr == NULL)
489
break;
490
else
491
continue;
492
}
493
494
if (!longstatus && jobcount == 0)
495
_cupsLangPuts(stdout,
496
_("Rank Owner Job File(s)"
497
" Total Size"));
498
499
jobcount ++;
500
501
/*
502
* Display the job...
503
*/
504
505
if (jobstate == IPP_JOB_PROCESSING)
506
strlcpy(rankstr, "active", sizeof(rankstr));
507
else
508
{
509
/*
510
* Make the rank show the "correct" suffix for each number
511
* (11-13 are the only special cases, for English anyways...)
512
*/
513
514
if ((rank % 100) >= 11 && (rank % 100) <= 13)
515
snprintf(rankstr, sizeof(rankstr), "%dth", rank);
516
else
517
snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
518
519
rank ++;
520
}
521
522
if (longstatus)
523
{
524
_cupsLangPuts(stdout, "\n");
525
526
if (jobcopies > 1)
527
snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
528
jobname);
529
else
530
strlcpy(namestr, jobname, sizeof(namestr));
531
532
_cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]"),
533
jobuser, rankstr, jobid);
534
_cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes"),
535
namestr, 1024.0 * jobsize);
536
}
537
else
538
_cupsLangPrintf(stdout,
539
_("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
540
rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
541
542
if (attr == NULL)
543
break;
544
}
545
546
ippDelete(response);
547
}
548
else
549
{
550
_cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
551
return (0);
552
}
553
554
if (jobcount == 0)
555
_cupsLangPuts(stdout, _("no entries"));
556
557
return (jobcount);
558
}
559
560
561
/*
562
* 'show_printer()' - Show printer status.
563
*/
564
565
static void
566
show_printer(const char *command, /* I - Command name */
567
http_t *http, /* I - HTTP connection to server */
568
const char *dest) /* I - Destination */
569
{
570
ipp_t *request, /* IPP Request */
571
*response; /* IPP Response */
572
ipp_attribute_t *attr; /* Current attribute */
573
ipp_pstate_t state; /* Printer state */
574
char uri[HTTP_MAX_URI]; /* Printer URI */
575
576
577
if (http == NULL)
578
return;
579
580
/*
581
* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
582
* attributes:
583
*
584
* attributes-charset
585
* attributes-natural-language
586
* printer-uri
587
*/
588
589
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
590
591
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
592
"localhost", 0, "/printers/%s", dest);
593
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
594
"printer-uri", NULL, uri);
595
596
/*
597
* Do the request and get back a response...
598
*/
599
600
if ((response = cupsDoRequest(http, request, "/")) != NULL)
601
{
602
if (response->request.status.status_code > IPP_OK_CONFLICT)
603
{
604
_cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
605
ippDelete(response);
606
return;
607
}
608
609
if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
610
state = (ipp_pstate_t)attr->values[0].integer;
611
else
612
state = IPP_PRINTER_STOPPED;
613
614
switch (state)
615
{
616
case IPP_PRINTER_IDLE :
617
_cupsLangPrintf(stdout, _("%s is ready"), dest);
618
break;
619
case IPP_PRINTER_PROCESSING :
620
_cupsLangPrintf(stdout, _("%s is ready and printing"),
621
dest);
622
break;
623
case IPP_PRINTER_STOPPED :
624
_cupsLangPrintf(stdout, _("%s is not ready"), dest);
625
break;
626
}
627
628
ippDelete(response);
629
}
630
else
631
_cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
632
}
633
634
635
/*
636
* 'usage()' - Show program usage.
637
*/
638
639
static void
640
usage(void)
641
{
642
_cupsLangPuts(stderr, _("Usage: lpq [options] [+interval]"));
643
_cupsLangPuts(stdout, _("Options:"));
644
_cupsLangPuts(stdout, _("-a Show jobs on all destinations"));
645
_cupsLangPuts(stdout, _("-E Encrypt the connection to the server"));
646
_cupsLangPuts(stdout, _("-h server[:port] Connect to the named server and port"));
647
_cupsLangPuts(stdout, _("-l Show verbose (long) output"));
648
_cupsLangPuts(stdout, _("-P destination Show status for the specified destination"));
649
_cupsLangPuts(stdout, _("-U username Specify the username to use for authentication"));
650
651
exit(1);
652
}
653
654