]> git.ipfire.org Git - thirdparty/cups.git/blob - berkeley/lpc.c
e81f166a83ccbf580cd8302eb5e12a721726d257
[thirdparty/cups.git] / berkeley / lpc.c
1 /*
2 * "lpc" command for CUPS.
3 *
4 * Copyright © 2020-2024 by OpenPrinting.
5 * Copyright 2007-2014 by Apple Inc.
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include <cups/cups-private.h>
16
17
18 /*
19 * Local functions...
20 */
21
22 static int compare_strings(const char *, const char *, size_t);
23 static void do_command(http_t *, const char *, const char *);
24 static void show_help(const char *);
25 static void show_prompt(const char *message);
26 static void show_status(http_t *, const char *);
27
28
29 /*
30 * 'main()' - Parse options and commands.
31 */
32
33 int
34 main(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
42 _cupsSetLocale(argv);
43
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
64 show_prompt(_("lpc> "));
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
92 show_prompt(_("lpc> "));
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
128 show_prompt(_("lpc> "));
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
146 static int /* O - -1 or 1 = no match, 0 = match */
147 compare_strings(const char *s, /* I - Command-line string */
148 const char *t, /* I - Option string */
149 size_t tmin) /* I - Minimum number of unique chars in option */
150 {
151 size_t slen; /* Length of command-line string */
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
166 static void
167 do_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
176 _cupsLangPrintf(stdout,
177 _("%s is not implemented by the CUPS version of lpc."),
178 command);
179 }
180
181
182 /*
183 * 'show_help()' - Show help messages.
184 */
185
186 static void
187 show_help(const char *command) /* I - Command to describe or NULL */
188 {
189 if (!command)
190 {
191 _cupsLangPrintf(stdout,
192 _("Commands may be abbreviated. Commands are:\n"
193 "\n"
194 "exit help quit status ?"));
195 }
196 else if (!compare_strings(command, "help", 1) || !strcmp(command, "?"))
197 _cupsLangPrintf(stdout, _("help\t\tGet help on commands."));
198 else if (!compare_strings(command, "status", 4))
199 _cupsLangPrintf(stdout, _("status\t\tShow status of daemon and queue."));
200 else
201 _cupsLangPrintf(stdout, _("?Invalid help command unknown."));
202 }
203
204
205 /*
206 * 'show_prompt()' - Show a localized prompt message.
207 */
208
209 static void
210 show_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
229 /*
230 * 'show_status()' - Show printers.
231 */
232
233 static void
234 show_status(http_t *http, /* I - HTTP connection to server */
235 const char *dests) /* I - Destinations */
236 {
237 ipp_t *request, /* IPP Request */
238 *response; /* IPP Response */
239 ipp_attribute_t *attr; /* Current attribute */
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 */
249 static const char *requested[] = /* Requested attributes */
250 {
251 "device-uri",
252 "printer-is-accepting-jobs",
253 "printer-name",
254 "printer-state",
255 "queued-job-count"
256 };
257
258
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
270 request = ippNewRequest(IPP_OP_CUPS_GET_PRINTERS);
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 {
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";
305 pstate = IPP_PSTATE_IDLE;
306 jobcount = 0;
307 accepting = 1;
308
309 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
310 {
311 if (!strcmp(attr->name, "device-uri") &&
312 attr->value_tag == IPP_TAG_URI)
313 device = attr->values[0].string.text;
314 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
315 attr->value_tag == IPP_TAG_BOOLEAN)
316 accepting = attr->values[0].boolean;
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;
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;
375 ptr ++, dptr ++)
376 /* do nothing */;
377
378 if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' ||
379 isspace(*dptr & 255)))
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 {
405 /*
406 * Display it...
407 */
408
409 printf("%s:\n", printer);
410 if (!strncmp(device, "file:", 5))
411 _cupsLangPrintf(stdout,
412 _("\tprinter is on device \'%s\' speed -1"),
413 device + 5);
414 else
415 {
416 /*
417 * Just show the scheme...
418 */
419
420 if ((delimiter = strchr(device, ':')) != NULL )
421 {
422 *delimiter = '\0';
423 _cupsLangPrintf(stdout,
424 _("\tprinter is on device \'%s\' speed -1"),
425 device);
426 }
427 }
428
429 if (accepting)
430 _cupsLangPuts(stdout, _("\tqueuing is enabled"));
431 else
432 _cupsLangPuts(stdout, _("\tqueuing is disabled"));
433
434 if (pstate != IPP_PSTATE_STOPPED)
435 _cupsLangPuts(stdout, _("\tprinting is enabled"));
436 else
437 _cupsLangPuts(stdout, _("\tprinting is disabled"));
438
439 if (jobcount == 0)
440 _cupsLangPuts(stdout, _("\tno entries"));
441 else
442 _cupsLangPrintf(stdout, _("\t%d entries"), jobcount);
443
444 _cupsLangPuts(stdout, _("\tdaemon present"));
445 }
446
447 if (attr == NULL)
448 break;
449 }
450
451 ippDelete(response);
452 }
453 }