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