]> git.ipfire.org Git - thirdparty/cups.git/blob - berkeley/lpq.c
Merge changes from CUPS 1.5svn-r8933.
[thirdparty/cups.git] / berkeley / lpq.c
1 /*
2 * "$Id: lpq.c 7460 2008-04-16 02:19:54Z mike $"
3 *
4 * "lpq" command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2009 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 <stdio.h>
32 #include <stdlib.h>
33 #include <cups/string.h>
34 #include <cups/cups.h>
35 #include <cups/i18n.h>
36 #include <cups/debug.h>
37
38
39 /*
40 * Local functions...
41 */
42
43 static http_t *connect_server(const char *, http_t *);
44 static int show_jobs(const char *, http_t *, const char *,
45 const char *, const int, const int);
46 static void show_printer(const char *, http_t *, const char *);
47 static void usage(void);
48
49
50 /*
51 * 'main()' - Parse options and commands.
52 */
53
54 int
55 main(int argc, /* I - Number of command-line arguments */
56 char *argv[]) /* I - Command-line arguments */
57 {
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 */
70
71
72 _cupsSetLocale(argv);
73
74 /*
75 * Check for command-line options...
76 */
77
78 http = NULL;
79 dest = NULL;
80 user = NULL;
81 id = 0;
82 interval = 0;
83 longstatus = 0;
84 all = 0;
85 num_dests = 0;
86 dests = NULL;
87
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 {
95 case 'E' : /* Encrypt */
96 #ifdef HAVE_SSL
97 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
98
99 if (http)
100 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
101 #else
102 _cupsLangPrintf(stderr,
103 _("%s: Sorry, no encryption support compiled in\n"),
104 argv[0]);
105 #endif /* HAVE_SSL */
106 break;
107
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
127 case 'P' : /* Printer */
128 if (argv[i][2])
129 dest = argv[i] + 2;
130 else
131 {
132 i ++;
133
134 if (i >= argc)
135 {
136 httpClose(http);
137 cupsFreeDests(num_dests, dests);
138
139 usage();
140 }
141
142 dest = argv[i];
143 }
144
145 if ((instance = strchr(dest, '/')) != NULL)
146 *instance++ = '\0';
147
148 http = connect_server(argv[0], http);
149
150 if (num_dests == 0)
151 num_dests = cupsGetDests2(http, &dests);
152
153 if (cupsGetDest(dest, instance, num_dests, dests) == NULL)
154 {
155 if (instance)
156 _cupsLangPrintf(stderr,
157 _("%s: Error - unknown destination \"%s/%s\"\n"),
158 argv[0], dest, instance);
159 else
160 _cupsLangPrintf(stderr,
161 _("%s: Unknown destination \"%s\"\n"),
162 argv[0], dest);
163
164 return (1);
165 }
166 break;
167
168 case 'a' : /* All printers */
169 all = 1;
170 break;
171
172 case 'h' : /* Connect to host */
173 if (http)
174 {
175 httpClose(http);
176 http = NULL;
177 }
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
198 case 'l' : /* Long status */
199 longstatus = 1;
200 break;
201
202 default :
203 httpClose(http);
204 cupsFreeDests(num_dests, dests);
205
206 usage();
207 break;
208 }
209 }
210 else if (isdigit(argv[i][0] & 255))
211 id = atoi(argv[i]);
212 else
213 user = argv[i];
214
215 http = connect_server(argv[0], http);
216
217 if (dest == NULL && !all)
218 {
219 if (num_dests == 0)
220 num_dests = cupsGetDests2(http, &dests);
221
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 {
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))
244 _cupsLangPrintf(stderr,
245 _("%s: error - %s environment variable names "
246 "non-existent destination \"%s\"\n"),
247 argv[0], val, dest);
248 else
249 _cupsLangPrintf(stderr,
250 _("%s: error - no default destination available.\n"),
251 argv[0]);
252 httpClose(http);
253 cupsFreeDests(num_dests, dests);
254 return (1);
255 }
256 }
257
258 /*
259 * Show the status in a loop...
260 */
261
262 for (;;)
263 {
264 if (dest)
265 show_printer(argv[0], http, dest);
266
267 i = show_jobs(argv[0], http, dest, user, id, longstatus);
268
269 if (i && interval)
270 {
271 fflush(stdout);
272 sleep(interval);
273 }
274 else
275 break;
276 }
277
278 /*
279 * Close the connection to the server and return...
280 */
281
282 cupsFreeDests(num_dests, dests);
283 httpClose(http);
284
285 return (0);
286 }
287
288
289 /*
290 * 'connect_server()' - Connect to the server as necessary...
291 */
292
293 static http_t * /* O - New HTTP connection */
294 connect_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
313 /*
314 * 'show_jobs()' - Show jobs.
315 */
316
317 static int /* O - Number of jobs in queue */
318 show_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 */
324 {
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 */
334 #ifdef __osf__
335 jobpriority, /* job-priority */
336 #endif /* __osf__ */
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 * const jobattrs[] =/* Job attributes we want to see */
344 {
345 "copies",
346 "job-id",
347 "job-k-octets",
348 "job-name",
349 "job-originating-user-name",
350 "job-printer-uri",
351 "job-priority",
352 "job-state"
353 };
354 static const char * const ranks[10] = /* Ranking strings */
355 {
356 "th",
357 "st",
358 "nd",
359 "rd",
360 "th",
361 "th",
362 "th",
363 "th",
364 "th",
365 "th"
366 };
367
368
369 DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%d)\n",
370 http, dest, user, id, longstatus));
371
372 if (http == NULL)
373 return (0);
374
375 /*
376 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
377 * the following attributes:
378 *
379 * attributes-charset
380 * attributes-natural-language
381 * job-uri or printer-uri
382 * requested-attributes
383 */
384
385 request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
386
387 if (id)
388 {
389 snprintf(resource, sizeof(resource), "ipp://localhost/jobs/%d", id);
390 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
391 NULL, resource);
392 }
393 else if (dest)
394 {
395 httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
396 NULL, "localhost", 0, "/printers/%s", dest);
397
398 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
399 NULL, resource);
400 }
401 else
402 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
403 NULL, "ipp://localhost/");
404
405 if (user)
406 {
407 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
408 "requesting-user-name", NULL, user);
409 ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
410 }
411
412 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
413 "requested-attributes",
414 (int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
415
416 /*
417 * Do the request and get back a response...
418 */
419
420 jobcount = 0;
421
422 if ((response = cupsDoRequest(http, request, "/")) != NULL)
423 {
424 if (response->request.status.status_code > IPP_OK_CONFLICT)
425 {
426 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
427 ippDelete(response);
428 return (0);
429 }
430
431 rank = 1;
432
433 /*
434 * Loop through the job list and display them...
435 */
436
437 for (attr = response->attrs; attr != NULL; attr = attr->next)
438 {
439 /*
440 * Skip leading attributes until we hit a job...
441 */
442
443 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
444 attr = attr->next;
445
446 if (attr == NULL)
447 break;
448
449 /*
450 * Pull the needed attributes from this job...
451 */
452
453 jobid = 0;
454 jobsize = 0;
455 #ifdef __osf__
456 jobpriority = 50;
457 #endif /* __osf__ */
458 jobstate = IPP_JOB_PENDING;
459 jobname = "untitled";
460 jobuser = NULL;
461 jobdest = NULL;
462 jobcopies = 1;
463
464 while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
465 {
466 if (!strcmp(attr->name, "job-id") &&
467 attr->value_tag == IPP_TAG_INTEGER)
468 jobid = attr->values[0].integer;
469
470 if (!strcmp(attr->name, "job-k-octets") &&
471 attr->value_tag == IPP_TAG_INTEGER)
472 jobsize = attr->values[0].integer;
473
474 #ifdef __osf__
475 if (!strcmp(attr->name, "job-priority") &&
476 attr->value_tag == IPP_TAG_INTEGER)
477 jobpriority = attr->values[0].integer;
478 #endif /* __osf__ */
479
480 if (!strcmp(attr->name, "job-state") &&
481 attr->value_tag == IPP_TAG_ENUM)
482 jobstate = (ipp_jstate_t)attr->values[0].integer;
483
484 if (!strcmp(attr->name, "job-printer-uri") &&
485 attr->value_tag == IPP_TAG_URI)
486 if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
487 jobdest ++;
488
489 if (!strcmp(attr->name, "job-originating-user-name") &&
490 attr->value_tag == IPP_TAG_NAME)
491 jobuser = attr->values[0].string.text;
492
493 if (!strcmp(attr->name, "job-name") &&
494 attr->value_tag == IPP_TAG_NAME)
495 jobname = attr->values[0].string.text;
496
497 if (!strcmp(attr->name, "copies") &&
498 attr->value_tag == IPP_TAG_INTEGER)
499 jobcopies = attr->values[0].integer;
500
501 attr = attr->next;
502 }
503
504 /*
505 * See if we have everything needed...
506 */
507
508 if (jobdest == NULL || jobid == 0)
509 {
510 if (attr == NULL)
511 break;
512 else
513 continue;
514 }
515
516 if (!longstatus && jobcount == 0)
517 #ifdef __osf__
518 _cupsLangPuts(stdout,
519 _("Rank Owner Pri Job Files"
520 " Total Size\n"));
521 #else
522 _cupsLangPuts(stdout,
523 _("Rank Owner Job File(s)"
524 " Total Size\n"));
525 #endif /* __osf__ */
526
527 jobcount ++;
528
529 /*
530 * Display the job...
531 */
532
533 if (jobstate == IPP_JOB_PROCESSING)
534 strcpy(rankstr, "active");
535 else
536 {
537 /*
538 * Make the rank show the "correct" suffix for each number
539 * (11-13 are the only special cases, for English anyways...)
540 */
541
542 if ((rank % 100) >= 11 && (rank % 100) <= 13)
543 snprintf(rankstr, sizeof(rankstr), "%dth", rank);
544 else
545 snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
546
547 rank ++;
548 }
549
550 if (longstatus)
551 {
552 _cupsLangPuts(stdout, "\n");
553
554 if (jobcopies > 1)
555 snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
556 jobname);
557 else
558 strlcpy(namestr, jobname, sizeof(namestr));
559
560 _cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]\n"),
561 jobuser, rankstr, jobid);
562 _cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes\n"),
563 namestr, 1024.0 * jobsize);
564 }
565 else
566 #ifdef __osf__
567 _cupsLangPrintf(stdout,
568 _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"),
569 rankstr, jobuser, jobpriority, jobid, jobname,
570 1024.0 * jobsize);
571 #else
572 _cupsLangPrintf(stdout,
573 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"),
574 rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
575 #endif /* __osf */
576
577 if (attr == NULL)
578 break;
579 }
580
581 ippDelete(response);
582 }
583 else
584 {
585 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
586 return (0);
587 }
588
589 if (jobcount == 0)
590 _cupsLangPuts(stdout, _("no entries\n"));
591
592 return (jobcount);
593 }
594
595
596 /*
597 * 'show_printer()' - Show printer status.
598 */
599
600 static void
601 show_printer(const char *command, /* I - Command name */
602 http_t *http, /* I - HTTP connection to server */
603 const char *dest) /* I - Destination */
604 {
605 ipp_t *request, /* IPP Request */
606 *response; /* IPP Response */
607 ipp_attribute_t *attr; /* Current attribute */
608 ipp_pstate_t state; /* Printer state */
609 char uri[HTTP_MAX_URI]; /* Printer URI */
610
611
612 if (http == NULL)
613 return;
614
615 /*
616 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
617 * attributes:
618 *
619 * attributes-charset
620 * attributes-natural-language
621 * printer-uri
622 */
623
624 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
625
626 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
627 "localhost", 0, "/printers/%s", dest);
628 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
629 "printer-uri", NULL, uri);
630
631 /*
632 * Do the request and get back a response...
633 */
634
635 if ((response = cupsDoRequest(http, request, "/")) != NULL)
636 {
637 if (response->request.status.status_code > IPP_OK_CONFLICT)
638 {
639 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
640 ippDelete(response);
641 return;
642 }
643
644 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
645 state = (ipp_pstate_t)attr->values[0].integer;
646 else
647 state = IPP_PRINTER_STOPPED;
648
649 switch (state)
650 {
651 case IPP_PRINTER_IDLE :
652 _cupsLangPrintf(stdout, _("%s is ready\n"), dest);
653 break;
654 case IPP_PRINTER_PROCESSING :
655 _cupsLangPrintf(stdout, _("%s is ready and printing\n"),
656 dest);
657 break;
658 case IPP_PRINTER_STOPPED :
659 _cupsLangPrintf(stdout, _("%s is not ready\n"), dest);
660 break;
661 }
662
663 ippDelete(response);
664 }
665 else
666 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
667 }
668
669
670 /*
671 * 'usage()' - Show program usage.
672 */
673
674 static void
675 usage(void)
676 {
677 _cupsLangPuts(stderr,
678 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
679 "[-l] [+interval]\n"));
680 exit(1);
681 }
682
683
684 /*
685 * End of "$Id: lpq.c 7460 2008-04-16 02:19:54Z mike $".
686 */