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