2 * "lpq" command for CUPS.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include <cups/cups-private.h>
25 static http_t
*connect_server(const char *, http_t
*);
26 static int show_jobs(const char *, http_t
*, const char *,
27 const char *, const int, const int);
28 static void show_printer(const char *, http_t
*, const char *);
29 static void usage(void) __attribute__((noreturn
));
33 * 'main()' - Parse options and commands.
37 main(int argc
, /* I - Number of command-line arguments */
38 char *argv
[]) /* I - Command-line arguments */
40 int i
; /* Looping var */
41 http_t
*http
; /* Connection to server */
42 const char *dest
, /* Desired printer */
43 *user
, /* Desired user */
44 *val
; /* Environment variable name */
45 char *instance
; /* Printer instance */
46 int id
, /* Desired job ID */
47 all
, /* All printers */
48 interval
, /* Reporting interval */
49 longstatus
; /* Show file details */
50 cups_dest_t
*named_dest
; /* Named destination */
56 * Check for command-line options...
67 for (i
= 1; i
< argc
; i
++)
68 if (argv
[i
][0] == '+')
69 interval
= atoi(argv
[i
] + 1);
70 else if (argv
[i
][0] == '-')
74 case 'E' : /* Encrypt */
76 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
79 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
81 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
86 case 'U' : /* Username */
87 if (argv
[i
][2] != '\0')
88 cupsSetUser(argv
[i
] + 2);
94 _cupsLangPrintf(stderr
,
95 _("%s: Error - expected username after "
96 "\"-U\" option."), argv
[0]);
100 cupsSetUser(argv
[i
]);
104 case 'P' : /* Printer */
121 if ((instance
= strchr(dest
, '/')) != NULL
)
124 http
= connect_server(argv
[0], http
);
126 if ((named_dest
= cupsGetNamedDest(http
, dest
, instance
)) == NULL
)
128 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
129 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
130 _cupsLangPrintf(stderr
,
131 _("%s: Error - add '/version=1.1' to server "
134 _cupsLangPrintf(stderr
,
135 _("%s: Error - unknown destination \"%s/%s\"."),
136 argv
[0], dest
, instance
);
138 _cupsLangPrintf(stderr
, _("%s: Unknown destination \"%s\"."),
144 cupsFreeDests(1, named_dest
);
147 case 'a' : /* All printers */
151 case 'h' : /* Connect to host */
158 if (argv
[i
][2] != '\0')
159 cupsSetServer(argv
[i
] + 2);
166 _cupsLangPrintf(stderr
,
167 _("%s: Error - expected hostname after "
168 "\"-h\" option."), argv
[0]);
172 cupsSetServer(argv
[i
]);
176 case 'l' : /* Long status */
186 else if (isdigit(argv
[i
][0] & 255))
191 http
= connect_server(argv
[0], http
);
193 if (dest
== NULL
&& !all
)
195 if ((named_dest
= cupsGetNamedDest(http
, NULL
, NULL
)) == NULL
)
197 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
198 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
200 _cupsLangPrintf(stderr
,
201 _("%s: Error - add '/version=1.1' to server name."),
208 if ((dest
= getenv("LPDEST")) == NULL
)
210 if ((dest
= getenv("PRINTER")) != NULL
)
212 if (!strcmp(dest
, "lp"))
222 _cupsLangPrintf(stderr
,
223 _("%s: Error - %s environment variable names "
224 "non-existent destination \"%s\"."), argv
[0], val
,
227 _cupsLangPrintf(stderr
,
228 _("%s: Error - no default destination available."),
234 dest
= named_dest
->name
;
238 * Show the status in a loop...
244 show_printer(argv
[0], http
, dest
);
246 i
= show_jobs(argv
[0], http
, dest
, user
, id
, longstatus
);
251 sleep((unsigned)interval
);
258 * Close the connection to the server and return...
268 * 'connect_server()' - Connect to the server as necessary...
271 static http_t
* /* O - New HTTP connection */
272 connect_server(const char *command
, /* I - Command name */
273 http_t
*http
) /* I - Current HTTP connection */
277 http
= httpConnectEncrypt(cupsServer(), ippPort(),
282 _cupsLangPrintf(stderr
, _("%s: Unable to connect to server."), command
);
292 * 'show_jobs()' - Show jobs.
295 static int /* O - Number of jobs in queue */
296 show_jobs(const char *command
, /* I - Command name */
297 http_t
*http
, /* I - HTTP connection to server */
298 const char *dest
, /* I - Destination */
299 const char *user
, /* I - User */
300 const int id
, /* I - Job ID */
301 const int longstatus
) /* I - 1 if long report desired */
303 ipp_t
*request
, /* IPP Request */
304 *response
; /* IPP Response */
305 ipp_attribute_t
*attr
; /* Current attribute */
306 const char *jobdest
, /* Pointer into job-printer-uri */
307 *jobuser
, /* Pointer to job-originating-user-name */
308 *jobname
; /* Pointer to job-name */
309 ipp_jstate_t jobstate
; /* job-state */
310 int jobid
, /* job-id */
311 jobsize
, /* job-k-octets */
312 jobcount
, /* Number of jobs */
313 jobcopies
, /* Number of copies */
314 rank
; /* Rank of job */
315 char resource
[1024]; /* Resource string */
316 char rankstr
[255]; /* Rank string */
317 char namestr
[1024]; /* Job name string */
318 static const char * const jobattrs
[] =/* Job attributes we want to see */
324 "job-originating-user-name",
329 static const char * const ranks
[10] = /* Ranking strings */
344 DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%d)\n",
345 http
, dest
, user
, id
, longstatus
));
351 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
352 * the following attributes:
355 * attributes-natural-language
356 * job-uri or printer-uri
357 * requested-attributes
358 * requesting-user-name
361 request
= ippNewRequest(id
? IPP_GET_JOB_ATTRIBUTES
: IPP_GET_JOBS
);
365 snprintf(resource
, sizeof(resource
), "ipp://localhost/jobs/%d", id
);
366 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
371 httpAssembleURIf(HTTP_URI_CODING_ALL
, resource
, sizeof(resource
), "ipp",
372 NULL
, "localhost", 0, "/printers/%s", dest
);
374 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
378 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
379 NULL
, "ipp://localhost/");
383 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
384 "requesting-user-name", NULL
, user
);
385 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
388 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
389 "requesting-user-name", NULL
, cupsUser());
391 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
392 "requested-attributes",
393 (int)(sizeof(jobattrs
) / sizeof(jobattrs
[0])), NULL
, jobattrs
);
396 * Do the request and get back a response...
401 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
403 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
405 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
413 * Loop through the job list and display them...
416 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
419 * Skip leading attributes until we hit a job...
422 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
429 * Pull the needed attributes from this job...
434 jobstate
= IPP_JOB_PENDING
;
440 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
442 if (!strcmp(attr
->name
, "job-id") &&
443 attr
->value_tag
== IPP_TAG_INTEGER
)
444 jobid
= attr
->values
[0].integer
;
446 if (!strcmp(attr
->name
, "job-k-octets") &&
447 attr
->value_tag
== IPP_TAG_INTEGER
)
448 jobsize
= attr
->values
[0].integer
;
450 if (!strcmp(attr
->name
, "job-state") &&
451 attr
->value_tag
== IPP_TAG_ENUM
)
452 jobstate
= (ipp_jstate_t
)attr
->values
[0].integer
;
454 if (!strcmp(attr
->name
, "job-printer-uri") &&
455 attr
->value_tag
== IPP_TAG_URI
)
456 if ((jobdest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
459 if (!strcmp(attr
->name
, "job-originating-user-name") &&
460 attr
->value_tag
== IPP_TAG_NAME
)
461 jobuser
= attr
->values
[0].string
.text
;
463 if (!strcmp(attr
->name
, "job-name") &&
464 attr
->value_tag
== IPP_TAG_NAME
)
465 jobname
= attr
->values
[0].string
.text
;
467 if (!strcmp(attr
->name
, "copies") &&
468 attr
->value_tag
== IPP_TAG_INTEGER
)
469 jobcopies
= attr
->values
[0].integer
;
475 * See if we have everything needed...
478 if (jobdest
== NULL
|| jobid
== 0)
486 if (!longstatus
&& jobcount
== 0)
487 _cupsLangPuts(stdout
,
488 _("Rank Owner Job File(s)"
497 if (jobstate
== IPP_JOB_PROCESSING
)
498 strlcpy(rankstr
, "active", sizeof(rankstr
));
502 * Make the rank show the "correct" suffix for each number
503 * (11-13 are the only special cases, for English anyways...)
506 if ((rank
% 100) >= 11 && (rank
% 100) <= 13)
507 snprintf(rankstr
, sizeof(rankstr
), "%dth", rank
);
509 snprintf(rankstr
, sizeof(rankstr
), "%d%s", rank
, ranks
[rank
% 10]);
516 _cupsLangPuts(stdout
, "\n");
519 snprintf(namestr
, sizeof(namestr
), "%d copies of %s", jobcopies
,
522 strlcpy(namestr
, jobname
, sizeof(namestr
));
524 _cupsLangPrintf(stdout
, _("%s: %-33.33s [job %d localhost]"),
525 jobuser
, rankstr
, jobid
);
526 _cupsLangPrintf(stdout
, _(" %-39.39s %.0f bytes"),
527 namestr
, 1024.0 * jobsize
);
530 _cupsLangPrintf(stdout
,
531 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
532 rankstr
, jobuser
, jobid
, jobname
, 1024.0 * jobsize
);
542 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
547 _cupsLangPuts(stdout
, _("no entries"));
554 * 'show_printer()' - Show printer status.
558 show_printer(const char *command
, /* I - Command name */
559 http_t
*http
, /* I - HTTP connection to server */
560 const char *dest
) /* I - Destination */
562 ipp_t
*request
, /* IPP Request */
563 *response
; /* IPP Response */
564 ipp_attribute_t
*attr
; /* Current attribute */
565 ipp_pstate_t state
; /* Printer state */
566 char uri
[HTTP_MAX_URI
]; /* Printer URI */
573 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
577 * attributes-natural-language
581 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
583 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
584 "localhost", 0, "/printers/%s", dest
);
585 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
586 "printer-uri", NULL
, uri
);
589 * Do the request and get back a response...
592 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
594 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
596 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
601 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
602 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
604 state
= IPP_PRINTER_STOPPED
;
608 case IPP_PRINTER_IDLE
:
609 _cupsLangPrintf(stdout
, _("%s is ready"), dest
);
611 case IPP_PRINTER_PROCESSING
:
612 _cupsLangPrintf(stdout
, _("%s is ready and printing"),
615 case IPP_PRINTER_STOPPED
:
616 _cupsLangPrintf(stdout
, _("%s is not ready"), dest
);
623 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
628 * 'usage()' - Show program usage.
634 _cupsLangPuts(stderr
,
635 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
636 "[-l] [+interval]"));