]> git.ipfire.org Git - thirdparty/cups.git/blame - berkeley/lpq.c
Fix source file header text duplication text duplication.
[thirdparty/cups.git] / berkeley / lpq.c
CommitLineData
ef416fc2 1/*
5a1d7a17 2 * "lpq" command for CUPS.
ef416fc2 3 *
bdbfacc7 4 * Copyright 2007-2016 by Apple Inc.
5a1d7a17 5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
5a1d7a17
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
57b7b66b 11 * missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 12 */
13
14/*
15 * Include necessary headers...
16 */
17
71e16022 18#include <cups/cups-private.h>
ef416fc2 19
20
21/*
22 * Local functions...
23 */
24
d6ae789d 25static http_t *connect_server(const char *, http_t *);
fa73b229 26static int show_jobs(const char *, http_t *, const char *,
27 const char *, const int, const int);
28static void show_printer(const char *, http_t *, const char *);
85dda01c 29static void usage(void) __attribute__((noreturn));
ef416fc2 30
31
32/*
33 * 'main()' - Parse options and commands.
34 */
35
36int
fa73b229 37main(int argc, /* I - Number of command-line arguments */
38 char *argv[]) /* I - Command-line arguments */
ef416fc2 39{
fa73b229 40 int i; /* Looping var */
41 http_t *http; /* Connection to server */
bdbfacc7
MS
42 const char *opt, /* Option pointer */
43 *dest, /* Desired printer */
fa73b229 44 *user, /* Desired user */
45 *val; /* Environment variable name */
46 char *instance; /* Printer instance */
47 int id, /* Desired job ID */
48 all, /* All printers */
49 interval, /* Reporting interval */
50 longstatus; /* Show file details */
c606bcae 51 cups_dest_t *named_dest; /* Named destination */
ef416fc2 52
53
07725fee 54 _cupsSetLocale(argv);
d09495fa 55
ef416fc2 56 /*
57 * Check for command-line options...
58 */
59
d6ae789d 60 http = NULL;
ef416fc2 61 dest = NULL;
62 user = NULL;
63 id = 0;
64 interval = 0;
65 longstatus = 0;
66 all = 0;
ef416fc2 67
68 for (i = 1; i < argc; i ++)
bdbfacc7 69 {
ef416fc2 70 if (argv[i][0] == '+')
bdbfacc7 71 {
ef416fc2 72 interval = atoi(argv[i] + 1);
bdbfacc7 73 }
ef416fc2 74 else if (argv[i][0] == '-')
75 {
bdbfacc7 76 for (opt = argv[i] + 1; *opt; opt ++)
ef416fc2 77 {
bdbfacc7
MS
78 switch (*opt)
79 {
80 case 'E' : /* Encrypt */
ef416fc2 81#ifdef HAVE_SSL
bdbfacc7 82 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
ef416fc2 83
bdbfacc7
MS
84 if (http)
85 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
ef416fc2 86#else
bdbfacc7 87 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
ef416fc2 88#endif /* HAVE_SSL */
bdbfacc7
MS
89 break;
90
91 case 'U' : /* Username */
92 if (opt[1] != '\0')
fa73b229 93 {
bdbfacc7
MS
94 cupsSetUser(opt + 1);
95 opt += strlen(opt) - 1;
fa73b229 96 }
bdbfacc7
MS
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;
fa73b229 109
bdbfacc7
MS
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 ++;
eac3a0a0 119
bdbfacc7
MS
120 if (i >= argc)
121 {
122 httpClose(http);
ef416fc2 123
bdbfacc7
MS
124 usage();
125 }
eac3a0a0 126
bdbfacc7 127 dest = argv[i];
ef416fc2 128 }
129
bdbfacc7
MS
130 if ((instance = strchr(dest, '/')) != NULL)
131 *instance++ = '\0';
fa73b229 132
bdbfacc7 133 http = connect_server(argv[0], http);
fa73b229 134
bdbfacc7 135 if ((named_dest = cupsGetNamedDest(http, dest, instance)) == NULL)
fa73b229 136 {
bdbfacc7
MS
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
fa73b229 145 return (1);
bdbfacc7
MS
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 }
fa73b229 167 else
bdbfacc7
MS
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;
fa73b229 180
bdbfacc7
MS
181 case 'l' : /* Long status */
182 longstatus = 1;
183 break;
ef416fc2 184
bdbfacc7
MS
185 default :
186 httpClose(http);
ef416fc2 187
bdbfacc7
MS
188 usage();
189 }
ef416fc2 190 }
191 }
192 else if (isdigit(argv[i][0] & 255))
bdbfacc7 193 {
ef416fc2 194 id = atoi(argv[i]);
bdbfacc7 195 }
ef416fc2 196 else
bdbfacc7 197 {
ef416fc2 198 user = argv[i];
bdbfacc7
MS
199 }
200 }
ef416fc2 201
d6ae789d 202 http = connect_server(argv[0], http);
203
ef416fc2 204 if (dest == NULL && !all)
205 {
c606bcae 206 if ((named_dest = cupsGetNamedDest(http, NULL, NULL)) == NULL)
ef416fc2 207 {
c606bcae
MS
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
ef416fc2 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
c606bcae 232 if (dest && val)
fa73b229 233 _cupsLangPrintf(stderr,
84315f46 234 _("%s: Error - %s environment variable names "
0837b7e8
MS
235 "non-existent destination \"%s\"."), argv[0], val,
236 dest);
ef416fc2 237 else
fa73b229 238 _cupsLangPrintf(stderr,
84315f46 239 _("%s: Error - no default destination available."),
fa73b229 240 argv[0]);
ef416fc2 241 httpClose(http);
ef416fc2 242 return (1);
243 }
c606bcae
MS
244
245 dest = named_dest->name;
ef416fc2 246 }
247
248 /*
249 * Show the status in a loop...
250 */
251
252 for (;;)
253 {
254 if (dest)
fa73b229 255 show_printer(argv[0], http, dest);
ef416fc2 256
fa73b229 257 i = show_jobs(argv[0], http, dest, user, id, longstatus);
ef416fc2 258
259 if (i && interval)
260 {
261 fflush(stdout);
7e86f2f6 262 sleep((unsigned)interval);
ef416fc2 263 }
264 else
265 break;
266 }
267
268 /*
269 * Close the connection to the server and return...
270 */
271
ef416fc2 272 httpClose(http);
273
274 return (0);
275}
276
277
d6ae789d 278/*
279 * 'connect_server()' - Connect to the server as necessary...
280 */
281
282static http_t * /* O - New HTTP connection */
283connect_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 {
0837b7e8 293 _cupsLangPrintf(stderr, _("%s: Unable to connect to server."), command);
d6ae789d 294 exit(1);
295 }
296 }
297
298 return (http);
299}
300
301
ef416fc2 302/*
303 * 'show_jobs()' - Show jobs.
304 */
305
fa73b229 306static int /* O - Number of jobs in queue */
307show_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 */
ef416fc2 313{
fa73b229 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 */
fa73b229 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 */
5a662dc0
MS
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 */
ef416fc2 341 {
342 "th",
343 "st",
344 "nd",
345 "rd",
346 "th",
347 "th",
348 "th",
349 "th",
350 "th",
351 "th"
352 };
353
354
ae71f5de
MS
355 DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%d)\n",
356 http, dest, user, id, longstatus));
ef416fc2 357
358 if (http == NULL)
359 return (0);
360
361 /*
362 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
363 * the following attributes:
364 *
365 * attributes-charset
366 * attributes-natural-language
367 * job-uri or printer-uri
5a662dc0 368 * requested-attributes
37e7e6e0 369 * requesting-user-name
ef416fc2 370 */
371
fa73b229 372 request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
ef416fc2 373
1340db2d 374 if (id)
ef416fc2 375 {
1340db2d 376 snprintf(resource, sizeof(resource), "ipp://localhost/jobs/%d", id);
ef416fc2 377 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
378 NULL, resource);
379 }
1340db2d 380 else if (dest)
ef416fc2 381 {
a4d04587 382 httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
383 NULL, "localhost", 0, "/printers/%s", dest);
ef416fc2 384
385 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
386 NULL, resource);
387 }
1340db2d
MS
388 else
389 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
390 NULL, "ipp://localhost/");
ef416fc2 391
392 if (user)
393 {
394 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
395 "requesting-user-name", NULL, user);
396 ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
397 }
37e7e6e0
MS
398 else
399 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
400 "requesting-user-name", NULL, cupsUser());
ef416fc2 401
5a662dc0
MS
402 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
403 "requested-attributes",
404 (int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
405
ef416fc2 406 /*
407 * Do the request and get back a response...
408 */
409
410 jobcount = 0;
411
412 if ((response = cupsDoRequest(http, request, "/")) != NULL)
413 {
414 if (response->request.status.status_code > IPP_OK_CONFLICT)
415 {
0837b7e8 416 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 417 ippDelete(response);
418 return (0);
419 }
420
421 rank = 1;
422
423 /*
424 * Loop through the job list and display them...
425 */
426
427 for (attr = response->attrs; attr != NULL; attr = attr->next)
428 {
429 /*
430 * Skip leading attributes until we hit a job...
431 */
432
433 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
434 attr = attr->next;
435
436 if (attr == NULL)
437 break;
438
439 /*
440 * Pull the needed attributes from this job...
441 */
442
443 jobid = 0;
444 jobsize = 0;
ef416fc2 445 jobstate = IPP_JOB_PENDING;
37e7e6e0
MS
446 jobname = "unknown";
447 jobuser = "unknown";
ef416fc2 448 jobdest = NULL;
449 jobcopies = 1;
450
451 while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
452 {
fa73b229 453 if (!strcmp(attr->name, "job-id") &&
ef416fc2 454 attr->value_tag == IPP_TAG_INTEGER)
455 jobid = attr->values[0].integer;
456
fa73b229 457 if (!strcmp(attr->name, "job-k-octets") &&
ef416fc2 458 attr->value_tag == IPP_TAG_INTEGER)
459 jobsize = attr->values[0].integer;
460
fa73b229 461 if (!strcmp(attr->name, "job-state") &&
ef416fc2 462 attr->value_tag == IPP_TAG_ENUM)
463 jobstate = (ipp_jstate_t)attr->values[0].integer;
464
fa73b229 465 if (!strcmp(attr->name, "job-printer-uri") &&
ef416fc2 466 attr->value_tag == IPP_TAG_URI)
467 if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
468 jobdest ++;
469
fa73b229 470 if (!strcmp(attr->name, "job-originating-user-name") &&
ef416fc2 471 attr->value_tag == IPP_TAG_NAME)
472 jobuser = attr->values[0].string.text;
473
fa73b229 474 if (!strcmp(attr->name, "job-name") &&
ef416fc2 475 attr->value_tag == IPP_TAG_NAME)
476 jobname = attr->values[0].string.text;
477
fa73b229 478 if (!strcmp(attr->name, "copies") &&
ef416fc2 479 attr->value_tag == IPP_TAG_INTEGER)
480 jobcopies = attr->values[0].integer;
481
482 attr = attr->next;
483 }
484
485 /*
486 * See if we have everything needed...
487 */
488
489 if (jobdest == NULL || jobid == 0)
490 {
491 if (attr == NULL)
492 break;
493 else
494 continue;
495 }
496
497 if (!longstatus && jobcount == 0)
fa73b229 498 _cupsLangPuts(stdout,
ef416fc2 499 _("Rank Owner Job File(s)"
0837b7e8 500 " Total Size"));
ef416fc2 501
502 jobcount ++;
503
504 /*
505 * Display the job...
506 */
507
508 if (jobstate == IPP_JOB_PROCESSING)
5a9febac 509 strlcpy(rankstr, "active", sizeof(rankstr));
ef416fc2 510 else
511 {
512 /*
513 * Make the rank show the "correct" suffix for each number
514 * (11-13 are the only special cases, for English anyways...)
515 */
516
517 if ((rank % 100) >= 11 && (rank % 100) <= 13)
518 snprintf(rankstr, sizeof(rankstr), "%dth", rank);
519 else
520 snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
521
522 rank ++;
523 }
524
525 if (longstatus)
526 {
fa73b229 527 _cupsLangPuts(stdout, "\n");
ef416fc2 528
529 if (jobcopies > 1)
530 snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
531 jobname);
532 else
533 strlcpy(namestr, jobname, sizeof(namestr));
534
0837b7e8 535 _cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]"),
ef416fc2 536 jobuser, rankstr, jobid);
0837b7e8 537 _cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes"),
ef416fc2 538 namestr, 1024.0 * jobsize);
539 }
540 else
fa73b229 541 _cupsLangPrintf(stdout,
0837b7e8 542 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
ef416fc2 543 rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
ef416fc2 544
545 if (attr == NULL)
546 break;
547 }
548
549 ippDelete(response);
550 }
551 else
552 {
0837b7e8 553 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 554 return (0);
555 }
556
557 if (jobcount == 0)
0837b7e8 558 _cupsLangPuts(stdout, _("no entries"));
ef416fc2 559
560 return (jobcount);
561}
562
563
564/*
565 * 'show_printer()' - Show printer status.
566 */
567
568static void
fa73b229 569show_printer(const char *command, /* I - Command name */
570 http_t *http, /* I - HTTP connection to server */
571 const char *dest) /* I - Destination */
ef416fc2 572{
fa73b229 573 ipp_t *request, /* IPP Request */
574 *response; /* IPP Response */
575 ipp_attribute_t *attr; /* Current attribute */
576 ipp_pstate_t state; /* Printer state */
577 char uri[HTTP_MAX_URI]; /* Printer URI */
ef416fc2 578
579
580 if (http == NULL)
581 return;
582
583 /*
584 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
585 * attributes:
586 *
587 * attributes-charset
588 * attributes-natural-language
589 * printer-uri
590 */
591
fa73b229 592 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 593
a4d04587 594 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
595 "localhost", 0, "/printers/%s", dest);
ef416fc2 596 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
597 "printer-uri", NULL, uri);
598
599 /*
600 * Do the request and get back a response...
601 */
602
603 if ((response = cupsDoRequest(http, request, "/")) != NULL)
604 {
605 if (response->request.status.status_code > IPP_OK_CONFLICT)
606 {
0837b7e8 607 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 608 ippDelete(response);
609 return;
610 }
611
612 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
613 state = (ipp_pstate_t)attr->values[0].integer;
614 else
615 state = IPP_PRINTER_STOPPED;
616
617 switch (state)
618 {
619 case IPP_PRINTER_IDLE :
0837b7e8 620 _cupsLangPrintf(stdout, _("%s is ready"), dest);
ef416fc2 621 break;
622 case IPP_PRINTER_PROCESSING :
0837b7e8 623 _cupsLangPrintf(stdout, _("%s is ready and printing"),
ef416fc2 624 dest);
625 break;
626 case IPP_PRINTER_STOPPED :
0837b7e8 627 _cupsLangPrintf(stdout, _("%s is not ready"), dest);
ef416fc2 628 break;
629 }
630
631 ippDelete(response);
632 }
633 else
0837b7e8 634 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 635}
636
637
638/*
639 * 'usage()' - Show program usage.
640 */
641
642static void
643usage(void)
644{
fa73b229 645 _cupsLangPuts(stderr,
646 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
0837b7e8 647 "[-l] [+interval]"));
ef416fc2 648 exit(1);
649}