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