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