Closed michaelrsweet closed 9 years ago
CUPS.org User: mike
Note that this bug may end up closed depending on when we actually implement IPP Everywhere printing support since PPDs are a legacy implementation detail of the CUPS printing infrastructure - if we end up with a native set of IPP Everywhere-based filters then this PPD generator will be unnecessary...
CUPS.org User: till.kamppeter
The filter set for PPD-less printing on IPP Everywhere printers (PWG Raster, PDF, PostScript) is already in place in cups-filters 1.0.43 and cups-browsed is already capable of auto-creating appropriate queues. A client (print dialog) can ask the printer for available options and capabilities now and send PDF jobs with appropriate IPP attributes to these queues.
CUPS.org User: mike
First part of the equation: a private API for generating a PPD from the response of a Get-Printer-Attributes request.
Next up will be lpadmin and web interface support.
CUPS.org User: mike
Fixed in Subversion repository.
Second part.
"str4258p1.patch":
--- cups/ppd-cache.c (revision 12508) +++ cups/ppd-cache.c (working copy) @@ -37,6 +37,7 @@ _pwg_finishings_t b); static void pwg_free_finishings(_pwg_finishings_t f); static void pwg_ppdize_name(const char ipp, char name, size_t namesize); +static void pwg_ppdize_resolution(ipp_attribute_t attr, int element, int xres, int yres, char name, size_t namesize); static void pwg_unppdize_name(const char ppd, char name, size_t namesize, const char *dashchars);
@@ -2782,6 +2783,479 @@
/*
* '_ppdCreateFromIPP()' - Create a PPD file describing the capabilities
* of an IPP printer.
/ + +char * / O - PPD filename or NULL on error _/ +ppdCreateFromIPP(char *buffer, / I - Filename buffer */
size_t bufsize, /* I - Size of filename buffer */
ipp_t response) / I - Get-Printer-Attributes response */ +{
cups_file_t fp; / PPD file */
ipp_attribute_t attr, / xxx-supported */
defattr, / xxx-default */
_x_dim, ydim; / Media dimensions /
ipp_t _mediasize; / Media size collection */
char make[256], /* Make and model */
model, / Model name */
ppdname[PPD_MAX_NAME];
/* PPD keyword */
int i, j, /* Looping vars */
count, /* Number of values */
bottom, /* Largest bottom margin */
left, /* Largest left margin */
right, /* Largest right margin */
top; /* Largest top margin */
pwg_media_t pwg; / PWG media size */
int xres, yres; /* Resolution values */ + +
/*
* Range check input...
*/ +
if (!buffer || bufsize < 1 || !response)
return (NULL); +
/*
* Open a temporary file for the PPD...
*/ +
if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL)
return (NULL); +
/*
* Standard stuff for PPD file...
*/ +
cupsFilePuts(fp, "*PPD-Adobe: \"4.3\"\n");
cupsFilePuts(fp, "*FormatVersion: \"4.3\"\n");
cupsFilePrintf(fp, "*FileVersion: \"%d.%d\"\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
cupsFilePuts(fp, "*LanguageVersion: English\n");
cupsFilePuts(fp, "*LanguageEncoding: ISOLatin1\n");
cupsFilePuts(fp, "*PSVersion: \"(3010.000) 0\"\n");
cupsFilePuts(fp, "*LanguageLevel: \"3\"\n");
cupsFilePuts(fp, "*FileSystem: False\n");
cupsFilePuts(fp, "*PCFileName: \"ippeve.ppd\"\n"); +
if ((attr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT)) != NULL)
strlcpy(make, ippGetString(attr, 0, NULL), sizeof(make));
else
strlcpy(make, "Unknown Printer", sizeof(make)); +
if (!_cups_strncasecmp(make, "Hewlett Packard ", 16) ||
!_cups_strncasecmp(make, "Hewlett-Packard ", 16))
{
model = make + 16;
strlcpy(make, "HP", sizeof(make));
}
else if ((model = strchr(make, ' ')) != NULL)
*model++ = '\0';
else
model = make; +
cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make);
cupsFilePrintf(fp, "*ModelName: \"%s\"\n", model);
cupsFilePrintf(fp, "*Product: \"(%s)\"\n", model);
cupsFilePrintf(fp, "*NickName: \"%s\"\n", model);
cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model); +
cupsFilePrintf(fp, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
cupsFilePuts(fp, "*cupsSNMPSupplies: False\n");
cupsFilePuts(fp, "*cupsLanguages: \"en\"\n"); +
/*
* Filters...
*/ +
if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL)
{
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
const char *format = ippGetString(attr, i, NULL);
/* PDL */ +
if (!_cups_strcasecmp(format, "application/pdf"))
cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n");
else if (_cups_strcasecmp(format, "application/octet-stream"))
cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 10 -\"\n", format, format);
}
} +
/*
* PageSize/PageRegion/ImageableArea/PaperDimension
*/ +
if ((attr = ippFindAttribute(response, "media-bottom-margin-supported", IPP_TAG_INTEGER)) != NULL)
{
for (i = 1, bottom = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
if (ippGetInteger(attr, i) > bottom)
bottom = ippGetInteger(attr, i);
}
else
bottom = 1270; +
if ((attr = ippFindAttribute(response, "media-left-margin-supported", IPP_TAG_INTEGER)) != NULL)
{
for (i = 1, left = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
if (ippGetInteger(attr, i) > left)
left = ippGetInteger(attr, i);
}
else
left = 635; +
if ((attr = ippFindAttribute(response, "media-right-margin-supported", IPP_TAG_INTEGER)) != NULL)
{
for (i = 1, right = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
if (ippGetInteger(attr, i) > right)
right = ippGetInteger(attr, i);
}
else
right = 635; +
if ((attr = ippFindAttribute(response, "media-top-margin-supported", IPP_TAG_INTEGER)) != NULL)
{
for (i = 1, top = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
if (ippGetInteger(attr, i) > top)
top = ippGetInteger(attr, i);
}
else
top = 1270; +
if ((defattr = ippFindAttribute(response, "media-col-default", IPP_TAG_BEGIN_COLLECTION)) != NULL)
{
if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL)
{
media_size = ippGetCollection(attr, 0);
x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); +
if (x_dim && y_dim)
{
pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
strlcpy(ppdname, pwg->ppd, sizeof(ppdname));
}
else
strlcpy(ppdname, "Unknown", sizeof(ppdname));
}
else
strlcpy(ppdname, "Unknown", sizeof(ppdname));
} +
if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL)
{
cupsFilePrintf(fp, "OpenUI PageSize: PickOne\n"
"OrderDependency: 10 AnySetup PageSize\n"
"*DefaultPageSize: %s\n", ppdname);
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
media_size = ippGetCollection(attr, i);
x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); +
if (x_dim && y_dim)
{
pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); +
cupsFilePrintf(fp, "PageSize %s: \"<</PageSize[%.1f %.1f]>>setpagedevice\"\n", pwg->ppd, pwg->width * 72.0 / 2540.0, pwg->length \ 72.0 / 2540.0);
}
}
cupsFilePuts(fp, "CloseUI: PageSize\n"); +
cupsFilePrintf(fp, "OpenUI PageRegion: PickOne\n"
"OrderDependency: 10 AnySetup PageRegion\n"
"*DefaultPageRegion: %s\n", ppdname);
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
media_size = ippGetCollection(attr, i);
x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); +
if (x_dim && y_dim)
{
pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); +
cupsFilePrintf(fp, "PageRegion %s: \"<</PageSize[%.1f %.1f]>>setpagedevice\"\n", pwg->ppd, pwg->width * 72.0 / 2540.0, pwg->length \ 72.0 / 2540.0);
}
}
cupsFilePuts(fp, "CloseUI: PageRegion\n"); +
cupsFilePrintf(fp, "*DefaultImageableArea: %s\n"
"*DefaultPaperDimension: %s\n", ppdname, ppdname);
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
media_size = ippGetCollection(attr, i);
x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); +
if (x_dim && y_dim)
{
pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); +
cupsFilePrintf(fp, "ImageableArea %s: \"%.1f %.1f %.1f %.1f\"\n", pwg->ppd, left * 72.0 / 2540.0, bottom * 72.0 / 2540.0, (pwg->width - right) * 72.0 / 2540.0, (pwg->length - top) \ 72.0 / 2540.0);
cupsFilePrintf(fp, "PaperDimension %s: \"%.1f %.1f\"\n", pwg->ppd, pwg->width * 72.0 / 2540.0, pwg->length \ 72.0 / 2540.0);
}
}
} +
/*
* InputSlot...
*/ +
if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_KEYWORD)) != NULL)
pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
else
strlcpy(ppdname, "Unknown", sizeof(ppdname)); +
if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1)
{
static const char * const sources[][2] =
{
{ "Auto", "Automatic" },
{ "Main", "Main" },
{ "Alternate", "Alternate" },
{ "LargeCapacity", "Large Capacity" },
{ "Manual", "Manual" },
{ "Envelope", "Envelope" },
{ "Disc", "Disc" },
{ "Photo", "Photo" },
{ "Hagaki", "Hagaki" },
{ "MainRoll", "Main Roll" },
{ "AlternateRoll", "Alternate Roll" },
{ "Top", "Top" },
{ "Middle", "Middle" },
{ "Bottom", "Bottom" },
{ "Side", "Side" },
{ "Left", "Left" },
{ "Right", "Right" },
{ "Center", "Center" },
{ "Rear", "Rear" },
{ "ByPassTray", "Multipurpose" },
{ "Tray1", "Tray 1" },
{ "Tray2", "Tray 2" },
{ "Tray3", "Tray 3" },
{ "Tray4", "Tray 4" },
{ "Tray5", "Tray 5" },
{ "Tray6", "Tray 6" },
{ "Tray7", "Tray 7" },
{ "Tray8", "Tray 8" },
{ "Tray9", "Tray 9" },
{ "Tray10", "Tray 10" },
{ "Tray11", "Tray 11" },
{ "Tray12", "Tray 12" },
{ "Tray13", "Tray 13" },
{ "Tray14", "Tray 14" },
{ "Tray15", "Tray 15" },
{ "Tray16", "Tray 16" },
{ "Tray17", "Tray 17" },
{ "Tray18", "Tray 18" },
{ "Tray19", "Tray 19" },
{ "Tray20", "Tray 20" },
{ "Roll1", "Roll 1" },
{ "Roll2", "Roll 2" },
{ "Roll3", "Roll 3" },
{ "Roll4", "Roll 4" },
{ "Roll5", "Roll 5" },
{ "Roll6", "Roll 6" },
{ "Roll7", "Roll 7" },
{ "Roll8", "Roll 8" },
{ "Roll9", "Roll 9" },
{ "Roll10", "Roll 10" }
}; +
cupsFilePrintf(fp, "OpenUI InputSlot: PickOne\n"
"OrderDependency: 10 AnySetup InputSlot\n"
"*DefaultInputSlot: %s\n", ppdname);
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname)); +
for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++)
if (!strcmp(sources[j][0], ppdname))
{
cupsFilePrintf(fp, "*InputSlot %s/%s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname, sources[j][1], j);
break;
}
}
cupsFilePuts(fp, "CloseUI: InputSlot\n");
} +
/*
* MediaType...
*/ +
if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_KEYWORD)) != NULL)
pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
else
strlcpy(ppdname, "Unknown", sizeof(ppdname)); +
if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1)
{
static const char * const types[][2] =
{ /* Media type strings (far from complete) */
{ "Auto", "Automatic" },
{ "Cardstock", "Cardstock" },
{ "Disc", "CD/DVD/Bluray" },
{ "Envelope", "Envelope" },
{ "Labels", "Label" },
{ "Other", "Other" },
{ "Photographic", "Photo" },
{ "PhotographicGlossy", "Glossy Photo" },
{ "PhotographicHighGloss", "High-Gloss Photo" },
{ "PhotographicMatte", "Matte Photo" },
{ "PhotographicSatin", "Satin Photo" },
{ "PhotographicSemiGloss", "Semi-Gloss Photo" },
{ "Stationery", "Plain Paper" },
{ "StationeryLetterhead", "Letterhead" },
{ "Transparency", "Transparency" }
}; +
cupsFilePrintf(fp, "OpenUI MediaType: PickOne\n"
"OrderDependency: 10 AnySetup MediaType\n"
"*DefaultMediaType: %s\n", ppdname);
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname)); +
for (j = 0; j < (int)(sizeof(types) / sizeof(types[0])); j ++)
if (!strcmp(types[j][0], ppdname))
{
cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, types[j][1], ppdname);
break;
} +
if (j >= (int)(sizeof(types) / sizeof(types[0])))
cupsFilePrintf(fp, "*MediaType %s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, ppdname); +
}
cupsFilePuts(fp, "CloseUI: MediaType\n");
} +
/*
* ColorModel...
*/ +
if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL)
attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD); +
if (attr)
{
const char _defaultcolor = NULL; / Default */ +
cupsFilePuts(fp, "OpenUI ColorModel/Color Mode: PickOne\n"
"OrderDependency: 10 AnySetup ColorModel\n");
for (i = 0, count = ippGetCount(attr); i < count; i ++)
{
const char *keyword = ippGetString(attr, i, NULL);
/* Keyword for color/bit depth */ +
if (!strcmp(keyword, "black_1"))
{
cupsFilePuts(fp, "*ColorModel FastGray/Fast Grayscale: \"<</cupsColorSpace 3/cupsBitsPerColor 1/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n"); +
if (!default_color)
default_color = "FastGray";
}
else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome"))
{
cupsFilePuts(fp, "*ColorModel Gray/Grayscale: \"<</cupsColorSpace 18/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n"); +
if (!default_color || !strcmp(default_color, "FastGray"))
default_color = "Gray";
}
else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "color"))
{
cupsFilePuts(fp, "*ColorModel RGB/Color: \"<</cupsColorSpace 19/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n"); +
default_color = "RGB";
}
} +
if (default_color)
cupsFilePrintf(fp, "*DefaultColorModel: %s\n", default_color); +
cupsFilePuts(fp, "CloseUI: ColorModel\n");
} +
/*
* Duplex...
*/ +
if ((attr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge"))
{
cupsFilePuts(fp, "OpenUI Duplex/2-Sided Printing: PickOne\n"
"OrderDependency: 10 AnySetup Duplex\n"
"*DefaultDuplex: None\n"
"*Duplex None/Off (1-Sided): \"<</Duplex false>>setpagedevice\"\n"
"*Duplex DuplexNoTumble/Long-Edge (Portrait): \"<</Duplex true/Tumble false>>setpagedevice\"\n"
"*Duplex DuplexTumble/Short-Edge (Landscape): \"<</Duplex true/Tumble true>>setpagedevice\"\n"
"CloseUI: Duplex\n"); +
if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL)
{
const char *keyword = ippGetString(attr, 0, NULL);
/* Keyword value */ +
if (!strcmp(keyword, "flipped"))
cupsFilePuts(fp, "*cupsBackSide: Flipped\n");
else if (!strcmp(keyword, "manual-tumble"))
cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n");
else if (!strcmp(keyword, "normal"))
cupsFilePuts(fp, "*cupsBackSide: Normal\n");
else
cupsFilePuts(fp, "*cupsBackSide: Rotated\n");
}
} +
/*
* cupsPrintQuality and DefaultResolution...
*/ +
if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL)
{
count = ippGetCount(attr); +
pwg_ppdize_resolution(attr, count / 2, &xres, &yres, ppdname, sizeof(ppdname));
cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); +
cupsFilePuts(fp, "OpenUI cupsPrintQuality/Print Quality: PickOne\n"
"OrderDependency: 10 AnySetup cupsPrintQuality\n"
"*DefaultcupsPrintQuality: Normal\n");
if (count > 2)
{
pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0);
cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
}
pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0);
cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
if (count > 1)
{
pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0);
cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
} +
cupsFilePuts(fp, "CloseUI: cupsPrintQuality\n");
}
else if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL)
{
pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname));
cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
}
else
cupsFilePuts(fp, "*DefaultResolution: 300dpi\n"); +
/*
* Close up and return...
*/ +
cupsFileClose(fp); +
return (buffer); +} + + +/*
/*
* 'pwg_ppdize_resolution()' - Convert PWG resolution values to PPD values.
*/ + +static void +pwg_ppdize_resolution(
ipp_attribute_t attr, / I - Attribute to convert */
int element, /* I - Element to convert */
int xres, / O - X resolution in DPI */
int yres, / O - Y resolution in DPI */
char name, / I - Name buffer */
size_t namesize) /* I - Size of name buffer */ +{
ipp_res_t units; /* Units for resolution */ + +
*xres = ippGetResolution(attr, element, yres, &units); +
if (units == IPP_RES_PER_CM)
{
_xres = (int)(_xres * 2.54);
_yres = (int)(_yres * 2.54);
} +
if (name && namesize > 4)
{
if (xres == yres)
snprintf(name, namesize, "%ddpi", *xres);
else
snprintf(name, namesize, "%dx%ddpi", xres, yres);
} +} + + +/*
--- cups/ppd-private.h (revision 12508) +++ cups/ppd-private.h (working copy) @@ -188,6 +188,7 @@ const char media_type); extern int _ppdCacheWriteFile(_ppd_cache_t pc, const char filename, ipp_t attrs); +extern char _ppdCreateFromIPP(char buffer, size_t bufsize, ipp_t response); extern void _ppdFreeLanguages(cups_array_t languages); extern cups_encoding_t _ppdGetEncoding(const char name); extern cups_array_t _ppdGetLanguages(ppd_file_t *ppd);
--- cups/testppd.c (revision 12508) +++ cups/testppd.c (working copy) @@ -3,7 +3,7 @@ *
"str4258p2.patch":
--- cups/ppd-cache.c (revision 12510) +++ cups/ppd-cache.c (working copy) @@ -2815,6 +2815,9 @@
--- cups/testppd.c (revision 12510) +++ cups/testppd.c (working copy) @@ -901,6 +901,7 @@ puts("Unable to create PPD.");
ippDelete(response);
--- man/lpadmin.man (revision 12508) +++ man/lpadmin.man (working copy) @@ -3,7 +3,7 @@ .\" .\" lpadmin man page for CUPS. .\" -.\" Copyright 2007-2014 by Apple Inc. +.\" Copyright 2007-2015 by Apple Inc. .\" Copyright 1997-2006 by Easy Software Products. .\" .\" These coded instructions, statements, and computer programs are the @@ -12,7 +12,7 @@ .\" which should have been included with this file. If this file is .\" file is missing or damaged, see the license at "http://www.cups.org/". .\" -.TH lpadmin 8 "CUPS" "11 June 2014" "Apple Inc." +.TH lpadmin 8 "CUPS" "11 February 2015" "Apple Inc." .SH NAME lpadmin - configure cups printers and classes .SH SYNOPSIS @@ -91,6 +91,7 @@ Use the \fI-m\fR option with the .BR lpinfo (8) command to get a list of supported models. +The model "raw" clears any existing interface script or PPD file and the model "everywhere" queries the printer referred to by the specified IPP \fIdevice-uri\fR. .TP 5 \fB-o cupsIPPSupplies=true\fR .TP 5 @@ -199,6 +200,13 @@ This differs from the System V version which requires the root user to execute this command. .SH NOTES The CUPS version of \fBlpadmin\fR does not support all of the System V or Solaris printing system configuration options. +.SH EXAMPLE +Create an IPP Everywhere print queue: +.nf +
--- systemv/lpadmin.c (revision 12508) +++ systemv/lpadmin.c (working copy) @@ -3,7 +3,7 @@ *
+#define _CUPS_NO_DEPRECATED +#define _PPD_DEPRECATED
@@ -32,6 +34,7 @@ static int delete_printer_option(http_t _http, char printer, char option); static int enable_printer(http_t http, char printer); +static char get_printer_ppd(const char uri, char buffer, size_t bufsize); static cups_ptype_t get_printer_type(http_t http, char printer, char uri, size_t urisize); static int set_printer_options(httpt http, char printer, @@ -55,7 +58,11 @@ *val; / Pointer to allow/deny value _/ int numoptions; / Number of options _/ cups_optiont *options; / Options */
*device_uri; /* device-uri value */
_cupsSetLocale(argv); @@ -73,8 +80,7 @@ case 'c' : /* Add printer to class */ if (!http) {
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL)
{
@@ -126,8 +132,7 @@ case 'd' : /* Set as default destination */ if (!http) {
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL)
{
@@ -217,10 +222,10 @@ if (printer == NULL) {
cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED);
if (http)
httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
_cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
argv[0]);
@@ -230,8 +235,7 @@
if (!http)
{
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL)
{
@@ -316,8 +320,7 @@ case 'r' : /* Remove printer from class */ if (!http) {
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL)
{
@@ -370,8 +373,7 @@ case 'R' : /* Remove option */ if (!http) {
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL)
{
@@ -487,8 +489,7 @@ case 'x' : /* Delete a printer */ if (!http) {
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL)
{
@@ -621,11 +622,19 @@
http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
if (http == NULL) { @@ -648,6 +657,9 @@ return (1); }
unlink(evefile); + if (printer == NULL) { _cupsLangPuts(stdout, @@ -692,7 +704,7 @@ printer, pclass));
/*
request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/classes/%s", pclass); @@ -717,7 +729,7 @@ response = cupsDoRequest(http, request, "/");
/*
request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -786,7 +798,7 @@ ippDelete(response);
ippDelete(cupsDoRequest(http, request, "/admin/"));
@@ -812,7 +824,7 @@ DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
/*
request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -837,7 +849,7 @@
ippDelete(cupsDoRequest(http, request, "/admin/"));
@@ -863,7 +875,7 @@ DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
/*
request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s", printer); @@ -887,7 +899,7 @@
ippDelete(cupsDoRequest(http, request, "/admin/"));
@@ -920,7 +932,7 @@ printer, pclass));
/*
request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/classes/%s", pclass); @@ -943,7 +955,7 @@ */
if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
@@ -983,7 +995,7 @@ if (members->num_values == 1) { /*
request = ippNewRequest(IPP_OP_CUPS_DELETE_CLASS);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -1002,7 +1014,7 @@ else { /*
request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -1041,7 +1053,7 @@
ippDelete(cupsDoRequest(http, request, "/admin/"));
@@ -1066,7 +1078,7 @@
/*
if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -1093,7 +1105,7 @@
ippDelete(cupsDoRequest(http, request, "/admin/"));
@@ -1119,7 +1131,7 @@ DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
/*
if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
IPP_PSTATE_IDLE);
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
/* @@ -1149,7 +1161,7 @@
ippDelete(cupsDoRequest(http, request, "/admin/"));
@@ -1161,6 +1173,63 @@
/*
@@ -1189,7 +1258,7 @@
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, @@ -1255,8 +1324,8 @@ options, file));
/*
if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
/*
@@ -1292,14 +1366,7 @@ NULL, "tbcp"); }
--- xcode/CUPS.xcodeproj/project.pbxproj (revision 12508) +++ xcode/CUPS.xcodeproj/project.pbxproj (working copy) @@ -31,6 +31,7 @@ buildPhases = ( ); dependencies = (
"str4258p3.patch":
--- cgi-bin/admin.c (revision 12514) +++ cgi-bin/admin.c (working copy) @@ -3,7 +3,7 @@ *
These coded instructions, statements, and computer programs are the @@ -18,6 +18,8 @@ */
+#include <cups/http-private.h> +#include <cups/ppd-private.h>
@@ -38,12 +40,7 @@
-static void choose_device_cb(const char *device_class,
const char *title);
+static void choose_device_cb(const char device_class, const char device_id, const char device_info, const char device_make_and_model, const char device_uri, const char device_location, const char title); static void do_add_rss_subscription(http_t http); static void do_am_class(http_t http, int modify); static void do_am_printer(http_t http, int modify); @@ -61,6 +58,7 @@ static char get_option_value(ppd_file_t ppd, const char name, char buffer, size_t bufsize); static double get_points(double number, const char uval); +static char get_printer_ppd(const char uri, char buffer, size_t bufsize);
/ @@ -832,7 +830,8 @@ const cgi_file_t file; / Uploaded file, if any _/ const char var; / CGI variable / char uri[HTTP_MAXURI], / Device or printer URI */
else if (strcmp(var, "__no_change__"))
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", NULL, var); } @@ -1384,6 +1385,11 @@
if (file) ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
@@ -4198,5 +4204,78 @@
/*
--- cups/ppd-cache.c (revision 12514) +++ cups/ppd-cache.c (working copy) @@ -2864,6 +2864,11 @@ cupsFilePrintf(fp, "_NickName: \"%s\"\n", model); cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model);
cupsFilePuts(fp, "_ColorDevice: False\n"); + cupsFilePrintf(fp, "_cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); cupsFilePuts(fp, "_cupsSNMPSupplies: False\n"); cupsFilePuts(fp, "_cupsLanguages: \"en\"\n"); @@ -2881,7 +2886,9 @@
if (!_cups_strcasecmp(format, "application/pdf")) cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n");
else if (_cups_strcasecmp(format, "application/octet-stream") && _cups_strcasecmp(format, "application/vnd.hp-pcl") && _cups_strcasecmp(format, "text/plain"))
cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 10 -\"\n", format, format);
} } @@ -3153,7 +3160,7 @@ const char keyword = ippGetString(attr, i, NULL); / Keyword for color/bit depth */
if (!strcmp(keyword, "black_1"))
@@ -3209,6 +3216,35 @@ else cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); }
} }
/* @@ -3240,6 +3276,53 @@
cupsFilePuts(fp, "CloseUI: cupsPrintQuality\n"); }
--- doc/help/man-lpadmin.html (revision 12514) +++ doc/help/man-lpadmin.html (working copy) @@ -79,6 +79,7 @@ Use the -m option with the lpinfo(8) command to get a list of supported models. +The model "raw" clears any existing interface script or PPD file and the model "everywhere" queries the printer referred to by the specified IPP device-uri.
+
lpadmin -p myprinter -E -v ipp://myprinter.local/ipp/print -m everywhere + +
cupsaccept(8), cupsenable(8), @@ -168,7 +176,7 @@ lpoptions(1), CUPS Online Help (http://localhost:631/help)
-Copyright © 2007-2014 by Apple Inc. +Copyright © 2007-2015 by Apple Inc.
Version: 2.1-feature CUPS.org User: mike
To fully support IPP Everywhere printers today, we need a PPD generator that will drive a traditional CUPS print queue. The PPD generator should query the IPP Everywhere printer, creating the necessary PPD options and values needed to support native PWG Raster, JPEG, and PDF printing.