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