2 * "$Id: lpq.c 7460 2008-04-16 02:19:54Z mike $"
4 * "lpq" command for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * main() - Parse options and commands.
18 * show_jobs() - Show jobs.
19 * show_printer() - Show printer status.
20 * usage() - Show program usage.
24 * Include necessary headers...
28 * Include necessary headers...
31 #include <cups/cups-private.h>
38 static http_t
*connect_server(const char *, http_t
*);
39 static int show_jobs(const char *, http_t
*, const char *,
40 const char *, const int, const int);
41 static void show_printer(const char *, http_t
*, const char *);
42 static void usage(void);
46 * 'main()' - Parse options and commands.
50 main(int argc
, /* I - Number of command-line arguments */
51 char *argv
[]) /* I - Command-line arguments */
53 int i
; /* Looping var */
54 http_t
*http
; /* Connection to server */
55 const char *dest
, /* Desired printer */
56 *user
, /* Desired user */
57 *val
; /* Environment variable name */
58 char *instance
; /* Printer instance */
59 int id
, /* Desired job ID */
60 all
, /* All printers */
61 interval
, /* Reporting interval */
62 longstatus
; /* Show file details */
63 int num_dests
; /* Number of destinations */
64 cups_dest_t
*dests
; /* Destinations */
70 * Check for command-line options...
83 for (i
= 1; i
< argc
; i
++)
84 if (argv
[i
][0] == '+')
85 interval
= atoi(argv
[i
] + 1);
86 else if (argv
[i
][0] == '-')
90 case 'E' : /* Encrypt */
92 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
95 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
97 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
102 case 'U' : /* Username */
103 if (argv
[i
][2] != '\0')
104 cupsSetUser(argv
[i
] + 2);
110 _cupsLangPrintf(stderr
,
111 _("%s: Error - expected username after "
112 "\"-U\" option."), argv
[0]);
116 cupsSetUser(argv
[i
]);
120 case 'P' : /* Printer */
130 cupsFreeDests(num_dests
, dests
);
138 if ((instance
= strchr(dest
, '/')) != NULL
)
141 http
= connect_server(argv
[0], http
);
144 num_dests
= cupsGetDests2(http
, &dests
);
146 if (cupsGetDest(dest
, instance
, num_dests
, dests
) == NULL
)
149 _cupsLangPrintf(stderr
,
150 _("%s: Error - unknown destination \"%s/%s\"."),
151 argv
[0], dest
, instance
);
153 _cupsLangPrintf(stderr
, _("%s: Unknown destination \"%s\"."),
160 case 'a' : /* All printers */
164 case 'h' : /* Connect to host */
171 if (argv
[i
][2] != '\0')
172 cupsSetServer(argv
[i
] + 2);
179 _cupsLangPrintf(stderr
,
180 _("%s: Error - expected hostname after "
181 "\"-h\" option."), argv
[0]);
185 cupsSetServer(argv
[i
]);
189 case 'l' : /* Long status */
195 cupsFreeDests(num_dests
, dests
);
201 else if (isdigit(argv
[i
][0] & 255))
206 http
= connect_server(argv
[0], http
);
208 if (dest
== NULL
&& !all
)
211 num_dests
= cupsGetDests2(http
, &dests
);
213 for (i
= 0; i
< num_dests
; i
++)
214 if (dests
[i
].is_default
)
215 dest
= dests
[i
].name
;
221 if ((dest
= getenv("LPDEST")) == NULL
)
223 if ((dest
= getenv("PRINTER")) != NULL
)
225 if (!strcmp(dest
, "lp"))
234 if (dest
&& !cupsGetDest(dest
, NULL
, num_dests
, dests
))
235 _cupsLangPrintf(stderr
,
236 _("%s: Error - %s environment variable names "
237 "non-existent destination \"%s\"."), argv
[0], val
,
240 _cupsLangPrintf(stderr
,
241 _("%s: Error - no default destination available."),
244 cupsFreeDests(num_dests
, dests
);
250 * Show the status in a loop...
256 show_printer(argv
[0], http
, dest
);
258 i
= show_jobs(argv
[0], http
, dest
, user
, id
, longstatus
);
270 * Close the connection to the server and return...
273 cupsFreeDests(num_dests
, dests
);
281 * 'connect_server()' - Connect to the server as necessary...
284 static http_t
* /* O - New HTTP connection */
285 connect_server(const char *command
, /* I - Command name */
286 http_t
*http
) /* I - Current HTTP connection */
290 http
= httpConnectEncrypt(cupsServer(), ippPort(),
295 _cupsLangPrintf(stderr
, _("%s: Unable to connect to server."), command
);
305 * 'show_jobs()' - Show jobs.
308 static int /* O - Number of jobs in queue */
309 show_jobs(const char *command
, /* I - Command name */
310 http_t
*http
, /* I - HTTP connection to server */
311 const char *dest
, /* I - Destination */
312 const char *user
, /* I - User */
313 const int id
, /* I - Job ID */
314 const int longstatus
) /* I - 1 if long report desired */
316 ipp_t
*request
, /* IPP Request */
317 *response
; /* IPP Response */
318 ipp_attribute_t
*attr
; /* Current attribute */
319 const char *jobdest
, /* Pointer into job-printer-uri */
320 *jobuser
, /* Pointer to job-originating-user-name */
321 *jobname
; /* Pointer to job-name */
322 ipp_jstate_t jobstate
; /* job-state */
323 int jobid
, /* job-id */
324 jobsize
, /* job-k-octets */
326 jobpriority
, /* job-priority */
328 jobcount
, /* Number of jobs */
329 jobcopies
, /* Number of copies */
330 rank
; /* Rank of job */
331 char resource
[1024]; /* Resource string */
332 char rankstr
[255]; /* Rank string */
333 char namestr
[1024]; /* Job name string */
334 static const char * const jobattrs
[] =/* Job attributes we want to see */
340 "job-originating-user-name",
345 static const char * const ranks
[10] = /* Ranking strings */
360 DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%d)\n",
361 http
, dest
, user
, id
, longstatus
));
367 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
368 * the following attributes:
371 * attributes-natural-language
372 * job-uri or printer-uri
373 * requested-attributes
376 request
= ippNewRequest(id
? IPP_GET_JOB_ATTRIBUTES
: IPP_GET_JOBS
);
380 snprintf(resource
, sizeof(resource
), "ipp://localhost/jobs/%d", id
);
381 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
386 httpAssembleURIf(HTTP_URI_CODING_ALL
, resource
, sizeof(resource
), "ipp",
387 NULL
, "localhost", 0, "/printers/%s", dest
);
389 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
393 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
394 NULL
, "ipp://localhost/");
398 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
399 "requesting-user-name", NULL
, user
);
400 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
403 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
404 "requested-attributes",
405 (int)(sizeof(jobattrs
) / sizeof(jobattrs
[0])), NULL
, jobattrs
);
408 * Do the request and get back a response...
413 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
415 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
417 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
425 * Loop through the job list and display them...
428 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
431 * Skip leading attributes until we hit a job...
434 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
441 * Pull the needed attributes from this job...
449 jobstate
= IPP_JOB_PENDING
;
450 jobname
= "untitled";
455 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
457 if (!strcmp(attr
->name
, "job-id") &&
458 attr
->value_tag
== IPP_TAG_INTEGER
)
459 jobid
= attr
->values
[0].integer
;
461 if (!strcmp(attr
->name
, "job-k-octets") &&
462 attr
->value_tag
== IPP_TAG_INTEGER
)
463 jobsize
= attr
->values
[0].integer
;
466 if (!strcmp(attr
->name
, "job-priority") &&
467 attr
->value_tag
== IPP_TAG_INTEGER
)
468 jobpriority
= attr
->values
[0].integer
;
471 if (!strcmp(attr
->name
, "job-state") &&
472 attr
->value_tag
== IPP_TAG_ENUM
)
473 jobstate
= (ipp_jstate_t
)attr
->values
[0].integer
;
475 if (!strcmp(attr
->name
, "job-printer-uri") &&
476 attr
->value_tag
== IPP_TAG_URI
)
477 if ((jobdest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
480 if (!strcmp(attr
->name
, "job-originating-user-name") &&
481 attr
->value_tag
== IPP_TAG_NAME
)
482 jobuser
= attr
->values
[0].string
.text
;
484 if (!strcmp(attr
->name
, "job-name") &&
485 attr
->value_tag
== IPP_TAG_NAME
)
486 jobname
= attr
->values
[0].string
.text
;
488 if (!strcmp(attr
->name
, "copies") &&
489 attr
->value_tag
== IPP_TAG_INTEGER
)
490 jobcopies
= attr
->values
[0].integer
;
496 * See if we have everything needed...
499 if (jobdest
== NULL
|| jobid
== 0)
507 if (!longstatus
&& jobcount
== 0)
509 _cupsLangPuts(stdout
,
510 /* TRANSLATORS: Pri is job priority. */
511 _("Rank Owner Pri Job Files"
514 _cupsLangPuts(stdout
,
515 _("Rank Owner Job File(s)"
525 if (jobstate
== IPP_JOB_PROCESSING
)
526 strcpy(rankstr
, "active");
530 * Make the rank show the "correct" suffix for each number
531 * (11-13 are the only special cases, for English anyways...)
534 if ((rank
% 100) >= 11 && (rank
% 100) <= 13)
535 snprintf(rankstr
, sizeof(rankstr
), "%dth", rank
);
537 snprintf(rankstr
, sizeof(rankstr
), "%d%s", rank
, ranks
[rank
% 10]);
544 _cupsLangPuts(stdout
, "\n");
547 snprintf(namestr
, sizeof(namestr
), "%d copies of %s", jobcopies
,
550 strlcpy(namestr
, jobname
, sizeof(namestr
));
552 _cupsLangPrintf(stdout
, _("%s: %-33.33s [job %d localhost]"),
553 jobuser
, rankstr
, jobid
);
554 _cupsLangPrintf(stdout
, _(" %-39.39s %.0f bytes"),
555 namestr
, 1024.0 * jobsize
);
559 _cupsLangPrintf(stdout
,
560 _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes"),
561 rankstr
, jobuser
, jobpriority
, jobid
, jobname
,
564 _cupsLangPrintf(stdout
,
565 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
566 rankstr
, jobuser
, jobid
, jobname
, 1024.0 * jobsize
);
577 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
582 _cupsLangPuts(stdout
, _("no entries"));
589 * 'show_printer()' - Show printer status.
593 show_printer(const char *command
, /* I - Command name */
594 http_t
*http
, /* I - HTTP connection to server */
595 const char *dest
) /* I - Destination */
597 ipp_t
*request
, /* IPP Request */
598 *response
; /* IPP Response */
599 ipp_attribute_t
*attr
; /* Current attribute */
600 ipp_pstate_t state
; /* Printer state */
601 char uri
[HTTP_MAX_URI
]; /* Printer URI */
608 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
612 * attributes-natural-language
616 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
618 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
619 "localhost", 0, "/printers/%s", dest
);
620 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
621 "printer-uri", NULL
, uri
);
624 * Do the request and get back a response...
627 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
629 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
631 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
636 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
637 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
639 state
= IPP_PRINTER_STOPPED
;
643 case IPP_PRINTER_IDLE
:
644 _cupsLangPrintf(stdout
, _("%s is ready"), dest
);
646 case IPP_PRINTER_PROCESSING
:
647 _cupsLangPrintf(stdout
, _("%s is ready and printing"),
650 case IPP_PRINTER_STOPPED
:
651 _cupsLangPrintf(stdout
, _("%s is not ready"), dest
);
658 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
663 * 'usage()' - Show program usage.
669 _cupsLangPuts(stderr
,
670 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
671 "[-l] [+interval]"));
677 * End of "$Id: lpq.c 7460 2008-04-16 02:19:54Z mike $".