1/* 2 * "$Id: lpoptions.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * Printer option program 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 <cups/cups-private.h> 21 22 23/* 24 * Local functions... 25 */ 26 27static void list_group(ppd_file_t *ppd, ppd_group_t *group); 28static void list_options(cups_dest_t *dest); 29static void usage(void) __attribute__((noreturn)); 30 31 32/* 33 * 'main()' - Main entry. 34 */ 35 36int /* O - Exit status */ 37main(int argc, /* I - Number of command-line arguments */ 38 char *argv[]) /* I - Command-line arguments */ 39{ 40 int i, j; /* Looping vars */ 41 int changes; /* Did we make changes? */ 42 int num_options; /* Number of options */ 43 cups_option_t *options; /* Options */ 44 int num_dests; /* Number of destinations */ 45 cups_dest_t *dests; /* Destinations */ 46 cups_dest_t *dest; /* Current destination */ 47 char *printer, /* Printer name */ 48 *instance, /* Instance name */ 49 *option; /* Current option */ 50 51 52 _cupsSetLocale(argv); 53 54 /* 55 * Loop through the command-line arguments... 56 */ 57 58 dest = NULL; 59 num_dests = 0; 60 dests = NULL; 61 num_options = 0; 62 options = NULL; 63 changes = 0; 64 65 for (i = 1; i < argc; i ++) 66 if (argv[i][0] == '-') 67 { 68 switch (argv[i][1]) 69 { 70 case 'd' : /* -d printer */ 71 if (argv[i][2]) 72 printer = argv[i] + 2; 73 else 74 { 75 i ++; 76 if (i >= argc) 77 usage(); 78 79 printer = argv[i]; 80 } 81 82 if ((instance = strrchr(printer, '/')) != NULL) 83 *instance++ = '\0'; 84 85 if (num_dests == 0) 86 num_dests = cupsGetDests(&dests); 87 88 if (num_dests == 0 || !dests || 89 (dest = cupsGetDest(printer, instance, num_dests, 90 dests)) == NULL) 91 { 92 _cupsLangPuts(stderr, _("lpoptions: Unknown printer or class.")); 93 return (1); 94 } 95 96 /* 97 * Set the default destination... 98 */ 99 100 for (j = 0; j < num_dests; j ++) 101 dests[j].is_default = 0; 102 103 dest->is_default = 1; 104 105 cupsSetDests(num_dests, dests); 106 107 for (j = 0; j < dest->num_options; j ++) 108 if (cupsGetOption(dest->options[j].name, num_options, 109 options) == NULL) 110 num_options = cupsAddOption(dest->options[j].name, 111 dest->options[j].value, 112 num_options, &options); 113 break; 114 115 case 'h' : /* -h server */ 116 if (argv[i][2]) 117 cupsSetServer(argv[i] + 2); 118 else 119 { 120 i ++; 121 if (i >= argc) 122 usage(); 123 124 cupsSetServer(argv[i]); 125 } 126 break; 127 128 case 'E' : /* Encrypt connection */ 129 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); 130 break; 131 132 case 'l' : /* -l (list options) */ 133 if (dest == NULL) 134 { 135 if (num_dests == 0) 136 num_dests = cupsGetDests(&dests); 137 138 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) 139 dest = dests; 140 } 141 142 if (dest == NULL) 143 _cupsLangPuts(stderr, _("lpoptions: No printers.")); 144 else 145 list_options(dest); 146 147 changes = -1; 148 break; 149 150 case 'o' : /* -o option[=value] */ 151 if (dest == NULL) 152 { 153 if (num_dests == 0) 154 num_dests = cupsGetDests(&dests); 155 156 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) 157 dest = dests; 158 159 if (dest == NULL) 160 { 161 _cupsLangPuts(stderr, _("lpoptions: No printers.")); 162 return (1); 163 } 164 165 for (j = 0; j < dest->num_options; j ++) 166 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) 167 num_options = cupsAddOption(dest->options[j].name, 168 dest->options[j].value, 169 num_options, &options); 170 } 171 172 if (argv[i][2]) 173 num_options = cupsParseOptions(argv[i] + 2, num_options, &options); 174 else 175 { 176 i ++; 177 if (i >= argc) 178 usage(); 179 180 num_options = cupsParseOptions(argv[i], num_options, &options); 181 } 182 183 changes = 1; 184 break; 185 186 case 'p' : /* -p printer */ 187 if (argv[i][2]) 188 printer = argv[i] + 2; 189 else 190 { 191 i ++; 192 if (i >= argc) 193 usage(); 194 195 printer = argv[i]; 196 } 197 198 if ((instance = strrchr(printer, '/')) != NULL) 199 *instance++ = '\0'; 200 201 if (num_dests == 0) 202 num_dests = cupsGetDests(&dests); 203 204 if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL) 205 { 206 num_dests = cupsAddDest(printer, instance, num_dests, &dests); 207 dest = cupsGetDest(printer, instance, num_dests, dests); 208 209 if (dest == NULL) 210 { 211 _cupsLangPrintf(stderr, 212 _("lpoptions: Unable to add printer or " 213 "instance: %s"), 214 strerror(errno)); 215 return (1); 216 } 217 } 218 219 for (j = 0; j < dest->num_options; j ++) 220 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) 221 num_options = cupsAddOption(dest->options[j].name, 222 dest->options[j].value, 223 num_options, &options); 224 break; 225 226 case 'r' : /* -r option (remove) */ 227 if (dest == NULL) 228 { 229 if (num_dests == 0) 230 num_dests = cupsGetDests(&dests); 231 232 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) 233 dest = dests; 234 235 if (dest == NULL) 236 { 237 _cupsLangPuts(stderr, _("lpoptions: No printers.")); 238 return (1); 239 } 240 241 for (j = 0; j < dest->num_options; j ++) 242 if (cupsGetOption(dest->options[j].name, num_options, 243 options) == NULL) 244 num_options = cupsAddOption(dest->options[j].name, 245 dest->options[j].value, 246 num_options, &options); 247 } 248 249 if (argv[i][2]) 250 option = argv[i] + 2; 251 else 252 { 253 i ++; 254 if (i >= argc) 255 usage(); 256 257 option = argv[i]; 258 } 259 260 for (j = 0; j < num_options; j ++) 261 if (!_cups_strcasecmp(options[j].name, option)) 262 { 263 /* 264 * Remove this option... 265 */ 266 267 num_options --; 268 269 if (j < num_options) 270 memmove(options + j, options + j + 1, sizeof(cups_option_t) * (size_t)(num_options - j)); 271 break; 272 } 273 274 changes = 1; 275 break; 276 277 case 'x' : /* -x printer */ 278 if (argv[i][2]) 279 printer = argv[i] + 2; 280 else 281 { 282 i ++; 283 if (i >= argc) 284 usage(); 285 286 printer = argv[i]; 287 } 288 289 if ((instance = strrchr(printer, '/')) != NULL) 290 *instance++ = '\0'; 291 292 if (num_dests == 0) 293 num_dests = cupsGetDests(&dests); 294 295 if ((dest = cupsGetDest(printer, instance, num_dests, 296 dests)) != NULL) 297 { 298 cupsFreeOptions(dest->num_options, dest->options); 299 300 /* 301 * If we are "deleting" the default printer, then just set the 302 * number of options to 0; if it is also the system default 303 * then cupsSetDests() will remove it for us... 304 */ 305 306 if (dest->is_default) 307 { 308 dest->num_options = 0; 309 dest->options = NULL; 310 } 311 else 312 { 313 num_dests --; 314 315 j = dest - dests; 316 if (j < num_dests) 317 memmove(dest, dest + 1, (size_t)(num_dests - j) * sizeof(cups_dest_t)); 318 } 319 } 320 321 cupsSetDests(num_dests, dests); 322 dest = NULL; 323 changes = -1; 324 break; 325 326 default : 327 usage(); 328 } 329 } 330 else 331 usage(); 332 333 if (num_dests == 0) 334 num_dests = cupsGetDests(&dests); 335 336 if (dest == NULL) 337 { 338 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) 339 { 340 for (j = 0; j < dest->num_options; j ++) 341 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) 342 num_options = cupsAddOption(dest->options[j].name, 343 dest->options[j].value, 344 num_options, &options); 345 } 346 } 347 348 if (dest == NULL) 349 return (0); 350 351 if (changes > 0) 352 { 353 /* 354 * Set printer options... 355 */ 356 357 cupsFreeOptions(dest->num_options, dest->options); 358 359 dest->num_options = num_options; 360 dest->options = options; 361 362 cupsSetDests(num_dests, dests); 363 } 364 else if (changes == 0) 365 { 366 char buffer[10240], /* String for options */ 367 *ptr; /* Pointer into string */ 368 369 num_options = dest->num_options; 370 options = dest->options; 371 372 for (i = 0, ptr = buffer; 373 ptr < (buffer + sizeof(buffer) - 1) && i < num_options; 374 i ++) 375 { 376 if (i) 377 *ptr++ = ' '; 378 379 if (!options[i].value[0]) 380 strlcpy(ptr, options[i].name, sizeof(buffer) - (size_t)(ptr - buffer)); 381 else if (strchr(options[i].value, ' ') != NULL || 382 strchr(options[i].value, '\t') != NULL) 383 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=\'%s\'", options[i].name, options[i].value); 384 else 385 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=%s", options[i].name, options[i].value); 386 387 ptr += strlen(ptr); 388 } 389 390 _cupsLangPuts(stdout, buffer); 391 } 392 393 return (0); 394} 395 396/* 397 * 'list_group()' - List printer-specific options from the PPD group. 398 */ 399 400static void 401list_group(ppd_file_t *ppd, /* I - PPD file */ 402 ppd_group_t *group) /* I - Group to show */ 403{ 404 int i, j; /* Looping vars */ 405 ppd_option_t *option; /* Current option */ 406 ppd_choice_t *choice; /* Current choice */ 407 ppd_group_t *subgroup; /* Current subgroup */ 408 char buffer[10240], /* Option string buffer */ 409 *ptr; /* Pointer into option string */ 410 411 412 for (i = group->num_options, option = group->options; i > 0; i --, option ++) 413 { 414 if (!_cups_strcasecmp(option->keyword, "PageRegion")) 415 continue; 416 417 snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text); 418 419 for (j = option->num_choices, choice = option->choices, 420 ptr = buffer + strlen(buffer); 421 j > 0 && ptr < (buffer + sizeof(buffer) - 1); 422 j --, choice ++) 423 { 424 if (!_cups_strcasecmp(choice->choice, "Custom")) 425 { 426 ppd_coption_t *coption; /* Custom option */ 427 ppd_cparam_t *cparam; /* Custom parameter */ 428 static const char * const types[] = 429 { /* Parameter types */ 430 "CURVE", 431 "INTEGER", 432 "INVCURVE", 433 "PASSCODE", 434 "PASSWORD", 435 "POINTS", 436 "REAL", 437 "STRING" 438 }; 439 440 441 if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL || 442 cupsArrayCount(coption->params) == 0) 443 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : ""); 444 else if (!_cups_strcasecmp(option->keyword, "PageSize") || 445 !_cups_strcasecmp(option->keyword, "PageRegion")) 446 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : ""); 447 else 448 { 449 cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); 450 451 if (cupsArrayCount(coption->params) == 1) 452 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]); 453 else 454 { 455 const char *prefix; /* Prefix string */ 456 457 458 if (choice->marked) 459 prefix = " *{"; 460 else 461 prefix = " {"; 462 463 while (cparam) 464 { 465 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]); 466 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params); 467 prefix = " "; 468 ptr += strlen(ptr); 469 } 470 471 if (ptr < (buffer + sizeof(buffer) - 1)) 472 strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer)); 473 } 474 } 475 } 476 else if (choice->marked) 477 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice); 478 else 479 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice); 480 481 ptr += strlen(ptr); 482 } 483 484 _cupsLangPuts(stdout, buffer); 485 } 486 487 for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++) 488 list_group(ppd, subgroup); 489} 490 491 492/* 493 * 'list_options()' - List printer-specific options from the PPD file. 494 */ 495 496static void 497list_options(cups_dest_t *dest) /* I - Destination to list */ 498{ 499 int i; /* Looping var */ 500 const char *filename; /* PPD filename */ 501 ppd_file_t *ppd; /* PPD data */ 502 ppd_group_t *group; /* Current group */ 503 504 505 if ((filename = cupsGetPPD(dest->name)) == NULL) 506 { 507 _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"), 508 dest->name, cupsLastErrorString()); 509 return; 510 } 511 512 if ((ppd = ppdOpenFile(filename)) == NULL) 513 { 514 unlink(filename); 515 _cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."), 516 dest->name); 517 return; 518 } 519 520 ppdMarkDefaults(ppd); 521 cupsMarkOptions(ppd, dest->num_options, dest->options); 522 523 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) 524 list_group(ppd, group); 525 526 ppdClose(ppd); 527 unlink(filename); 528} 529 530 531/* 532 * 'usage()' - Show program usage and exit. 533 */ 534 535static void 536usage(void) 537{ 538 _cupsLangPuts(stdout, 539 _("Usage: lpoptions [-h server] [-E] -d printer\n" 540 " lpoptions [-h server] [-E] [-p printer] -l\n" 541 " lpoptions [-h server] [-E] -p printer -o " 542 "option[=value] ...\n" 543 " lpoptions [-h server] [-E] -x printer")); 544 545 exit(1); 546} 547 548 549/* 550 * End of "$Id: lpoptions.c 11560 2014-02-06 20:10:19Z msweet $". 551 */ 552