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