]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/cupsaddsmb.c
Update copyright notices, addresses, etc.
[thirdparty/cups.git] / systemv / cupsaddsmb.c
1 /*
2 * "$Id$"
3 *
4 * "cupsaddsmb" command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2001-2005 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Export printers on the command-line.
27 * convert_ppd() - Convert a PPD file to a form usable by any of the
28 * Windows PostScript printer drivers.
29 * do_samba_command() - Do a SAMBA command, asking for a password as needed.
30 * export_dest() - Export a destination to SAMBA.
31 * ppd_gets() - Get a CR and/or LF-terminated line.
32 * usage() - Show program usage and exit...
33 * write_option() - Write a CUPS option to a PPD file.
34 */
35
36 /*
37 * Include necessary headers...
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <cups/cups.h>
43 #include <cups/language.h>
44 #include <cups/string.h>
45 #include <errno.h>
46
47
48 /*
49 * Local globals...
50 */
51
52 int Verbosity = 0;
53 const char *SAMBAUser,
54 *SAMBAServer;
55
56
57 /*
58 * Local functions...
59 */
60
61 int convert_ppd(const char *src, char *dst, int dstsize, ipp_t *info);
62 int do_samba_command(const char *command, const char *subcommand);
63 int export_dest(const char *dest);
64 char *ppd_gets(FILE *fp, char *buf, int buflen);
65 void usage(void);
66 int write_option(FILE *dstfp, int order, const char *name,
67 const char *text, const char *attrname,
68 ipp_attribute_t *suppattr, ipp_attribute_t *defattr,
69 int defval, int valcount);
70
71
72 /*
73 * 'main()' - Export printers on the command-line.
74 */
75
76 int /* O - Exit status */
77 main(int argc, /* I - Number of command-line arguments */
78 char *argv[]) /* I - Command-line arguments */
79 {
80 int i, j; /* Looping vars */
81 int status; /* Status from export_dest() */
82 int export_all; /* Export all printers? */
83 int num_printers; /* Number of printers */
84 char **printers; /* Printers */
85
86
87 /*
88 * Parse command-line arguments...
89 */
90
91 export_all = 0;
92
93 SAMBAUser = cupsUser();
94 SAMBAServer = NULL;
95
96 for (i = 1; i < argc; i ++)
97 if (strcmp(argv[i], "-a") == 0)
98 export_all = 1;
99 else if (strcmp(argv[i], "-U") == 0)
100 {
101 i ++;
102 if (i >= argc)
103 usage();
104
105 SAMBAUser = argv[i];
106 }
107 else if (strcmp(argv[i], "-H") == 0)
108 {
109 i ++;
110 if (i >= argc)
111 usage();
112
113 SAMBAServer = argv[i];
114 }
115 else if (strcmp(argv[i], "-h") == 0)
116 {
117 i ++;
118 if (i >= argc)
119 usage();
120
121 cupsSetServer(argv[i]);
122 }
123 else if (strcmp(argv[i], "-v") == 0)
124 Verbosity = 1;
125 else if (argv[i][0] != '-')
126 {
127 if (SAMBAServer == NULL)
128 SAMBAServer = cupsServer();
129
130 if ((status = export_dest(argv[i])) != 0)
131 return (status);
132 }
133 else
134 usage();
135
136 /*
137 * See if the user specified "-a"...
138 */
139
140 if (export_all)
141 {
142 /*
143 * Export all printers...
144 */
145
146 if (SAMBAServer == NULL)
147 SAMBAServer = cupsServer();
148
149 num_printers = cupsGetPrinters(&printers);
150
151 for (j = 0, status = 0; j < num_printers; j ++)
152 if ((status = export_dest(printers[j])) != 0)
153 break;
154
155 for (j = 0; j < num_printers; j ++)
156 free(printers[j]);
157
158 if (num_printers)
159 free(printers);
160
161 if (status)
162 return (status);
163 }
164
165 return (0);
166 }
167
168
169 /*
170 * 'convert_ppd()' - Convert a PPD file to a form usable by any of the
171 * Windows PostScript printer drivers.
172 */
173
174 int /* O - 0 on success, 1 on failure */
175 convert_ppd(const char *src, /* I - Source (original) PPD */
176 char *dst, /* O - Destination PPD */
177 int dstsize, /* I - Size of destination buffer */
178 ipp_t *info) /* I - Printer attributes */
179 {
180 FILE *srcfp, /* Source file */
181 *dstfp; /* Destination file */
182 int dstfd; /* Destination file descriptor */
183 ipp_attribute_t *suppattr, /* IPP -supported attribute */
184 *defattr; /* IPP -default attribute */
185 char line[256], /* Line from PPD file */
186 junk[256], /* Extra junk to throw away */
187 *ptr, /* Pointer into line */
188 option[41], /* Option */
189 choice[41]; /* Choice */
190 int jcloption, /* In a JCL option? */
191 linenum; /* Current line number */
192 time_t curtime; /* Current time */
193 struct tm *curdate; /* Current date */
194
195
196 /*
197 * Open the original PPD file...
198 */
199
200 if ((srcfp = fopen(src, "rb")) == NULL)
201 return (1);
202
203 /*
204 * Create a temporary output file using the destination buffer...
205 */
206
207 if ((dstfd = cupsTempFd(dst, dstsize)) < 0)
208 {
209 fclose(srcfp);
210
211 return (1);
212 }
213
214 if ((dstfp = fdopen(dstfd, "w")) == NULL)
215 {
216 /*
217 * Unable to convert to FILE *...
218 */
219
220 close(dstfd);
221
222 fclose(srcfp);
223
224 return (1);
225 }
226
227 /*
228 * Write a new header explaining that this isn't the original PPD...
229 */
230
231 fputs("*PPD-Adobe: \"4.3\"\n", dstfp);
232
233 curtime = time(NULL);
234 curdate = gmtime(&curtime);
235
236 fprintf(dstfp, "*%% Modified on %04d%02d%02d%02d%02d%02d+0000 by cupsaddsmb\n",
237 curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday,
238 curdate->tm_hour, curdate->tm_min, curdate->tm_sec);
239
240 /*
241 * Read the existing PPD file, converting all PJL commands to CUPS
242 * job ticket comments...
243 */
244
245 jcloption = 0;
246 linenum = 0;
247
248 while (ppd_gets(srcfp, line, sizeof(line)) != NULL)
249 {
250 linenum ++;
251
252 if (!strncmp(line, "*PPD-Adobe:", 11))
253 {
254 /*
255 * Already wrote the PPD header...
256 */
257
258 continue;
259 }
260 else if (!strncmp(line, "*JCLBegin:", 10) ||
261 !strncmp(line, "*JCLToPSInterpreter:", 20) ||
262 !strncmp(line, "*JCLEnd:", 8) ||
263 !strncmp(line, "*Protocols:", 11))
264 {
265 /*
266 * Don't use existing JCL keywords; we'll create our own, below...
267 */
268
269 fprintf(dstfp, "*%% Commented out by cupsaddsmb...\n*%%%s", line + 1);
270 continue;
271 }
272 else if (!strncmp(line, "*JCLOpenUI", 10))
273 {
274 jcloption = 1;
275 fputs(line, dstfp);
276 }
277 else if (!strncmp(line, "*JCLCloseUI", 11))
278 {
279 jcloption = 0;
280 fputs(line, dstfp);
281 }
282 else if (jcloption &&
283 strncmp(line, "*End", 4) &&
284 strncmp(line, "*Default", 8) &&
285 strncmp(line, "*OrderDependency", 16))
286 {
287 if ((ptr = strchr(line, ':')) == NULL)
288 {
289 fprintf(stderr, "cupsaddsmb: Missing value on line %d!\n", linenum);
290 fclose(srcfp);
291 fclose(dstfp);
292 close(dstfd);
293 unlink(dst);
294 return (1);
295 }
296
297 if ((ptr = strchr(ptr, '\"')) == NULL)
298 {
299 fprintf(stderr, "cupsaddsmb: Missing double quote on line %d!\n",
300 linenum);
301 fclose(srcfp);
302 fclose(dstfp);
303 close(dstfd);
304 unlink(dst);
305 return (1);
306 }
307
308 if (sscanf(line, "*%40s%*[ \t]%40[^/]", option, choice) != 2)
309 {
310 fprintf(stderr, "cupsaddsmb: Bad option + choice on line %d!\n",
311 linenum);
312 fclose(srcfp);
313 fclose(dstfp);
314 close(dstfd);
315 unlink(dst);
316 return (1);
317 }
318
319 if (strchr(ptr + 1, '\"') == NULL)
320 {
321 /*
322 * Skip remaining...
323 */
324
325 while (ppd_gets(srcfp, junk, sizeof(junk)) != NULL)
326 {
327 linenum ++;
328
329 if (!strncmp(junk, "*End", 4))
330 break;
331 }
332 }
333
334 snprintf(ptr + 1, sizeof(line) - (ptr - line + 1),
335 "%%cupsJobTicket: %s=%s\n\"\n*End\n", option, choice);
336
337 fprintf(dstfp, "*%% Changed by cupsaddsmb...\n%s", line);
338 }
339 else
340 fputs(line, dstfp);
341 }
342
343 fclose(srcfp);
344
345 /*
346 * Now add the CUPS-specific attributes and options...
347 */
348
349 fputs("\n*% CUPS Job Ticket support and options...\n", dstfp);
350 fputs("*Protocols: PJL\n", dstfp);
351 fputs("*JCLBegin: \"%!PS-Adobe-3.0<0A>\"\n", dstfp);
352 fputs("*JCLToPSInterpreter: \"\"\n", dstfp);
353 fputs("*JCLEnd: \"\"\n", dstfp);
354
355 fputs("\n*OpenGroup: CUPS/CUPS Options\n\n", dstfp);
356
357 if ((defattr = ippFindAttribute(info, "job-hold-until-default",
358 IPP_TAG_ZERO)) != NULL &&
359 (suppattr = ippFindAttribute(info, "job-hold-until-supported",
360 IPP_TAG_ZERO)) != NULL)
361 write_option(dstfp, 10, "cupsJobHoldUntil", "Hold Until", "job-hold-until",
362 suppattr, defattr, 0, 1);
363
364 if ((defattr = ippFindAttribute(info, "job-priority-default",
365 IPP_TAG_INTEGER)) != NULL &&
366 (suppattr = ippFindAttribute(info, "job-priority-supported",
367 IPP_TAG_RANGE)) != NULL)
368 write_option(dstfp, 11, "cupsJobPriority", "Priority", "job-priority",
369 suppattr, defattr, 0, 1);
370
371 if ((defattr = ippFindAttribute(info, "job-sheets-default",
372 IPP_TAG_ZERO)) != NULL &&
373 (suppattr = ippFindAttribute(info, "job-sheets-supported",
374 IPP_TAG_ZERO)) != NULL)
375 {
376 write_option(dstfp, 20, "cupsJobSheetsStart", "Start Banner",
377 "job-sheets", suppattr, defattr, 0, 2);
378 write_option(dstfp, 21, "cupsJobSheetsEnd", "End Banner",
379 "job-sheets", suppattr, defattr, 1, 2);
380 }
381
382 fputs("*CloseGroup: CUPS\n", dstfp);
383
384 fclose(dstfp);
385 close(dstfd);
386
387 return (0);
388 }
389
390
391 /*
392 * 'do_samba_command()' - Do a SAMBA command, asking for
393 * a password as needed.
394 */
395
396 int /* O - Status of command */
397 do_samba_command(const char *command, /* I - Command to run */
398 const char *subcmd) /* I - Sub-command */
399 {
400 int status; /* Status of command */
401 char temp[4096]; /* Command/prompt string */
402 static const char *p = NULL; /* Password data */
403
404
405 for (status = 1;;)
406 {
407 if (p == NULL)
408 {
409 snprintf(temp, sizeof(temp),
410 "Password for %s required to access %s via SAMBA: ",
411 SAMBAUser, SAMBAServer);
412
413 if ((p = cupsGetPassword(temp)) == NULL)
414 break;
415 }
416
417 snprintf(temp, sizeof(temp), "%s -N -U\'%s%%%s\' -c \'%s\'",
418 command, SAMBAUser, p, subcmd);
419
420 if (Verbosity)
421 printf("Running command: %s\n", temp);
422 else
423 strlcat(temp, " </dev/null >/dev/null 2>/dev/null", sizeof(temp));
424
425 if ((status = system(temp)) != 0)
426 {
427 if (Verbosity)
428 puts("");
429
430 if (p[0])
431 p = NULL;
432 else
433 break;
434 }
435 else
436 {
437 if (Verbosity)
438 puts("");
439
440 break;
441 }
442 }
443
444 return (status);
445 }
446
447
448 /*
449 * 'export_dest()' - Export a destination to SAMBA.
450 */
451
452 int /* O - 0 on success, non-zero on error */
453 export_dest(const char *dest) /* I - Destination to export */
454 {
455 int status; /* Status of smbclient/rpcclient commands */
456 const char *ppdfile; /* PPD file for printer drivers */
457 char newppd[1024], /* New PPD file for printer drivers */
458 file[1024], /* File to test for */
459 command[1024], /* Command to run */
460 subcmd[1024]; /* Sub-command */
461 const char *datadir; /* CUPS_DATADIR */
462 http_t *http; /* Connection to server */
463 cups_lang_t *language; /* Default language */
464 ipp_t *request, /* IPP request */
465 *response; /* IPP response */
466 static const char *pattrs[] = /* Printer attributes we want */
467 {
468 "job-hold-until-supported",
469 "job-hold-until-default",
470 "job-sheets-supported",
471 "job-sheets-default",
472 "job-priority-supported",
473 "job-priority-default"
474 };
475
476
477 /*
478 * Get the location of the printer driver files...
479 */
480
481 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
482 datadir = CUPS_DATADIR;
483
484 /*
485 * Open a connection to the scheduler...
486 */
487
488 if ((http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption())) == NULL)
489 {
490 fprintf(stderr, "cupsaddsmb: Unable to connect to server \"%s\" for %s - %s\n",
491 cupsServer(), dest, strerror(errno));
492 return (1);
493 }
494
495 /*
496 * Get the PPD file...
497 */
498
499 if ((ppdfile = cupsGetPPD2(http, dest)) == NULL)
500 {
501 fprintf(stderr, "cupsaddsmb: No PPD file for printer \"%s\" - skipping!\n",
502 dest);
503 httpClose(http);
504 return (0);
505 }
506
507 /*
508 * Append the supported banner pages to the PPD file...
509 */
510
511 request = ippNew();
512 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
513 request->request.op.request_id = 1;
514
515 language = cupsLangDefault();
516
517 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
518 "attributes-charset", NULL, cupsLangEncoding(language));
519
520 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
521 "attributes-natural-language", NULL, language->language);
522
523 snprintf(command, sizeof(command), "ipp://localhost/printers/%s", dest);
524 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
525 "printer-uri", NULL, command);
526
527 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
528 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
529 NULL, pattrs);
530
531 /*
532 * Do the request and get back a response...
533 */
534
535 if ((response = cupsDoRequest(http, request, "/")) != NULL)
536 {
537 if (response->request.status.status_code > IPP_OK_CONFLICT)
538 {
539 fprintf(stderr, "cupsaddsmb: get-printer-attributes failed for \"%s\": %s\n",
540 dest, ippErrorString(response->request.status.status_code));
541 ippDelete(response);
542 cupsLangFree(language);
543 httpClose(http);
544 unlink(ppdfile);
545 return (2);
546 }
547 }
548 else
549 {
550 fprintf(stderr, "cupsaddsmb: get-printer-attributes failed for \"%s\": %s\n",
551 dest, ippErrorString(cupsLastError()));
552 cupsLangFree(language);
553 httpClose(http);
554 unlink(ppdfile);
555 return (2);
556 }
557
558 /*
559 * Convert the PPD file to the Windows driver format...
560 */
561
562 if (convert_ppd(ppdfile, newppd, sizeof(newppd), response))
563 {
564 fprintf(stderr, "cupsaddsmb: Unable to convert PPD file for %s - %s\n",
565 dest, strerror(errno));
566 ippDelete(response);
567 cupsLangFree(language);
568 httpClose(http);
569 unlink(ppdfile);
570 return (3);
571 }
572
573 ippDelete(response);
574 cupsLangFree(language);
575 httpClose(http);
576
577 /*
578 * Remove the old PPD and point to the new one...
579 */
580
581 unlink(ppdfile);
582
583 ppdfile = newppd;
584
585 /*
586 * See which drivers are available; the new CUPS v6 and Adobe drivers
587 * depend on the Windows 2k PS driver, so copy that driver first:
588 *
589 * Files:
590 *
591 * ps5ui.dll
592 * pscript.hlp
593 * pscript.ntf
594 * pscript5.dll
595 */
596
597 snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", datadir);
598 if (!access(file, 0))
599 {
600 /*
601 * Windows 2k driver is installed; do the smbclient commands needed
602 * to copy the Win2k drivers over...
603 */
604
605 snprintf(command, sizeof(command), "smbclient //%s/print\\$", SAMBAServer);
606
607 snprintf(subcmd, sizeof(subcmd),
608 "mkdir W32X86;"
609 "put %s W32X86/%s.ppd;"
610 "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;"
611 "put %s/drivers/pscript.hlp W32X86/pscript.hlp;"
612 "put %s/drivers/pscript.ntf W32X86/pscript.ntf;"
613 "put %s/drivers/pscript5.dll W32X86/pscript5.dll",
614 ppdfile, dest, datadir, datadir, datadir, datadir);
615
616 if ((status = do_samba_command(command, subcmd)) != 0)
617 {
618 fprintf(stderr, "cupsaddsmb: Unable to copy Windows 2000 printer driver files (%d)!\n",
619 status);
620 unlink(ppdfile);
621 return (4);
622 }
623
624 /*
625 * See if we also have the CUPS driver files; if so, use them!
626 */
627
628 snprintf(file, sizeof(file), "%s/drivers/cupsdrv6.dll", datadir);
629 if (!access(file, 0))
630 {
631 /*
632 * Copy the CUPS driver files over...
633 */
634
635 snprintf(subcmd, sizeof(subcmd),
636 "put %s/drivers/cupsdrv6.dll W32X86/cupsdrv6.dll;"
637 "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll",
638 datadir, datadir);
639
640 if ((status = do_samba_command(command, subcmd)) != 0)
641 {
642 fprintf(stderr, "cupsaddsmb: Unable to copy CUPS printer driver files (%d)!\n",
643 status);
644 unlink(ppdfile);
645 return (4);
646 }
647
648 /*
649 * Do the rpcclient command needed for the CUPS drivers...
650 */
651
652 snprintf(subcmd, sizeof(subcmd),
653 "adddriver \"Windows NT x86\" \"%s:"
654 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
655 "cupsdrv6.dll,cupsui6.dll,pscript.ntf\"",
656 dest, dest);
657 }
658 else
659 {
660 /*
661 * Don't have the CUPS drivers, so just use the standard Windows
662 * drivers...
663 */
664
665 snprintf(subcmd, sizeof(subcmd),
666 "adddriver \"Windows NT x86\" \"%s:"
667 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
668 "pscript.ntf\"",
669 dest, dest);
670 }
671
672 snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
673
674 if ((status = do_samba_command(command, subcmd)) != 0)
675 {
676 fprintf(stderr, "cupsaddsmb: Unable to install Windows 2000 printer driver files (%d)!\n",
677 status);
678 unlink(ppdfile);
679 return (5);
680 }
681 }
682
683 snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", datadir);
684 if (!access(file, 0))
685 {
686 /*
687 * Do the smbclient commands needed for the Adobe Win9x drivers...
688 */
689
690 snprintf(command, sizeof(command), "smbclient //%s/print\\$", SAMBAServer);
691
692 snprintf(subcmd, sizeof(subcmd),
693 "mkdir WIN40;"
694 "put %s WIN40/%s.PPD;"
695 "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
696 "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
697 "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
698 "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
699 "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
700 ppdfile, dest, datadir, datadir, datadir, datadir, datadir);
701
702 if ((status = do_samba_command(command, subcmd)) != 0)
703 {
704 fprintf(stderr, "cupsaddsmb: Unable to copy Windows 9x printer driver files (%d)!\n",
705 status);
706 unlink(ppdfile);
707 return (6);
708 }
709
710 /*
711 * Do the rpcclient commands needed for the Adobe Win9x drivers...
712 */
713
714 snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
715
716 snprintf(subcmd, sizeof(subcmd),
717 "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:"
718 "ADOBEPS4.HLP:PSMON.DLL:RAW:"
719 "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM,"
720 "ICONLIB.DLL\"",
721 dest, dest, dest);
722
723 if ((status = do_samba_command(command, subcmd)) != 0)
724 {
725 fprintf(stderr, "cupsaddsmb: Unable to install Windows 9x printer driver files (%d)!\n",
726 status);
727 unlink(ppdfile);
728 return (7);
729 }
730 }
731
732 unlink(ppdfile);
733
734 /*
735 * Finally, associate the drivers we just added with the queue...
736 */
737
738 snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
739
740 snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest);
741
742 if ((status = do_samba_command(command, subcmd)) != 0)
743 {
744 fprintf(stderr, "cupsaddsmb: Unable to set Windows printer driver (%d)!\n",
745 status);
746 return (8);
747 }
748
749 return (0);
750 }
751
752
753 /*
754 * 'ppd_gets()' - Get a CR and/or LF-terminated line.
755 */
756
757 char * /* O - Line read or NULL on eof/error */
758 ppd_gets(FILE *fp, /* I - File to read from*/
759 char *buf, /* O - String buffer */
760 int buflen) /* I - Size of string buffer */
761 {
762 int ch; /* Character from file */
763 char *ptr, /* Current position in line buffer */
764 *end; /* End of line buffer */
765
766
767 /*
768 * Range check input...
769 */
770
771 if (!fp || !buf || buflen < 2 || feof(fp))
772 return (NULL);
773
774 /*
775 * Now loop until we have a valid line...
776 */
777
778 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
779 {
780 if ((ch = getc(fp)) == EOF)
781 {
782 if (ptr == buf)
783 return (NULL);
784 else
785 break;
786 }
787
788 *ptr++ = ch;
789
790 if (ch == '\r')
791 {
792 /*
793 * Check for CR LF...
794 */
795
796 if ((ch = getc(fp)) != '\n')
797 ungetc(ch, fp);
798 else if (ptr < end)
799 *ptr++ = ch;
800
801 break;
802 }
803 else if (ch == '\n')
804 {
805 /*
806 * Line feed ends a line...
807 */
808
809 break;
810 }
811 }
812
813 *ptr = '\0';
814
815 return (buf);
816 }
817
818
819 /*
820 * 'usage()' - Show program usage and exit...
821 */
822
823 void
824 usage(void)
825 {
826 puts("Usage: cupsaddsmb [options] printer1 ... printerN");
827 puts(" cupsaddsmb [options] -a");
828 puts("");
829 puts("Options:");
830 puts(" -H samba-server Use the named SAMBA server");
831 puts(" -U samba-user Authenticate using the named SAMBA user");
832 puts(" -a Export all printers");
833 puts(" -h cups-server Use the named CUPS server");
834 puts(" -v Be verbose (show commands)");
835 exit(1);
836 }
837
838
839 /*
840 * 'write_option()' - Write a CUPS option to a PPD file.
841 */
842
843 int /* O - 0 on success, 1 on failure */
844 write_option(FILE *dstfp, /* I - PPD file */
845 int order, /* I - Order dependency */
846 const char *name, /* I - Option name */
847 const char *text, /* I - Option text */
848 const char *attrname, /* I - Attribute name */
849 ipp_attribute_t *suppattr, /* I - IPP -supported attribute */
850 ipp_attribute_t *defattr, /* I - IPP -default attribute */
851 int defval, /* I - Default value number */
852 int valcount) /* I - Number of values */
853 {
854 int i; /* Looping var */
855
856
857 if (!dstfp || !name || !text || !suppattr || !defattr)
858 return (1);
859
860 fprintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n"
861 "*OrderDependency: %d JCLSetup *%s\n",
862 name, text, order, name);
863
864 if (defattr->value_tag == IPP_TAG_INTEGER)
865 {
866 /*
867 * Do numeric options with a range or list...
868 */
869
870 fprintf(dstfp, "*Default%s: %d\n", name, defattr->values[defval].integer);
871
872 if (suppattr->value_tag == IPP_TAG_RANGE)
873 {
874 /*
875 * List each number in the range...
876 */
877
878 for (i = suppattr->values[0].range.lower;
879 i <= suppattr->values[0].range.upper;
880 i ++)
881 {
882 fprintf(dstfp, "*%s %d: \"", name, i);
883
884 if (valcount == 1)
885 fprintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname, i);
886 else if (defval == 0)
887 fprintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i);
888 else if (defval < (valcount - 1))
889 fprintf(dstfp, ",%d\"\n", i);
890 else
891 fprintf(dstfp, ",%d\n\"\n*End\n", i);
892 }
893 }
894 else
895 {
896 /*
897 * List explicit numbers...
898 */
899
900 for (i = 0; i < suppattr->num_values; i ++)
901 {
902 fprintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer);
903
904 if (valcount == 1)
905 fprintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname,
906 suppattr->values[i].integer);
907 else if (defval == 0)
908 fprintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname,
909 suppattr->values[i].integer);
910 else if (defval < (valcount - 1))
911 fprintf(dstfp, ",%d\"\n", suppattr->values[i].integer);
912 else
913 fprintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer);
914 }
915 }
916 }
917 else
918 {
919 /*
920 * Do text options with a list...
921 */
922
923 fprintf(dstfp, "*Default%s: %s\n", name,
924 defattr->values[defval].string.text);
925
926 for (i = 0; i < suppattr->num_values; i ++)
927 {
928 fprintf(dstfp, "*%s %s: \"", name, suppattr->values[i].string.text);
929
930 if (valcount == 1)
931 fprintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname,
932 suppattr->values[i].string.text);
933 else if (defval == 0)
934 fprintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname,
935 suppattr->values[i].string.text);
936 else if (defval < (valcount - 1))
937 fprintf(dstfp, ",%s\"\n", suppattr->values[i].string.text);
938 else
939 fprintf(dstfp, ",%s\n\"\n*End\n", suppattr->values[i].string.text);
940 }
941 }
942
943 fprintf(dstfp, "*JCLCloseUI: *%s\n\n", name);
944
945 return (0);
946 }
947
948
949 /*
950 * End of "$Id$".
951 */