]> git.ipfire.org Git - thirdparty/cups.git/blame - berkeley/lpq.c
Full sweep of all Clang warnings, plus some bug fixes for incorrect memcpy usage.
[thirdparty/cups.git] / berkeley / lpq.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
5a1d7a17 4 * "lpq" command for CUPS.
ef416fc2 5 *
7e86f2f6 6 * Copyright 2007-2014 by Apple Inc.
5a1d7a17 7 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 8 *
5a1d7a17
MS
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/".
ef416fc2 14 */
15
16/*
17 * Include necessary headers...
18 */
19
71e16022 20#include <cups/cups-private.h>
ef416fc2 21
22
23/*
24 * Local functions...
25 */
26
d6ae789d 27static http_t *connect_server(const char *, http_t *);
fa73b229 28static int show_jobs(const char *, http_t *, const char *,
29 const char *, const int, const int);
30static void show_printer(const char *, http_t *, const char *);
85dda01c 31static void usage(void) __attribute__((noreturn));
ef416fc2 32
33
34/*
35 * 'main()' - Parse options and commands.
36 */
37
38int
fa73b229 39main(int argc, /* I - Number of command-line arguments */
40 char *argv[]) /* I - Command-line arguments */
ef416fc2 41{
fa73b229 42 int i; /* Looping var */
43 http_t *http; /* Connection to server */
44 const char *dest, /* Desired printer */
45 *user, /* Desired user */
46 *val; /* Environment variable name */
47 char *instance; /* Printer instance */
48 int id, /* Desired job ID */
49 all, /* All printers */
50 interval, /* Reporting interval */
51 longstatus; /* Show file details */
c606bcae 52 cups_dest_t *named_dest; /* Named destination */
ef416fc2 53
54
07725fee 55 _cupsSetLocale(argv);
d09495fa 56
ef416fc2 57 /*
58 * Check for command-line options...
59 */
60
d6ae789d 61 http = NULL;
ef416fc2 62 dest = NULL;
63 user = NULL;
64 id = 0;
65 interval = 0;
66 longstatus = 0;
67 all = 0;
ef416fc2 68
69 for (i = 1; i < argc; i ++)
70 if (argv[i][0] == '+')
71 interval = atoi(argv[i] + 1);
72 else if (argv[i][0] == '-')
73 {
74 switch (argv[i][1])
75 {
76 case 'E' : /* Encrypt */
77#ifdef HAVE_SSL
d6ae789d 78 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
ef416fc2 79
80 if (http)
d6ae789d 81 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
ef416fc2 82#else
0837b7e8 83 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
ef416fc2 84 argv[0]);
85#endif /* HAVE_SSL */
86 break;
87
fa73b229 88 case 'U' : /* Username */
89 if (argv[i][2] != '\0')
90 cupsSetUser(argv[i] + 2);
91 else
92 {
93 i ++;
94 if (i >= argc)
95 {
96 _cupsLangPrintf(stderr,
97 _("%s: Error - expected username after "
0837b7e8 98 "\"-U\" option."), argv[0]);
fa73b229 99 return (1);
100 }
101
102 cupsSetUser(argv[i]);
103 }
104 break;
eac3a0a0 105
ef416fc2 106 case 'P' : /* Printer */
107 if (argv[i][2])
108 dest = argv[i] + 2;
109 else
110 {
111 i ++;
112
113 if (i >= argc)
114 {
115 httpClose(http);
eac3a0a0 116
ef416fc2 117 usage();
118 }
119
120 dest = argv[i];
121 }
122
123 if ((instance = strchr(dest, '/')) != NULL)
124 *instance++ = '\0';
125
d6ae789d 126 http = connect_server(argv[0], http);
127
c606bcae 128 if ((named_dest = cupsGetNamedDest(http, dest, instance)) == NULL)
ef416fc2 129 {
c606bcae
MS
130 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
131 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
132 _cupsLangPrintf(stderr,
133 _("%s: Error - add '/version=1.1' to server "
134 "name."), argv[0]);
135 else if (instance)
fa73b229 136 _cupsLangPrintf(stderr,
0837b7e8 137 _("%s: Error - unknown destination \"%s/%s\"."),
fa73b229 138 argv[0], dest, instance);
ef416fc2 139 else
0837b7e8 140 _cupsLangPrintf(stderr, _("%s: Unknown destination \"%s\"."),
fa73b229 141 argv[0], dest);
ef416fc2 142
143 return (1);
144 }
c606bcae
MS
145
146 cupsFreeDests(1, named_dest);
ef416fc2 147 break;
148
149 case 'a' : /* All printers */
150 all = 1;
151 break;
152
fa73b229 153 case 'h' : /* Connect to host */
d6ae789d 154 if (http)
155 {
fa73b229 156 httpClose(http);
d6ae789d 157 http = NULL;
158 }
fa73b229 159
160 if (argv[i][2] != '\0')
161 cupsSetServer(argv[i] + 2);
162 else
163 {
164 i ++;
165
166 if (i >= argc)
167 {
168 _cupsLangPrintf(stderr,
169 _("%s: Error - expected hostname after "
0837b7e8 170 "\"-h\" option."), argv[0]);
fa73b229 171 return (1);
172 }
173 else
174 cupsSetServer(argv[i]);
175 }
176 break;
177
ef416fc2 178 case 'l' : /* Long status */
179 longstatus = 1;
180 break;
181
182 default :
183 httpClose(http);
ef416fc2 184
185 usage();
ef416fc2 186 }
187 }
188 else if (isdigit(argv[i][0] & 255))
189 id = atoi(argv[i]);
190 else
191 user = argv[i];
192
d6ae789d 193 http = connect_server(argv[0], http);
194
ef416fc2 195 if (dest == NULL && !all)
196 {
c606bcae 197 if ((named_dest = cupsGetNamedDest(http, NULL, NULL)) == NULL)
ef416fc2 198 {
c606bcae
MS
199 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
200 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
201 {
202 _cupsLangPrintf(stderr,
203 _("%s: Error - add '/version=1.1' to server name."),
204 argv[0]);
205 return (1);
206 }
207
ef416fc2 208 val = NULL;
209
210 if ((dest = getenv("LPDEST")) == NULL)
211 {
212 if ((dest = getenv("PRINTER")) != NULL)
213 {
214 if (!strcmp(dest, "lp"))
215 dest = NULL;
216 else
217 val = "PRINTER";
218 }
219 }
220 else
221 val = "LPDEST";
222
c606bcae 223 if (dest && val)
fa73b229 224 _cupsLangPrintf(stderr,
84315f46 225 _("%s: Error - %s environment variable names "
0837b7e8
MS
226 "non-existent destination \"%s\"."), argv[0], val,
227 dest);
ef416fc2 228 else
fa73b229 229 _cupsLangPrintf(stderr,
84315f46 230 _("%s: Error - no default destination available."),
fa73b229 231 argv[0]);
ef416fc2 232 httpClose(http);
ef416fc2 233 return (1);
234 }
c606bcae
MS
235
236 dest = named_dest->name;
ef416fc2 237 }
238
239 /*
240 * Show the status in a loop...
241 */
242
243 for (;;)
244 {
245 if (dest)
fa73b229 246 show_printer(argv[0], http, dest);
ef416fc2 247
fa73b229 248 i = show_jobs(argv[0], http, dest, user, id, longstatus);
ef416fc2 249
250 if (i && interval)
251 {
252 fflush(stdout);
7e86f2f6 253 sleep((unsigned)interval);
ef416fc2 254 }
255 else
256 break;
257 }
258
259 /*
260 * Close the connection to the server and return...
261 */
262
ef416fc2 263 httpClose(http);
264
265 return (0);
266}
267
268
d6ae789d 269/*
270 * 'connect_server()' - Connect to the server as necessary...
271 */
272
273static http_t * /* O - New HTTP connection */
274connect_server(const char *command, /* I - Command name */
275 http_t *http) /* I - Current HTTP connection */
276{
277 if (!http)
278 {
279 http = httpConnectEncrypt(cupsServer(), ippPort(),
280 cupsEncryption());
281
282 if (http == NULL)
283 {
0837b7e8 284 _cupsLangPrintf(stderr, _("%s: Unable to connect to server."), command);
d6ae789d 285 exit(1);
286 }
287 }
288
289 return (http);
290}
291
292
ef416fc2 293/*
294 * 'show_jobs()' - Show jobs.
295 */
296
fa73b229 297static int /* O - Number of jobs in queue */
298show_jobs(const char *command, /* I - Command name */
299 http_t *http, /* I - HTTP connection to server */
300 const char *dest, /* I - Destination */
301 const char *user, /* I - User */
302 const int id, /* I - Job ID */
303 const int longstatus) /* I - 1 if long report desired */
ef416fc2 304{
fa73b229 305 ipp_t *request, /* IPP Request */
306 *response; /* IPP Response */
307 ipp_attribute_t *attr; /* Current attribute */
308 const char *jobdest, /* Pointer into job-printer-uri */
309 *jobuser, /* Pointer to job-originating-user-name */
310 *jobname; /* Pointer to job-name */
311 ipp_jstate_t jobstate; /* job-state */
312 int jobid, /* job-id */
313 jobsize, /* job-k-octets */
fa73b229 314 jobcount, /* Number of jobs */
315 jobcopies, /* Number of copies */
316 rank; /* Rank of job */
317 char resource[1024]; /* Resource string */
318 char rankstr[255]; /* Rank string */
319 char namestr[1024]; /* Job name string */
5a662dc0
MS
320 static const char * const jobattrs[] =/* Job attributes we want to see */
321 {
322 "copies",
323 "job-id",
324 "job-k-octets",
325 "job-name",
326 "job-originating-user-name",
327 "job-printer-uri",
328 "job-priority",
329 "job-state"
330 };
331 static const char * const ranks[10] = /* Ranking strings */
ef416fc2 332 {
333 "th",
334 "st",
335 "nd",
336 "rd",
337 "th",
338 "th",
339 "th",
340 "th",
341 "th",
342 "th"
343 };
344
345
ae71f5de
MS
346 DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%d)\n",
347 http, dest, user, id, longstatus));
ef416fc2 348
349 if (http == NULL)
350 return (0);
351
352 /*
353 * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires
354 * the following attributes:
355 *
356 * attributes-charset
357 * attributes-natural-language
358 * job-uri or printer-uri
5a662dc0 359 * requested-attributes
37e7e6e0 360 * requesting-user-name
ef416fc2 361 */
362
fa73b229 363 request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
ef416fc2 364
1340db2d 365 if (id)
ef416fc2 366 {
1340db2d 367 snprintf(resource, sizeof(resource), "ipp://localhost/jobs/%d", id);
ef416fc2 368 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
369 NULL, resource);
370 }
1340db2d 371 else if (dest)
ef416fc2 372 {
a4d04587 373 httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
374 NULL, "localhost", 0, "/printers/%s", dest);
ef416fc2 375
376 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
377 NULL, resource);
378 }
1340db2d
MS
379 else
380 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
381 NULL, "ipp://localhost/");
ef416fc2 382
383 if (user)
384 {
385 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
386 "requesting-user-name", NULL, user);
387 ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
388 }
37e7e6e0
MS
389 else
390 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
391 "requesting-user-name", NULL, cupsUser());
ef416fc2 392
5a662dc0
MS
393 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
394 "requested-attributes",
395 (int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
396
ef416fc2 397 /*
398 * Do the request and get back a response...
399 */
400
401 jobcount = 0;
402
403 if ((response = cupsDoRequest(http, request, "/")) != NULL)
404 {
405 if (response->request.status.status_code > IPP_OK_CONFLICT)
406 {
0837b7e8 407 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 408 ippDelete(response);
409 return (0);
410 }
411
412 rank = 1;
413
414 /*
415 * Loop through the job list and display them...
416 */
417
418 for (attr = response->attrs; attr != NULL; attr = attr->next)
419 {
420 /*
421 * Skip leading attributes until we hit a job...
422 */
423
424 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
425 attr = attr->next;
426
427 if (attr == NULL)
428 break;
429
430 /*
431 * Pull the needed attributes from this job...
432 */
433
434 jobid = 0;
435 jobsize = 0;
ef416fc2 436 jobstate = IPP_JOB_PENDING;
37e7e6e0
MS
437 jobname = "unknown";
438 jobuser = "unknown";
ef416fc2 439 jobdest = NULL;
440 jobcopies = 1;
441
442 while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
443 {
fa73b229 444 if (!strcmp(attr->name, "job-id") &&
ef416fc2 445 attr->value_tag == IPP_TAG_INTEGER)
446 jobid = attr->values[0].integer;
447
fa73b229 448 if (!strcmp(attr->name, "job-k-octets") &&
ef416fc2 449 attr->value_tag == IPP_TAG_INTEGER)
450 jobsize = attr->values[0].integer;
451
fa73b229 452 if (!strcmp(attr->name, "job-state") &&
ef416fc2 453 attr->value_tag == IPP_TAG_ENUM)
454 jobstate = (ipp_jstate_t)attr->values[0].integer;
455
fa73b229 456 if (!strcmp(attr->name, "job-printer-uri") &&
ef416fc2 457 attr->value_tag == IPP_TAG_URI)
458 if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
459 jobdest ++;
460
fa73b229 461 if (!strcmp(attr->name, "job-originating-user-name") &&
ef416fc2 462 attr->value_tag == IPP_TAG_NAME)
463 jobuser = attr->values[0].string.text;
464
fa73b229 465 if (!strcmp(attr->name, "job-name") &&
ef416fc2 466 attr->value_tag == IPP_TAG_NAME)
467 jobname = attr->values[0].string.text;
468
fa73b229 469 if (!strcmp(attr->name, "copies") &&
ef416fc2 470 attr->value_tag == IPP_TAG_INTEGER)
471 jobcopies = attr->values[0].integer;
472
473 attr = attr->next;
474 }
475
476 /*
477 * See if we have everything needed...
478 */
479
480 if (jobdest == NULL || jobid == 0)
481 {
482 if (attr == NULL)
483 break;
484 else
485 continue;
486 }
487
488 if (!longstatus && jobcount == 0)
fa73b229 489 _cupsLangPuts(stdout,
ef416fc2 490 _("Rank Owner Job File(s)"
0837b7e8 491 " Total Size"));
ef416fc2 492
493 jobcount ++;
494
495 /*
496 * Display the job...
497 */
498
499 if (jobstate == IPP_JOB_PROCESSING)
5a9febac 500 strlcpy(rankstr, "active", sizeof(rankstr));
ef416fc2 501 else
502 {
503 /*
504 * Make the rank show the "correct" suffix for each number
505 * (11-13 are the only special cases, for English anyways...)
506 */
507
508 if ((rank % 100) >= 11 && (rank % 100) <= 13)
509 snprintf(rankstr, sizeof(rankstr), "%dth", rank);
510 else
511 snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
512
513 rank ++;
514 }
515
516 if (longstatus)
517 {
fa73b229 518 _cupsLangPuts(stdout, "\n");
ef416fc2 519
520 if (jobcopies > 1)
521 snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
522 jobname);
523 else
524 strlcpy(namestr, jobname, sizeof(namestr));
525
0837b7e8 526 _cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]"),
ef416fc2 527 jobuser, rankstr, jobid);
0837b7e8 528 _cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes"),
ef416fc2 529 namestr, 1024.0 * jobsize);
530 }
531 else
fa73b229 532 _cupsLangPrintf(stdout,
0837b7e8 533 _("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
ef416fc2 534 rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
ef416fc2 535
536 if (attr == NULL)
537 break;
538 }
539
540 ippDelete(response);
541 }
542 else
543 {
0837b7e8 544 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 545 return (0);
546 }
547
548 if (jobcount == 0)
0837b7e8 549 _cupsLangPuts(stdout, _("no entries"));
ef416fc2 550
551 return (jobcount);
552}
553
554
555/*
556 * 'show_printer()' - Show printer status.
557 */
558
559static void
fa73b229 560show_printer(const char *command, /* I - Command name */
561 http_t *http, /* I - HTTP connection to server */
562 const char *dest) /* I - Destination */
ef416fc2 563{
fa73b229 564 ipp_t *request, /* IPP Request */
565 *response; /* IPP Response */
566 ipp_attribute_t *attr; /* Current attribute */
567 ipp_pstate_t state; /* Printer state */
568 char uri[HTTP_MAX_URI]; /* Printer URI */
ef416fc2 569
570
571 if (http == NULL)
572 return;
573
574 /*
575 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
576 * attributes:
577 *
578 * attributes-charset
579 * attributes-natural-language
580 * printer-uri
581 */
582
fa73b229 583 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 584
a4d04587 585 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
586 "localhost", 0, "/printers/%s", dest);
ef416fc2 587 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
588 "printer-uri", NULL, uri);
589
590 /*
591 * Do the request and get back a response...
592 */
593
594 if ((response = cupsDoRequest(http, request, "/")) != NULL)
595 {
596 if (response->request.status.status_code > IPP_OK_CONFLICT)
597 {
0837b7e8 598 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 599 ippDelete(response);
600 return;
601 }
602
603 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
604 state = (ipp_pstate_t)attr->values[0].integer;
605 else
606 state = IPP_PRINTER_STOPPED;
607
608 switch (state)
609 {
610 case IPP_PRINTER_IDLE :
0837b7e8 611 _cupsLangPrintf(stdout, _("%s is ready"), dest);
ef416fc2 612 break;
613 case IPP_PRINTER_PROCESSING :
0837b7e8 614 _cupsLangPrintf(stdout, _("%s is ready and printing"),
ef416fc2 615 dest);
616 break;
617 case IPP_PRINTER_STOPPED :
0837b7e8 618 _cupsLangPrintf(stdout, _("%s is not ready"), dest);
ef416fc2 619 break;
620 }
621
622 ippDelete(response);
623 }
624 else
0837b7e8 625 _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
ef416fc2 626}
627
628
629/*
630 * 'usage()' - Show program usage.
631 */
632
633static void
634usage(void)
635{
fa73b229 636 _cupsLangPuts(stderr,
637 _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
0837b7e8 638 "[-l] [+interval]"));
ef416fc2 639 exit(1);
640}
641
642
643/*
f2d18633 644 * End of "$Id$".
ef416fc2 645 */