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