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