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