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