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