]> git.ipfire.org Git - thirdparty/cups.git/blob - berkeley/lpq.c
More svn:properties changes.
[thirdparty/cups.git] / berkeley / lpq.c
1 /*
2 * "$Id$"
3 *
4 * "lpq" command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Parse options and commands.
27 * show_jobs() - Show jobs.
28 * show_printer() - Show printer status.
29 * usage() - Show program usage.
30 */
31
32 /*
33 * Include necessary headers...
34 */
35
36 /*
37 * Include necessary headers...
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <cups/string.h>
43 #include <cups/cups.h>
44 #include <cups/i18n.h>
45 #include <cups/debug.h>
46
47
48 /*
49 * Local functions...
50 */
51
52 static http_t *connect_server(const char *, http_t *);
53 static int show_jobs(const char *, http_t *, const char *,
54 const char *, const int, const int);
55 static void show_printer(const char *, http_t *, const char *);
56 static void usage(void);
57
58
59 /*
60 * 'main()' - Parse options and commands.
61 */
62
63 int
64 main(int argc, /* I - Number of command-line arguments */
65 char *argv[]) /* I - Command-line arguments */
66 {
67 int i; /* Looping var */
68 http_t *http; /* Connection to server */
69 const char *dest, /* Desired printer */
70 *user, /* Desired user */
71 *val; /* Environment variable name */
72 char *instance; /* Printer instance */
73 int id, /* Desired job ID */
74 all, /* All printers */
75 interval, /* Reporting interval */
76 longstatus; /* Show file details */
77 int num_dests; /* Number of destinations */
78 cups_dest_t *dests; /* Destinations */
79 cups_lang_t *language; /* Language */
80
81
82
83
84 /*
85 * Check for command-line options...
86 */
87
88 http = NULL;
89 dest = NULL;
90 user = NULL;
91 id = 0;
92 interval = 0;
93 longstatus = 0;
94 all = 0;
95 language = cupsLangDefault();
96 num_dests = 0;
97
98 for (i = 1; i < argc; i ++)
99 if (argv[i][0] == '+')
100 interval = atoi(argv[i] + 1);
101 else if (argv[i][0] == '-')
102 {
103 switch (argv[i][1])
104 {
105 case 'E' : /* Encrypt */
106 #ifdef HAVE_SSL
107 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
108
109 if (http)
110 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
111 #else
112 _cupsLangPrintf(stderr,
113 _("%s: Sorry, no encryption support compiled in!\n"),
114 argv[0]);
115 #endif /* HAVE_SSL */
116 break;
117
118 case 'U' : /* Username */
119 if (argv[i][2] != '\0')
120 cupsSetUser(argv[i] + 2);
121 else
122 {
123 i ++;
124 if (i >= argc)
125 {
126 _cupsLangPrintf(stderr,
127 _("%s: Error - expected username after "
128 "\'-U\' option!\n"),
129 argv[0]);
130 return (1);
131 }
132
133 cupsSetUser(argv[i]);
134 }
135 break;
136
137 case 'P' : /* Printer */
138 if (argv[i][2])
139 dest = argv[i] + 2;
140 else
141 {
142 i ++;
143
144 if (i >= argc)
145 {
146 httpClose(http);
147 cupsFreeDests(num_dests, dests);
148
149 usage();
150 }
151
152 dest = argv[i];
153 }
154
155 if ((instance = strchr(dest, '/')) != NULL)
156 *instance++ = '\0';
157
158 http = connect_server(argv[0], http);
159
160 if (num_dests == 0)
161 num_dests = cupsGetDests2(http, &dests);
162
163 if (cupsGetDest(dest, instance, num_dests, dests) == NULL)
164 {
165 if (instance)
166 _cupsLangPrintf(stderr,
167 _("%s: Error - unknown destination \"%s/%s\"!\n"),
168 argv[0], dest, instance);
169 else
170 _cupsLangPrintf(stderr,
171 _("%s: Unknown destination \"%s\"!\n"),
172 argv[0], dest);
173
174 return (1);
175 }
176 break;
177
178 case 'a' : /* All printers */
179 all = 1;
180 break;
181
182 case 'h' : /* Connect to host */
183 if (http)
184 {
185 httpClose(http);
186 http = NULL;
187 }
188
189 if (argv[i][2] != '\0')
190 cupsSetServer(argv[i] + 2);
191 else
192 {
193 i ++;
194
195 if (i >= argc)
196 {
197 _cupsLangPrintf(stderr,
198 _("%s: Error - expected hostname after "
199 "\'-h\' option!\n"),
200 argv[0]);
201 return (1);
202 }
203 else
204 cupsSetServer(argv[i]);
205 }
206 break;
207
208 case 'l' : /* Long status */
209 longstatus = 1;
210 break;
211
212 default :
213 httpClose(http);
214 cupsFreeDests(num_dests, dests);
215
216 usage();
217 break;
218 }
219 }
220 else if (isdigit(argv[i][0] & 255))
221 id = atoi(argv[i]);
222 else
223 user = argv[i];
224
225 http = connect_server(argv[0], http);
226
227 if (dest == NULL && !all)
228 {
229 if (num_dests == 0)
230 num_dests = cupsGetDests2(http, &dests);
231
232 for (i = 0; i < num_dests; i ++)
233 if (dests[i].is_default)
234 dest = dests[i].name;
235
236 if (dest == NULL)
237 {
238 val = NULL;
239
240 if ((dest = getenv("LPDEST")) == NULL)
241 {
242 if ((dest = getenv("PRINTER")) != NULL)
243 {
244 if (!strcmp(dest, "lp"))
245 dest = NULL;
246 else
247 val = "PRINTER";
248 }
249 }
250 else
251 val = "LPDEST";
252
253 if (dest && !cupsGetDest(dest, NULL, num_dests, dests))
254 _cupsLangPrintf(stderr,
255 _("%s: error - %s environment variable names "
256 "non-existent destination \"%s\"!\n"),
257 argv[0], val, dest);
258 else
259 _cupsLangPrintf(stderr,
260 _("%s: error - no default destination available.\n"),
261 argv[0]);
262 httpClose(http);
263 cupsFreeDests(num_dests, dests);
264 return (1);
265 }
266 }
267
268 /*
269 * Show the status in a loop...
270 */
271
272 for (;;)
273 {
274 if (dest)
275 show_printer(argv[0], http, dest);
276
277 i = show_jobs(argv[0], http, dest, user, id, longstatus);
278
279 if (i && interval)
280 {
281 fflush(stdout);
282 sleep(interval);
283 }
284 else
285 break;
286 }
287
288 /*
289 * Close the connection to the server and return...
290 */
291
292 cupsFreeDests(num_dests, dests);
293 httpClose(http);
294
295 return (0);
296 }
297
298
299 /*
300 * 'connect_server()' - Connect to the server as necessary...
301 */
302
303 static http_t * /* O - New HTTP connection */
304 connect_server(const char *command, /* I - Command name */
305 http_t *http) /* I - Current HTTP connection */
306 {
307 if (!http)
308 {
309 http = httpConnectEncrypt(cupsServer(), ippPort(),
310 cupsEncryption());
311
312 if (http == NULL)
313 {
314 _cupsLangPrintf(stderr, _("%s: Unable to connect to server\n"), command);
315 exit(1);
316 }
317 }
318
319 return (http);
320 }
321
322
323 /*
324 * 'show_jobs()' - Show jobs.
325 */
326
327 static int /* O - Number of jobs in queue */
328 show_jobs(const char *command, /* I - Command name */
329 http_t *http, /* I - HTTP connection to server */
330 const char *dest, /* I - Destination */
331 const char *user, /* I - User */
332 const int id, /* I - Job ID */
333 const int longstatus) /* I - 1 if long report desired */
334 {
335 ipp_t *request, /* IPP Request */
336 *response; /* IPP Response */
337 ipp_attribute_t *attr; /* Current attribute */
338 const char *jobdest, /* Pointer into job-printer-uri */
339 *jobuser, /* Pointer to job-originating-user-name */
340 *jobname; /* Pointer to job-name */
341 ipp_jstate_t jobstate; /* job-state */
342 int jobid, /* job-id */
343 jobsize, /* job-k-octets */
344 #ifdef __osf__
345 jobpriority, /* job-priority */
346 #endif /* __osf__ */
347 jobcount, /* Number of jobs */
348 jobcopies, /* Number of copies */
349 rank; /* Rank of job */
350 char resource[1024]; /* Resource string */
351 char rankstr[255]; /* Rank string */
352 char namestr[1024]; /* Job name string */
353 static const char *ranks[10] = /* Ranking strings */
354 {
355 "th",
356 "st",
357 "nd",
358 "rd",
359 "th",
360 "th",
361 "th",
362 "th",
363 "th",
364 "th"
365 };
366
367
368 DEBUG_printf(("show_jobs(%08x, %08x, %08x, %d, %d)\n", http, dest, user, id,
369 longstatus));
370
371 if (http == NULL)
372 return (0);
373
374 /*
375 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
376 * the following attributes:
377 *
378 * attributes-charset
379 * attributes-natural-language
380 * job-uri or printer-uri
381 */
382
383 request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
384
385 if (dest == NULL)
386 {
387 if (id)
388 sprintf(resource, "ipp://localhost/jobs/%d", id);
389 else
390 strcpy(resource, "ipp://localhost/jobs");
391
392 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
393 NULL, resource);
394 }
395 else
396 {
397 httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
398 NULL, "localhost", 0, "/printers/%s", dest);
399
400 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
401 NULL, resource);
402 }
403
404 if (user)
405 {
406 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
407 "requesting-user-name", NULL, user);
408 ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
409 }
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\n", 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 = "untitled";
455 jobuser = NULL;
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 _("Rank Owner Pri Job Files"
515 " Total Size\n"));
516 #else
517 _cupsLangPuts(stdout,
518 _("Rank Owner Job File(s)"
519 " Total Size\n"));
520 #endif /* __osf__ */
521
522 jobcount ++;
523
524 /*
525 * Display the job...
526 */
527
528 if (jobstate == IPP_JOB_PROCESSING)
529 strcpy(rankstr, "active");
530 else
531 {
532 /*
533 * Make the rank show the "correct" suffix for each number
534 * (11-13 are the only special cases, for English anyways...)
535 */
536
537 if ((rank % 100) >= 11 && (rank % 100) <= 13)
538 snprintf(rankstr, sizeof(rankstr), "%dth", rank);
539 else
540 snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
541
542 rank ++;
543 }
544
545 if (longstatus)
546 {
547 _cupsLangPuts(stdout, "\n");
548
549 if (jobcopies > 1)
550 snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
551 jobname);
552 else
553 strlcpy(namestr, jobname, sizeof(namestr));
554
555 _cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]\n"),
556 jobuser, rankstr, jobid);
557 _cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes\n"),
558 namestr, 1024.0 * jobsize);
559 }
560 else
561 #ifdef __osf__
562 _cupsLangPrintf(stdout,
563 _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"),
564 rankstr, jobuser, jobpriority, jobid, jobname,
565 1024.0 * jobsize);
566 #else
567 _cupsLangPrintf(stdout,
568 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"),
569 rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
570 #endif /* __osf */
571
572 if (attr == NULL)
573 break;
574 }
575
576 ippDelete(response);
577 }
578 else
579 {
580 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
581 return (0);
582 }
583
584 if (jobcount == 0)
585 _cupsLangPuts(stdout, _("no entries\n"));
586
587 return (jobcount);
588 }
589
590
591 /*
592 * 'show_printer()' - Show printer status.
593 */
594
595 static void
596 show_printer(const char *command, /* I - Command name */
597 http_t *http, /* I - HTTP connection to server */
598 const char *dest) /* I - Destination */
599 {
600 ipp_t *request, /* IPP Request */
601 *response; /* IPP Response */
602 ipp_attribute_t *attr; /* Current attribute */
603 ipp_pstate_t state; /* Printer state */
604 char uri[HTTP_MAX_URI]; /* Printer URI */
605
606
607 if (http == NULL)
608 return;
609
610 /*
611 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
612 * attributes:
613 *
614 * attributes-charset
615 * attributes-natural-language
616 * printer-uri
617 */
618
619 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
620
621 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
622 "localhost", 0, "/printers/%s", dest);
623 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
624 "printer-uri", NULL, uri);
625
626 /*
627 * Do the request and get back a response...
628 */
629
630 if ((response = cupsDoRequest(http, request, "/")) != NULL)
631 {
632 if (response->request.status.status_code > IPP_OK_CONFLICT)
633 {
634 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
635 ippDelete(response);
636 return;
637 }
638
639 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
640 state = (ipp_pstate_t)attr->values[0].integer;
641 else
642 state = IPP_PRINTER_STOPPED;
643
644 switch (state)
645 {
646 case IPP_PRINTER_IDLE :
647 _cupsLangPrintf(stdout, _("%s is ready\n"), dest);
648 break;
649 case IPP_PRINTER_PROCESSING :
650 _cupsLangPrintf(stdout, _("%s is ready and printing\n"),
651 dest);
652 break;
653 case IPP_PRINTER_STOPPED :
654 _cupsLangPrintf(stdout, _("%s is not ready\n"), dest);
655 break;
656 }
657
658 ippDelete(response);
659 }
660 else
661 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
662 }
663
664
665 /*
666 * 'usage()' - Show program usage.
667 */
668
669 static void
670 usage(void)
671 {
672 _cupsLangPuts(stderr,
673 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
674 "[-l] [+interval]\n"));
675 exit(1);
676 }
677
678
679 /*
680 * End of "$Id$".
681 */