#include <stdio.h>
#include <stdlib.h>
#include <cups/cups.h>
#include <cups/language.h>
#include <cups/string.h>
#include <errno.h>
int Verbosity = 0;
const char *SAMBAUser,
*SAMBAServer;
int do_samba_command(const char *, const char *);
int export_dest(const char *);
void usage();
int
main(int argc,
char *argv[])
{
int i, j;
int status;
int export_all;
int num_printers;
char **printers;
export_all = 0;
SAMBAUser = cupsUser();
SAMBAServer = NULL;
for (i = 1; i < argc; i ++)
if (strcmp(argv[i], "-a") == 0)
export_all = 1;
else if (strcmp(argv[i], "-U") == 0)
{
i ++;
if (i >= argc)
usage();
SAMBAUser = argv[i];
}
else if (strcmp(argv[i], "-H") == 0)
{
i ++;
if (i >= argc)
usage();
SAMBAServer = argv[i];
}
else if (strcmp(argv[i], "-h") == 0)
{
i ++;
if (i >= argc)
usage();
cupsSetServer(argv[i]);
}
else if (strcmp(argv[i], "-v") == 0)
Verbosity = 1;
else if (argv[i][0] != '-')
{
if (SAMBAServer == NULL)
SAMBAServer = cupsServer();
if ((status = export_dest(argv[i])) != 0)
return (status);
}
else
usage();
if (export_all)
{
if (SAMBAServer == NULL)
SAMBAServer = cupsServer();
num_printers = cupsGetPrinters(&printers);
for (j = 0, status = 0; j < num_printers; j ++)
if ((status = export_dest(printers[j])) != 0)
break;
for (j = 0; j < num_printers; j ++)
free(printers[j]);
if (num_printers)
free(printers);
if (status)
return (status);
}
return (0);
}
int
do_samba_command(const char *command,
const char *subcmd)
{
int status;
char temp[4096];
static const char *p = NULL;
for (status = 1;;)
{
if (p == NULL)
{
snprintf(temp, sizeof(temp),
"Password for %s required to access %s via SAMBA: ",
SAMBAUser, SAMBAServer);
if ((p = cupsGetPassword(temp)) == NULL)
break;
}
snprintf(temp, sizeof(temp), "%s -N -U\'%s%%%s\' -c \'%s\'",
command, SAMBAUser, p, subcmd);
if (Verbosity)
printf("Running command: %s\n", temp);
else
strlcat(temp, " </dev/null >/dev/null 2>/dev/null", sizeof(temp));
if ((status = system(temp)) != 0)
{
if (Verbosity)
puts("");
if (p[0])
p = NULL;
else
break;
}
else
{
if (Verbosity)
puts("");
break;
}
}
return (status);
}
int
export_dest(const char *dest)
{
int i;
int status;
const char *ppdfile;
char command[1024],
subcmd[1024];
const char *datadir;
FILE *fp;
http_t *http;
cups_lang_t *language;
ipp_t *request,
*response;
ipp_attribute_t *attr;
static const char *pattrs[] =
{
"job-sheets-supported",
"job-sheets-default"
};
if ((datadir = getenv("CUPS_DATADIR")) == NULL)
datadir = CUPS_DATADIR;
if ((ppdfile = cupsGetPPD(dest)) == NULL)
{
fprintf(stderr, "Warning: No PPD file for printer \"%s\" - skipping!\n", dest);
return (0);
}
if ((http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption())) == NULL)
{
fprintf(stderr, "Unable to connect to server \"%s\" for %s - %s\n",
cupsServer(), dest, strerror(errno));
unlink(ppdfile);
return (1);
}
request = ippNew();
request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
snprintf(command, sizeof(command), "ipp://localhost/printers/%s", dest);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, command);
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
NULL, pattrs);
if ((response = cupsDoRequest(http, request, "/")) != NULL)
{
if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "ERROR: get-printer-attributes failed for %s: %s\n",
dest, ippErrorString(response->request.status.status_code));
ippDelete(response);
unlink(ppdfile);
return (2);
}
}
else
{
fprintf(stderr, "ERROR: get-printer-attributes failed for %s: %s\n",
dest, ippErrorString(cupsLastError()));
unlink(ppdfile);
return (2);
}
if ((fp = fopen(ppdfile, "a")) == NULL)
{
fprintf(stderr, "ERROR: Unable to append banner attributes to PPD file for %s - %s\n",
dest, strerror(errno));
ippDelete(response);
unlink(ppdfile);
return (3);
}
if ((attr = ippFindAttribute(response, "job-sheets-supported", IPP_TAG_NAME)) != NULL)
{
fprintf(fp, "*cupsJobSheetsSupported: \"%s", attr->values[0].string.text);
for (i = 1; i < attr->num_values; i ++)
fprintf(fp, ",%s", attr->values[i].string.text);
fputs("\"\n", fp);
}
if ((attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_NAME)) != NULL)
{
fprintf(fp, "*cupsJobSheetsDefault: \"%s", attr->values[0].string.text);
if (attr->num_values > 1)
fprintf(fp, ",%s", attr->values[1].string.text);
fputs("\"\n", fp);
}
fclose(fp);
ippDelete(response);
cupsLangFree(language);
httpClose(http);
snprintf(command, sizeof(command), "%s/drivers/cupsdrvr.dll", datadir);
if (access(command, 0) == 0)
{
snprintf(command, sizeof(command), "smbclient //%s/print\\$", SAMBAServer);
snprintf(subcmd, sizeof(subcmd),
"mkdir W32X86;"
"put %s W32X86/%s.ppd;"
"put %s/drivers/cupsdrvr.dll W32X86/cupsdrvr.dll;"
"put %s/drivers/cupsui.dll W32X86/cupsui.dll;"
"put %s/drivers/cups.hlp W32X86/cups.hlp",
ppdfile, dest, datadir, datadir, datadir);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to copy Windows printer driver files (%d)!\n",
status);
unlink(ppdfile);
return (4);
}
snprintf(subcmd, sizeof(subcmd),
"adddriver \"Windows NT x86\" \"%s:cupsdrvr.dll:%s.ppd:cupsui.dll:cups.hlp:NULL:RAW:NULL\"",
dest, dest);
snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
status);
unlink(ppdfile);
return (5);
}
}
else
{
snprintf(command, sizeof(command), "smbclient //%s/print\\$", SAMBAServer);
snprintf(subcmd, sizeof(subcmd),
"mkdir W32X86;"
"put %s W32X86/%s.PPD;"
"put %s/drivers/ADOBEPS5.DLL W32X86/ADOBEPS5.DLL;"
"put %s/drivers/ADOBEPSU.DLL W32X86/ADOBEPSU.DLL;"
"put %s/drivers/ADOBEPSU.HLP W32X86/ADOBEPSU.HLP",
ppdfile, dest, datadir, datadir, datadir);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to copy Windows printer driver files (%d)!\n",
status);
unlink(ppdfile);
return (4);
}
snprintf(subcmd, sizeof(subcmd),
"adddriver \"Windows NT x86\" \"%s:ADOBEPS5.DLL:%s.PPD:ADOBEPSU.DLL:ADOBEPSU.HLP:NULL:RAW:NULL\"",
dest, dest);
snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
status);
unlink(ppdfile);
return (5);
}
}
snprintf(command, sizeof(command), "%s/drivers/ADOBEPS4.DRV", datadir);
if (access(command, 0) == 0)
{
snprintf(command, sizeof(command), "smbclient //%s/print\\$", SAMBAServer);
snprintf(subcmd, sizeof(subcmd),
"mkdir WIN40;"
"put %s WIN40/%s.PPD;"
"put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
"put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
"put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
"put %s/drivers/DEFPRTR2.PPD WIN40/DEFPRTR2.PPD;"
"put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
"put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
ppdfile, dest, datadir, datadir, datadir,
datadir, datadir, datadir);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to copy Windows printer driver files (%d)!\n",
status);
unlink(ppdfile);
return (6);
}
snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
snprintf(subcmd, sizeof(subcmd),
"adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:ADOBEPS4.HLP:PSMON.DLL:RAW:"
"ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM,DEFPRTR2.PPD,ICONLIB.DLL\"",
dest, dest, dest);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
status);
unlink(ppdfile);
return (7);
}
}
unlink(ppdfile);
snprintf(command, sizeof(command), "rpcclient %s", SAMBAServer);
snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest);
if ((status = do_samba_command(command, subcmd)) != 0)
{
fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
status);
return (8);
}
return (0);
}
void
usage()
{
puts("Usage: cupsaddsmb [options] printer1 ... printerN");
puts(" cupsaddsmb [options] -a");
puts("");
puts("Options:");
puts(" -H samba-server Use the named SAMBA server");
puts(" -U samba-user Authenticate using the named SAMBA user");
puts(" -a Export all printers");
puts(" -h cups-server Use the named CUPS server");
puts(" -v Be verbose (show commands)");
exit(1);
}