1/*
2 * "$Id: printers.c 11934 2014-06-17 18:58:29Z msweet $"
3 *
4 * Printer status CGI for CUPS.
5 *
6 * Copyright 2007-2014 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
16/*
17 * Include necessary headers...
18 */
19
20#include "cgi-private.h"
21#include <errno.h>
22
23
24/*
25 * Local functions...
26 */
27
28static void	do_printer_op(http_t *http, const char *printer, ipp_op_t op,
29		              const char *title);
30static void	show_all_printers(http_t *http, const char *username);
31static void	show_printer(http_t *http, const char *printer);
32
33
34/*
35 * 'main()' - Main entry for CGI.
36 */
37
38int					/* O - Exit status */
39main(void)
40{
41  const char	*printer;		/* Printer name */
42  const char	*user;			/* Username */
43  http_t	*http;			/* Connection to the server */
44  ipp_t		*request,		/* IPP request */
45		*response;		/* IPP response */
46  ipp_attribute_t *attr;		/* IPP attribute */
47  const char	*op;			/* Operation to perform, if any */
48  static const char *def_attrs[] =	/* Attributes for default printer */
49		{
50		  "printer-name",
51		  "printer-uri-supported"
52		};
53
54
55 /*
56  * Get any form variables...
57  */
58
59  cgiInitialize();
60
61  op = cgiGetVariable("OP");
62
63 /*
64  * Set the web interface section...
65  */
66
67  cgiSetVariable("SECTION", "printers");
68  cgiSetVariable("REFRESH_PAGE", "");
69
70 /*
71  * See if we are displaying a printer or all printers...
72  */
73
74  if ((printer = getenv("PATH_INFO")) != NULL)
75  {
76    printer ++;
77
78    if (!*printer)
79      printer = NULL;
80
81    if (printer)
82      cgiSetVariable("PRINTER_NAME", printer);
83  }
84
85 /*
86  * See who is logged in...
87  */
88
89  user = getenv("REMOTE_USER");
90
91 /*
92  * Connect to the HTTP server...
93  */
94
95  http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
96
97 /*
98  * Get the default printer...
99  */
100
101  if (!op || !cgiIsPOST())
102  {
103   /*
104    * Get the default destination...
105    */
106
107    request = ippNewRequest(CUPS_GET_DEFAULT);
108
109    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
110                  "requested-attributes",
111		  sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs);
112
113    if ((response = cupsDoRequest(http, request, "/")) != NULL)
114    {
115      if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
116        cgiSetVariable("DEFAULT_NAME", attr->values[0].string.text);
117
118      if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL)
119      {
120	char	url[HTTP_MAX_URI];	/* New URL */
121
122
123        cgiSetVariable("DEFAULT_URI",
124	               cgiRewriteURL(attr->values[0].string.text,
125		                     url, sizeof(url), NULL));
126      }
127
128      ippDelete(response);
129    }
130
131   /*
132    * See if we need to show a list of printers or the status of a
133    * single printer...
134    */
135
136    if (!printer)
137      show_all_printers(http, user);
138    else
139      show_printer(http, printer);
140  }
141  else if (printer)
142  {
143    if (!*op)
144    {
145      const char *server_port = getenv("SERVER_PORT");
146					/* Port number string */
147      int	port = atoi(server_port ? server_port : "0");
148      					/* Port number */
149      char	uri[1024];		/* URL */
150
151      httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
152		       getenv("HTTPS") ? "https" : "http", NULL,
153		       getenv("SERVER_NAME"), port, "/printers/%s", printer);
154
155      printf("Location: %s\n\n", uri);
156    }
157    else if (!strcmp(op, "start-printer"))
158      do_printer_op(http, printer, IPP_RESUME_PRINTER,
159                    cgiText(_("Resume Printer")));
160    else if (!strcmp(op, "stop-printer"))
161      do_printer_op(http, printer, IPP_PAUSE_PRINTER,
162                    cgiText(_("Pause Printer")));
163    else if (!strcmp(op, "accept-jobs"))
164      do_printer_op(http, printer, CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs")));
165    else if (!strcmp(op, "reject-jobs"))
166      do_printer_op(http, printer, CUPS_REJECT_JOBS, cgiText(_("Reject Jobs")));
167    else if (!strcmp(op, "cancel-jobs"))
168      do_printer_op(http, printer, IPP_OP_CANCEL_JOBS, cgiText(_("Cancel Jobs")));
169    else if (!_cups_strcasecmp(op, "print-self-test-page"))
170      cgiPrintCommand(http, printer, "PrintSelfTestPage",
171                      cgiText(_("Print Self-Test Page")));
172    else if (!_cups_strcasecmp(op, "clean-print-heads"))
173      cgiPrintCommand(http, printer, "Clean all",
174                      cgiText(_("Clean Print Heads")));
175    else if (!_cups_strcasecmp(op, "print-test-page"))
176      cgiPrintTestPage(http, printer);
177    else if (!_cups_strcasecmp(op, "move-jobs"))
178      cgiMoveJobs(http, printer, 0);
179    else
180    {
181     /*
182      * Unknown/bad operation...
183      */
184
185      cgiStartHTML(printer);
186      cgiCopyTemplateLang("error-op.tmpl");
187      cgiEndHTML();
188    }
189  }
190  else
191  {
192   /*
193    * Unknown/bad operation...
194    */
195
196    cgiStartHTML(cgiText(_("Printers")));
197    cgiCopyTemplateLang("error-op.tmpl");
198    cgiEndHTML();
199  }
200
201 /*
202  * Close the HTTP server connection...
203  */
204
205  httpClose(http);
206
207 /*
208  * Return with no errors...
209  */
210
211  return (0);
212}
213
214
215/*
216 * 'do_printer_op()' - Do a printer operation.
217 */
218
219static void
220do_printer_op(http_t      *http,	/* I - HTTP connection */
221              const char  *printer,	/* I - Printer name */
222	      ipp_op_t    op,		/* I - Operation to perform */
223	      const char  *title)	/* I - Title of page */
224{
225  ipp_t		*request;		/* IPP request */
226  char		uri[HTTP_MAX_URI],	/* Printer URI */
227		resource[HTTP_MAX_URI];	/* Path for request */
228
229
230 /*
231  * Build a printer request, which requires the following
232  * attributes:
233  *
234  *    attributes-charset
235  *    attributes-natural-language
236  *    printer-uri
237  */
238
239  request = ippNewRequest(op);
240
241  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
242                   "localhost", 0, "/printers/%s", printer);
243  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
244               NULL, uri);
245
246 /*
247  * Do the request and get back a response...
248  */
249
250  snprintf(resource, sizeof(resource), "/printers/%s", printer);
251  ippDelete(cupsDoRequest(http, request, resource));
252
253  if (cupsLastError() == IPP_NOT_AUTHORIZED)
254  {
255    puts("Status: 401\n");
256    exit(0);
257  }
258  else if (cupsLastError() > IPP_OK_CONFLICT)
259  {
260    cgiStartHTML(title);
261    cgiShowIPPError(_("Unable to do maintenance command"));
262  }
263  else
264  {
265   /*
266    * Redirect successful updates back to the printer page...
267    */
268
269    char	url[1024],		/* Printer/class URL */
270		refresh[1024];		/* Refresh URL */
271
272
273    cgiRewriteURL(uri, url, sizeof(url), NULL);
274    cgiFormEncode(uri, url, sizeof(uri));
275    snprintf(refresh, sizeof(refresh), "5;URL=%s", uri);
276    cgiSetVariable("refresh_page", refresh);
277
278    cgiStartHTML(title);
279
280    if (op == IPP_PAUSE_PRINTER)
281      cgiCopyTemplateLang("printer-stop.tmpl");
282    else if (op == IPP_RESUME_PRINTER)
283      cgiCopyTemplateLang("printer-start.tmpl");
284    else if (op == CUPS_ACCEPT_JOBS)
285      cgiCopyTemplateLang("printer-accept.tmpl");
286    else if (op == CUPS_REJECT_JOBS)
287      cgiCopyTemplateLang("printer-reject.tmpl");
288    else if (op == IPP_OP_CANCEL_JOBS)
289      cgiCopyTemplateLang("printer-cancel-jobs.tmpl");
290  }
291
292  cgiEndHTML();
293}
294
295
296/*
297 * 'show_all_printers()' - Show all printers...
298 */
299
300static void
301show_all_printers(http_t     *http,	/* I - Connection to server */
302                  const char *user)	/* I - Username */
303{
304  int			i;		/* Looping var */
305  ipp_t			*request,	/* IPP request */
306			*response;	/* IPP response */
307  cups_array_t		*printers;	/* Array of printer objects */
308  ipp_attribute_t	*printer;	/* Printer object */
309  int			ascending,	/* Order of printers (0 = descending) */
310			first,		/* First printer to show */
311			count;		/* Number of printers */
312  const char		*var;		/* Form variable */
313  void			*search;	/* Search data */
314  char			val[1024];	/* Form variable */
315
316
317  fprintf(stderr, "DEBUG: show_all_printers(http=%p, user=\"%s\")\n",
318          http, user ? user : "(null)");
319
320 /*
321  * Show the standard header...
322  */
323
324  cgiStartHTML(cgiText(_("Printers")));
325
326 /*
327  * Build a CUPS_GET_PRINTERS request, which requires the following
328  * attributes:
329  *
330  *    attributes-charset
331  *    attributes-natural-language
332  *    printer-type
333  *    printer-type-mask
334  *    requesting-user-name
335  */
336
337  request = ippNewRequest(CUPS_GET_PRINTERS);
338
339  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
340                "printer-type", 0);
341  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
342                "printer-type-mask", CUPS_PRINTER_CLASS);
343
344  if (user)
345    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
346        	 "requesting-user-name", NULL, user);
347
348  cgiGetAttributes(request, "printers.tmpl");
349
350 /*
351  * Do the request and get back a response...
352  */
353
354  if ((response = cupsDoRequest(http, request, "/")) != NULL)
355  {
356   /*
357    * Get a list of matching job objects.
358    */
359
360    if ((var = cgiGetVariable("QUERY")) != NULL &&
361        !cgiGetVariable("CLEAR"))
362      search = cgiCompileSearch(var);
363    else
364      search = NULL;
365
366    printers  = cgiGetIPPObjects(response, search);
367    count     = cupsArrayCount(printers);
368
369    if (search)
370      cgiFreeSearch(search);
371
372   /*
373    * Figure out which printers to display...
374    */
375
376    if ((var = cgiGetVariable("FIRST")) != NULL)
377      first = atoi(var);
378    else
379      first = 0;
380
381    if (first >= count)
382      first = count - CUPS_PAGE_MAX;
383
384    first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
385
386    if (first < 0)
387      first = 0;
388
389    sprintf(val, "%d", count);
390    cgiSetVariable("TOTAL", val);
391
392    if ((var = cgiGetVariable("ORDER")) != NULL && *var)
393      ascending = !_cups_strcasecmp(var, "asc");
394    else
395      ascending = 1;
396
397    if (ascending)
398    {
399      for (i = 0, printer = (ipp_attribute_t *)cupsArrayIndex(printers, first);
400	   i < CUPS_PAGE_MAX && printer;
401	   i ++, printer = (ipp_attribute_t *)cupsArrayNext(printers))
402        cgiSetIPPObjectVars(printer, NULL, i);
403    }
404    else
405    {
406      for (i = 0, printer = (ipp_attribute_t *)cupsArrayIndex(printers, count - first - 1);
407	   i < CUPS_PAGE_MAX && printer;
408	   i ++, printer = (ipp_attribute_t *)cupsArrayPrev(printers))
409        cgiSetIPPObjectVars(printer, NULL, i);
410    }
411
412   /*
413    * Save navigation URLs...
414    */
415
416    cgiSetVariable("THISURL", "/printers/");
417
418    if (first > 0)
419    {
420      sprintf(val, "%d", first - CUPS_PAGE_MAX);
421      cgiSetVariable("PREV", val);
422    }
423
424    if ((first + CUPS_PAGE_MAX) < count)
425    {
426      sprintf(val, "%d", first + CUPS_PAGE_MAX);
427      cgiSetVariable("NEXT", val);
428    }
429
430   /*
431    * Then show everything...
432    */
433
434    cgiCopyTemplateLang("search.tmpl");
435
436    cgiCopyTemplateLang("printers-header.tmpl");
437
438    if (count > CUPS_PAGE_MAX)
439      cgiCopyTemplateLang("pager.tmpl");
440
441    cgiCopyTemplateLang("printers.tmpl");
442
443    if (count > CUPS_PAGE_MAX)
444      cgiCopyTemplateLang("pager.tmpl");
445
446   /*
447    * Delete the response...
448    */
449
450    cupsArrayDelete(printers);
451    ippDelete(response);
452  }
453  else
454  {
455   /*
456    * Show the error...
457    */
458
459    cgiShowIPPError(_("Unable to get printer list"));
460  }
461
462   cgiEndHTML();
463}
464
465
466/*
467 * 'show_printer()' - Show a single printer.
468 */
469
470static void
471show_printer(http_t     *http,		/* I - Connection to server */
472             const char *printer)	/* I - Name of printer */
473{
474  ipp_t		*request,		/* IPP request */
475		*response;		/* IPP response */
476  ipp_attribute_t *attr;		/* IPP attribute */
477  char		uri[HTTP_MAX_URI];	/* Printer URI */
478  char		refresh[1024];		/* Refresh URL */
479
480
481  fprintf(stderr, "DEBUG: show_printer(http=%p, printer=\"%s\")\n",
482          http, printer ? printer : "(null)");
483
484 /*
485  * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
486  * attributes:
487  *
488  *    attributes-charset
489  *    attributes-natural-language
490  *    printer-uri
491  */
492
493  request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
494
495  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
496                   "localhost", 0, "/printers/%s", printer);
497  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
498               uri);
499
500  cgiGetAttributes(request, "printer.tmpl");
501
502 /*
503  * Do the request and get back a response...
504  */
505
506  if ((response = cupsDoRequest(http, request, "/")) != NULL)
507  {
508   /*
509    * Got the result; set the CGI variables and check the status of a
510    * single-queue request...
511    */
512
513    cgiSetIPPVars(response, NULL, NULL, NULL, 0);
514
515    if (printer && (attr = ippFindAttribute(response, "printer-state",
516                                            IPP_TAG_ENUM)) != NULL &&
517        attr->values[0].integer == IPP_PRINTER_PROCESSING)
518    {
519     /*
520      * Printer is processing - automatically refresh the page until we
521      * are done printing...
522      */
523
524      cgiFormEncode(uri, printer, sizeof(uri));
525      snprintf(refresh, sizeof(refresh), "10;URL=/printers/%s", uri);
526      cgiSetVariable("refresh_page", refresh);
527    }
528
529   /*
530    * Delete the response...
531    */
532
533    ippDelete(response);
534
535   /*
536    * Show the standard header...
537    */
538
539    cgiStartHTML(printer);
540
541   /*
542    * Show the printer status...
543    */
544
545    cgiCopyTemplateLang("printer.tmpl");
546
547   /*
548    * Show jobs for the specified printer...
549    */
550
551    cgiCopyTemplateLang("printer-jobs-header.tmpl");
552    cgiShowJobs(http, printer);
553  }
554  else
555  {
556   /*
557    * Show the IPP error...
558    */
559
560    cgiStartHTML(printer);
561    cgiShowIPPError(_("Unable to get printer status"));
562  }
563
564   cgiEndHTML();
565}
566
567
568/*
569 * End of "$Id: printers.c 11934 2014-06-17 18:58:29Z msweet $".
570 */
571