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