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