]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
b423cd4c | 2 | * "$Id: cupsaddsmb.c 5187 2006-02-26 20:36:03Z mike $" |
ef416fc2 | 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 | { | |
fa73b229 | 310 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 321 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 333 | _cupsLangPrintf(stderr, |
ef416fc2 | 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) | |
fa73b229 | 450 | _cupsLangPrintf(stdout, |
ef416fc2 | 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 | ||
fa73b229 | 479 | _cupsLangPrintf(stderr, _("cupsaddsmb: Unable to run \"%s\": %s\n"), |
ef416fc2 | 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) | |
fa73b229 | 494 | _cupsLangPuts(stdout, "\n"); |
ef416fc2 | 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 */ | |
fa73b229 | 517 | int have_drivers; /* Have drivers? */ |
ef416fc2 | 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 */ | |
ef416fc2 | 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 | ||
ef416fc2 | 546 | /* |
547 | * Open a connection to the scheduler... | |
548 | */ | |
549 | ||
550 | if ((http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption())) == NULL) | |
551 | { | |
fa73b229 | 552 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 565 | _cupsLangPrintf(stderr, |
ef416fc2 | 566 | _("cupsaddsmb: No PPD file for printer \"%s\" - " |
b423cd4c | 567 | "%s\n"), |
568 | dest, cupsLastErrorString()); | |
ef416fc2 | 569 | httpClose(http); |
570 | return (0); | |
571 | } | |
572 | ||
573 | /* | |
574 | * Append the supported banner pages to the PPD file... | |
575 | */ | |
576 | ||
fa73b229 | 577 | request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); |
ef416fc2 | 578 | |
a4d04587 | 579 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
580 | "localhost", 0, "/printers/%s", dest); | |
ef416fc2 | 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 | { | |
fa73b229 | 596 | _cupsLangPrintf(stderr, "cupsaddsmb: %s - %s\n", dest, |
597 | cupsLastErrorString()); | |
ef416fc2 | 598 | ippDelete(response); |
ef416fc2 | 599 | httpClose(http); |
600 | unlink(ppdfile); | |
601 | return (2); | |
602 | } | |
603 | } | |
604 | else | |
605 | { | |
fa73b229 | 606 | _cupsLangPrintf(stderr, "cupsaddsmb: %s - %s\n", dest, |
607 | cupsLastErrorString()); | |
ef416fc2 | 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 | { | |
fa73b229 | 619 | _cupsLangPrintf(stderr, |
ef416fc2 | 620 | _("cupsaddsmb: Unable to convert PPD file for %s - %s\n"), |
621 | dest, strerror(errno)); | |
622 | ippDelete(response); | |
ef416fc2 | 623 | httpClose(http); |
624 | unlink(ppdfile); | |
625 | return (3); | |
626 | } | |
627 | ||
628 | ippDelete(response); | |
ef416fc2 | 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 | ||
fa73b229 | 651 | have_drivers = 0; |
652 | ||
ef416fc2 | 653 | snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", datadir); |
654 | if (!access(file, 0)) | |
655 | { | |
fa73b229 | 656 | have_drivers |= 1; |
657 | ||
ef416fc2 | 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 | { | |
fa73b229 | 676 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 703 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 738 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 750 | have_drivers |= 2; |
751 | ||
ef416fc2 | 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 | { | |
fa73b229 | 770 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 791 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | ||
fa73b229 | 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 | ||
ef416fc2 | 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 | { | |
fa73b229 | 821 | _cupsLangPrintf(stderr, |
ef416fc2 | 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 | { | |
fa73b229 | 904 | _cupsLangPuts(stdout, |
ef416fc2 | 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 | /* | |
b423cd4c | 1029 | * End of "$Id: cupsaddsmb.c 5187 2006-02-26 20:36:03Z mike $". |
ef416fc2 | 1030 | */ |