2 * "$Id: lpq.c 181 2006-06-22 20:01:18Z jlovell $"
4 * "lpq" command for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Parse options and commands.
27 * show_jobs() - Show jobs.
28 * show_printer() - Show printer status.
29 * usage() - Show program usage.
33 * Include necessary headers...
37 * Include necessary headers...
42 #include <cups/string.h>
43 #include <cups/cups.h>
44 #include <cups/i18n.h>
45 #include <cups/debug.h>
52 static http_t
*connect_server(const char *, http_t
*);
53 static int show_jobs(const char *, http_t
*, const char *,
54 const char *, const int, const int);
55 static void show_printer(const char *, http_t
*, const char *);
56 static void usage(void);
60 * 'main()' - Parse options and commands.
64 main(int argc
, /* I - Number of command-line arguments */
65 char *argv
[]) /* I - Command-line arguments */
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 */
83 * Check for command-line options...
93 language
= cupsLangDefault();
96 for (i
= 1; i
< argc
; i
++)
97 if (argv
[i
][0] == '+')
98 interval
= atoi(argv
[i
] + 1);
99 else if (argv
[i
][0] == '-')
103 case 'E' : /* Encrypt */
105 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
108 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
110 _cupsLangPrintf(stderr
,
111 _("%s: Sorry, no encryption support compiled in!\n"),
113 #endif /* HAVE_SSL */
116 case 'U' : /* Username */
117 if (argv
[i
][2] != '\0')
118 cupsSetUser(argv
[i
] + 2);
124 _cupsLangPrintf(stderr
,
125 _("%s: Error - expected username after "
131 cupsSetUser(argv
[i
]);
135 case 'P' : /* Printer */
145 cupsFreeDests(num_dests
, dests
);
153 if ((instance
= strchr(dest
, '/')) != NULL
)
156 http
= connect_server(argv
[0], http
);
159 num_dests
= cupsGetDests2(http
, &dests
);
161 if (cupsGetDest(dest
, instance
, num_dests
, dests
) == NULL
)
164 _cupsLangPrintf(stderr
,
165 _("%s: Error - unknown destination \"%s/%s\"!\n"),
166 argv
[0], dest
, instance
);
168 _cupsLangPrintf(stderr
,
169 _("%s: Unknown destination \"%s\"!\n"),
176 case 'a' : /* All printers */
180 case 'h' : /* Connect to host */
187 if (argv
[i
][2] != '\0')
188 cupsSetServer(argv
[i
] + 2);
195 _cupsLangPrintf(stderr
,
196 _("%s: Error - expected hostname after "
202 cupsSetServer(argv
[i
]);
206 case 'l' : /* Long status */
212 cupsFreeDests(num_dests
, dests
);
218 else if (isdigit(argv
[i
][0] & 255))
223 http
= connect_server(argv
[0], http
);
225 if (dest
== NULL
&& !all
)
228 num_dests
= cupsGetDests2(http
, &dests
);
230 for (i
= 0; i
< num_dests
; i
++)
231 if (dests
[i
].is_default
)
232 dest
= dests
[i
].name
;
238 if ((dest
= getenv("LPDEST")) == NULL
)
240 if ((dest
= getenv("PRINTER")) != NULL
)
242 if (!strcmp(dest
, "lp"))
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"),
257 _cupsLangPrintf(stderr
,
258 _("%s: error - no default destination available.\n"),
261 cupsFreeDests(num_dests
, dests
);
267 * Show the status in a loop...
273 show_printer(argv
[0], http
, dest
);
275 i
= show_jobs(argv
[0], http
, dest
, user
, id
, longstatus
);
287 * Close the connection to the server and return...
290 cupsFreeDests(num_dests
, dests
);
298 * 'connect_server()' - Connect to the server as necessary...
301 static http_t
* /* O - New HTTP connection */
302 connect_server(const char *command
, /* I - Command name */
303 http_t
*http
) /* I - Current HTTP connection */
307 http
= httpConnectEncrypt(cupsServer(), ippPort(),
312 _cupsLangPrintf(stderr
, _("%s: Unable to connect to server\n"), command
);
322 * 'show_jobs()' - Show jobs.
325 static int /* O - Number of jobs in queue */
326 show_jobs(const char *command
, /* I - Command name */
327 http_t
*http
, /* I - HTTP connection to server */
328 const char *dest
, /* I - Destination */
329 const char *user
, /* I - User */
330 const int id
, /* I - Job ID */
331 const int longstatus
) /* I - 1 if long report desired */
333 ipp_t
*request
, /* IPP Request */
334 *response
; /* IPP Response */
335 ipp_attribute_t
*attr
; /* Current attribute */
336 const char *jobdest
, /* Pointer into job-printer-uri */
337 *jobuser
, /* Pointer to job-originating-user-name */
338 *jobname
; /* Pointer to job-name */
339 ipp_jstate_t jobstate
; /* job-state */
340 int jobid
, /* job-id */
341 jobsize
, /* job-k-octets */
343 jobpriority
, /* job-priority */
345 jobcount
, /* Number of jobs */
346 jobcopies
, /* Number of copies */
347 rank
; /* Rank of job */
348 char resource
[1024]; /* Resource string */
349 char rankstr
[255]; /* Rank string */
350 char namestr
[1024]; /* Job name string */
351 static const char *ranks
[10] = /* Ranking strings */
366 DEBUG_printf(("show_jobs(%08x, %08x, %08x, %d, %d)\n", http
, dest
, user
, id
,
373 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
374 * the following attributes:
377 * attributes-natural-language
378 * job-uri or printer-uri
381 request
= ippNewRequest(id
? IPP_GET_JOB_ATTRIBUTES
: IPP_GET_JOBS
);
386 sprintf(resource
, "ipp://localhost/jobs/%d", id
);
388 strcpy(resource
, "ipp://localhost/jobs");
390 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
395 httpAssembleURIf(HTTP_URI_CODING_ALL
, resource
, sizeof(resource
), "ipp",
396 NULL
, "localhost", 0, "/printers/%s", dest
);
398 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
404 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
405 "requesting-user-name", NULL
, user
);
406 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
410 * Do the request and get back a response...
415 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
417 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
419 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
427 * Loop through the job list and display them...
430 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
433 * Skip leading attributes until we hit a job...
436 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
443 * Pull the needed attributes from this job...
451 jobstate
= IPP_JOB_PENDING
;
452 jobname
= "untitled";
457 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
459 if (!strcmp(attr
->name
, "job-id") &&
460 attr
->value_tag
== IPP_TAG_INTEGER
)
461 jobid
= attr
->values
[0].integer
;
463 if (!strcmp(attr
->name
, "job-k-octets") &&
464 attr
->value_tag
== IPP_TAG_INTEGER
)
465 jobsize
= attr
->values
[0].integer
;
468 if (!strcmp(attr
->name
, "job-priority") &&
469 attr
->value_tag
== IPP_TAG_INTEGER
)
470 jobpriority
= attr
->values
[0].integer
;
473 if (!strcmp(attr
->name
, "job-state") &&
474 attr
->value_tag
== IPP_TAG_ENUM
)
475 jobstate
= (ipp_jstate_t
)attr
->values
[0].integer
;
477 if (!strcmp(attr
->name
, "job-printer-uri") &&
478 attr
->value_tag
== IPP_TAG_URI
)
479 if ((jobdest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
482 if (!strcmp(attr
->name
, "job-originating-user-name") &&
483 attr
->value_tag
== IPP_TAG_NAME
)
484 jobuser
= attr
->values
[0].string
.text
;
486 if (!strcmp(attr
->name
, "job-name") &&
487 attr
->value_tag
== IPP_TAG_NAME
)
488 jobname
= attr
->values
[0].string
.text
;
490 if (!strcmp(attr
->name
, "copies") &&
491 attr
->value_tag
== IPP_TAG_INTEGER
)
492 jobcopies
= attr
->values
[0].integer
;
498 * See if we have everything needed...
501 if (jobdest
== NULL
|| jobid
== 0)
509 if (!longstatus
&& jobcount
== 0)
511 _cupsLangPuts(stdout
,
512 _("Rank Owner Pri Job Files"
515 _cupsLangPuts(stdout
,
516 _("Rank Owner Job File(s)"
526 if (jobstate
== IPP_JOB_PROCESSING
)
527 strcpy(rankstr
, "active");
531 * Make the rank show the "correct" suffix for each number
532 * (11-13 are the only special cases, for English anyways...)
535 if ((rank
% 100) >= 11 && (rank
% 100) <= 13)
536 snprintf(rankstr
, sizeof(rankstr
), "%dth", rank
);
538 snprintf(rankstr
, sizeof(rankstr
), "%d%s", rank
, ranks
[rank
% 10]);
545 _cupsLangPuts(stdout
, "\n");
548 snprintf(namestr
, sizeof(namestr
), "%d copies of %s", jobcopies
,
551 strlcpy(namestr
, jobname
, sizeof(namestr
));
553 _cupsLangPrintf(stdout
, _("%s: %-33.33s [job %d localhost]\n"),
554 jobuser
, rankstr
, jobid
);
555 _cupsLangPrintf(stdout
, _(" %-39.39s %.0f bytes\n"),
556 namestr
, 1024.0 * jobsize
);
560 _cupsLangPrintf(stdout
,
561 _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"),
562 rankstr
, jobuser
, jobpriority
, jobid
, jobname
,
565 _cupsLangPrintf(stdout
,
566 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"),
567 rankstr
, jobuser
, jobid
, jobname
, 1024.0 * jobsize
);
578 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
583 _cupsLangPuts(stdout
, _("no entries\n"));
590 * 'show_printer()' - Show printer status.
594 show_printer(const char *command
, /* I - Command name */
595 http_t
*http
, /* I - HTTP connection to server */
596 const char *dest
) /* I - Destination */
598 ipp_t
*request
, /* IPP Request */
599 *response
; /* IPP Response */
600 ipp_attribute_t
*attr
; /* Current attribute */
601 ipp_pstate_t state
; /* Printer state */
602 char uri
[HTTP_MAX_URI
]; /* Printer URI */
609 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
613 * attributes-natural-language
617 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
619 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
620 "localhost", 0, "/printers/%s", dest
);
621 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
622 "printer-uri", NULL
, uri
);
625 * Do the request and get back a response...
628 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
630 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
632 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
637 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
638 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
640 state
= IPP_PRINTER_STOPPED
;
644 case IPP_PRINTER_IDLE
:
645 _cupsLangPrintf(stdout
, _("%s is ready\n"), dest
);
647 case IPP_PRINTER_PROCESSING
:
648 _cupsLangPrintf(stdout
, _("%s is ready and printing\n"),
651 case IPP_PRINTER_STOPPED
:
652 _cupsLangPrintf(stdout
, _("%s is not ready\n"), dest
);
659 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
664 * 'usage()' - Show program usage.
670 _cupsLangPuts(stderr
,
671 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
672 "[-l] [+interval]\n"));
678 * End of "$Id: lpq.c 181 2006-06-22 20:01:18Z jlovell $".