113-cups-remote-printing.diff   [plain text]


--- samba/source/printing/print_cups.c.orig	2004-12-15 22:02:03.000000000 -0800
+++ samba/source/printing/print_cups.c	2004-12-15 21:59:57.000000000 -0800
@@ -26,6 +26,11 @@
 #include <cups/language.h>
 
 
+static const char printerprefsfile[] = "/Library/Preferences/com.apple.printservice.plist";
+
+static char *cups_map_printer_name(http_t *http_p, const char *name);
+
+
 /*
  * 'cups_passwd_cb()' - The CUPS password callback...
  */
@@ -68,13 +73,24 @@
 	char		*name,		/* printer-name attribute */
 			*make_model,	/* printer-make-and-model attribute */
 			*info;		/* printer-info attribute */
+	int		remote,		/* Remote printer */
+			shared;		/* Shared printer */
 	static const char *requested[] =/* Requested attributes */
 			{
 			  "printer-name",
 			  "printer-make-and-model",
-			  "printer-info"
+			  "printer-info",
+			  "printer-type",
+			  "printer-is-shared"
 			};       
 
+	Boolean		displayPrinter;
+	CFArrayRef	smbQarray;
+	CFDataRef	xmlData;
+	CFURLRef	prefsurl;
+	Boolean		printerprefs;
+	CFStringRef	printername;
+	CFPropertyListRef plist;
 
 	DEBUG(5,("cups_printer_fn(%p)\n", fn));
 
@@ -134,6 +150,33 @@
 		return;
 	}
 
+	/*
+	 * Retrieve PrintService's list of queue names that have sharing enabled...
+	 */
+
+	printerprefs	= false;
+	smbQarray	= NULL;
+
+	prefsurl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)printerprefsfile, (CFIndex)strlen(printerprefsfile), false);
+	if (prefsurl)
+	{
+		printerprefs = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, prefsurl, &xmlData, NULL, NULL, NULL);
+		if (printerprefs)
+		{
+			plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL);
+			if (plist)
+			{
+				smbQarray = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)plist, CFSTR("smbSharedQueues"));
+				if (smbQarray)
+					CFRetain(smbQarray);
+				CFRelease(plist);
+			}
+			CFRelease(xmlData);
+		}
+		CFRelease(prefsurl);
+	}
+
+
 	for (attr = response->attrs; attr != NULL;)
 	{
 	       /*
@@ -153,6 +196,8 @@
 		name       = NULL;
 		make_model = NULL;
 		info       = NULL;
+		remote     = 0;
+		shared     = 1;
 
 		while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
 		{
@@ -168,6 +213,14 @@
 			    attr->value_tag == IPP_TAG_TEXT)
 				info = attr->values[0].string.text;
 
+        		if (strcmp(attr->name, "printer-type") == 0 &&
+			    attr->value_tag == IPP_TAG_ENUM)
+				remote = attr->values[0].integer & CUPS_PRINTER_REMOTE;
+
+        		if (strcmp(attr->name, "printer-is-shared") == 0 &&
+			    attr->value_tag == IPP_TAG_ENUM)
+				shared = attr->values[0].integer;
+
         		attr = attr->next;
 		}
 
@@ -175,13 +228,32 @@
 		* See if we have everything needed...
 		*/
 
-		if (name == NULL)
-			break;
+		if (!name || remote || !shared)
+			continue;
+
+		/*
+		 * Make sure it's in PrintService's list of queues that are shared...
+		 */
+
+		if (printerprefs)
+		{
+			printername = CFStringCreateWithCString( kCFAllocatorDefault, name, kCFStringEncodingUTF8 );
+			if (printername)
+			{
+				displayPrinter = smbQarray && 
+						 CFArrayContainsValue(smbQarray, CFRangeMake(0, CFArrayGetCount(smbQarray)), printername);
+
+				CFRelease(printername);
+
+				if (!displayPrinter)
+					continue;
+			}
+		}
 
  		if (info == NULL || !info[0])
 			(*fn)(name, make_model);
 		else
-			(*fn)(name, info);
+			(*fn)(info, make_model);
 		
 
 	}
@@ -247,6 +319,8 @@
 		name       = NULL;
 		make_model = NULL;
 		info       = NULL;
+		remote     = 0;
+		shared     = 1;
 
 		while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
 		{
@@ -262,6 +336,14 @@
 			    attr->value_tag == IPP_TAG_TEXT)
 				info = attr->values[0].string.text;
 
+        		if (strcmp(attr->name, "printer-type") == 0 &&
+			    attr->value_tag == IPP_TAG_ENUM)
+				remote = attr->values[0].integer & CUPS_PRINTER_REMOTE;
+
+        		if (strcmp(attr->name, "printer-is-shared") == 0 &&
+			    attr->value_tag == IPP_TAG_ENUM)
+				shared = attr->values[0].integer;
+
         		attr = attr->next;
 		}
 
@@ -269,13 +351,32 @@
 		* See if we have everything needed...
 		*/
 
-		if (name == NULL)
-			break;
+		if (!name || remote || !shared)
+			continue;
+
+		/*
+		 * Make sure it's in PrintService's list of queues that are shared...
+		 */
+
+		if (printerprefs)
+		{
+			printername = CFStringCreateWithCString( kCFAllocatorDefault, name, kCFStringEncodingUTF8 );
+			if (printername)
+			{
+				displayPrinter = smbQarray && 
+						 CFArrayContainsValue(smbQarray, CFRangeMake(0, CFArrayGetCount(smbQarray)), printername);
+
+				CFRelease(printername);
+
+				if (!displayPrinter)
+					continue;
+			}
+		}
 
  		if (info == NULL || !info[0])
 			(*fn)(name, make_model);
 		else
-			(*fn)(name, info);
+			(*fn)(info, make_model);
 		
 
 	}
@@ -287,6 +388,9 @@
 	*/
 
 	httpClose(http);
+
+	if (smbQarray)
+		CFRelease(smbQarray);
 }
 
 
@@ -325,6 +429,14 @@
 	}
 
        /*
+	 * Map from "printer-info" queue names to the real "printer-name" queue id.
+	 */
+
+	name = cups_map_printer_name(http, name);
+	if (name == NULL)
+		return 0;
+
+       /*
 	* Build an IPP_GET_PRINTER_ATTRS request, which requires the following
 	* attributes:
 	*
@@ -671,6 +783,7 @@
 	pstring		new_jobname;
 	int		num_options = 0; 
 	cups_option_t 	*options;
+	char 		*printername; 	/* Printer name */
 
 	DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
 
@@ -692,6 +805,14 @@
 	}
 
        /*
+	 * Map from "printer-info" queue names to the real "printer-name" queue id.
+	 */
+
+	printername = cups_map_printer_name(http, PRINTERNAME(snum));
+	if (printername == NULL)
+		return 2;
+
+       /*
 	* Build an IPP_PRINT_JOB request, which requires the following
 	* attributes:
 	*
@@ -716,7 +837,7 @@
         	     "attributes-natural-language", NULL, language->language);
 
 	slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
-	         PRINTERNAME(snum));
+	         printername);
 
 	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
         	     "printer-uri", NULL, uri);
@@ -754,7 +875,7 @@
 	* Do the request and get back a response...
 	*/
 
-	slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
+	slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
 
         ret = 1;
 	if ((response = cupsDoFileRequest(http, request, uri,
@@ -846,6 +967,14 @@
 	}
 
        /*
+	 * Map from "printer-info" queue names to the real "printer-name" queue id.
+	 */
+
+	printer_name = cups_map_printer_name(http, printer_name);
+	if (printer_name == NULL)
+		return 2;
+
+       /*
         * Generate the printer URI...
 	*/
 
@@ -1128,6 +1257,7 @@
 			*response;	/* IPP Response */
 	cups_lang_t	*language;	/* Default language */
 	char		uri[HTTP_MAX_URI]; /* printer-uri attribute */
+	char 		*printername; 	/* Printer name */
 
 
 	DEBUG(5,("cups_queue_pause(%d)\n", snum));
@@ -1150,6 +1280,14 @@
 	}
 
 	/*
+	 * Map from "printer-info" queue names to the real "printer-name" queue id.
+	 */
+
+	printername = cups_map_printer_name(http, PRINTERNAME(snum));
+	if (printername == NULL)
+		return 2;
+
+	/*
 	 * Build an IPP_PAUSE_PRINTER request, which requires the following
 	 * attributes:
 	 *
@@ -1173,7 +1311,7 @@
         	     "attributes-natural-language", NULL, language->language);
 
 	slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
-	         PRINTERNAME(snum));
+	         printername);
 
 	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
 
@@ -1220,6 +1358,7 @@
 			*response;	/* IPP Response */
 	cups_lang_t	*language;	/* Default language */
 	char		uri[HTTP_MAX_URI]; /* printer-uri attribute */
+	char 		*printername; 	/* Printer name */
 
 
 	DEBUG(5,("cups_queue_resume(%d)\n", snum));
@@ -1242,6 +1381,14 @@
 	}
 
        /*
+	 * Map from "printer-info" queue names to the real "printer-name" queue id.
+	 */
+
+	printername = cups_map_printer_name(http, PRINTERNAME(snum));
+	if (printername == NULL)
+		return 2;
+
+       /*
 	* Build an IPP_RESUME_PRINTER request, which requires the following
 	* attributes:
 	*
@@ -1265,7 +1412,7 @@
         	     "attributes-natural-language", NULL, language->language);
 
 	slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
-	         PRINTERNAME(snum));
+	         printername);
 
 	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
 
@@ -1297,6 +1444,296 @@
 	return (ret);
 }
 
+
+/*
+ * 'cups_map_printer_name()' -	Map from the "printer-info" values OSX uses as queue names 
+ *				to the real "printer-name" queue id.
+ */
+
+static char *					/* O - mapped name or NULL */
+cups_map_printer_name(http_t *http, 		/* I - HTTP connection */
+		      const char *name)		/* I - name to map */
+{
+	ipp_t		*request,		/* IPP Request */
+			*response;		/* IPP Response */
+	ipp_attribute_t	*attr;			/* Current attribute */
+	cups_lang_t	*language;		/* Default language */
+	char		*printer_name,		/* printer-name attribute */
+			*printer_info;		/* printer-info attribute */
+	int		remote,			/* Remote printer */
+			shared;			/* Shared printer */
+	static char	*mapped_name = NULL;	/* Returned printer name */
+	static const char *requested[] =	/* Requested attributes */
+			{
+			  "printer-name",
+			  "printer-info",
+			  "printer-type",
+			  "printer-is-shared"
+			};       
+
+	CFArrayRef	smbQarray;
+	CFDataRef	xmlData;
+	CFURLRef	prefsurl;
+	Boolean		printerprefs;
+	CFStringRef	printername;
+	CFPropertyListRef plist;
+
+	DEBUG(5,("cups_map_printer_name(%s)\n", name));
+
+	/*
+	 * Free the old mapped queue name.
+	 */
+
+	if (mapped_name)
+	{
+		free(mapped_name);
+		mapped_name = NULL;
+	}
+
+       /*
+	* Build a CUPS_GET_PRINTERS request, which requires the following
+	* attributes:
+	*
+	*    attributes-charset
+	*    attributes-natural-language
+	*    requested-attributes
+	*/
+
+	request = ippNew();
+
+	request->request.op.operation_id = CUPS_GET_PRINTERS;
+	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);
+
+        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	              "requested-attributes",
+		      (sizeof(requested) / sizeof(requested[0])),
+		      NULL, requested);
+
+       /*
+	* Do the request and get back a response...
+	*/
+
+	if ((response = cupsDoRequest(http, request, "/")) == NULL)
+	{
+		DEBUG(0,("Unable to get printer list - %s\n",
+			 ippErrorString(cupsLastError())));
+		httpClose(http);
+		return NULL;
+	}
+
+	for (attr = response->attrs; attr != NULL;)
+	{
+	       /*
+		* Skip leading attributes until we hit a printer...
+		*/
+
+		while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+			attr = attr->next;
+
+		if (attr == NULL)
+        		break;
+
+	       /*
+		* Pull the needed attributes from this printer...
+		*/
+
+		printer_name= NULL;
+		printer_info= NULL;
+		remote	    = 0;
+		shared	    = 1;
+
+		while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+		{
+        		if (strcmp(attr->name, "printer-name") == 0 &&
+			    attr->value_tag == IPP_TAG_NAME)
+				printer_name = attr->values[0].string.text;
+
+        		if (strcmp(attr->name, "printer-info") == 0 &&
+			    attr->value_tag == IPP_TAG_TEXT)
+				printer_info = attr->values[0].string.text;
+
+        		if (strcmp(attr->name, "printer-type") == 0 &&
+			    attr->value_tag == IPP_TAG_ENUM)
+				remote = attr->values[0].integer & CUPS_PRINTER_REMOTE;
+
+        		if (strcmp(attr->name, "printer-is-shared") == 0 &&
+			    attr->value_tag == IPP_TAG_ENUM)
+				shared = attr->values[0].integer;
+
+        		attr = attr->next;
+		}
+
+	       /*
+		* We're only interested in local shared printers that have names...
+		*/
+
+		if (!name || remote || !shared)
+			continue;
+
+ 		if (!strcmp(name, printer_name) || !strcmp(name, printer_info))
+ 		{
+ 			mapped_name = strdup(printer_name);
+ 			break;
+ 		}
+	}
+
+	ippDelete(response);
+
+
+	/*
+	 * If we match the name in the printer list then look at the classes list...
+	 */
+
+	if (!mapped_name)
+	{
+	       /*
+		* Build a CUPS_GET_CLASSES request, which requires the following
+		* attributes:
+		*
+		*    attributes-charset
+		*    attributes-natural-language
+		*    requested-attributes
+		*/
+	
+		request = ippNew();
+	
+		request->request.op.operation_id = CUPS_GET_CLASSES;
+		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);
+	
+		ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+			      "requested-attributes",
+			      (sizeof(requested) / sizeof(requested[0])),
+			      NULL, requested);
+	
+	       /*
+		* Do the request and get back a response...
+		*/
+	
+		if ((response = cupsDoRequest(http, request, "/")) == NULL)
+		{
+			DEBUG(0,("Unable to get printer list - %s\n",
+				 ippErrorString(cupsLastError())));
+			httpClose(http);
+			return;
+		}
+	
+		for (attr = response->attrs; attr != NULL;)
+		{
+		       /*
+			* Skip leading attributes until we hit a printer...
+			*/
+	
+			while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+				attr = attr->next;
+	
+			if (attr == NULL)
+				break;
+	
+		       /*
+			* Pull the needed attributes from this printer...
+			*/
+	
+			printer_name= NULL;
+			printer_info= NULL;
+			remote	    = 0;
+			shared	    = 1;
+	
+			while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+			{
+				if (strcmp(attr->name, "printer-name") == 0 &&
+				    attr->value_tag == IPP_TAG_NAME)
+					printer_name = attr->values[0].string.text;
+	
+				if (strcmp(attr->name, "printer-info") == 0 &&
+				    attr->value_tag == IPP_TAG_TEXT)
+					printer_info = attr->values[0].string.text;
+	
+				if (strcmp(attr->name, "printer-type") == 0 &&
+				    attr->value_tag == IPP_TAG_ENUM)
+					remote = attr->values[0].integer & CUPS_PRINTER_REMOTE;
+	
+				if (strcmp(attr->name, "printer-is-shared") == 0 &&
+				    attr->value_tag == IPP_TAG_ENUM)
+					shared = attr->values[0].integer;
+	
+				attr = attr->next;
+			}
+	
+		       /*
+			* We're only interested in local shared printers that have names...
+			*/
+	
+			if (!name || remote || !shared)
+				continue;
+	
+			if (!strcmp(name, printer_name) || !strcmp(name, printer_info))
+			{
+				mapped_name = strdup(printer_name);
+				break;
+			}
+		}
+	
+		ippDelete(response);
+	}
+
+	/*
+	 * If we've mapped the name make sure it's in PrintService's list of queues that are shared...
+	 */
+
+	if (mapped_name)
+	{
+		prefsurl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)printerprefsfile, (CFIndex)strlen(printerprefsfile), false);
+		if (prefsurl)
+		{
+			printerprefs = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, prefsurl, &xmlData, NULL, NULL, NULL);
+			if (printerprefs)
+			{
+				plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL);
+				if (plist)
+				{
+					smbQarray = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)plist, CFSTR("smbSharedQueues"));
+					if (smbQarray)
+					{
+						printername = CFStringCreateWithCString( kCFAllocatorDefault, mapped_name, kCFStringEncodingUTF8 );
+						if (printername)
+						{
+							if (!CFArrayContainsValue(smbQarray, CFRangeMake(0, CFArrayGetCount(smbQarray)), printername)) {
+								free(mapped_name);
+								mapped_name = NULL;
+							}
+							CFRelease(printername);
+						}
+					} else {
+						free(mapped_name);
+						mapped_name = NULL;
+					}
+					CFRelease(xmlData);
+					CFRelease(plist);
+				}
+			}
+			CFRelease(prefsurl);
+		}
+	}
+
+	return mapped_name;
+}
+
 /*******************************************************************
  * CUPS printing interface definitions...
  ******************************************************************/