]> git.ipfire.org Git - thirdparty/cups.git/blame - berkeley/lpq.c
Load cups into easysw/current.
[thirdparty/cups.git] / berkeley / lpq.c
CommitLineData
ef416fc2 1/*
d6ae789d 2 * "$Id: lpq.c 5345 2006-03-28 16:00:17Z mike $"
ef416fc2 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
d6ae789d 52static http_t *connect_server(const char *, http_t *);
fa73b229 53static int show_jobs(const char *, http_t *, const char *,
54 const char *, const int, const int);
55static void show_printer(const char *, http_t *, const char *);
ef416fc2 56static void usage(void);
57
58
59/*
60 * 'main()' - Parse options and commands.
61 */
62
63int
fa73b229 64main(int argc, /* I - Number of command-line arguments */
65 char *argv[]) /* I - Command-line arguments */
ef416fc2 66{
fa73b229 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 */
ef416fc2 80
81
ef416fc2 82
ef416fc2 83
84 /*
85 * Check for command-line options...
86 */
87
d6ae789d 88 http = NULL;
ef416fc2 89 dest = NULL;
90 user = NULL;
91 id = 0;
92 interval = 0;
93 longstatus = 0;
94 all = 0;
d6ae789d 95 language = cupsLangDefault();
96 num_dests = 0;
ef416fc2 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
d6ae789d 107 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
ef416fc2 108
109 if (http)
d6ae789d 110 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
ef416fc2 111#else
fa73b229 112 _cupsLangPrintf(stderr,
ef416fc2 113 _("%s: Sorry, no encryption support compiled in!\n"),
114 argv[0]);
115#endif /* HAVE_SSL */
116 break;
117
fa73b229 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
ef416fc2 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
d6ae789d 158 http = connect_server(argv[0], http);
159
160 if (num_dests == 0)
161 num_dests = cupsGetDests2(http, &dests);
162
ef416fc2 163 if (cupsGetDest(dest, instance, num_dests, dests) == NULL)
164 {
165 if (instance)
fa73b229 166 _cupsLangPrintf(stderr,
167 _("%s: Error - unknown destination \"%s/%s\"!\n"),
168 argv[0], dest, instance);
ef416fc2 169 else
fa73b229 170 _cupsLangPrintf(stderr,
171 _("%s: Unknown destination \"%s\"!\n"),
172 argv[0], dest);
ef416fc2 173
174 return (1);
175 }
176 break;
177
178 case 'a' : /* All printers */
179 all = 1;
180 break;
181
fa73b229 182 case 'h' : /* Connect to host */
d6ae789d 183 if (http)
184 {
fa73b229 185 httpClose(http);
d6ae789d 186 http = NULL;
187 }
fa73b229 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
ef416fc2 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
d6ae789d 225 http = connect_server(argv[0], http);
226
ef416fc2 227 if (dest == NULL && !all)
228 {
d6ae789d 229 if (num_dests == 0)
230 num_dests = cupsGetDests2(http, &dests);
231
ef416fc2 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))
fa73b229 254 _cupsLangPrintf(stderr,
255 _("%s: error - %s environment variable names "
ef416fc2 256 "non-existent destination \"%s\"!\n"),
fa73b229 257 argv[0], val, dest);
ef416fc2 258 else
fa73b229 259 _cupsLangPrintf(stderr,
260 _("%s: error - no default destination available.\n"),
261 argv[0]);
ef416fc2 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)
fa73b229 275 show_printer(argv[0], http, dest);
ef416fc2 276
fa73b229 277 i = show_jobs(argv[0], http, dest, user, id, longstatus);
ef416fc2 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
d6ae789d 299/*
300 * 'connect_server()' - Connect to the server as necessary...
301 */
302
303static http_t * /* O - New HTTP connection */
304connect_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
ef416fc2 323/*
324 * 'show_jobs()' - Show jobs.
325 */
326
fa73b229 327static int /* O - Number of jobs in queue */
328show_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 */
ef416fc2 334{
fa73b229 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 */
ef416fc2 344#ifdef __osf__
fa73b229 345 jobpriority, /* job-priority */
ef416fc2 346#endif /* __osf__ */
fa73b229 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 */
ef416fc2 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
fa73b229 383 request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
ef416fc2 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 {
a4d04587 397 httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
398 NULL, "localhost", 0, "/printers/%s", dest);
ef416fc2 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 {
fa73b229 421 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
ef416fc2 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 {
fa73b229 461 if (!strcmp(attr->name, "job-id") &&
ef416fc2 462 attr->value_tag == IPP_TAG_INTEGER)
463 jobid = attr->values[0].integer;
464
fa73b229 465 if (!strcmp(attr->name, "job-k-octets") &&
ef416fc2 466 attr->value_tag == IPP_TAG_INTEGER)
467 jobsize = attr->values[0].integer;
468
469#ifdef __osf__
fa73b229 470 if (!strcmp(attr->name, "job-priority") &&
ef416fc2 471 attr->value_tag == IPP_TAG_INTEGER)
472 jobpriority = attr->values[0].integer;
473#endif /* __osf__ */
474
fa73b229 475 if (!strcmp(attr->name, "job-state") &&
ef416fc2 476 attr->value_tag == IPP_TAG_ENUM)
477 jobstate = (ipp_jstate_t)attr->values[0].integer;
478
fa73b229 479 if (!strcmp(attr->name, "job-printer-uri") &&
ef416fc2 480 attr->value_tag == IPP_TAG_URI)
481 if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
482 jobdest ++;
483
fa73b229 484 if (!strcmp(attr->name, "job-originating-user-name") &&
ef416fc2 485 attr->value_tag == IPP_TAG_NAME)
486 jobuser = attr->values[0].string.text;
487
fa73b229 488 if (!strcmp(attr->name, "job-name") &&
ef416fc2 489 attr->value_tag == IPP_TAG_NAME)
490 jobname = attr->values[0].string.text;
491
fa73b229 492 if (!strcmp(attr->name, "copies") &&
ef416fc2 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__
fa73b229 513 _cupsLangPuts(stdout,
ef416fc2 514 _("Rank Owner Pri Job Files"
515 " Total Size\n"));
516#else
fa73b229 517 _cupsLangPuts(stdout,
ef416fc2 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 {
fa73b229 547 _cupsLangPuts(stdout, "\n");
ef416fc2 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
fa73b229 555 _cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]\n"),
ef416fc2 556 jobuser, rankstr, jobid);
fa73b229 557 _cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes\n"),
ef416fc2 558 namestr, 1024.0 * jobsize);
559 }
560 else
561#ifdef __osf__
fa73b229 562 _cupsLangPrintf(stdout,
ef416fc2 563 _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"),
564 rankstr, jobuser, jobpriority, jobid, jobname,
565 1024.0 * jobsize);
566#else
fa73b229 567 _cupsLangPrintf(stdout,
ef416fc2 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 {
fa73b229 580 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
ef416fc2 581 return (0);
582 }
583
584 if (jobcount == 0)
fa73b229 585 _cupsLangPuts(stdout, _("no entries\n"));
ef416fc2 586
587 return (jobcount);
588}
589
590
591/*
592 * 'show_printer()' - Show printer status.
593 */
594
595static void
fa73b229 596show_printer(const char *command, /* I - Command name */
597 http_t *http, /* I - HTTP connection to server */
598 const char *dest) /* I - Destination */
ef416fc2 599{
fa73b229 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 */
ef416fc2 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
fa73b229 619 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 620
a4d04587 621 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
622 "localhost", 0, "/printers/%s", dest);
ef416fc2 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 {
fa73b229 634 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
ef416fc2 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 :
fa73b229 647 _cupsLangPrintf(stdout, _("%s is ready\n"), dest);
ef416fc2 648 break;
649 case IPP_PRINTER_PROCESSING :
fa73b229 650 _cupsLangPrintf(stdout, _("%s is ready and printing\n"),
ef416fc2 651 dest);
652 break;
653 case IPP_PRINTER_STOPPED :
fa73b229 654 _cupsLangPrintf(stdout, _("%s is not ready\n"), dest);
ef416fc2 655 break;
656 }
657
658 ippDelete(response);
659 }
660 else
fa73b229 661 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
ef416fc2 662}
663
664
665/*
666 * 'usage()' - Show program usage.
667 */
668
669static void
670usage(void)
671{
fa73b229 672 _cupsLangPuts(stderr,
673 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
674 "[-l] [+interval]\n"));
ef416fc2 675 exit(1);
676}
677
678
679/*
d6ae789d 680 * End of "$Id: lpq.c 5345 2006-03-28 16:00:17Z mike $".
ef416fc2 681 */