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