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