void ChooserDialog::PopulateServicesList( void ) { ServiceTypeVector::iterator i; CString type; CString desc; std::string tmp; // Add a fixed list of known services. if( mServiceTypes.empty() ) { const KnownServiceEntry * service; for( service = kKnownServiceTable; service->serviceType; ++service ) { ServiceTypeInfo info; info.serviceType = service->serviceType; info.description = service->description; info.urlScheme = service->urlScheme; mServiceTypes.push_back( info ); } } // Add each service to the list. for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i ) { const char * p; const char * q; p = ( *i ).serviceType.c_str(); if( *p == '_' ) ++p; // Skip leading '_'. q = strchr( p, '.' ); // Find first '.'. if( q ) tmp.assign( p, (size_t)( q - p ) ); // Use only up to the first '.'. else tmp.assign( p ); // No '.' so use the entire string. UTF8StringToStringObject( tmp.c_str(), type ); UTF8StringToStringObject( ( *i ).description.c_str(), desc ); int n; n = mServiceList.GetItemCount(); mServiceList.InsertItem( n, type ); mServiceList.SetItemText( n, 1, desc ); } // Select the first service type by default. if( !mServiceTypes.empty() ) { mServiceList.SetItemState( 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); } }
OSStatus CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded ) { char nextLabel[128] = "\0"; char decodedDomainString[kDNSServiceMaxDomainName]; char * buffer = (char *) raw; int labels = 0, i; char text[64]; const char *label[128]; OSStatus err; // Initialize decodedDomainString[0] = '\0'; // Count the labels while ( *buffer ) { label[labels++] = buffer; buffer = (char *) GetNextLabel(buffer, text); } buffer = (char*) raw; for (i = 0; i < labels; i++) { buffer = (char *)GetNextLabel(buffer, nextLabel); strcat(decodedDomainString, nextLabel); strcat(decodedDomainString, "."); } // Remove trailing dot from domain name. decodedDomainString[ strlen( decodedDomainString ) - 1 ] = '\0'; // Convert to Unicode err = UTF8StringToStringObject( decodedDomainString, decoded ); return err; }
// Printer::EventHandler implementation OSStatus CSecondPage::OnAddPrinter( uint32_t inInterfaceIndex, const char * inName, const char * inType, const char * inDomain, bool moreComing) { Printer * printer; Service * service; CPrinterSetupWizardSheet * psheet; DWORD printerNameCount; bool newPrinter = false; OSStatus err = kNoErr; check( IsWindow( m_hWnd ) ); m_browseList.SetRedraw(FALSE); psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent()); require_quiet( psheet, exit ); printer = Lookup( inName ); if (printer == NULL) { try { printer = new Printer; } catch (...) { printer = NULL; } require_action( printer, exit, err = E_OUTOFMEMORY ); printer->window = this; printer->name = inName; err = UTF8StringToStringObject(inName, printer->displayName); check_noerr( err ); printer->actualName = printer->displayName; printer->installed = false; printer->deflt = false; printer->resolving = 0; // // Compare this name against printers that are already installed // to avoid name clashes. Rename as necessary // to come up with a unique name. // printerNameCount = 2; for (;;) { PrinterNameMap::iterator it; it = m_printerNames.find(printer->actualName); if (it != m_printerNames.end()) { printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount); } else { break; } printerNameCount++; } newPrinter = true; } check( printer ); service = printer->LookupService( inType ); if ( service != NULL ) { service->refs++; } else { try { service = new Service; } catch (...) { service = NULL; } require_action( service, exit, err = E_OUTOFMEMORY ); service->printer = printer; service->ifi = inInterfaceIndex; service->type = inType; service->domain = inDomain; service->qtotal = 1; service->refs = 1; service->serviceRef = NULL; printer->services.push_back( service ); // // if the printer is selected, then we'll want to start a // resolve on this guy // if ( m_selected == printer ) { StartResolve( service ); } } if ( newPrinter ) { printer->item = m_browseList.InsertItem(printer->displayName); m_browseList.SetItemData( printer->item, (DWORD_PTR) printer ); m_printers.push_back( printer ); m_browseList.SortChildren(TVI_ROOT); if ( printer->name == m_selectedName ) { m_browseList.SelectItem( printer->item ); } // // if the searching item is still in the list // get rid of it // // note that order is important here. Insert the printer // item before removing the placeholder so we always have // an item in the list to avoid experiencing the bug // in Microsoft's implementation of CTreeCtrl // if (m_emptyListItem != NULL) { m_browseList.DeleteItem(m_emptyListItem); m_emptyListItem = NULL; m_browseList.EnableWindow(TRUE); } } exit: if (!moreComing) { m_browseList.SetRedraw(TRUE); m_browseList.Invalidate(); } return err; }
void DNSSD_API CSecondPage::OnResolve( DNSServiceRef inRef, DNSServiceFlags inFlags, uint32_t inInterfaceIndex, DNSServiceErrorType inErrorCode, const char * inFullName, const char * inHostName, uint16_t inPort, uint16_t inTXTSize, const char * inTXT, void * inContext ) { DEBUG_UNUSED(inFullName); DEBUG_UNUSED(inInterfaceIndex); DEBUG_UNUSED(inFlags); DEBUG_UNUSED(inRef); CSecondPage * self; Service * service; Queue * q; bool qtotalDefined = false; uint32_t qpriority = kDefaultPriority; CString qname; int idx; OSStatus err; require_noerr( inErrorCode, exit ); service = reinterpret_cast<Service*>( inContext ); require_quiet( service, exit); check( service->refs != 0 ); self = service->printer->window; require_quiet( self, exit ); err = self->StopOperation( service->serviceRef ); require_noerr( err, exit ); // // hold on to the hostname... // err = UTF8StringToStringObject( inHostName, service->hostname ); require_noerr( err, exit ); // // <rdar://problem/3739200> remove the trailing dot on hostname // idx = service->hostname.ReverseFind('.'); if ((idx > 1) && ((service->hostname.GetLength() - 1) == idx)) { service->hostname.Delete(idx, 1); } // // hold on to the port // service->portNumber = ntohs(inPort); // // parse the text record. // err = self->ParseTextRecord( service, inTXTSize, inTXT, qtotalDefined, qname, qpriority ); require_noerr( err, exit ); if ( service->qtotal == 1 ) { // // create a new queue // try { q = new Queue; } catch (...) { q = NULL; } require_action( q, exit, err = E_OUTOFMEMORY ); if ( qtotalDefined ) { q->name = qname; } q->priority = qpriority; service->queues.push_back( q ); // // we've completely resolved this service // self->OnResolveService( service ); } else { // // if qtotal is more than 1, then we need to get additional // text records. if not, then this service is considered // resolved // err = DNSServiceQueryRecord(&service->serviceRef, 0, inInterfaceIndex, inFullName, kDNSServiceType_TXT, kDNSServiceClass_IN, OnQuery, (void*) service ); require_noerr( err, exit ); err = self->StartOperation( service->serviceRef ); require_noerr( err, exit ); } exit: return; }
OSStatus CSecondPage::ParseTextRecord( Service * service, uint16_t inTXTSize, const char * inTXT, bool & qtotalDefined, CString & qname, uint32_t & qpriority ) { bool rpOnly = true; OSStatus err = kNoErr; while (inTXTSize) { char buf[256]; unsigned char num = *inTXT; check( (int) num < inTXTSize ); if ( num ) { memset(buf, 0, sizeof(buf)); memcpy(buf, inTXT + 1, num); CString elem; err = UTF8StringToStringObject( buf, elem ); require_noerr( err, exit ); int curPos = 0; CString key = elem.Tokenize(L"=", curPos); CString val = elem.Tokenize(L"=", curPos); key.MakeLower(); if ( key == L"rp" ) { qname = val; } else { rpOnly = false; if ((key == L"usb_mfg") || (key == L"usb_manufacturer")) { service->usb_MFG = val; } else if ((key == L"usb_mdl") || (key == L"usb_model")) { service->usb_MDL = val; } else if (key == L"ty") { service->description = val; } else if (key == L"product") { service->product = val; } else if (key == L"note") { service->location = val; } else if (key == L"qtotal") { service->qtotal = (unsigned short) _ttoi((LPCTSTR) val); qtotalDefined = true; } else if (key == L"priority") { qpriority = _ttoi((LPCTSTR) val); } } } inTXTSize -= (num + 1); inTXT += (num + 1); } exit: if ( rpOnly ) { qtotalDefined = true; } return err; }
OSStatus CPrinterSetupWizardSheet::ParseTextRecord( Service * service, Queue * q, uint16_t inTXTSize, const char * inTXT ) { check( service ); check( q ); // <rdar://problem/3946587> Use TXTRecord APIs declared in dns_sd.h bool qtotalDefined = false; const void * val; char buf[256]; uint8_t len; OSStatus err = kNoErr; // <rdar://problem/3987680> Default to queue "lp" q->name = L"lp"; // <rdar://problem/4003710> Default pdl key to be "application/postscript" q->pdl = L"application/postscript"; if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "rp", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->name ); require_noerr( err, exit ); } if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "pdl", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->pdl ); require_noerr( err, exit ); } if ( ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_mfg", &len ) ) != NULL ) || ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_manufacturer", &len ) ) != NULL ) ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->usb_MFG ); require_noerr( err, exit ); } if ( ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_mdl", &len ) ) != NULL ) || ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_model", &len ) ) != NULL ) ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->usb_MDL ); require_noerr( err, exit ); } if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "ty", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->description ); require_noerr( err, exit ); } if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "product", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->product ); require_noerr( err, exit ); } if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "note", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; err = UTF8StringToStringObject( buf, q->location ); require_noerr( err, exit ); } if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "qtotal", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; service->qtotal = (unsigned short) atoi( buf ); qtotalDefined = true; } if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "priority", &len ) ) != NULL ) { // Stringize val ( doesn't have trailing '\0' yet ) memcpy( buf, val, len ); buf[len] = '\0'; q->priority = atoi( buf ); } // <rdar://problem/4124524> Was this printer discovered via OS X Printer Sharing? if ( TXTRecordContainsKey( inTXTSize, inTXT, "printer-state" ) || TXTRecordContainsKey( inTXTSize, inTXT, "printer-type" ) ) { service->printer->isSharedFromOSX = true; } exit: // The following code is to fix a problem with older HP // printers that don't include "qtotal" in their text // record. We'll check to see if the q->name is "TEXT" // and if so, we're going to modify it to be "lp" so // that we don't use the wrong queue if ( !err && !qtotalDefined && ( q->name == L"TEXT" ) ) { q->name = "lp"; } return err; }
Printer* CPrinterSetupWizardSheet::OnAddPrinter( uint32_t inInterfaceIndex, const char * inName, const char * inType, const char * inDomain, bool moreComing) { Printer * printer = NULL; DWORD printerNameCount; OSStatus err; DEBUG_UNUSED( inInterfaceIndex ); DEBUG_UNUSED( inType ); DEBUG_UNUSED( inDomain ); try { printer = new Printer; } catch (...) { printer = NULL; } require_action( printer, exit, err = E_OUTOFMEMORY ); printer->window = this; printer->name = inName; err = UTF8StringToStringObject(inName, printer->displayName); check_noerr( err ); printer->actualName = printer->displayName; printer->installed = false; printer->deflt = false; printer->resolving = 0; // Compare this name against printers that are already installed // to avoid name clashes. Rename as necessary // to come up with a unique name. printerNameCount = 2; for (;;) { CPrinterSetupWizardSheet::PrinterNames::iterator it; // <rdar://problem/4141221> Don't use find to do comparisons because we need to // do a case insensitive string comparison for ( it = m_printerNames.begin(); it != m_printerNames.end(); it++ ) { if ( (*it).CompareNoCase( printer->actualName ) == 0 ) { break; } } if (it != m_printerNames.end()) { printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount); } else { break; } printerNameCount++; } m_printers.push_back( printer ); if ( GetActivePage() == &m_pgSecond ) { m_pgSecond.OnAddPrinter( printer, moreComing ); } exit: return printer; }
void DNSSD_API ExplorerBarWindow::ResolveCallBack( DNSServiceRef inRef, DNSServiceFlags inFlags, uint32_t inInterfaceIndex, DNSServiceErrorType inErrorCode, const char * inFullName, const char * inHostName, uint16_t inPort, uint16_t inTXTSize, const char * inTXT, void * inContext ) { ExplorerBarWindow * obj; ServiceHandlerEntry * handler; OSStatus err; DEBUG_UNUSED( inRef ); DEBUG_UNUSED( inFlags ); DEBUG_UNUSED( inErrorCode ); DEBUG_UNUSED( inFullName ); require_noerr( inErrorCode, exit ); handler = (ServiceHandlerEntry *) inContext; check( handler ); obj = handler->obj; check( obj ); try { ResolveInfo * resolve; int idx; dlog( kDebugLevelNotice, "resolved %s on ifi %d to %s\n", inFullName, inInterfaceIndex, inHostName ); // Stop resolving after the first good result. obj->StopResolve(); // Post a message to the main thread so it can handle it since MFC is not thread safe. resolve = new ResolveInfo; require_action( resolve, exit, err = kNoMemoryErr ); UTF8StringToStringObject( inHostName, resolve->host ); // rdar://problem/3841564 // // strip trailing dot from hostname because some flavors of Windows // have trouble parsing it. idx = resolve->host.ReverseFind('.'); if ((idx > 1) && ((resolve->host.GetLength() - 1) == idx)) { resolve->host.Delete(idx, 1); } resolve->port = ntohs( inPort ); resolve->ifi = inInterfaceIndex; resolve->handler = handler; err = resolve->txt.SetData( inTXT, inTXTSize ); check_noerr( err ); obj->OnResolve(resolve); } catch( ... ) { dlog( kDebugLevelError, "ResolveCallBack: exception thrown\n" ); } exit: return; }
void DNSSD_API ExplorerBarWindow::BrowseCallBack( DNSServiceRef inRef, DNSServiceFlags inFlags, uint32_t inInterfaceIndex, DNSServiceErrorType inErrorCode, const char * inName, const char * inType, const char * inDomain, void * inContext ) { ServiceHandlerEntry * obj; ServiceInfo * service; OSStatus err; DEBUG_UNUSED( inRef ); obj = NULL; service = NULL; require_noerr( inErrorCode, exit ); obj = reinterpret_cast < ServiceHandlerEntry * > ( inContext ); check( obj ); check( obj->obj ); // // set the UI to hold off on updates // obj->obj->mTree.SetRedraw(FALSE); try { service = new ServiceInfo; require_action( service, exit, err = kNoMemoryErr ); err = UTF8StringToStringObject( inName, service->displayName ); check_noerr( err ); service->name = strdup( inName ); require_action( service->name, exit, err = kNoMemoryErr ); service->type = strdup( inType ); require_action( service->type, exit, err = kNoMemoryErr ); service->domain = strdup( inDomain ); require_action( service->domain, exit, err = kNoMemoryErr ); service->ifi = inInterfaceIndex; service->handler = obj; service->refs = 1; if (inFlags & kDNSServiceFlagsAdd) obj->obj->OnServiceAdd (service); else obj->obj->OnServiceRemove(service); service = NULL; } catch( ... ) { dlog( kDebugLevelError, "BrowseCallBack: exception thrown\n" ); } exit: // // If no more coming, then update UI // if (obj && obj->obj && ((inFlags & kDNSServiceFlagsMoreComing) == 0)) { obj->obj->mTree.SetRedraw(TRUE); obj->obj->mTree.Invalidate(); } if( service ) { delete service; } }
void ChooserDialog::UpdateInfoDisplay( void ) { int selectedItem; std::string name; CString s; std::string ip; std::string ifIP; std::string text; std::string textNewLines; std::string hostName; CWnd * item; std::string::iterator i; // Display the service instance if it is selected. Otherwise, clear all the info. selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED ); if( selectedItem >= 0 ) { ServiceInstanceInfo * p; assert( selectedItem < (int) mServiceInstances.size() ); p = &mServiceInstances[ selectedItem ]; name = p->name; ip = p->ip; ifIP = p->ifIP; text = p->text; hostName = p->hostName; // Sync up the list items with the actual data (IP address may change). UTF8StringToStringObject( ip.c_str(), s ); mChooserList.SetItemText( selectedItem, 1, s ); } // Name item = (CWnd *) this->GetDlgItem( IDC_INFO_NAME_TEXT ); assert( item ); UTF8StringToStringObject( name.c_str(), s ); item->SetWindowText( s ); // IP item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT ); assert( item ); UTF8StringToStringObject( ip.c_str(), s ); item->SetWindowText( s ); // Interface item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT ); assert( item ); UTF8StringToStringObject( ifIP.c_str(), s ); item->SetWindowText( s ); item = (CWnd *) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT ); assert( item ); UTF8StringToStringObject( hostName.c_str(), s ); item->SetWindowText( s ); // Text item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT ); assert( item ); for( i = text.begin(); i != text.end(); ++i ) { if( *i == '\1' ) { textNewLines += "\r\n"; } else { textNewLines += *i; } } UTF8StringToStringObject( textNewLines.c_str(), s ); item->SetWindowText( s ); }
LONG ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam ) { ServiceInstanceInfo * p; std::auto_ptr < ServiceInstanceInfo > pAutoPtr; int selectedType; int n; int i; bool found; UNUSED_ALWAYS( inWParam ); assert( inLParam ); p = reinterpret_cast <ServiceInstanceInfo *> ( inLParam ); pAutoPtr.reset( p ); // Make sure it is for an item of the correct type. This handles any resolves that may have been queued up. selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED ); assert( selectedType >= 0 ); if( selectedType >= 0 ) { assert( selectedType <= (int) mServiceTypes.size() ); if( p->type != mServiceTypes[ selectedType ].serviceType ) { goto exit; } } // Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list. found = false; n = (int) mServiceInstances.size(); for( i = 0; i < n; ++i ) { ServiceInstanceInfo * q; // If the name, type, domain, and interface matches, treat it as the same service instance. q = &mServiceInstances[ i ]; if( ( p->name == q->name ) && ( p->type == q->type ) && ( p->domain == q->domain ) && ( p->ifIP == q->ifIP ) ) { found = true; break; } } if( found ) { mServiceInstances[ i ] = *p; } else { CString s; mServiceInstances.push_back( *p ); UTF8StringToStringObject( p->name.c_str(), s ); mChooserList.InsertItem( n, s ); UTF8StringToStringObject( p->ip.c_str(), s ); mChooserList.SetItemText( n, 1, s ); // If this is the only item, select it. if( n == 0 ) { mChooserList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); } } UpdateInfoDisplay(); exit: return( 0 ); }