--- 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 +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... ******************************************************************/