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