]> 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 4916 2006-01-11 21:42:55Z 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, NULL,
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, NULL,
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, NULL,
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, NULL,
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, NULL, _("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, NULL, "\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 const char *ppdfile; /* PPD file for printer drivers */
518 char newppd[1024], /* New PPD file for printer drivers */
519 file[1024], /* File to test for */
520 address[1024], /* Address for command */
521 uri[1024], /* Printer URI */
522 subcmd[1024]; /* Sub-command */
523 const char *datadir; /* CUPS_DATADIR */
524 http_t *http; /* Connection to server */
525 cups_lang_t *language; /* Default language */
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 language = cupsLangDefault();
547
548 /*
549 * Open a connection to the scheduler...
550 */
551
552 if ((http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption())) == NULL)
553 {
554 _cupsLangPrintf(stderr, language,
555 _("cupsaddsmb: Unable to connect to server \"%s\" for "
556 "%s - %s\n"),
557 cupsServer(), dest, strerror(errno));
558 return (1);
559 }
560
561 /*
562 * Get the PPD file...
563 */
564
565 if ((ppdfile = cupsGetPPD2(http, dest)) == NULL)
566 {
567 _cupsLangPrintf(stderr, language,
568 _("cupsaddsmb: No PPD file for printer \"%s\" - "
569 "skipping!\n"),
570 dest);
571 httpClose(http);
572 return (0);
573 }
574
575 /*
576 * Append the supported banner pages to the PPD file...
577 */
578
579 request = ippNew();
580 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
581 request->request.op.request_id = 1;
582
583 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
584 "attributes-charset", NULL, cupsLangEncoding(language));
585
586 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
587 "attributes-natural-language", NULL, language->language);
588
589 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
590 "/printers/%s", dest);
591 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
592 "printer-uri", NULL, uri);
593
594 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
595 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
596 NULL, pattrs);
597
598 /*
599 * Do the request and get back a response...
600 */
601
602 if ((response = cupsDoRequest(http, request, "/")) != NULL)
603 {
604 if (response->request.status.status_code > IPP_OK_CONFLICT)
605 {
606 _cupsLangPrintf(stderr, language,
607 _("cupsaddsmb: get-printer-attributes failed for "
608 "\"%s\": %s\n"),
609 dest,
610 ippErrorString(response->request.status.status_code));
611 ippDelete(response);
612 cupsLangFree(language);
613 httpClose(http);
614 unlink(ppdfile);
615 return (2);
616 }
617 }
618 else
619 {
620 _cupsLangPrintf(stderr, language,
621 _("cupsaddsmb: get-printer-attributes failed for "
622 "\"%s\": %s\n"),
623 dest, ippErrorString(cupsLastError()));
624 cupsLangFree(language);
625 httpClose(http);
626 unlink(ppdfile);
627 return (2);
628 }
629
630 /*
631 * Convert the PPD file to the Windows driver format...
632 */
633
634 if (convert_ppd(ppdfile, newppd, sizeof(newppd), response))
635 {
636 _cupsLangPrintf(stderr, language,
637 _("cupsaddsmb: Unable to convert PPD file for %s - %s\n"),
638 dest, strerror(errno));
639 ippDelete(response);
640 cupsLangFree(language);
641 httpClose(http);
642 unlink(ppdfile);
643 return (3);
644 }
645
646 ippDelete(response);
647 cupsLangFree(language);
648 httpClose(http);
649
650 /*
651 * Remove the old PPD and point to the new one...
652 */
653
654 unlink(ppdfile);
655
656 ppdfile = newppd;
657
658 /*
659 * See which drivers are available; the new CUPS v6 and Adobe drivers
660 * depend on the Windows 2k PS driver, so copy that driver first:
661 *
662 * Files:
663 *
664 * ps5ui.dll
665 * pscript.hlp
666 * pscript.ntf
667 * pscript5.dll
668 */
669
670 snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", datadir);
671 if (!access(file, 0))
672 {
673 /*
674 * Windows 2k driver is installed; do the smbclient commands needed
675 * to copy the Win2k drivers over...
676 */
677
678 snprintf(address, sizeof(address), "//%s/print$", SAMBAServer);
679
680 snprintf(subcmd, sizeof(subcmd),
681 "mkdir W32X86;"
682 "put %s W32X86/%s.ppd;"
683 "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;"
684 "put %s/drivers/pscript.hlp W32X86/pscript.hlp;"
685 "put %s/drivers/pscript.ntf W32X86/pscript.ntf;"
686 "put %s/drivers/pscript5.dll W32X86/pscript5.dll",
687 ppdfile, dest, datadir, datadir, datadir, datadir);
688
689 if ((status = do_samba_command("smbclient", address, subcmd)) != 0)
690 {
691 _cupsLangPrintf(stderr, language,
692 _("cupsaddsmb: Unable to copy Windows 2000 printer "
693 "driver files (%d)!\n"),
694 status);
695 unlink(ppdfile);
696 return (4);
697 }
698
699 /*
700 * See if we also have the CUPS driver files; if so, use them!
701 */
702
703 snprintf(file, sizeof(file), "%s/drivers/cupsps6.dll", datadir);
704 if (!access(file, 0))
705 {
706 /*
707 * Copy the CUPS driver files over...
708 */
709
710 snprintf(subcmd, sizeof(subcmd),
711 "put %s/drivers/cups6.ini W32X86/cups6.ini;"
712 "put %s/drivers/cupsps6.dll W32X86/cupsps6.dll;"
713 "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll",
714 datadir, datadir, datadir);
715
716 if ((status = do_samba_command("smbclient", address, subcmd)) != 0)
717 {
718 _cupsLangPrintf(stderr, language,
719 _("cupsaddsmb: Unable to copy CUPS printer driver "
720 "files (%d)!\n"),
721 status);
722 unlink(ppdfile);
723 return (4);
724 }
725
726 /*
727 * Do the rpcclient command needed for the CUPS drivers...
728 */
729
730 snprintf(subcmd, sizeof(subcmd),
731 "adddriver \"Windows NT x86\" \"%s:"
732 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
733 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf,"
734 "cups6.ini,cupsps6.dll,cupsui6.dll\"",
735 dest, dest, dest);
736 }
737 else
738 {
739 /*
740 * Don't have the CUPS drivers, so just use the standard Windows
741 * drivers...
742 */
743
744 snprintf(subcmd, sizeof(subcmd),
745 "adddriver \"Windows NT x86\" \"%s:"
746 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
747 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"",
748 dest, dest, dest);
749 }
750
751 if ((status = do_samba_command("rpcclient", SAMBAServer, subcmd)) != 0)
752 {
753 _cupsLangPrintf(stderr, language,
754 _("cupsaddsmb: Unable to install Windows 2000 printer "
755 "driver files (%d)!\n"),
756 status);
757 unlink(ppdfile);
758 return (5);
759 }
760 }
761
762 snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", datadir);
763 if (!access(file, 0))
764 {
765 /*
766 * Do the smbclient commands needed for the Adobe Win9x drivers...
767 */
768
769 snprintf(address, sizeof(address), "//%s/print$", SAMBAServer);
770
771 snprintf(subcmd, sizeof(subcmd),
772 "mkdir WIN40;"
773 "put %s WIN40/%s.PPD;"
774 "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
775 "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
776 "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
777 "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
778 "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
779 ppdfile, dest, datadir, datadir, datadir, datadir, datadir);
780
781 if ((status = do_samba_command("smbclient", address, subcmd)) != 0)
782 {
783 _cupsLangPrintf(stderr, language,
784 _("cupsaddsmb: Unable to copy Windows 9x printer "
785 "driver files (%d)!\n"),
786 status);
787 unlink(ppdfile);
788 return (6);
789 }
790
791 /*
792 * Do the rpcclient commands needed for the Adobe Win9x drivers...
793 */
794
795 snprintf(subcmd, sizeof(subcmd),
796 "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:"
797 "ADOBEPS4.HLP:PSMON.DLL:RAW:"
798 "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM,"
799 "ICONLIB.DLL\"",
800 dest, dest, dest);
801
802 if ((status = do_samba_command("rpcclient", SAMBAServer, subcmd)) != 0)
803 {
804 _cupsLangPrintf(stderr, language,
805 _("cupsaddsmb: Unable to install Windows 9x printer "
806 "driver files (%d)!\n"),
807 status);
808 unlink(ppdfile);
809 return (7);
810 }
811 }
812
813 unlink(ppdfile);
814
815 /*
816 * Finally, associate the drivers we just added with the queue...
817 */
818
819 snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest);
820
821 if ((status = do_samba_command("rpcclient", SAMBAServer, subcmd)) != 0)
822 {
823 _cupsLangPrintf(stderr, language,
824 _("cupsaddsmb: Unable to set Windows printer driver (%d)!\n"),
825 status);
826 return (8);
827 }
828
829 return (0);
830 }
831
832
833 /*
834 * 'ppd_gets()' - Get a CR and/or LF-terminated line.
835 */
836
837 char * /* O - Line read or NULL on eof/error */
838 ppd_gets(FILE *fp, /* I - File to read from*/
839 char *buf, /* O - String buffer */
840 int buflen) /* I - Size of string buffer */
841 {
842 int ch; /* Character from file */
843 char *ptr, /* Current position in line buffer */
844 *end; /* End of line buffer */
845
846
847 /*
848 * Range check input...
849 */
850
851 if (!fp || !buf || buflen < 2 || feof(fp))
852 return (NULL);
853
854 /*
855 * Now loop until we have a valid line...
856 */
857
858 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
859 {
860 if ((ch = getc(fp)) == EOF)
861 {
862 if (ptr == buf)
863 return (NULL);
864 else
865 break;
866 }
867
868 *ptr++ = ch;
869
870 if (ch == '\r')
871 {
872 /*
873 * Check for CR LF...
874 */
875
876 if ((ch = getc(fp)) != '\n')
877 ungetc(ch, fp);
878 else if (ptr < end)
879 *ptr++ = ch;
880
881 break;
882 }
883 else if (ch == '\n')
884 {
885 /*
886 * Line feed ends a line...
887 */
888
889 break;
890 }
891 }
892
893 *ptr = '\0';
894
895 return (buf);
896 }
897
898
899 /*
900 * 'usage()' - Show program usage and exit...
901 */
902
903 void
904 usage(void)
905 {
906 _cupsLangPuts(stdout, NULL,
907 _("Usage: cupsaddsmb [options] printer1 ... printerN\n"
908 " cupsaddsmb [options] -a\n"
909 "\n"
910 "Options:\n"
911 " -H samba-server Use the named SAMBA server\n"
912 " -U samba-user Authenticate using the named SAMBA user\n"
913 " -a Export all printers\n"
914 " -h cups-server Use the named CUPS server\n"
915 " -v Be verbose (show commands)\n"));
916 exit(1);
917 }
918
919
920 /*
921 * 'write_option()' - Write a CUPS option to a PPD file.
922 */
923
924 int /* O - 0 on success, 1 on failure */
925 write_option(FILE *dstfp, /* I - PPD file */
926 int order, /* I - Order dependency */
927 const char *name, /* I - Option name */
928 const char *text, /* I - Option text */
929 const char *attrname, /* I - Attribute name */
930 ipp_attribute_t *suppattr, /* I - IPP -supported attribute */
931 ipp_attribute_t *defattr, /* I - IPP -default attribute */
932 int defval, /* I - Default value number */
933 int valcount) /* I - Number of values */
934 {
935 int i; /* Looping var */
936
937
938 if (!dstfp || !name || !text || !suppattr || !defattr)
939 return (1);
940
941 fprintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n"
942 "*OrderDependency: %d JCLSetup *%s\n",
943 name, text, order, name);
944
945 if (defattr->value_tag == IPP_TAG_INTEGER)
946 {
947 /*
948 * Do numeric options with a range or list...
949 */
950
951 fprintf(dstfp, "*Default%s: %d\n", name, defattr->values[defval].integer);
952
953 if (suppattr->value_tag == IPP_TAG_RANGE)
954 {
955 /*
956 * List each number in the range...
957 */
958
959 for (i = suppattr->values[0].range.lower;
960 i <= suppattr->values[0].range.upper;
961 i ++)
962 {
963 fprintf(dstfp, "*%s %d: \"", name, i);
964
965 if (valcount == 1)
966 fprintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname, i);
967 else if (defval == 0)
968 fprintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i);
969 else if (defval < (valcount - 1))
970 fprintf(dstfp, ",%d\"\n", i);
971 else
972 fprintf(dstfp, ",%d\n\"\n*End\n", i);
973 }
974 }
975 else
976 {
977 /*
978 * List explicit numbers...
979 */
980
981 for (i = 0; i < suppattr->num_values; i ++)
982 {
983 fprintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer);
984
985 if (valcount == 1)
986 fprintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname,
987 suppattr->values[i].integer);
988 else if (defval == 0)
989 fprintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname,
990 suppattr->values[i].integer);
991 else if (defval < (valcount - 1))
992 fprintf(dstfp, ",%d\"\n", suppattr->values[i].integer);
993 else
994 fprintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer);
995 }
996 }
997 }
998 else
999 {
1000 /*
1001 * Do text options with a list...
1002 */
1003
1004 fprintf(dstfp, "*Default%s: %s\n", name,
1005 defattr->values[defval].string.text);
1006
1007 for (i = 0; i < suppattr->num_values; i ++)
1008 {
1009 fprintf(dstfp, "*%s %s: \"", name, suppattr->values[i].string.text);
1010
1011 if (valcount == 1)
1012 fprintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname,
1013 suppattr->values[i].string.text);
1014 else if (defval == 0)
1015 fprintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname,
1016 suppattr->values[i].string.text);
1017 else if (defval < (valcount - 1))
1018 fprintf(dstfp, ",%s\"\n", suppattr->values[i].string.text);
1019 else
1020 fprintf(dstfp, ",%s\n\"\n*End\n", suppattr->values[i].string.text);
1021 }
1022 }
1023
1024 fprintf(dstfp, "*JCLCloseUI: *%s\n\n", name);
1025
1026 return (0);
1027 }
1028
1029
1030 /*
1031 * End of "$Id: cupsaddsmb.c 4916 2006-01-11 21:42:55Z mike $".
1032 */