]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/classes.c
Merge pull request #1308 from weblate/weblate-cups-cups
[thirdparty/cups.git] / cgi-bin / classes.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Class status CGI for CUPS.
ef416fc2 3 *
d3006fcc 4 * Copyright © 2020-2025 by OpenPrinting.
f9927a4b
MS
5 * Copyright © 2007-2016 by Apple Inc.
6 * Copyright © 1997-2006 by Easy Software Products.
ef416fc2 7 *
f9927a4b
MS
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more
9 * information.
ef416fc2 10 */
11
ef416fc2 12#include "cgi-private.h"
13
14
fa73b229 15/*
16 * Local functions...
17 */
18
58dc1933
MS
19static void do_class_op(http_t *http, const char *printer, ipp_op_t op,
20 const char *title);
21static void show_all_classes(http_t *http, const char *username);
22static void show_class(http_t *http, const char *printer);
fa73b229 23
24
ef416fc2 25/*
26 * 'main()' - Main entry for CGI.
27 */
28
29int /* O - Exit status */
7e86f2f6 30main(void)
ef416fc2 31{
fa73b229 32 const char *pclass; /* Class name */
33 const char *user; /* Username */
ef416fc2 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 */
ef416fc2 38 const char *op; /* Operation to perform, if any */
fa73b229 39 static const char *def_attrs[] = /* Attributes for default printer */
ef416fc2 40 {
41 "printer-name",
42 "printer-uri-supported"
43 };
44
45
46 /*
47 * Get any form variables...
48 */
49
50 cgiInitialize();
fa73b229 51
ef416fc2 52 op = cgiGetVariable("OP");
53
54 /*
55 * Set the web interface section...
56 */
57
58 cgiSetVariable("SECTION", "classes");
ef55b745 59 cgiSetVariable("REFRESH_PAGE", "");
ef416fc2 60
61 /*
fa73b229 62 * See if we are displaying a printer or all classes...
ef416fc2 63 */
64
b423cd4c 65 if ((pclass = getenv("PATH_INFO")) != NULL)
4744bd90 66 {
b423cd4c 67 pclass ++;
ef416fc2 68
4744bd90 69 if (!*pclass)
70 pclass = NULL;
58dc1933
MS
71
72 if (pclass)
73 cgiSetVariable("PRINTER_NAME", pclass);
4744bd90 74 }
75
ef416fc2 76 /*
fa73b229 77 * See who is logged in...
ef416fc2 78 */
79
f301802f 80 user = getenv("REMOTE_USER");
ef416fc2 81
82 /*
fa73b229 83 * Connect to the HTTP server...
ef416fc2 84 */
85
d3006fcc
MS
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);
ef416fc2 103
104 /*
fa73b229 105 * Get the default printer...
ef416fc2 106 */
107
2e4ff8af 108 if (!op || !cgiIsPOST())
ef416fc2 109 {
ef416fc2 110 /*
111 * Get the default destination...
112 */
113
4f05fa3b 114 request = ippNewRequest(IPP_OP_CUPS_GET_DEFAULT);
ef416fc2 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 /*
fa73b229 139 * See if we need to show a list of classes or the status of a
140 * single printer...
ef416fc2 141 */
142
fa73b229 143 if (!pclass)
144 show_all_classes(http, user);
145 else
146 show_class(http, pclass);
147 }
58dc1933
MS
148 else if (pclass)
149 {
0268488e
MS
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"))
4f05fa3b 165 do_class_op(http, pclass, IPP_OP_RESUME_PRINTER, cgiText(_("Resume Class")));
58dc1933 166 else if (!strcmp(op, "stop-class"))
4f05fa3b 167 do_class_op(http, pclass, IPP_OP_PAUSE_PRINTER, cgiText(_("Pause Class")));
58dc1933 168 else if (!strcmp(op, "accept-jobs"))
4f05fa3b 169 do_class_op(http, pclass, IPP_OP_CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs")));
58dc1933 170 else if (!strcmp(op, "reject-jobs"))
4f05fa3b 171 do_class_op(http, pclass, IPP_OP_CUPS_REJECT_JOBS, cgiText(_("Reject Jobs")));
96be8b6c
MS
172 else if (!strcmp(op, "cancel-jobs"))
173 do_class_op(http, pclass, IPP_OP_CANCEL_JOBS, cgiText(_("Cancel Jobs")));
88f9aafc 174 else if (!_cups_strcasecmp(op, "print-test-page"))
58dc1933 175 cgiPrintTestPage(http, pclass);
88f9aafc 176 else if (!_cups_strcasecmp(op, "move-jobs"))
58dc1933
MS
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 }
fa73b229 189 else
190 {
191 /*
192 * Unknown/bad operation...
193 */
ef416fc2 194
58dc1933 195 cgiStartHTML(cgiText(_("Classes")));
fa73b229 196 cgiCopyTemplateLang("error-op.tmpl");
197 cgiEndHTML();
198 }
ef416fc2 199
fa73b229 200 /*
201 * Close the HTTP server connection...
202 */
ef416fc2 203
fa73b229 204 httpClose(http);
ef416fc2 205
fa73b229 206 /*
207 * Return with no errors...
208 */
ef416fc2 209
fa73b229 210 return (0);
211}
ef416fc2 212
ef416fc2 213
58dc1933
MS
214/*
215 * 'do_class_op()' - Do a class operation.
216 */
217
218static void
219do_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
4f05fa3b 252 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED)
58dc1933
MS
253 {
254 puts("Status: 401\n");
255 exit(0);
256 }
4f05fa3b 257 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING)
58dc1933
MS
258 {
259 cgiStartHTML(title);
f3c17241 260 cgiShowIPPError(_("Unable to do maintenance command"));
58dc1933
MS
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
4f05fa3b 281 if (op == IPP_OP_PAUSE_PRINTER)
58dc1933 282 cgiCopyTemplateLang("printer-stop.tmpl");
4f05fa3b 283 else if (op == IPP_OP_RESUME_PRINTER)
58dc1933 284 cgiCopyTemplateLang("printer-start.tmpl");
4f05fa3b 285 else if (op == IPP_OP_CUPS_ACCEPT_JOBS)
58dc1933 286 cgiCopyTemplateLang("printer-accept.tmpl");
4f05fa3b 287 else if (op == IPP_OP_CUPS_REJECT_JOBS)
58dc1933 288 cgiCopyTemplateLang("printer-reject.tmpl");
96be8b6c
MS
289 else if (op == IPP_OP_CANCEL_JOBS)
290 cgiCopyTemplateLang("printer-cancel-jobs.tmpl");
58dc1933
MS
291 }
292
293 cgiEndHTML();
294}
295
296
fa73b229 297/*
298 * 'show_all_classes()' - Show all classes...
299 */
ef416fc2 300
58dc1933 301static void
fa73b229 302show_all_classes(http_t *http, /* I - Connection to server */
f301802f 303 const char *user) /* I - Username */
fa73b229 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 */
9e6d7a0f 310 int first, /* First class to show */
fa73b229 311 count; /* Number of classes */
312 const char *var; /* Form variable */
313 void *search; /* Search data */
2e4ff8af 314 char val[1024]; /* Form variable */
ef416fc2 315
ef416fc2 316
fa73b229 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
4f05fa3b 332 request = ippNewRequest(IPP_OP_CUPS_GET_CLASSES);
fa73b229 333
f301802f 334 if (user)
335 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
336 "requesting-user-name", NULL, user);
fa73b229 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 {
ef416fc2 346 /*
fa73b229 347 * Get a list of matching job objects.
ef416fc2 348 */
349
f9927a4b 350 if ((var = cgiGetTextfield("QUERY")) != NULL &&
2e4ff8af 351 !cgiGetVariable("CLEAR"))
fa73b229 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);
ef416fc2 361
362 /*
fa73b229 363 * Figure out which classes to display...
ef416fc2 364 */
365
fa73b229 366 if ((var = cgiGetVariable("FIRST")) != NULL)
367 first = atoi(var);
368 else
369 first = 0;
ef416fc2 370
fa73b229 371 if (first >= count)
372 first = count - CUPS_PAGE_MAX;
ef416fc2 373
fa73b229 374 first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
ef416fc2 375
fa73b229 376 if (first < 0)
377 first = 0;
ef416fc2 378
fbcea290 379 snprintf(val, sizeof(val), "%d", count);
2e4ff8af 380 cgiSetVariable("TOTAL", val);
ef416fc2 381
9e6d7a0f
MS
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);
ef416fc2 386
fa73b229 387 /*
388 * Save navigation URLs...
389 */
ef416fc2 390
2e4ff8af 391 cgiSetVariable("THISURL", "/classes/");
fa73b229 392
393 if (first > 0)
394 {
fbcea290 395 snprintf(val, sizeof(val), "%d", first - CUPS_PAGE_MAX);
2e4ff8af 396 cgiSetVariable("PREV", val);
ef416fc2 397 }
fa73b229 398
399 if ((first + CUPS_PAGE_MAX) < count)
400 {
fbcea290 401 snprintf(val, sizeof(val), "%d", first + CUPS_PAGE_MAX);
2e4ff8af 402 cgiSetVariable("NEXT", val);
fa73b229 403 }
404
9e6d7a0f
MS
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
ef416fc2 411 /*
fa73b229 412 * Then show everything...
ef416fc2 413 */
414
fa73b229 415 cgiCopyTemplateLang("search.tmpl");
ef416fc2 416
fa73b229 417 cgiCopyTemplateLang("classes-header.tmpl");
ef416fc2 418
b19ccc9e 419 if (count > CUPS_PAGE_MAX)
fa73b229 420 cgiCopyTemplateLang("pager.tmpl");
ef416fc2 421
fa73b229 422 cgiCopyTemplateLang("classes.tmpl");
ef416fc2 423
b19ccc9e 424 if (count > CUPS_PAGE_MAX)
fa73b229 425 cgiCopyTemplateLang("pager.tmpl");
ef416fc2 426
427 /*
fa73b229 428 * Delete the response...
ef416fc2 429 */
430
bd7854cb 431 cupsArrayDelete(classes);
fa73b229 432 ippDelete(response);
433 }
434 else
435 {
436 /*
437 * Show the error...
438 */
ef416fc2 439
f3c17241 440 cgiShowIPPError(_("Unable to get class list"));
fa73b229 441 }
ef416fc2 442
fa73b229 443 cgiEndHTML();
444}
ef416fc2 445
ef416fc2 446
fa73b229 447/*
448 * 'show_class()' - Show a single class.
449 */
ef416fc2 450
58dc1933 451static void
fa73b229 452show_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 */
ef416fc2 470
4f05fa3b 471 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
ef416fc2 472
a4d04587 473 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
474 "localhost", 0, "/classes/%s", pclass);
fa73b229 475 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
476 uri);
ef416fc2 477
b19ccc9e 478 cgiGetAttributes(request, "class.tmpl");
fa73b229 479
480 /*
481 * Do the request and get back a response...
482 */
483
484 if ((response = cupsDoRequest(http, request, "/")) != NULL)
485 {
ef416fc2 486 /*
fa73b229 487 * Got the result; set the CGI variables and check the status of a
488 * single-queue request...
ef416fc2 489 */
490
fa73b229 491 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
492
493 if (pclass && (attr = ippFindAttribute(response, "printer-state",
494 IPP_TAG_ENUM)) != NULL &&
4f05fa3b 495 attr->values[0].integer == IPP_PSTATE_PROCESSING)
ef416fc2 496 {
fa73b229 497 /*
498 * Class is processing - automatically refresh the page until we
499 * are done printing...
500 */
ef416fc2 501
fa73b229 502 cgiFormEncode(uri, pclass, sizeof(uri));
f301802f 503 snprintf(refresh, sizeof(refresh), "10;URL=/classes/%s", uri);
fa73b229 504 cgiSetVariable("refresh_page", refresh);
ef416fc2 505 }
ef416fc2 506
fa73b229 507 /*
508 * Delete the response...
509 */
510
511 ippDelete(response);
ef416fc2 512
513 /*
514 * Show the standard header...
515 */
516
fa73b229 517 cgiStartHTML(pclass);
ef416fc2 518
519 /*
fa73b229 520 * Show the class status...
ef416fc2 521 */
522
b19ccc9e 523 cgiCopyTemplateLang("class.tmpl");
ef416fc2 524
fa73b229 525 /*
526 * Show jobs for the specified class...
527 */
ef416fc2 528
fa73b229 529 cgiCopyTemplateLang("class-jobs-header.tmpl");
530 cgiShowJobs(http, pclass);
531 }
532 else
533 {
534 /*
535 * Show the IPP error...
536 */
ef416fc2 537
fa73b229 538 cgiStartHTML(pclass);
f3c17241 539 cgiShowIPPError(_("Unable to get class status"));
fa73b229 540 }
ef416fc2 541
fa73b229 542 cgiEndHTML();
ef416fc2 543}