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