]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
mDNSResponder-107.5.tar.gz
[apple/mdnsresponder.git] / Clients / PrinterSetupWizard / PrinterSetupWizardSheet.cpp
1 /*
2 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: PrinterSetupWizardSheet.cpp,v $
26 Revision 1.34 2005/10/05 17:32:51 herscher
27 <rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
28
29 Revision 1.33 2005/07/11 20:17:15 shersche
30 <rdar://problem/4124524> UI fixes associated with CUPS printer workaround fix.
31
32 Revision 1.32 2005/07/07 17:53:20 shersche
33 Fix problems associated with the CUPS printer workaround fix.
34
35 Revision 1.31 2005/06/30 18:02:54 shersche
36 <rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
37
38 Revision 1.30 2005/04/13 17:46:22 shersche
39 <rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
40
41 Revision 1.29 2005/02/14 20:48:37 shersche
42 <rdar://problem/4003710> Default pdl key to "application/postscript"
43
44 Revision 1.28 2005/02/14 20:37:53 shersche
45 <rdar://problem/4003944> Populate comment field with the model name that users see in the wizard UI.
46
47 Revision 1.27 2005/02/09 05:04:03 shersche
48 <rdar://problem/3946587> Use TXTRecordGetValuePtr() API in ParseTextRecord
49
50 Revision 1.26 2005/02/08 21:45:06 shersche
51 <rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
52
53 Revision 1.25 2005/02/08 18:54:17 shersche
54 <rdar://problem/3987680> Default queue name is "lp" when rp key is not specified.
55
56 Revision 1.24 2005/02/01 02:15:55 shersche
57 <rdar://problem/3946587> Use TXTRecord parsing APIs in ParseTextRecord
58
59 Revision 1.23 2005/01/31 23:54:30 shersche
60 <rdar://problem/3947508> Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object.
61
62 Revision 1.22 2005/01/25 18:49:43 shersche
63 Get icon resources from resource DLL
64
65 Revision 1.21 2005/01/10 01:09:32 shersche
66 Use the "note" key to populate pLocation field when setting up printer
67
68 Revision 1.20 2005/01/03 19:05:01 shersche
69 Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window
70
71 Revision 1.19 2004/12/31 07:23:53 shersche
72 Don't modify the button setting in SetSelectedPrinter()
73
74 Revision 1.18 2004/12/29 18:53:38 shersche
75 <rdar://problem/3725106>
76 <rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
77 Bug #: 3725106, 3737413
78
79 Revision 1.17 2004/10/12 18:02:53 shersche
80 <rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
81 Bug #: 3764873
82
83 Revision 1.16 2004/09/13 21:27:22 shersche
84 <rdar://problem/3796483> Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks
85 Bug #: 3796483
86
87 Revision 1.15 2004/09/11 05:59:06 shersche
88 <rdar://problem/3785766> Fix code that generates unique printer names based on currently installed printers
89 Bug #: 3785766
90
91 Revision 1.14 2004/09/02 01:57:58 cheshire
92 <rdar://problem/3783611> Fix incorrect testing of MoreComing flag
93
94 Revision 1.13 2004/07/26 21:06:29 shersche
95 <rdar://problem/3739200> Removing trailing '.' in hostname
96 Bug #: 3739200
97
98 Revision 1.12 2004/07/13 21:24:23 rpantos
99 Fix for <rdar://problem/3701120>.
100
101 Revision 1.11 2004/06/28 00:51:47 shersche
102 Move call to EnumPrinters out of browse callback into standalone function
103
104 Revision 1.10 2004/06/27 23:06:47 shersche
105 code cleanup, make sure EnumPrinters returns non-zero value
106
107 Revision 1.9 2004/06/27 15:49:31 shersche
108 clean up some cruft in the printer browsing code
109
110 Revision 1.8 2004/06/27 08:04:51 shersche
111 copy selected printer to prevent printer being deleted out from under
112
113 Revision 1.7 2004/06/26 23:27:12 shersche
114 support for installing multiple printers of the same name
115
116 Revision 1.6 2004/06/26 21:22:39 shersche
117 handle spaces in file names
118
119 Revision 1.5 2004/06/26 03:19:57 shersche
120 clean up warning messages
121
122 Submitted by: herscher
123
124 Revision 1.4 2004/06/25 02:26:52 shersche
125 Normalize key fields in text record entries
126 Submitted by: herscher
127
128 Revision 1.3 2004/06/24 20:12:07 shersche
129 Clean up source code
130 Submitted by: herscher
131
132 Revision 1.2 2004/06/23 17:58:21 shersche
133 <rdar://problem/3701837> eliminated memory leaks on exit
134 <rdar://problem/3701926> installation of a printer that is already installed results in a no-op
135 Bug #: 3701837, 3701926
136 Submitted by: herscher
137
138 Revision 1.1 2004/06/18 04:36:57 rpantos
139 First checked in
140
141
142 */
143
144 #include "stdafx.h"
145 #include "PrinterSetupWizardApp.h"
146 #include "PrinterSetupWizardSheet.h"
147 #include "CommonServices.h"
148 #include "DebugServices.h"
149 #include "WinServices.h"
150 #include "About.h"
151 #include <winspool.h>
152 #include <tcpxcv.h>
153 #include <string>
154
155 // unreachable code
156 #pragma warning(disable:4702)
157
158
159 #if( !TARGET_OS_WINDOWS_CE )
160 # include <mswsock.h>
161 # include <process.h>
162 #endif
163
164 // Private Messages
165
166 #define WM_SOCKET_EVENT ( WM_USER + 0x100 )
167 #define WM_PROCESS_EVENT ( WM_USER + 0x101 )
168
169
170 // CPrinterSetupWizardSheet
171 CPrinterSetupWizardSheet * CPrinterSetupWizardSheet::m_self;
172
173 IMPLEMENT_DYNAMIC(CPrinterSetupWizardSheet, CPropertySheet)
174 CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
175 :CPropertySheet(nIDCaption, pParentWnd, iSelectPage),
176 m_selectedPrinter(NULL),
177 m_driverThreadExitCode( 0 ),
178 m_driverThreadFinished( false ),
179 m_pdlBrowser( NULL ),
180 m_ippBrowser( NULL ),
181 m_lprBrowser( NULL ),
182 m_lastPage( NULL )
183 {
184 m_arrow = LoadCursor(0, IDC_ARROW);
185 m_wait = LoadCursor(0, IDC_APPSTARTING);
186 m_active = m_arrow;
187 m_self = this;
188
189 Init();
190
191 LoadPrinterNames();
192 }
193
194
195 CPrinterSetupWizardSheet::~CPrinterSetupWizardSheet()
196 {
197 Printer * printer;
198
199 while ( m_printers.size() > 0 )
200 {
201 printer = m_printers.front();
202 m_printers.pop_front();
203
204 delete printer;
205 }
206
207 m_self = NULL;
208 }
209
210
211 // ------------------------------------------------------
212 // SetSelectedPrinter
213 //
214 // Manages setting a printer as the printer to install. Stops
215 // any pending resolves.
216 //
217 void
218 CPrinterSetupWizardSheet::SetSelectedPrinter(Printer * printer)
219 {
220 check( !printer || ( printer != m_selectedPrinter ) );
221
222 m_selectedPrinter = printer;
223 }
224
225
226 OSStatus
227 CPrinterSetupWizardSheet::LoadPrinterNames()
228 {
229 PBYTE buffer = NULL;
230 OSStatus err = 0;
231
232 //
233 // rdar://problem/3701926 - Printer can't be installed twice
234 //
235 // First thing we want to do is make sure the printer isn't already installed.
236 // If the printer name is found, we'll try and rename it until we
237 // find a unique name
238 //
239 DWORD dwNeeded = 0, dwNumPrinters = 0;
240
241 BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
242 err = translate_errno( ok, errno_compat(), kUnknownErr );
243
244 if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
245 {
246 try
247 {
248 buffer = new unsigned char[dwNeeded];
249 }
250 catch (...)
251 {
252 buffer = NULL;
253 }
254
255 require_action( buffer, exit, kNoMemoryErr );
256 ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
257 err = translate_errno( ok, errno_compat(), kUnknownErr );
258 require_noerr( err, exit );
259
260 for (DWORD index = 0; index < dwNumPrinters; index++)
261 {
262 PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
263
264 m_printerNames.push_back( lppi4->pPrinterName );
265 }
266 }
267
268 exit:
269
270 if (buffer != NULL)
271 {
272 delete [] buffer;
273 }
274
275 return err;
276 }
277
278
279
280 // ------------------------------------------------------
281 // InstallPrinter
282 //
283 // Installs a printer with Windows.
284 //
285 // NOTE: this works one of two ways, depending on whether
286 // there are drivers already installed for this printer.
287 // If there are, then we can just create a port with XcvData,
288 // and then call AddPrinter. If not, we use the printui.dll
289 // to install the printer. Actually installing drivers that
290 // are not currently installed is painful, and it's much
291 // easier and less error prone to just let printui.dll do
292 // the hard work for us.
293 //
294
295 OSStatus
296 CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
297 {
298 Service * service;
299 BOOL ok;
300 OSStatus err;
301
302 service = printer->services.front();
303 check( service );
304
305 //
306 // if the driver isn't installed, then install it
307 //
308
309 if ( !printer->driverInstalled )
310 {
311 DWORD dwResult;
312 HANDLE hThread;
313 unsigned threadID;
314
315 m_driverThreadFinished = false;
316
317 //
318 // create the thread
319 //
320 hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID );
321 err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
322 require_noerr( err, exit );
323
324 //
325 // go modal
326 //
327 while (!m_driverThreadFinished)
328 {
329 MSG msg;
330
331 GetMessage( &msg, m_hWnd, 0, 0 );
332 TranslateMessage(&msg);
333 DispatchMessage(&msg);
334 }
335
336 //
337 // Wait until child process exits.
338 //
339 dwResult = WaitForSingleObject( hThread, INFINITE );
340 err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
341 require_noerr( err, exit );
342
343 //
344 // check the return value of thread
345 //
346 require_noerr( m_driverThreadExitCode, exit );
347
348 //
349 // now we know that the driver was successfully installed
350 //
351 printer->driverInstalled = true;
352 }
353
354 if ( service->type == kPDLServiceType )
355 {
356 err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE );
357 require_noerr( err, exit );
358 }
359 else if ( service->type == kLPRServiceType )
360 {
361 err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE );
362 require_noerr( err, exit );
363 }
364 else if ( service->type == kIPPServiceType )
365 {
366 err = InstallPrinterIPP( printer, service );
367 require_noerr( err, exit );
368 }
369 else
370 {
371 err = kUnknownErr;
372 require_noerr( err, exit );
373 }
374
375 printer->installed = true;
376
377 //
378 // if the user specified a default printer, set it
379 //
380 if (printer->deflt)
381 {
382 ok = SetDefaultPrinter( printer->actualName );
383 err = translate_errno( ok, errno_compat(), err = kUnknownErr );
384 require_noerr( err, exit );
385 }
386
387 exit:
388
389 return err;
390 }
391
392
393 OSStatus
394 CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol )
395 {
396 PRINTER_DEFAULTS printerDefaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER };
397 DWORD dwStatus;
398 DWORD cbInputData = 100;
399 PBYTE pOutputData = NULL;
400 DWORD cbOutputNeeded = 0;
401 PORT_DATA_1 portData;
402 PRINTER_INFO_2 pInfo;
403 HANDLE hXcv = NULL;
404 HANDLE hPrinter = NULL;
405 Queue * q;
406 BOOL ok;
407 OSStatus err;
408
409 check(printer != NULL);
410 check(printer->installed == false);
411
412 q = service->queues.front();
413 check( q );
414
415 ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults);
416 err = translate_errno( ok, errno_compat(), kUnknownErr );
417 require_noerr( err, exit );
418
419 //
420 // BUGBUG: MSDN said this is not required, but my experience shows it is required
421 //
422 try
423 {
424 pOutputData = new BYTE[cbInputData];
425 }
426 catch (...)
427 {
428 pOutputData = NULL;
429 }
430
431 require_action( pOutputData, exit, err = kNoMemoryErr );
432
433 //
434 // setup the port
435 //
436 ZeroMemory(&portData, sizeof(PORT_DATA_1));
437 wcscpy(portData.sztPortName, printer->portName);
438
439 portData.dwPortNumber = service->portNumber;
440 portData.dwVersion = 1;
441
442 portData.dwProtocol = protocol;
443 portData.cbSize = sizeof PORT_DATA_1;
444 portData.dwReserved = 0L;
445
446 wcscpy(portData.sztQueue, q->name);
447 wcscpy(portData.sztIPAddress, service->hostname);
448 wcscpy(portData.sztHostAddress, service->hostname);
449
450 ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData, &cbOutputNeeded, &dwStatus);
451 err = translate_errno( ok, errno_compat(), kUnknownErr );
452 require_noerr( err, exit );
453
454 //
455 // add the printer
456 //
457 ZeroMemory(&pInfo, sizeof(pInfo));
458
459 pInfo.pPrinterName = printer->actualName.GetBuffer();
460 pInfo.pServerName = NULL;
461 pInfo.pShareName = NULL;
462 pInfo.pPortName = printer->portName.GetBuffer();
463 pInfo.pDriverName = printer->modelName.GetBuffer();
464 pInfo.pComment = printer->displayModelName.GetBuffer();
465 pInfo.pLocation = q->location.GetBuffer();
466 pInfo.pDevMode = NULL;
467 pInfo.pDevMode = NULL;
468 pInfo.pSepFile = L"";
469 pInfo.pPrintProcessor = L"winprint";
470 pInfo.pDatatype = L"RAW";
471 pInfo.pParameters = L"";
472 pInfo.pSecurityDescriptor = NULL;
473 pInfo.Attributes = PRINTER_ATTRIBUTE_QUEUED;
474 pInfo.Priority = 0;
475 pInfo.DefaultPriority = 0;
476 pInfo.StartTime = 0;
477 pInfo.UntilTime = 0;
478
479 hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
480 err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
481 require_noerr( err, exit );
482
483 exit:
484
485 if (hPrinter != NULL)
486 {
487 ClosePrinter(hPrinter);
488 }
489
490 if (hXcv != NULL)
491 {
492 ClosePrinter(hXcv);
493 }
494
495 if (pOutputData != NULL)
496 {
497 delete [] pOutputData;
498 }
499
500 return err;
501 }
502
503
504 OSStatus
505 CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service)
506 {
507 DEBUG_UNUSED( service );
508
509 Queue * q = service->SelectedQueue();
510 HANDLE hPrinter = NULL;
511 PRINTER_INFO_2 pInfo;
512 OSStatus err;
513
514 check( q );
515
516 //
517 // add the printer
518 //
519 ZeroMemory(&pInfo, sizeof(PRINTER_INFO_2));
520
521 pInfo.pPrinterName = printer->actualName.GetBuffer();
522 pInfo.pPortName = printer->portName.GetBuffer();
523 pInfo.pDriverName = printer->modelName.GetBuffer();
524 pInfo.pPrintProcessor = L"winprint";
525 pInfo.pLocation = q->location.GetBuffer();
526 pInfo.pComment = printer->displayModelName.GetBuffer();
527 pInfo.Attributes = PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL;
528
529 hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo);
530 err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
531 require_noerr( err, exit );
532
533 exit:
534
535 if ( hPrinter != NULL )
536 {
537 ClosePrinter(hPrinter);
538 }
539
540 return err;
541 }
542
543
544 BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet, CPropertySheet)
545 ON_MESSAGE( WM_SOCKET_EVENT, OnSocketEvent )
546 ON_MESSAGE( WM_PROCESS_EVENT, OnProcessEvent )
547 ON_WM_SETCURSOR()
548 ON_WM_TIMER()
549 END_MESSAGE_MAP()
550
551
552 // ------------------------------------------------------
553 // OnCommand
554 //
555 // Traps when the user hits Finish
556 //
557 BOOL CPrinterSetupWizardSheet::OnCommand(WPARAM wParam, LPARAM lParam)
558 {
559 //
560 // Check if this is OK
561 //
562 if (wParam == ID_WIZFINISH) // If OK is hit...
563 {
564 OnOK();
565 }
566
567 return CPropertySheet::OnCommand(wParam, lParam);
568 }
569
570
571 // ------------------------------------------------------
572 // OnInitDialog
573 //
574 // Initializes this Dialog object.
575 //
576 BOOL CPrinterSetupWizardSheet::OnInitDialog()
577 {
578 OSStatus err;
579
580 CPropertySheet::OnInitDialog();
581
582 err = StartBrowse();
583 require_noerr( err, exit );
584
585 exit:
586
587 if ( err )
588 {
589 StopBrowse();
590
591 if ( err == kDNSServiceErr_Firewall )
592 {
593 CString text, caption;
594
595 text.LoadString( IDS_FIREWALL );
596 caption.LoadString( IDS_FIREWALL_CAPTION );
597
598 MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION);
599 }
600 else
601 {
602 CPrinterSetupWizardSheet::WizardException exc;
603
604 exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT );
605 exc.caption.LoadString( IDS_ERROR_CAPTION );
606
607 throw(exc);
608 }
609 }
610
611 return TRUE;
612 }
613
614
615 // ------------------------------------------------------
616 // OnSetCursor
617 //
618 // This is called when Windows wants to know what cursor
619 // to display. So we tell it.
620 //
621 BOOL
622 CPrinterSetupWizardSheet::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
623 {
624 DEBUG_UNUSED(pWnd);
625 DEBUG_UNUSED(nHitTest);
626 DEBUG_UNUSED(message);
627
628 SetCursor(m_active);
629 return TRUE;
630 }
631
632
633 // ------------------------------------------------------
634 // OnContextMenu
635 //
636 // This is not fully implemented yet.
637 //
638
639 void
640 CPrinterSetupWizardSheet::OnContextMenu(CWnd * pWnd, CPoint pos)
641 {
642 DEBUG_UNUSED(pWnd);
643 DEBUG_UNUSED(pos);
644
645 CAbout dlg;
646
647 dlg.DoModal();
648 }
649
650
651 // ------------------------------------------------------
652 // OnOK
653 //
654 // This is called when the user hits the "Finish" button
655 //
656 void
657 CPrinterSetupWizardSheet::OnOK()
658 {
659 check ( m_selectedPrinter != NULL );
660
661 SetWizardButtons( PSWIZB_DISABLEDFINISH );
662
663 if ( InstallPrinter( m_selectedPrinter ) != kNoErr )
664 {
665 CString caption;
666 CString message;
667
668 caption.LoadString(IDS_INSTALL_ERROR_CAPTION);
669 message.LoadString(IDS_INSTALL_ERROR_MESSAGE);
670
671 MessageBox(message, caption, MB_OK|MB_ICONEXCLAMATION);
672 }
673
674 StopBrowse();
675 }
676
677
678 // CPrinterSetupWizardSheet message handlers
679
680 void CPrinterSetupWizardSheet::Init(void)
681 {
682 AddPage(&m_pgFirst);
683 AddPage(&m_pgSecond);
684 AddPage(&m_pgThird);
685 AddPage(&m_pgFourth);
686
687 m_psh.dwFlags &= (~PSH_HASHELP);
688
689 m_psh.dwFlags |= PSH_WIZARD97|PSH_WATERMARK|PSH_HEADER;
690 m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
691 m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER_ICON);
692
693 m_psh.hInstance = GetNonLocalizedResources();
694
695 SetWizardMode();
696 }
697
698
699 LONG
700 CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam)
701 {
702 if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
703 {
704 dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
705 }
706 else
707 {
708 SOCKET sock = (SOCKET) inWParam;
709
710 // iterate thru list
711 ServiceRefList::iterator begin = m_serviceRefList.begin();
712 ServiceRefList::iterator end = m_serviceRefList.end();
713
714 while (begin != end)
715 {
716 DNSServiceRef ref = *begin++;
717
718 check(ref != NULL);
719
720 if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
721 {
722 DNSServiceProcessResult(ref);
723 break;
724 }
725 }
726 }
727
728 return ( 0 );
729 }
730
731
732 LONG
733 CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam)
734 {
735 DEBUG_UNUSED(inLParam);
736
737 m_driverThreadExitCode = (DWORD) inWParam;
738 m_driverThreadFinished = true;
739
740 return 0;
741 }
742
743
744 unsigned WINAPI
745 CPrinterSetupWizardSheet::InstallDriverThread( LPVOID inParam )
746 {
747 Printer * printer = (Printer*) inParam;
748 DWORD exitCode = 0;
749 DWORD dwResult;
750 OSStatus err;
751 STARTUPINFO si;
752 PROCESS_INFORMATION pi;
753 BOOL ok;
754
755 check( printer );
756 check( m_self );
757
758 //
759 // because we're calling endthreadex(), C++ objects won't be cleaned up
760 // correctly. we'll nest the CString 'command' inside a block so
761 // that it's destructor will be invoked.
762 //
763 {
764 CString command;
765
766 ZeroMemory( &si, sizeof(si) );
767 si.cb = sizeof(si);
768 ZeroMemory( &pi, sizeof(pi) );
769
770 command.Format(L"rundll32.exe printui.dll,PrintUIEntry /ia /m \"%s\" /f \"%s\"", (LPCTSTR) printer->modelName, (LPCTSTR) printer->infFileName );
771
772 ok = CreateProcess(NULL, command.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
773 err = translate_errno( ok, errno_compat(), kUnknownErr );
774 require_noerr( err, exit );
775
776 dwResult = WaitForSingleObject( pi.hProcess, INFINITE );
777 translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
778 require_noerr( err, exit );
779
780 ok = GetExitCodeProcess( pi.hProcess, &exitCode );
781 err = translate_errno( ok, errno_compat(), kUnknownErr );
782 require_noerr( err, exit );
783 }
784
785 exit:
786
787 //
788 // Close process and thread handles.
789 //
790 if ( pi.hProcess )
791 {
792 CloseHandle( pi.hProcess );
793 }
794
795 if ( pi.hThread )
796 {
797 CloseHandle( pi.hThread );
798 }
799
800 //
801 // alert the main thread
802 //
803 m_self->PostMessage( WM_PROCESS_EVENT, err, exitCode );
804
805 _endthreadex_compat( 0 );
806
807 return 0;
808 }
809
810
811 void DNSSD_API
812 CPrinterSetupWizardSheet::OnBrowse(
813 DNSServiceRef inRef,
814 DNSServiceFlags inFlags,
815 uint32_t inInterfaceIndex,
816 DNSServiceErrorType inErrorCode,
817 const char * inName,
818 const char * inType,
819 const char * inDomain,
820 void * inContext )
821 {
822 DEBUG_UNUSED(inRef);
823
824 CPrinterSetupWizardSheet * self;
825 bool moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
826 CPropertyPage * active;
827 Printer * printer = NULL;
828 Service * service = NULL;
829 OSStatus err = kNoErr;
830
831 require_noerr( inErrorCode, exit );
832
833 self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
834 require_quiet( self, exit );
835
836 active = self->GetActivePage();
837 require_quiet( active, exit );
838
839 // Have we seen this printer before?
840
841 printer = self->Lookup( inName );
842
843 if ( printer )
844 {
845 service = printer->LookupService( inType );
846 }
847
848 if ( inFlags & kDNSServiceFlagsAdd )
849 {
850 if (printer == NULL)
851 {
852 // If not, then create a new one
853
854 printer = self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing );
855 require_action( printer, exit, err = kUnknownErr );
856 }
857
858 if ( !service )
859 {
860 err = self->OnAddService( printer, inInterfaceIndex, inName, inType, inDomain );
861 require_noerr( err, exit );
862 }
863 else
864 {
865 service->refs++;
866 }
867 }
868 else if ( printer )
869 {
870 check( service );
871
872 err = self->OnRemoveService( service );
873 require_noerr( err, exit );
874
875 if ( printer->services.size() == 0 )
876 {
877 err = self->OnRemovePrinter( printer, moreComing );
878 require_noerr( err, exit );
879 }
880 }
881
882 exit:
883
884 return;
885 }
886
887
888 void DNSSD_API
889 CPrinterSetupWizardSheet::OnResolve(
890 DNSServiceRef inRef,
891 DNSServiceFlags inFlags,
892 uint32_t inInterfaceIndex,
893 DNSServiceErrorType inErrorCode,
894 const char * inFullName,
895 const char * inHostName,
896 uint16_t inPort,
897 uint16_t inTXTSize,
898 const char * inTXT,
899 void * inContext )
900 {
901 DEBUG_UNUSED(inFullName);
902 DEBUG_UNUSED(inInterfaceIndex);
903 DEBUG_UNUSED(inFlags);
904 DEBUG_UNUSED(inRef);
905
906 CPrinterSetupWizardSheet * self;
907 Service * service;
908 Queue * q;
909 int idx;
910 OSStatus err;
911
912 require_noerr( inErrorCode, exit );
913
914 service = reinterpret_cast<Service*>( inContext );
915 require_quiet( service, exit);
916
917 check( service->refs != 0 );
918
919 self = service->printer->window;
920 require_quiet( self, exit );
921
922 err = self->StopOperation( service->serviceRef );
923 require_noerr( err, exit );
924
925 //
926 // hold on to the hostname...
927 //
928 err = UTF8StringToStringObject( inHostName, service->hostname );
929 require_noerr( err, exit );
930
931 //
932 // <rdar://problem/3739200> remove the trailing dot on hostname
933 //
934 idx = service->hostname.ReverseFind('.');
935
936 if ((idx > 1) && ((service->hostname.GetLength() - 1) == idx))
937 {
938 service->hostname.Delete(idx, 1);
939 }
940
941 //
942 // hold on to the port
943 //
944 service->portNumber = ntohs(inPort);
945
946 if ( service->qtotal == 1 )
947 {
948 //
949 // create a new queue
950 //
951 try
952 {
953 q = new Queue;
954 }
955 catch (...)
956 {
957 q = NULL;
958 }
959
960 require_action( q, exit, err = E_OUTOFMEMORY );
961
962 //
963 // parse the text record.
964 //
965
966 err = self->ParseTextRecord( service, q, inTXTSize, inTXT );
967 require_noerr( err, exit );
968
969 service->queues.push_back( q );
970
971 //
972 // we've completely resolved this service
973 //
974
975 self->OnResolveService( service );
976 }
977 else
978 {
979 //
980 // if qtotal is more than 1, then we need to get additional
981 // text records. if not, then this service is considered
982 // resolved
983 //
984
985 err = DNSServiceQueryRecord(&service->serviceRef, 0, inInterfaceIndex, inFullName, kDNSServiceType_TXT, kDNSServiceClass_IN, OnQuery, (void*) service );
986 require_noerr( err, exit );
987
988 err = self->StartOperation( service->serviceRef );
989 require_noerr( err, exit );
990 }
991
992 exit:
993
994 return;
995 }
996
997
998 void DNSSD_API
999 CPrinterSetupWizardSheet::OnQuery(
1000 DNSServiceRef inRef,
1001 DNSServiceFlags inFlags,
1002 uint32_t inInterfaceIndex,
1003 DNSServiceErrorType inErrorCode,
1004 const char * inFullName,
1005 uint16_t inRRType,
1006 uint16_t inRRClass,
1007 uint16_t inRDLen,
1008 const void * inRData,
1009 uint32_t inTTL,
1010 void * inContext)
1011 {
1012 DEBUG_UNUSED( inTTL );
1013 DEBUG_UNUSED( inRRClass );
1014 DEBUG_UNUSED( inRRType );
1015 DEBUG_UNUSED( inFullName );
1016 DEBUG_UNUSED( inInterfaceIndex );
1017 DEBUG_UNUSED( inRef );
1018
1019 Service * service = NULL;
1020 Queue * q;
1021 CPrinterSetupWizardSheet * self;
1022 OSStatus err = kNoErr;
1023
1024 require_noerr( inErrorCode, exit );
1025
1026 service = reinterpret_cast<Service*>( inContext );
1027 require_quiet( service, exit);
1028
1029 self = service->printer->window;
1030 require_quiet( self, exit );
1031
1032 if ( ( inFlags & kDNSServiceFlagsAdd ) && ( inRDLen > 0 ) && ( inRData != NULL ) )
1033 {
1034 const char * inTXT = ( const char * ) inRData;
1035
1036 //
1037 // create a new queue
1038 //
1039 try
1040 {
1041 q = new Queue;
1042 }
1043 catch (...)
1044 {
1045 q = NULL;
1046 }
1047
1048 require_action( q, exit, err = E_OUTOFMEMORY );
1049
1050 err = service->printer->window->ParseTextRecord( service, q, inRDLen, inTXT );
1051 require_noerr( err, exit );
1052
1053 //
1054 // add this queue
1055 //
1056
1057 service->queues.push_back( q );
1058
1059 if ( service->queues.size() == service->qtotal )
1060 {
1061 //
1062 // else if moreComing is not set, then we're going
1063 // to assume that we're done
1064 //
1065
1066 self->StopOperation( service->serviceRef );
1067
1068 //
1069 // sort the queues
1070 //
1071
1072 service->queues.sort( OrderQueueFunc );
1073
1074 //
1075 // we've completely resolved this service
1076 //
1077
1078 self->OnResolveService( service );
1079 }
1080 }
1081
1082 exit:
1083
1084 if ( err && service && ( service->serviceRef != NULL ) )
1085 {
1086 service->printer->window->StopOperation( service->serviceRef );
1087 }
1088
1089 return;
1090 }
1091
1092
1093 Printer*
1094 CPrinterSetupWizardSheet::OnAddPrinter(
1095 uint32_t inInterfaceIndex,
1096 const char * inName,
1097 const char * inType,
1098 const char * inDomain,
1099 bool moreComing)
1100 {
1101 Printer * printer = NULL;
1102 DWORD printerNameCount;
1103 OSStatus err;
1104
1105 DEBUG_UNUSED( inInterfaceIndex );
1106 DEBUG_UNUSED( inType );
1107 DEBUG_UNUSED( inDomain );
1108
1109 try
1110 {
1111 printer = new Printer;
1112 }
1113 catch (...)
1114 {
1115 printer = NULL;
1116 }
1117
1118 require_action( printer, exit, err = E_OUTOFMEMORY );
1119
1120 printer->window = this;
1121 printer->name = inName;
1122
1123 err = UTF8StringToStringObject(inName, printer->displayName);
1124 check_noerr( err );
1125 printer->actualName = printer->displayName;
1126 printer->installed = false;
1127 printer->deflt = false;
1128 printer->resolving = 0;
1129
1130 // Compare this name against printers that are already installed
1131 // to avoid name clashes. Rename as necessary
1132 // to come up with a unique name.
1133
1134 printerNameCount = 2;
1135
1136 for (;;)
1137 {
1138 CPrinterSetupWizardSheet::PrinterNames::iterator it;
1139
1140 // <rdar://problem/4141221> Don't use find to do comparisons because we need to
1141 // do a case insensitive string comparison
1142
1143 for ( it = m_printerNames.begin(); it != m_printerNames.end(); it++ )
1144 {
1145 if ( (*it).CompareNoCase( printer->actualName ) == 0 )
1146 {
1147 break;
1148 }
1149 }
1150
1151 if (it != m_printerNames.end())
1152 {
1153 printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount);
1154 }
1155 else
1156 {
1157 break;
1158 }
1159
1160 printerNameCount++;
1161 }
1162
1163 m_printers.push_back( printer );
1164
1165 if ( GetActivePage() == &m_pgSecond )
1166 {
1167 m_pgSecond.OnAddPrinter( printer, moreComing );
1168 }
1169
1170 exit:
1171
1172 return printer;
1173 }
1174
1175
1176 OSStatus
1177 CPrinterSetupWizardSheet::OnAddService(
1178 Printer * printer,
1179 uint32_t inInterfaceIndex,
1180 const char * inName,
1181 const char * inType,
1182 const char * inDomain)
1183 {
1184 Service * service = NULL;
1185 OSStatus err = kNoErr;
1186
1187 DEBUG_UNUSED( inName );
1188 DEBUG_UNUSED( inDomain );
1189
1190 try
1191 {
1192 service = new Service;
1193 }
1194 catch (...)
1195 {
1196 service = NULL;
1197 }
1198
1199 require_action( service, exit, err = E_OUTOFMEMORY );
1200
1201 service->printer = printer;
1202 service->ifi = inInterfaceIndex;
1203 service->type = inType;
1204 service->domain = inDomain;
1205 service->qtotal = 1;
1206 service->refs = 1;
1207 service->serviceRef = NULL;
1208
1209 printer->services.push_back( service );
1210
1211 //
1212 // if the printer is selected, then we'll want to start a
1213 // resolve on this guy
1214 //
1215
1216 if ( printer == m_selectedPrinter )
1217 {
1218 StartResolve( service );
1219 }
1220
1221 exit:
1222
1223 return err;
1224 }
1225
1226
1227 OSStatus
1228 CPrinterSetupWizardSheet::OnRemovePrinter( Printer * printer, bool moreComing )
1229 {
1230 CPropertyPage * active = GetActivePage();
1231 OSStatus err = kNoErr;
1232
1233 if ( active == &m_pgSecond )
1234 {
1235 m_pgSecond.OnRemovePrinter( printer, moreComing );
1236 }
1237
1238 m_printers.remove( printer );
1239
1240 if ( m_selectedPrinter == printer )
1241 {
1242 m_selectedPrinter = NULL;
1243
1244 if ( ( active == &m_pgThird ) || ( active == &m_pgFourth ) )
1245 {
1246 CString caption;
1247 CString message;
1248
1249 caption.LoadString( IDS_ERROR_CAPTION );
1250 message.LoadString( IDS_PRINTER_UNAVAILABLE );
1251
1252 MessageBox(message, caption, MB_OK|MB_ICONEXCLAMATION);
1253
1254 SetActivePage( &m_pgSecond );
1255 }
1256 }
1257
1258 delete printer;
1259
1260 return err;
1261 }
1262
1263
1264 OSStatus
1265 CPrinterSetupWizardSheet::OnRemoveService( Service * service )
1266 {
1267 OSStatus err = kNoErr;
1268
1269 if ( service && ( --service->refs == 0 ) )
1270 {
1271 if ( service->serviceRef != NULL )
1272 {
1273 err = StopResolve( service );
1274 require_noerr( err, exit );
1275 }
1276
1277 service->printer->services.remove( service );
1278
1279 delete service;
1280 }
1281
1282 exit:
1283
1284 return err;
1285 }
1286
1287
1288 void
1289 CPrinterSetupWizardSheet::OnResolveService( Service * service )
1290 {
1291 // Make sure that the active page is page 2
1292
1293 require_quiet( GetActivePage() == &m_pgSecond, exit );
1294
1295 if ( !--service->printer->resolving )
1296 {
1297 // sort the services now. we want the service that
1298 // has the highest priority queue to be first in
1299 // the list.
1300
1301 service->printer->services.sort( OrderServiceFunc );
1302
1303 // Now we can hit next
1304
1305 SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT );
1306
1307 // Reset the cursor
1308
1309 m_active = m_arrow;
1310
1311 // And tell page 2 about it
1312
1313 m_pgSecond.OnResolveService( service );
1314 }
1315
1316 exit:
1317
1318 return;
1319 }
1320
1321
1322 OSStatus
1323 CPrinterSetupWizardSheet::StartBrowse()
1324 {
1325 OSStatus err;
1326
1327 //
1328 // setup the DNS-SD browsing
1329 //
1330 err = DNSServiceBrowse( &m_pdlBrowser, 0, 0, kPDLServiceType, NULL, OnBrowse, this );
1331 require_noerr( err, exit );
1332
1333 err = StartOperation( m_pdlBrowser );
1334 require_noerr( err, exit );
1335
1336 err = DNSServiceBrowse( &m_lprBrowser, 0, 0, kLPRServiceType, NULL, OnBrowse, this );
1337 require_noerr( err, exit );
1338
1339 err = StartOperation( m_lprBrowser );
1340 require_noerr( err, exit );
1341
1342 err = DNSServiceBrowse( &m_ippBrowser, 0, 0, kIPPServiceType, NULL, OnBrowse, this );
1343 require_noerr( err, exit );
1344
1345 err = StartOperation( m_ippBrowser );
1346 require_noerr( err, exit );
1347
1348 exit:
1349
1350 return err;
1351 }
1352
1353
1354 OSStatus
1355 CPrinterSetupWizardSheet::StopBrowse()
1356 {
1357 OSStatus err;
1358
1359 err = StopOperation( m_pdlBrowser );
1360 require_noerr( err, exit );
1361
1362 err = StopOperation( m_lprBrowser );
1363 require_noerr( err, exit );
1364
1365 err = StopOperation( m_ippBrowser );
1366 require_noerr( err, exit );
1367
1368 while ( m_printers.size() > 0 )
1369 {
1370 Printer * printer = m_printers.front();
1371
1372 m_printers.pop_front();
1373
1374 if ( printer->resolving )
1375 {
1376 StopResolve( printer );
1377 }
1378
1379 delete printer;
1380 }
1381
1382 exit:
1383
1384 return err;
1385 }
1386
1387
1388 OSStatus
1389 CPrinterSetupWizardSheet::StartResolve( Printer * printer )
1390 {
1391 OSStatus err = kNoErr;
1392 Services::iterator it;
1393
1394 check( printer );
1395
1396 for ( it = printer->services.begin(); it != printer->services.end(); it++ )
1397 {
1398 if ( (*it)->serviceRef == NULL )
1399 {
1400 err = StartResolve( *it );
1401 require_noerr( err, exit );
1402 }
1403 }
1404
1405 m_selectedPrinter = printer;
1406
1407 exit:
1408
1409 return err;
1410 }
1411
1412
1413 OSStatus
1414 CPrinterSetupWizardSheet::StartResolve( Service * service )
1415 {
1416 OSStatus err = kNoErr;
1417
1418 check( service->serviceRef == NULL );
1419
1420 //
1421 // clean out any queues that were collected during a previous
1422 // resolve
1423 //
1424
1425 service->EmptyQueues();
1426
1427 //
1428 // now start the new resolve
1429 //
1430
1431 err = DNSServiceResolve( &service->serviceRef, 0, 0, service->printer->name.c_str(), service->type.c_str(), service->domain.c_str(), (DNSServiceResolveReply) OnResolve, service );
1432 require_noerr( err, exit );
1433
1434 err = StartOperation( service->serviceRef );
1435 require_noerr( err, exit );
1436
1437 //
1438 // If we're not currently resolving, then disable the next button
1439 // and set the cursor to hourglass
1440 //
1441
1442 if ( !service->printer->resolving )
1443 {
1444 SetWizardButtons( PSWIZB_BACK );
1445
1446 m_active = m_wait;
1447 SetCursor(m_active);
1448 }
1449
1450 service->printer->resolving++;
1451
1452 exit:
1453
1454 return err;
1455 }
1456
1457
1458 OSStatus
1459 CPrinterSetupWizardSheet::StopResolve(Printer * printer)
1460 {
1461 OSStatus err = kNoErr;
1462
1463 check( printer );
1464
1465 Services::iterator it;
1466
1467 for ( it = printer->services.begin(); it != printer->services.end(); it++ )
1468 {
1469 if ( (*it)->serviceRef )
1470 {
1471 err = StopResolve( *it );
1472 require_noerr( err, exit );
1473 }
1474 }
1475
1476 exit:
1477
1478 return err;
1479 }
1480
1481
1482 OSStatus
1483 CPrinterSetupWizardSheet::StopResolve( Service * service )
1484 {
1485 OSStatus err;
1486
1487 check( service->serviceRef );
1488
1489 err = StopOperation( service->serviceRef );
1490 require_noerr( err, exit );
1491
1492 service->printer->resolving--;
1493
1494 exit:
1495
1496 return err;
1497 }
1498
1499
1500 OSStatus
1501 CPrinterSetupWizardSheet::StartOperation( DNSServiceRef ref )
1502 {
1503 OSStatus err;
1504
1505 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(ref), m_hWnd, WM_SOCKET_EVENT, FD_READ|FD_CLOSE);
1506 require_noerr( err, exit );
1507
1508 m_serviceRefList.push_back( ref );
1509
1510 exit:
1511
1512 return err;
1513 }
1514
1515
1516 OSStatus
1517 CPrinterSetupWizardSheet::StopOperation( DNSServiceRef & ref )
1518 {
1519 OSStatus err = kNoErr;
1520
1521 if ( ref )
1522 {
1523 m_serviceRefList.remove( ref );
1524
1525 if ( IsWindow( m_hWnd ) )
1526 {
1527 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD( ref ), m_hWnd, 0, 0 );
1528 require_noerr( err, exit );
1529 }
1530
1531 DNSServiceRefDeallocate( ref );
1532 ref = NULL;
1533 }
1534
1535 exit:
1536
1537 return err;
1538 }
1539
1540
1541 OSStatus
1542 CPrinterSetupWizardSheet::ParseTextRecord( Service * service, Queue * q, uint16_t inTXTSize, const char * inTXT )
1543 {
1544 check( service );
1545 check( q );
1546
1547 // <rdar://problem/3946587> Use TXTRecord APIs declared in dns_sd.h
1548
1549 bool qtotalDefined = false;
1550 const void * val;
1551 char buf[256];
1552 uint8_t len;
1553 OSStatus err = kNoErr;
1554
1555 // <rdar://problem/3987680> Default to queue "lp"
1556
1557 q->name = L"lp";
1558
1559 // <rdar://problem/4003710> Default pdl key to be "application/postscript"
1560
1561 q->pdl = L"application/postscript";
1562
1563 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "rp", &len ) ) != NULL )
1564 {
1565 // Stringize val ( doesn't have trailing '\0' yet )
1566
1567 memcpy( buf, val, len );
1568 buf[len] = '\0';
1569
1570 err = UTF8StringToStringObject( buf, q->name );
1571 require_noerr( err, exit );
1572 }
1573
1574 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "pdl", &len ) ) != NULL )
1575 {
1576 // Stringize val ( doesn't have trailing '\0' yet )
1577
1578 memcpy( buf, val, len );
1579 buf[len] = '\0';
1580
1581 err = UTF8StringToStringObject( buf, q->pdl );
1582 require_noerr( err, exit );
1583 }
1584
1585 if ( ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_mfg", &len ) ) != NULL ) ||
1586 ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_manufacturer", &len ) ) != NULL ) )
1587 {
1588 // Stringize val ( doesn't have trailing '\0' yet )
1589
1590 memcpy( buf, val, len );
1591 buf[len] = '\0';
1592
1593 err = UTF8StringToStringObject( buf, q->usb_MFG );
1594 require_noerr( err, exit );
1595 }
1596
1597 if ( ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_mdl", &len ) ) != NULL ) ||
1598 ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_model", &len ) ) != NULL ) )
1599 {
1600 // Stringize val ( doesn't have trailing '\0' yet )
1601
1602 memcpy( buf, val, len );
1603 buf[len] = '\0';
1604
1605 err = UTF8StringToStringObject( buf, q->usb_MDL );
1606 require_noerr( err, exit );
1607 }
1608
1609 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "ty", &len ) ) != NULL )
1610 {
1611 // Stringize val ( doesn't have trailing '\0' yet )
1612
1613 memcpy( buf, val, len );
1614 buf[len] = '\0';
1615
1616 err = UTF8StringToStringObject( buf, q->description );
1617 require_noerr( err, exit );
1618 }
1619
1620 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "product", &len ) ) != NULL )
1621 {
1622 // Stringize val ( doesn't have trailing '\0' yet )
1623
1624 memcpy( buf, val, len );
1625 buf[len] = '\0';
1626
1627 err = UTF8StringToStringObject( buf, q->product );
1628 require_noerr( err, exit );
1629 }
1630
1631 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "note", &len ) ) != NULL )
1632 {
1633 // Stringize val ( doesn't have trailing '\0' yet )
1634
1635 memcpy( buf, val, len );
1636 buf[len] = '\0';
1637
1638 err = UTF8StringToStringObject( buf, q->location );
1639 require_noerr( err, exit );
1640 }
1641
1642 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "qtotal", &len ) ) != NULL )
1643 {
1644 // Stringize val ( doesn't have trailing '\0' yet )
1645
1646 memcpy( buf, val, len );
1647 buf[len] = '\0';
1648
1649 service->qtotal = (unsigned short) atoi( buf );
1650 qtotalDefined = true;
1651 }
1652
1653 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "priority", &len ) ) != NULL )
1654 {
1655 // Stringize val ( doesn't have trailing '\0' yet )
1656
1657 memcpy( buf, val, len );
1658 buf[len] = '\0';
1659
1660 q->priority = atoi( buf );
1661 }
1662
1663 // <rdar://problem/4124524> Was this printer discovered via OS X Printer Sharing?
1664
1665 if ( TXTRecordContainsKey( inTXTSize, inTXT, "printer-state" ) || TXTRecordContainsKey( inTXTSize, inTXT, "printer-type" ) )
1666 {
1667 service->printer->isSharedFromOSX = true;
1668 }
1669
1670 exit:
1671
1672 // The following code is to fix a problem with older HP
1673 // printers that don't include "qtotal" in their text
1674 // record. We'll check to see if the q->name is "TEXT"
1675 // and if so, we're going to modify it to be "lp" so
1676 // that we don't use the wrong queue
1677
1678 if ( !err && !qtotalDefined && ( q->name == L"TEXT" ) )
1679 {
1680 q->name = "lp";
1681 }
1682
1683 return err;
1684 }
1685
1686
1687 Printer*
1688 CPrinterSetupWizardSheet::Lookup(const char * inName)
1689 {
1690 check( inName );
1691
1692 Printer * printer = NULL;
1693 Printers::iterator it;
1694
1695 for ( it = m_printers.begin(); it != m_printers.end(); it++ )
1696 {
1697 if ( (*it)->name == inName )
1698 {
1699 printer = *it;
1700 break;
1701 }
1702 }
1703
1704 return printer;
1705 }
1706
1707
1708 bool
1709 CPrinterSetupWizardSheet::OrderServiceFunc( const Service * a, const Service * b )
1710 {
1711 Queue * q1, * q2;
1712
1713 q1 = (a->queues.size() > 0) ? a->queues.front() : NULL;
1714
1715 q2 = (b->queues.size() > 0) ? b->queues.front() : NULL;
1716
1717 if ( !q1 && !q2 )
1718 {
1719 return true;
1720 }
1721 else if ( q1 && !q2 )
1722 {
1723 return true;
1724 }
1725 else if ( !q1 && q2 )
1726 {
1727 return false;
1728 }
1729 else if ( q1->priority < q2->priority )
1730 {
1731 return true;
1732 }
1733 else if ( q1->priority > q2->priority )
1734 {
1735 return false;
1736 }
1737 else if ( ( a->type == kPDLServiceType ) || ( ( a->type == kLPRServiceType ) && ( b->type == kIPPServiceType ) ) )
1738 {
1739 return true;
1740 }
1741 else
1742 {
1743 return false;
1744 }
1745 }
1746
1747
1748 bool
1749 CPrinterSetupWizardSheet::OrderQueueFunc( const Queue * q1, const Queue * q2 )
1750 {
1751 return ( q1->priority <= q2->priority ) ? true : false;
1752 }
1753
1754
1755