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