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