2 * "lpq" command for CUPS.
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * Include necessary headers...
15 #include <cups/cups-private.h>
22 static http_t
*connect_server(const char *, http_t
*);
23 static int show_jobs(const char *, http_t
*, const char *,
24 const char *, const int, const int);
25 static void show_printer(const char *, http_t
*, const char *);
26 static void usage(void) _CUPS_NORETURN
;
30 * 'main()' - Parse options and commands.
34 main(int argc
, /* I - Number of command-line arguments */
35 char *argv
[]) /* I - Command-line arguments */
37 int i
; /* Looping var */
38 http_t
*http
; /* Connection to server */
39 const char *opt
, /* Option pointer */
40 *dest
, /* Desired printer */
41 *user
, /* Desired user */
42 *val
; /* Environment variable name */
43 char *instance
; /* Printer instance */
44 int id
, /* Desired job ID */
45 all
, /* All printers */
46 interval
, /* Reporting interval */
47 longstatus
; /* Show file details */
48 cups_dest_t
*named_dest
; /* Named destination */
54 * Check for command-line options...
65 for (i
= 1; i
< argc
; i
++)
67 if (argv
[i
][0] == '+')
69 interval
= atoi(argv
[i
] + 1);
71 else if (!strcmp(argv
[i
], "--help"))
73 else if (argv
[i
][0] == '-')
75 for (opt
= argv
[i
] + 1; *opt
; opt
++)
79 case 'E' : /* Encrypt */
81 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
84 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
86 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."), argv
[0]);
90 case 'U' : /* Username */
94 opt
+= strlen(opt
) - 1;
101 _cupsLangPrintf(stderr
, _("%s: Error - expected username after \"-U\" option."), argv
[0]);
105 cupsSetUser(argv
[i
]);
109 case 'P' : /* Printer */
113 opt
+= strlen(opt
) - 1;
129 if ((instance
= strchr(dest
, '/')) != NULL
)
132 http
= connect_server(argv
[0], http
);
134 if ((named_dest
= cupsGetNamedDest(http
, dest
, instance
)) == NULL
)
136 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
137 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
138 _cupsLangPrintf(stderr
, _("%s: Error - add '/version=1.1' to server name."), argv
[0]);
140 _cupsLangPrintf(stderr
, _("%s: Error - unknown destination \"%s/%s\"."), argv
[0], dest
, instance
);
142 _cupsLangPrintf(stderr
, _("%s: Unknown destination \"%s\"."), argv
[0], dest
);
147 cupsFreeDests(1, named_dest
);
150 case 'a' : /* All printers */
154 case 'h' : /* Connect to host */
163 cupsSetServer(opt
+ 1);
164 opt
+= strlen(opt
) - 1;
172 _cupsLangPrintf(stderr
, _("%s: Error - expected hostname after \"-h\" option."), argv
[0]);
176 cupsSetServer(argv
[i
]);
180 case 'l' : /* Long status */
191 else if (isdigit(argv
[i
][0] & 255))
201 http
= connect_server(argv
[0], http
);
203 if (dest
== NULL
&& !all
)
205 if ((named_dest
= cupsGetNamedDest(http
, NULL
, NULL
)) == NULL
)
207 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
208 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
210 _cupsLangPrintf(stderr
,
211 _("%s: Error - add '/version=1.1' to server name."),
218 if ((dest
= getenv("LPDEST")) == NULL
)
220 if ((dest
= getenv("PRINTER")) != NULL
)
222 if (!strcmp(dest
, "lp"))
232 _cupsLangPrintf(stderr
,
233 _("%s: Error - %s environment variable names "
234 "non-existent destination \"%s\"."), argv
[0], val
,
237 _cupsLangPrintf(stderr
,
238 _("%s: Error - no default destination available."),
244 dest
= named_dest
->name
;
248 * Show the status in a loop...
254 show_printer(argv
[0], http
, dest
);
256 i
= show_jobs(argv
[0], http
, dest
, user
, id
, longstatus
);
261 sleep((unsigned)interval
);
268 * Close the connection to the server and return...
278 * 'connect_server()' - Connect to the server as necessary...
281 static http_t
* /* O - New HTTP connection */
282 connect_server(const char *command
, /* I - Command name */
283 http_t
*http
) /* I - Current HTTP connection */
287 http
= httpConnectEncrypt(cupsServer(), ippPort(),
292 _cupsLangPrintf(stderr
, _("%s: Unable to connect to server."), command
);
302 * 'show_jobs()' - Show jobs.
305 static int /* O - Number of jobs in queue */
306 show_jobs(const char *command
, /* I - Command name */
307 http_t
*http
, /* I - HTTP connection to server */
308 const char *dest
, /* I - Destination */
309 const char *user
, /* I - User */
310 const int id
, /* I - Job ID */
311 const int longstatus
) /* I - 1 if long report desired */
313 ipp_t
*request
, /* IPP Request */
314 *response
; /* IPP Response */
315 ipp_attribute_t
*attr
; /* Current attribute */
316 const char *jobdest
, /* Pointer into job-printer-uri */
317 *jobuser
, /* Pointer to job-originating-user-name */
318 *jobname
; /* Pointer to job-name */
319 ipp_jstate_t jobstate
; /* job-state */
320 int jobid
, /* job-id */
321 jobsize
, /* job-k-octets */
322 jobcount
, /* Number of jobs */
323 jobcopies
, /* Number of copies */
324 rank
; /* Rank of job */
325 char resource
[1024]; /* Resource string */
326 char rankstr
[255]; /* Rank string */
327 char namestr
[1024]; /* Job name string */
328 static const char * const jobattrs
[] =/* Job attributes we want to see */
334 "job-originating-user-name",
339 static const char * const ranks
[10] = /* Ranking strings */
358 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
359 * the following attributes:
362 * attributes-natural-language
363 * job-uri or printer-uri
364 * requested-attributes
365 * requesting-user-name
368 request
= ippNewRequest(id
? IPP_GET_JOB_ATTRIBUTES
: IPP_GET_JOBS
);
372 snprintf(resource
, sizeof(resource
), "ipp://localhost/jobs/%d", id
);
373 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
378 httpAssembleURIf(HTTP_URI_CODING_ALL
, resource
, sizeof(resource
), "ipp",
379 NULL
, "localhost", 0, "/printers/%s", dest
);
381 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
385 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
386 NULL
, "ipp://localhost/");
390 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
391 "requesting-user-name", NULL
, user
);
392 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
395 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
396 "requesting-user-name", NULL
, cupsUser());
398 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
399 "requested-attributes",
400 (int)(sizeof(jobattrs
) / sizeof(jobattrs
[0])), NULL
, jobattrs
);
403 * Do the request and get back a response...
408 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
410 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
412 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
420 * Loop through the job list and display them...
423 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
426 * Skip leading attributes until we hit a job...
429 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
436 * Pull the needed attributes from this job...
441 jobstate
= IPP_JOB_PENDING
;
447 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
449 if (!strcmp(attr
->name
, "job-id") &&
450 attr
->value_tag
== IPP_TAG_INTEGER
)
451 jobid
= attr
->values
[0].integer
;
453 if (!strcmp(attr
->name
, "job-k-octets") &&
454 attr
->value_tag
== IPP_TAG_INTEGER
)
455 jobsize
= attr
->values
[0].integer
;
457 if (!strcmp(attr
->name
, "job-state") &&
458 attr
->value_tag
== IPP_TAG_ENUM
)
459 jobstate
= (ipp_jstate_t
)attr
->values
[0].integer
;
461 if (!strcmp(attr
->name
, "job-printer-uri") &&
462 attr
->value_tag
== IPP_TAG_URI
)
463 if ((jobdest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
466 if (!strcmp(attr
->name
, "job-originating-user-name") &&
467 attr
->value_tag
== IPP_TAG_NAME
)
468 jobuser
= attr
->values
[0].string
.text
;
470 if (!strcmp(attr
->name
, "job-name") &&
471 attr
->value_tag
== IPP_TAG_NAME
)
472 jobname
= attr
->values
[0].string
.text
;
474 if (!strcmp(attr
->name
, "copies") &&
475 attr
->value_tag
== IPP_TAG_INTEGER
)
476 jobcopies
= attr
->values
[0].integer
;
482 * See if we have everything needed...
485 if (jobdest
== NULL
|| jobid
== 0)
493 if (!longstatus
&& jobcount
== 0)
494 _cupsLangPuts(stdout
,
495 _("Rank Owner Job File(s)"
504 if (jobstate
== IPP_JOB_PROCESSING
)
505 strlcpy(rankstr
, "active", sizeof(rankstr
));
509 * Make the rank show the "correct" suffix for each number
510 * (11-13 are the only special cases, for English anyways...)
513 if ((rank
% 100) >= 11 && (rank
% 100) <= 13)
514 snprintf(rankstr
, sizeof(rankstr
), "%dth", rank
);
516 snprintf(rankstr
, sizeof(rankstr
), "%d%s", rank
, ranks
[rank
% 10]);
523 _cupsLangPuts(stdout
, "\n");
526 snprintf(namestr
, sizeof(namestr
), "%d copies of %s", jobcopies
,
529 strlcpy(namestr
, jobname
, sizeof(namestr
));
531 _cupsLangPrintf(stdout
, _("%s: %-33.33s [job %d localhost]"),
532 jobuser
, rankstr
, jobid
);
533 _cupsLangPrintf(stdout
, _(" %-39.39s %.0f bytes"),
534 namestr
, 1024.0 * jobsize
);
537 _cupsLangPrintf(stdout
,
538 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
539 rankstr
, jobuser
, jobid
, jobname
, 1024.0 * jobsize
);
549 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
554 _cupsLangPuts(stdout
, _("no entries"));
561 * 'show_printer()' - Show printer status.
565 show_printer(const char *command
, /* I - Command name */
566 http_t
*http
, /* I - HTTP connection to server */
567 const char *dest
) /* I - Destination */
569 ipp_t
*request
, /* IPP Request */
570 *response
; /* IPP Response */
571 ipp_attribute_t
*attr
; /* Current attribute */
572 ipp_pstate_t state
; /* Printer state */
573 char uri
[HTTP_MAX_URI
]; /* Printer URI */
580 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
584 * attributes-natural-language
588 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
590 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
591 "localhost", 0, "/printers/%s", dest
);
592 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
593 "printer-uri", NULL
, uri
);
596 * Do the request and get back a response...
599 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
601 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
603 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
608 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
609 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
611 state
= IPP_PRINTER_STOPPED
;
615 case IPP_PRINTER_IDLE
:
616 _cupsLangPrintf(stdout
, _("%s is ready"), dest
);
618 case IPP_PRINTER_PROCESSING
:
619 _cupsLangPrintf(stdout
, _("%s is ready and printing"),
622 case IPP_PRINTER_STOPPED
:
623 _cupsLangPrintf(stdout
, _("%s is not ready"), dest
);
630 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
635 * 'usage()' - Show program usage.
641 _cupsLangPuts(stderr
, _("Usage: lpq [options] [+interval]"));
642 _cupsLangPuts(stdout
, _("Options:"));
643 _cupsLangPuts(stdout
, _("-a Show jobs on all destinations"));
644 _cupsLangPuts(stdout
, _("-E Encrypt the connection to the server"));
645 _cupsLangPuts(stdout
, _("-h server[:port] Connect to the named server and port"));
646 _cupsLangPuts(stdout
, _("-l Show verbose (long) output"));
647 _cupsLangPuts(stdout
, _("-P destination Show status for the specified destination"));
648 _cupsLangPuts(stdout
, _("-U username Specify the username to use for authentication"));