]> git.ipfire.org Git - thirdparty/cups.git/blame - berkeley/lpc.c
Merge pull request #1311 from weblate/weblate-cups-cups
[thirdparty/cups.git] / berkeley / lpc.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * "lpc" command for CUPS.
ef416fc2 3 *
76b6aade 4 * Copyright © 2020-2024 by OpenPrinting.
7e86f2f6
MS
5 * Copyright 2007-2014 by Apple Inc.
6 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 7 *
e3101897 8 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
ef416fc2 9 */
10
11/*
12 * Include necessary headers...
13 */
14
71e16022 15#include <cups/cups-private.h>
ef416fc2 16
17
18/*
19 * Local functions...
20 */
21
7e86f2f6 22static int compare_strings(const char *, const char *, size_t);
ef416fc2 23static void do_command(http_t *, const char *, const char *);
24static void show_help(const char *);
e6be1092 25static void show_prompt(const char *message);
ef416fc2 26static void show_status(http_t *, const char *);
27
28
29/*
30 * 'main()' - Parse options and commands.
31 */
32
33int
34main(int argc, /* I - Number of command-line arguments */
35 char *argv[]) /* I - Command-line arguments */
36{
37 http_t *http; /* Connection to server */
38 char line[1024], /* Input line from user */
39 *params; /* Pointer to parameters */
40
41
07725fee 42 _cupsSetLocale(argv);
d09495fa 43
ef416fc2 44 /*
45 * Connect to the scheduler...
46 */
47
48 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
49
50 if (argc > 1)
51 {
52 /*
53 * Process a single command on the command-line...
54 */
55
56 do_command(http, argv[1], argv[2]);
57 }
58 else
59 {
60 /*
61 * Do the command prompt thing...
62 */
63
e6be1092 64 show_prompt(_("lpc> "));
ef416fc2 65 while (fgets(line, sizeof(line), stdin) != NULL)
66 {
67 /*
68 * Strip trailing whitespace...
69 */
70
71 for (params = line + strlen(line) - 1; params >= line;)
72 if (!isspace(*params & 255))
73 break;
74 else
75 *params-- = '\0';
76
77 /*
78 * Strip leading whitespace...
79 */
80
81 for (params = line; isspace(*params & 255); params ++);
82
83 if (params > line)
84 _cups_strcpy(line, params);
85
86 if (!line[0])
87 {
88 /*
89 * Nothing left, just show a prompt...
90 */
91
e6be1092 92 show_prompt(_("lpc> "));
ef416fc2 93 continue;
94 }
95
96 /*
97 * Find any options in the string...
98 */
99
100 for (params = line; *params != '\0'; params ++)
101 if (isspace(*params & 255))
102 break;
103
104 /*
105 * Remove whitespace between the command and parameters...
106 */
107
108 while (isspace(*params & 255))
109 *params++ = '\0';
110
111 /*
112 * The "quit" and "exit" commands exit; otherwise, process as needed...
113 */
114
115 if (!compare_strings(line, "quit", 1) ||
116 !compare_strings(line, "exit", 2))
117 break;
118
119 if (*params == '\0')
120 do_command(http, line, NULL);
121 else
122 do_command(http, line, params);
123
124 /*
125 * Put another prompt out to the user...
126 */
127
e6be1092 128 show_prompt(_("lpc> "));
ef416fc2 129 }
130 }
131
132 /*
133 * Close the connection to the server and return...
134 */
135
136 httpClose(http);
137
138 return (0);
139}
140
141
142/*
143 * 'compare_strings()' - Compare two command-line strings.
144 */
145
146static int /* O - -1 or 1 = no match, 0 = match */
147compare_strings(const char *s, /* I - Command-line string */
148 const char *t, /* I - Option string */
7e86f2f6 149 size_t tmin) /* I - Minimum number of unique chars in option */
ef416fc2 150{
7e86f2f6 151 size_t slen; /* Length of command-line string */
ef416fc2 152
153
154 slen = strlen(s);
155 if (slen < tmin)
156 return (-1);
157 else
158 return (strncmp(s, t, slen));
159}
160
161
162/*
163 * 'do_command()' - Do an lpc command...
164 */
165
166static void
167do_command(http_t *http, /* I - HTTP connection to server */
168 const char *command, /* I - Command string */
169 const char *params) /* I - Parameters for command */
170{
171 if (!compare_strings(command, "status", 4))
172 show_status(http, params);
173 else if (!compare_strings(command, "help", 1) || !strcmp(command, "?"))
174 show_help(params);
175 else
fa73b229 176 _cupsLangPrintf(stdout,
0837b7e8 177 _("%s is not implemented by the CUPS version of lpc."),
ef416fc2 178 command);
179}
180
181
182/*
183 * 'show_help()' - Show help messages.
184 */
185
186static void
187show_help(const char *command) /* I - Command to describe or NULL */
188{
189 if (!command)
190 {
fa73b229 191 _cupsLangPrintf(stdout,
ef416fc2 192 _("Commands may be abbreviated. Commands are:\n"
193 "\n"
0837b7e8 194 "exit help quit status ?"));
ef416fc2 195 }
196 else if (!compare_strings(command, "help", 1) || !strcmp(command, "?"))
0837b7e8 197 _cupsLangPrintf(stdout, _("help\t\tGet help on commands."));
ef416fc2 198 else if (!compare_strings(command, "status", 4))
0837b7e8 199 _cupsLangPrintf(stdout, _("status\t\tShow status of daemon and queue."));
ef416fc2 200 else
0837b7e8 201 _cupsLangPrintf(stdout, _("?Invalid help command unknown."));
ef416fc2 202}
203
204
e6be1092
MS
205/*
206 * 'show_prompt()' - Show a localized prompt message.
207 */
208
209static void
210show_prompt(const char *message) /* I - Message string to use */
211{
212 ssize_t bytes; /* Number of bytes formatted */
213 char output[8192]; /* Message buffer */
214 cups_lang_t *lang = cupsLangDefault();
215 /* Default language */
216
217 /*
218 * Transcode to the destination charset and write the prompt...
219 */
220
221 if ((bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)_cupsLangString(lang, message), sizeof(output), lang->encoding)) > 0)
222 {
223 fwrite(output, 1, (size_t)bytes, stdout);
224 fflush(stdout);
225 }
226}
227
228
ef416fc2 229/*
230 * 'show_status()' - Show printers.
231 */
232
233static void
234show_status(http_t *http, /* I - HTTP connection to server */
235 const char *dests) /* I - Destinations */
236{
237 ipp_t *request, /* IPP Request */
26d47ec6 238 *response; /* IPP Response */
239 ipp_attribute_t *attr; /* Current attribute */
ef416fc2 240 char *printer, /* Printer name */
241 *device, /* Device URI */
242 *delimiter; /* Char search result */
243 ipp_pstate_t pstate; /* Printer state */
244 int accepting; /* Is printer accepting jobs? */
245 int jobcount; /* Count of current jobs */
246 const char *dptr, /* Pointer into destination list */
247 *ptr; /* Pointer into printer name */
248 int match; /* Non-zero if this job matches */
ef416fc2 249 static const char *requested[] = /* Requested attributes */
250 {
ef416fc2 251 "device-uri",
26d47ec6 252 "printer-is-accepting-jobs",
253 "printer-name",
ef416fc2 254 "printer-state",
26d47ec6 255 "queued-job-count"
ef416fc2 256 };
257
258
ef416fc2 259 if (http == NULL)
260 return;
261
262 /*
263 * Build a CUPS_GET_PRINTERS request, which requires the following
264 * attributes:
265 *
266 * attributes-charset
267 * attributes-natural-language
268 */
269
4f05fa3b 270 request = ippNewRequest(IPP_OP_CUPS_GET_PRINTERS);
ef416fc2 271
272 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
273 "requested-attributes", sizeof(requested) / sizeof(requested[0]),
274 NULL, requested);
275
276 /*
277 * Do the request and get back a response...
278 */
279
280 if ((response = cupsDoRequest(http, request, "/")) != NULL)
281 {
ef416fc2 282 /*
283 * Loop through the printers returned in the list and display
284 * their status...
285 */
286
287 for (attr = response->attrs; attr != NULL; attr = attr->next)
288 {
289 /*
290 * Skip leading attributes until we hit a job...
291 */
292
293 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
294 attr = attr->next;
295
296 if (attr == NULL)
297 break;
298
299 /*
300 * Pull the needed attributes from this job...
301 */
302
303 printer = NULL;
304 device = "file:/dev/null";
4f05fa3b 305 pstate = IPP_PSTATE_IDLE;
ef416fc2 306 jobcount = 0;
307 accepting = 1;
308
309 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
310 {
ef416fc2 311 if (!strcmp(attr->name, "device-uri") &&
312 attr->value_tag == IPP_TAG_URI)
313 device = attr->values[0].string.text;
26d47ec6 314 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
315 attr->value_tag == IPP_TAG_BOOLEAN)
ef416fc2 316 accepting = attr->values[0].boolean;
26d47ec6 317 else if (!strcmp(attr->name, "printer-name") &&
318 attr->value_tag == IPP_TAG_NAME)
319 printer = attr->values[0].string.text;
320 else if (!strcmp(attr->name, "printer-state") &&
321 attr->value_tag == IPP_TAG_ENUM)
322 pstate = (ipp_pstate_t)attr->values[0].integer;
323 else if (!strcmp(attr->name, "queued-job-count") &&
324 attr->value_tag == IPP_TAG_INTEGER)
325 jobcount = attr->values[0].integer;
ef416fc2 326
327 attr = attr->next;
328 }
329
330 /*
331 * See if we have everything needed...
332 */
333
334 if (printer == NULL)
335 {
336 if (attr == NULL)
337 break;
338 else
339 continue;
340 }
341
342 /*
343 * A single 'all' printer name is special, meaning all printers.
344 */
345
346 if (dests != NULL && !strcmp(dests, "all"))
347 dests = NULL;
348
349 /*
350 * See if this is a printer we're interested in...
351 */
352
353 match = dests == NULL;
354
355 if (dests != NULL)
356 {
357 for (dptr = dests; *dptr != '\0';)
358 {
359 /*
360 * Skip leading whitespace and commas...
361 */
362
363 while (isspace(*dptr & 255) || *dptr == ',')
364 dptr ++;
365
366 if (*dptr == '\0')
367 break;
368
369 /*
370 * Compare names...
371 */
372
373 for (ptr = printer;
374 *ptr != '\0' && *dptr != '\0' && *ptr == *dptr;
82cc1f9a
MS
375 ptr ++, dptr ++)
376 /* do nothing */;
ef416fc2 377
26d47ec6 378 if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' ||
379 isspace(*dptr & 255)))
ef416fc2 380 {
381 match = 1;
382 break;
383 }
384
385 /*
386 * Skip trailing junk...
387 */
388
389 while (!isspace(*dptr & 255) && *dptr != '\0')
390 dptr ++;
391 while (isspace(*dptr & 255) || *dptr == ',')
392 dptr ++;
393
394 if (*dptr == '\0')
395 break;
396 }
397 }
398
399 /*
400 * Display the printer entry if needed...
401 */
402
403 if (match)
404 {
ef416fc2 405 /*
406 * Display it...
407 */
408
409 printf("%s:\n", printer);
410 if (!strncmp(device, "file:", 5))
fa73b229 411 _cupsLangPrintf(stdout,
0837b7e8 412 _("\tprinter is on device \'%s\' speed -1"),
ef416fc2 413 device + 5);
414 else
415 {
416 /*
417 * Just show the scheme...
418 */
419
420 if ((delimiter = strchr(device, ':')) != NULL )
421 {
422 *delimiter = '\0';
fa73b229 423 _cupsLangPrintf(stdout,
0837b7e8 424 _("\tprinter is on device \'%s\' speed -1"),
ef416fc2 425 device);
426 }
427 }
428
429 if (accepting)
0837b7e8 430 _cupsLangPuts(stdout, _("\tqueuing is enabled"));
ef416fc2 431 else
0837b7e8 432 _cupsLangPuts(stdout, _("\tqueuing is disabled"));
ef416fc2 433
4f05fa3b 434 if (pstate != IPP_PSTATE_STOPPED)
0837b7e8 435 _cupsLangPuts(stdout, _("\tprinting is enabled"));
ef416fc2 436 else
0837b7e8 437 _cupsLangPuts(stdout, _("\tprinting is disabled"));
ef416fc2 438
439 if (jobcount == 0)
0837b7e8 440 _cupsLangPuts(stdout, _("\tno entries"));
ef416fc2 441 else
0837b7e8 442 _cupsLangPrintf(stdout, _("\t%d entries"), jobcount);
ef416fc2 443
0837b7e8 444 _cupsLangPuts(stdout, _("\tdaemon present"));
ef416fc2 445 }
446
447 if (attr == NULL)
448 break;
449 }
450
451 ippDelete(response);
452 }
453}