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