]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
mDNSResponder-107.1.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.30 2005/04/13 17:46:22 shersche
27 <rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
28
29 Revision 1.29 2005/02/14 20:48:37 shersche
30 <rdar://problem/4003710> Default pdl key to "application/postscript"
31
32 Revision 1.28 2005/02/14 20:37:53 shersche
33 <rdar://problem/4003944> Populate comment field with the model name that users see in the wizard UI.
34
35 Revision 1.27 2005/02/09 05:04:03 shersche
36 <rdar://problem/3946587> Use TXTRecordGetValuePtr() API in ParseTextRecord
37
38 Revision 1.26 2005/02/08 21:45:06 shersche
39 <rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
40
41 Revision 1.25 2005/02/08 18:54:17 shersche
42 <rdar://problem/3987680> Default queue name is "lp" when rp key is not specified.
43
44 Revision 1.24 2005/02/01 02:15:55 shersche
45 <rdar://problem/3946587> Use TXTRecord parsing APIs in ParseTextRecord
46
47 Revision 1.23 2005/01/31 23:54:30 shersche
48 <rdar://problem/3947508> Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object.
49
50 Revision 1.22 2005/01/25 18:49:43 shersche
51 Get icon resources from resource DLL
52
53 Revision 1.21 2005/01/10 01:09:32 shersche
54 Use the "note" key to populate pLocation field when setting up printer
55
56 Revision 1.20 2005/01/03 19:05:01 shersche
57 Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window
58
59 Revision 1.19 2004/12/31 07:23:53 shersche
60 Don't modify the button setting in SetSelectedPrinter()
61
62 Revision 1.18 2004/12/29 18:53:38 shersche
63 <rdar://problem/3725106>
64 <rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
65 Bug #: 3725106, 3737413
66
67 Revision 1.17 2004/10/12 18:02:53 shersche
68 <rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
69 Bug #: 3764873
70
71 Revision 1.16 2004/09/13 21:27:22 shersche
72 <rdar://problem/3796483> Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks
73 Bug #: 3796483
74
75 Revision 1.15 2004/09/11 05:59:06 shersche
76 <rdar://problem/3785766> Fix code that generates unique printer names based on currently installed printers
77 Bug #: 3785766
78
79 Revision 1.14 2004/09/02 01:57:58 cheshire
80 <rdar://problem/3783611> Fix incorrect testing of MoreComing flag
81
82 Revision 1.13 2004/07/26 21:06:29 shersche
83 <rdar://problem/3739200> Removing trailing '.' in hostname
84 Bug #: 3739200
85
86 Revision 1.12 2004/07/13 21:24:23 rpantos
87 Fix for <rdar://problem/3701120>.
88
89 Revision 1.11 2004/06/28 00:51:47 shersche
90 Move call to EnumPrinters out of browse callback into standalone function
91
92 Revision 1.10 2004/06/27 23:06:47 shersche
93 code cleanup, make sure EnumPrinters returns non-zero value
94
95 Revision 1.9 2004/06/27 15:49:31 shersche
96 clean up some cruft in the printer browsing code
97
98 Revision 1.8 2004/06/27 08:04:51 shersche
99 copy selected printer to prevent printer being deleted out from under
100
101 Revision 1.7 2004/06/26 23:27:12 shersche
102 support for installing multiple printers of the same name
103
104 Revision 1.6 2004/06/26 21:22:39 shersche
105 handle spaces in file names
106
107 Revision 1.5 2004/06/26 03:19:57 shersche
108 clean up warning messages
109
110 Submitted by: herscher
111
112 Revision 1.4 2004/06/25 02:26:52 shersche
113 Normalize key fields in text record entries
114 Submitted by: herscher
115
116 Revision 1.3 2004/06/24 20:12:07 shersche
117 Clean up source code
118 Submitted by: herscher
119
120 Revision 1.2 2004/06/23 17:58:21 shersche
121 <rdar://problem/3701837> eliminated memory leaks on exit
122 <rdar://problem/3701926> installation of a printer that is already installed results in a no-op
123 Bug #: 3701837, 3701926
124 Submitted by: herscher
125
126 Revision 1.1 2004/06/18 04:36:57 rpantos
127 First checked in
128
129
130 */
131
132 #include "stdafx.h"
133 #include "PrinterSetupWizardApp.h"
134 #include "PrinterSetupWizardSheet.h"
135 #include "CommonServices.h"
136 #include "DebugServices.h"
137 #include "WinServices.h"
138 #include "About.h"
139 #include <winspool.h>
140 #include <tcpxcv.h>
141 #include <string>
142
143 // unreachable code
144 #pragma warning(disable:4702)
145
146
147 #if( !TARGET_OS_WINDOWS_CE )
148 # include <mswsock.h>
149 # include <process.h>
150 #endif
151
152 // Private Messages
153
154 #define WM_SOCKET_EVENT ( WM_USER + 0x100 )
155 #define WM_PROCESS_EVENT ( WM_USER + 0x101 )
156
157
158 // CPrinterSetupWizardSheet
159 CPrinterSetupWizardSheet * CPrinterSetupWizardSheet::m_self;
160
161 IMPLEMENT_DYNAMIC(CPrinterSetupWizardSheet, CPropertySheet)
162 CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
163 :CPropertySheet(nIDCaption, pParentWnd, iSelectPage),
164 m_selectedPrinter(NULL),
165 m_driverThreadExitCode( 0 ),
166 m_driverThreadFinished( false ),
167 m_pdlBrowser( NULL ),
168 m_ippBrowser( NULL ),
169 m_lprBrowser( NULL )
170 {
171 m_arrow = LoadCursor(0, IDC_ARROW);
172 m_wait = LoadCursor(0, IDC_APPSTARTING);
173 m_active = m_arrow;
174 m_self = this;
175
176 Init();
177
178 LoadPrinterNames();
179 }
180
181
182 CPrinterSetupWizardSheet::~CPrinterSetupWizardSheet()
183 {
184 Printer * printer;
185
186 while ( m_printers.size() > 0 )
187 {
188 printer = m_printers.front();
189 m_printers.pop_front();
190
191 delete printer;
192 }
193
194 m_self = NULL;
195 }
196
197
198 // ------------------------------------------------------
199 // SetSelectedPrinter
200 //
201 // Manages setting a printer as the printer to install. Stops
202 // any pending resolves.
203 //
204 void
205 CPrinterSetupWizardSheet::SetSelectedPrinter(Printer * printer)
206 {
207 check( !printer || ( printer != m_selectedPrinter ) );
208
209 m_selectedPrinter = printer;
210 }
211
212
213 OSStatus
214 CPrinterSetupWizardSheet::LoadPrinterNames()
215 {
216 PBYTE buffer = NULL;
217 OSStatus err = 0;
218
219 //
220 // rdar://problem/3701926 - Printer can't be installed twice
221 //
222 // First thing we want to do is make sure the printer isn't already installed.
223 // If the printer name is found, we'll try and rename it until we
224 // find a unique name
225 //
226 DWORD dwNeeded = 0, dwNumPrinters = 0;
227
228 BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
229 err = translate_errno( ok, errno_compat(), kUnknownErr );
230
231 if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
232 {
233 try
234 {
235 buffer = new unsigned char[dwNeeded];
236 }
237 catch (...)
238 {
239 buffer = NULL;
240 }
241
242 require_action( buffer, exit, kNoMemoryErr );
243 ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
244 err = translate_errno( ok, errno_compat(), kUnknownErr );
245 require_noerr( err, exit );
246
247 for (DWORD index = 0; index < dwNumPrinters; index++)
248 {
249 PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
250
251 m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
252 }
253 }
254
255 exit:
256
257 if (buffer != NULL)
258 {
259 delete [] buffer;
260 }
261
262 return err;
263 }
264
265
266
267 // ------------------------------------------------------
268 // InstallPrinter
269 //
270 // Installs a printer with Windows.
271 //
272 // NOTE: this works one of two ways, depending on whether
273 // there are drivers already installed for this printer.
274 // If there are, then we can just create a port with XcvData,
275 // and then call AddPrinter. If not, we use the printui.dll
276 // to install the printer. Actually installing drivers that
277 // are not currently installed is painful, and it's much
278 // easier and less error prone to just let printui.dll do
279 // the hard work for us.
280 //
281
282 OSStatus
283 CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
284 {
285 Service * service;
286 BOOL ok;
287 OSStatus err;
288
289 service = printer->services.front();
290 check( service );
291
292 //
293 // if the driver isn't installed, then install it
294 //
295 if ( !printer->driverInstalled )
296 {
297 DWORD dwResult;
298 HANDLE hThread;
299 unsigned threadID;
300
301 m_driverThreadFinished = false;
302
303 //
304 // create the thread
305 //
306 hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID );
307 err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
308 require_noerr( err, exit );
309
310 //
311 // go modal
312 //
313 while (!m_driverThreadFinished)
314 {
315 MSG msg;
316
317 GetMessage( &msg, m_hWnd, 0, 0 );
318 TranslateMessage(&msg);
319 DispatchMessage(&msg);
320 }
321
322 //
323 // Wait until child process exits.
324 //
325 dwResult = WaitForSingleObject( hThread, INFINITE );
326 err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
327 require_noerr( err, exit );
328
329 //
330 // check the return value of thread
331 //
332 require_noerr( m_driverThreadExitCode, exit );
333
334 //
335 // now we know that the driver was successfully installed
336 //
337 printer->driverInstalled = true;
338 }
339
340 if ( service->type == kPDLServiceType )
341 {
342 err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE );
343 require_noerr( err, exit );
344 }
345 else if ( service->type == kLPRServiceType )
346 {
347 err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE );
348 require_noerr( err, exit );
349 }
350 else if ( service->type == kIPPServiceType )
351 {
352 err = InstallPrinterIPP( printer, service );
353 require_noerr( err, exit );
354 }
355 else
356 {
357 err = kUnknownErr;
358 require_noerr( err, exit );
359 }
360
361 printer->installed = true;
362
363 //
364 // if the user specified a default printer, set it
365 //
366 if (printer->deflt)
367 {
368 ok = SetDefaultPrinter( printer->actualName );
369 err = translate_errno( ok, errno_compat(), err = kUnknownErr );
370 require_noerr( err, exit );
371 }
372
373 exit:
374
375 return err;
376 }
377
378
379 OSStatus
380 CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol )
381 {
382 PRINTER_DEFAULTS printerDefaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER };
383 DWORD dwStatus;
384 DWORD cbInputData = 100;
385 PBYTE pOutputData = NULL;
386 DWORD cbOutputNeeded = 0;
387 PORT_DATA_1 portData;
388 PRINTER_INFO_2 pInfo;
389 HANDLE hXcv = NULL;
390 HANDLE hPrinter = NULL;
391 Queue * q;
392 BOOL ok;
393 OSStatus err;
394
395 check(printer != NULL);
396 check(printer->installed == false);
397
398 q = service->queues.front();
399 check( q );
400
401 ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults);
402 err = translate_errno( ok, errno_compat(), kUnknownErr );
403 require_noerr( err, exit );
404
405 //
406 // BUGBUG: MSDN said this is not required, but my experience shows it is required
407 //
408 try
409 {
410 pOutputData = new BYTE[cbInputData];
411 }
412 catch (...)
413 {
414 pOutputData = NULL;
415 }
416
417 require_action( pOutputData, exit, err = kNoMemoryErr );
418
419 //
420 // setup the port
421 //
422 ZeroMemory(&portData, sizeof(PORT_DATA_1));
423 wcscpy(portData.sztPortName, printer->portName);
424
425 portData.dwPortNumber = service->portNumber;
426 portData.dwVersion = 1;
427
428 portData.dwProtocol = protocol;
429 portData.cbSize = sizeof PORT_DATA_1;
430 portData.dwReserved = 0L;
431
432 wcscpy(portData.sztQueue, q->name);
433 wcscpy(portData.sztIPAddress, service->hostname);
434 wcscpy(portData.sztHostAddress, service->hostname);
435
436 ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData, &cbOutputNeeded, &dwStatus);
437 err = translate_errno( ok, errno_compat(), kUnknownErr );
438 require_noerr( err, exit );
439
440 //
441 // add the printer
442 //
443 ZeroMemory(&pInfo, sizeof(pInfo));
444
445 pInfo.pPrinterName = printer->actualName.GetBuffer();
446 pInfo.pServerName = NULL;
447 pInfo.pShareName = NULL;
448 pInfo.pPortName = printer->portName.GetBuffer();
449 pInfo.pDriverName = printer->modelName.GetBuffer();
450 pInfo.pComment = printer->displayModelName.GetBuffer();
451 pInfo.pLocation = q->location.GetBuffer();
452 pInfo.pDevMode = NULL;
453 pInfo.pDevMode = NULL;
454 pInfo.pSepFile = L"";
455 pInfo.pPrintProcessor = L"winprint";
456 pInfo.pDatatype = L"RAW";
457 pInfo.pParameters = L"";
458 pInfo.pSecurityDescriptor = NULL;
459 pInfo.Attributes = PRINTER_ATTRIBUTE_QUEUED;
460 pInfo.Priority = 0;
461 pInfo.DefaultPriority = 0;
462 pInfo.StartTime = 0;
463 pInfo.UntilTime = 0;
464
465 hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
466 err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
467 require_noerr( err, exit );
468
469 exit:
470
471 if (hPrinter != NULL)
472 {
473 ClosePrinter(hPrinter);
474 }
475
476 if (hXcv != NULL)
477 {
478 ClosePrinter(hXcv);
479 }
480
481 if (pOutputData != NULL)
482 {
483 delete [] pOutputData;
484 }
485
486 return err;
487 }
488
489
490 OSStatus
491 CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service)
492 {
493 DEBUG_UNUSED( service );
494
495 Queue * q = service->SelectedQueue();
496 HANDLE hPrinter = NULL;
497 PRINTER_INFO_2 pInfo;
498 OSStatus err;
499
500 check( q );
501
502 //
503 // add the printer
504 //
505 ZeroMemory(&pInfo, sizeof(PRINTER_INFO_2));
506
507 pInfo.pPrinterName = printer->actualName.GetBuffer();
508 pInfo.pPortName = printer->portName.GetBuffer();
509 pInfo.pDriverName = printer->modelName.GetBuffer();
510 pInfo.pPrintProcessor = L"winprint";
511 pInfo.pLocation = q->location.GetBuffer();
512 pInfo.pComment = printer->displayModelName.GetBuffer();
513 pInfo.Attributes = PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL;
514
515 hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo);
516 err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
517 require_noerr( err, exit );
518
519 exit:
520
521 if ( hPrinter != NULL )
522 {
523 ClosePrinter(hPrinter);
524 }
525
526 return err;
527 }
528
529
530 BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet, CPropertySheet)
531 ON_MESSAGE( WM_SOCKET_EVENT, OnSocketEvent )
532 ON_MESSAGE( WM_PROCESS_EVENT, OnProcessEvent )
533 ON_WM_SETCURSOR()
534 ON_WM_TIMER()
535 END_MESSAGE_MAP()
536
537
538 // ------------------------------------------------------
539 // OnCommand
540 //
541 // Traps when the user hits Finish
542 //
543 BOOL CPrinterSetupWizardSheet::OnCommand(WPARAM wParam, LPARAM lParam)
544 {
545 //
546 // Check if this is OK
547 //
548 if (wParam == ID_WIZFINISH) // If OK is hit...
549 {
550 OnOK();
551 }
552
553 return CPropertySheet::OnCommand(wParam, lParam);
554 }
555
556
557 // ------------------------------------------------------
558 // OnInitDialog
559 //
560 // Initializes this Dialog object.
561 //
562 BOOL CPrinterSetupWizardSheet::OnInitDialog()
563 {
564 OSStatus err;
565
566 CPropertySheet::OnInitDialog();
567
568 err = StartBrowse();
569 require_noerr( err, exit );
570
571 exit:
572
573 if ( err )
574 {
575 StopBrowse();
576
577 if ( err == kDNSServiceErr_Firewall )
578 {
579 CString text, caption;
580
581 text.LoadString( IDS_FIREWALL );
582 caption.LoadString( IDS_FIREWALL_CAPTION );
583
584 MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION);
585 }
586 else
587 {
588 CPrinterSetupWizardSheet::WizardException exc;
589
590 exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT );
591 exc.caption.LoadString( IDS_ERROR_CAPTION );
592
593 throw(exc);
594 }
595 }
596
597 return TRUE;
598 }
599
600
601 // ------------------------------------------------------
602 // OnSetCursor
603 //
604 // This is called when Windows wants to know what cursor
605 // to display. So we tell it.
606 //
607 BOOL
608 CPrinterSetupWizardSheet::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
609 {
610 DEBUG_UNUSED(pWnd);
611 DEBUG_UNUSED(nHitTest);
612 DEBUG_UNUSED(message);
613
614 SetCursor(m_active);
615 return TRUE;
616 }
617
618
619 // ------------------------------------------------------
620 // OnContextMenu
621 //
622 // This is not fully implemented yet.
623 //
624
625 void
626 CPrinterSetupWizardSheet::OnContextMenu(CWnd * pWnd, CPoint pos)
627 {
628 DEBUG_UNUSED(pWnd);
629 DEBUG_UNUSED(pos);
630
631 CAbout dlg;
632
633 dlg.DoModal();
634 }
635
636
637 // ------------------------------------------------------
638 // OnOK
639 //
640 // This is called when the user hits the "Finish" button
641 //
642 void
643 CPrinterSetupWizardSheet::OnOK()
644 {
645 check ( m_selectedPrinter != NULL );
646
647 SetWizardButtons( PSWIZB_DISABLEDFINISH );
648
649 if ( InstallPrinter( m_selectedPrinter ) != kNoErr )
650 {
651 CString caption;
652 CString message;
653
654 caption.LoadString(IDS_INSTALL_ERROR_CAPTION);
655 message.LoadString(IDS_INSTALL_ERROR_MESSAGE);
656
657 MessageBox(message, caption, MB_OK|MB_ICONEXCLAMATION);
658 }
659
660 StopBrowse();
661 }
662
663
664 // CPrinterSetupWizardSheet message handlers
665
666 void CPrinterSetupWizardSheet::Init(void)
667 {
668 AddPage(&m_pgFirst);
669 AddPage(&m_pgSecond);
670 AddPage(&m_pgThird);
671 AddPage(&m_pgFourth);
672
673 m_psh.dwFlags &= (~PSH_HASHELP);
674
675 m_psh.dwFlags |= PSH_WIZARD97|PSH_WATERMARK|PSH_HEADER;
676 m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
677 m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER_ICON);
678
679 m_psh.hInstance = GetNonLocalizedResources();
680
681 SetWizardMode();
682 }
683
684
685 LONG
686 CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam)
687 {
688 if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
689 {
690 dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
691 }
692 else
693 {
694 SOCKET sock = (SOCKET) inWParam;
695
696 // iterate thru list
697 ServiceRefList::iterator begin = m_serviceRefList.begin();
698 ServiceRefList::iterator end = m_serviceRefList.end();
699
700 while (begin != end)
701 {
702 DNSServiceRef ref = *begin++;
703
704 check(ref != NULL);
705
706 if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
707 {
708 DNSServiceProcessResult(ref);
709 break;
710 }
711 }
712 }
713
714 return ( 0 );
715 }
716
717
718 LONG
719 CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam)
720 {
721 DEBUG_UNUSED(inLParam);
722
723 m_driverThreadExitCode = (DWORD) inWParam;
724 m_driverThreadFinished = true;
725
726 return 0;
727 }
728
729
730 unsigned WINAPI
731 CPrinterSetupWizardSheet::InstallDriverThread( LPVOID inParam )
732 {
733 Printer * printer = (Printer*) inParam;
734 DWORD exitCode = 0;
735 DWORD dwResult;
736 OSStatus err;
737 STARTUPINFO si;
738 PROCESS_INFORMATION pi;
739 BOOL ok;
740
741 check( printer );
742 check( m_self );
743
744 //
745 // because we're calling endthreadex(), C++ objects won't be cleaned up
746 // correctly. we'll nest the CString 'command' inside a block so
747 // that it's destructor will be invoked.
748 //
749 {
750 CString command;
751
752 ZeroMemory( &si, sizeof(si) );
753 si.cb = sizeof(si);
754 ZeroMemory( &pi, sizeof(pi) );
755
756 command.Format(L"rundll32.exe printui.dll,PrintUIEntry /ia /m \"%s\" /f \"%s\"", (LPCTSTR) printer->modelName, (LPCTSTR) printer->infFileName );
757
758 ok = CreateProcess(NULL, command.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
759 err = translate_errno( ok, errno_compat(), kUnknownErr );
760 require_noerr( err, exit );
761
762 dwResult = WaitForSingleObject( pi.hProcess, INFINITE );
763 translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
764 require_noerr( err, exit );
765
766 ok = GetExitCodeProcess( pi.hProcess, &exitCode );
767 err = translate_errno( ok, errno_compat(), kUnknownErr );
768 require_noerr( err, exit );
769 }
770
771 exit:
772
773 //
774 // Close process and thread handles.
775 //
776 if ( pi.hProcess )
777 {
778 CloseHandle( pi.hProcess );
779 }
780
781 if ( pi.hThread )
782 {
783 CloseHandle( pi.hThread );
784 }
785
786 //
787 // alert the main thread
788 //
789 m_self->PostMessage( WM_PROCESS_EVENT, err, exitCode );
790
791 _endthreadex_compat( 0 );
792
793 return 0;
794 }
795
796
797 void DNSSD_API
798 CPrinterSetupWizardSheet::OnBrowse(
799 DNSServiceRef inRef,
800 DNSServiceFlags inFlags,
801 uint32_t inInterfaceIndex,
802 DNSServiceErrorType inErrorCode,
803 const char * inName,
804 const char * inType,
805 const char * inDomain,
806 void * inContext )
807 {
808 DEBUG_UNUSED(inRef);
809
810 CPrinterSetupWizardSheet * self;
811 bool moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
812 CPropertyPage * active;
813 Printer * printer = NULL;
814 Service * service = NULL;
815 OSStatus err = kNoErr;
816
817 require_noerr( inErrorCode, exit );
818
819 self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
820 require_quiet( self, exit );
821
822 active = self->GetActivePage();
823 require_quiet( active, exit );
824
825 // Have we seen this printer before?
826
827 printer = self->Lookup( inName );
828
829 if ( printer )
830 {
831 service = printer->LookupService( inType );
832 }
833
834 if ( inFlags & kDNSServiceFlagsAdd )
835 {
836 if (printer == NULL)
837 {
838 // If not, then create a new one
839
840 printer = self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing );
841 require_action( printer, exit, err = kUnknownErr );
842 }
843
844 if ( !service )
845 {
846 err = self->OnAddService( printer, inInterfaceIndex, inName, inType, inDomain );
847 require_noerr( err, exit );
848 }
849 else
850 {
851 service->refs++;
852 }
853 }
854 else if ( printer )
855 {
856 check( service );
857
858 err = self->OnRemoveService( service );
859 require_noerr( err, exit );
860
861 if ( printer->services.size() == 0 )
862 {
863 err = self->OnRemovePrinter( printer, moreComing );
864 require_noerr( err, exit );
865 }
866 }
867
868 exit:
869
870 return;
871 }
872
873
874 void DNSSD_API
875 CPrinterSetupWizardSheet::OnResolve(
876 DNSServiceRef inRef,
877 DNSServiceFlags inFlags,
878 uint32_t inInterfaceIndex,
879 DNSServiceErrorType inErrorCode,
880 const char * inFullName,
881 const char * inHostName,
882 uint16_t inPort,
883 uint16_t inTXTSize,
884 const char * inTXT,
885 void * inContext )
886 {
887 DEBUG_UNUSED(inFullName);
888 DEBUG_UNUSED(inInterfaceIndex);
889 DEBUG_UNUSED(inFlags);
890 DEBUG_UNUSED(inRef);
891
892 CPrinterSetupWizardSheet * self;
893 Service * service;
894 Queue * q;
895 int idx;
896 OSStatus err;
897
898 require_noerr( inErrorCode, exit );
899
900 service = reinterpret_cast<Service*>( inContext );
901 require_quiet( service, exit);
902
903 check( service->refs != 0 );
904
905 self = service->printer->window;
906 require_quiet( self, exit );
907
908 err = self->StopOperation( service->serviceRef );
909 require_noerr( err, exit );
910
911 //
912 // hold on to the hostname...
913 //
914 err = UTF8StringToStringObject( inHostName, service->hostname );
915 require_noerr( err, exit );
916
917 //
918 // <rdar://problem/3739200> remove the trailing dot on hostname
919 //
920 idx = service->hostname.ReverseFind('.');
921
922 if ((idx > 1) && ((service->hostname.GetLength() - 1) == idx))
923 {
924 service->hostname.Delete(idx, 1);
925 }
926
927 //
928 // hold on to the port
929 //
930 service->portNumber = ntohs(inPort);
931
932 if ( service->qtotal == 1 )
933 {
934 //
935 // create a new queue
936 //
937 try
938 {
939 q = new Queue;
940 }
941 catch (...)
942 {
943 q = NULL;
944 }
945
946 require_action( q, exit, err = E_OUTOFMEMORY );
947
948 //
949 // parse the text record.
950 //
951
952 err = self->ParseTextRecord( service, q, inTXTSize, inTXT );
953 require_noerr( err, exit );
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, q, inRDLen, inTXT );
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, Queue * q, uint16_t inTXTSize, const char * inTXT )
1516 {
1517 check( service );
1518 check( q );
1519
1520 // <rdar://problem/3946587> Use TXTRecord APIs declared in dns_sd.h
1521
1522 bool qtotalDefined = false;
1523 const void * val;
1524 char buf[256];
1525 uint8_t len;
1526 OSStatus err = kNoErr;
1527
1528 // <rdar://problem/3987680> Default to queue "lp"
1529
1530 q->name = L"lp";
1531
1532 // <rdar://problem/4003710> Default pdl key to be "application/postscript"
1533
1534 q->pdl = L"application/postscript";
1535
1536 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "rp", &len ) ) != NULL )
1537 {
1538 // Stringize val ( doesn't have trailing '\0' yet )
1539
1540 memcpy( buf, val, len );
1541 buf[len] = '\0';
1542
1543 err = UTF8StringToStringObject( buf, q->name );
1544 require_noerr( err, exit );
1545 }
1546
1547 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "pdl", &len ) ) != NULL )
1548 {
1549 // Stringize val ( doesn't have trailing '\0' yet )
1550
1551 memcpy( buf, val, len );
1552 buf[len] = '\0';
1553
1554 err = UTF8StringToStringObject( buf, q->pdl );
1555 require_noerr( err, exit );
1556 }
1557
1558 if ( ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_mfg", &len ) ) != NULL ) ||
1559 ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_manufacturer", &len ) ) != NULL ) )
1560 {
1561 // Stringize val ( doesn't have trailing '\0' yet )
1562
1563 memcpy( buf, val, len );
1564 buf[len] = '\0';
1565
1566 err = UTF8StringToStringObject( buf, q->usb_MFG );
1567 require_noerr( err, exit );
1568 }
1569
1570 if ( ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_mdl", &len ) ) != NULL ) ||
1571 ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "usb_model", &len ) ) != NULL ) )
1572 {
1573 // Stringize val ( doesn't have trailing '\0' yet )
1574
1575 memcpy( buf, val, len );
1576 buf[len] = '\0';
1577
1578 err = UTF8StringToStringObject( buf, q->usb_MDL );
1579 require_noerr( err, exit );
1580 }
1581
1582 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "ty", &len ) ) != NULL )
1583 {
1584 // Stringize val ( doesn't have trailing '\0' yet )
1585
1586 memcpy( buf, val, len );
1587 buf[len] = '\0';
1588
1589 err = UTF8StringToStringObject( buf, q->description );
1590 require_noerr( err, exit );
1591 }
1592
1593 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "product", &len ) ) != NULL )
1594 {
1595 // Stringize val ( doesn't have trailing '\0' yet )
1596
1597 memcpy( buf, val, len );
1598 buf[len] = '\0';
1599
1600 err = UTF8StringToStringObject( buf, q->product );
1601 require_noerr( err, exit );
1602 }
1603
1604 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "note", &len ) ) != NULL )
1605 {
1606 // Stringize val ( doesn't have trailing '\0' yet )
1607
1608 memcpy( buf, val, len );
1609 buf[len] = '\0';
1610
1611 err = UTF8StringToStringObject( buf, q->location );
1612 require_noerr( err, exit );
1613 }
1614
1615 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "qtotal", &len ) ) != NULL )
1616 {
1617 // Stringize val ( doesn't have trailing '\0' yet )
1618
1619 memcpy( buf, val, len );
1620 buf[len] = '\0';
1621
1622 service->qtotal = (unsigned short) atoi( buf );
1623 qtotalDefined = true;
1624 }
1625
1626 if ( ( val = TXTRecordGetValuePtr( inTXTSize, inTXT, "priority", &len ) ) != NULL )
1627 {
1628 // Stringize val ( doesn't have trailing '\0' yet )
1629
1630 memcpy( buf, val, len );
1631 buf[len] = '\0';
1632
1633 q->priority = atoi( buf );
1634 }
1635
1636 exit:
1637
1638 // The following code is to fix a problem with older HP
1639 // printers that don't include "qtotal" in their text
1640 // record. We'll check to see if the q->name is "TEXT"
1641 // and if so, we're going to modify it to be "lp" so
1642 // that we don't use the wrong queue
1643
1644 if ( !err && !qtotalDefined && ( q->name == L"TEXT" ) )
1645 {
1646 q->name = "lp";
1647 }
1648
1649 return err;
1650 }
1651
1652
1653 Printer*
1654 CPrinterSetupWizardSheet::Lookup(const char * inName)
1655 {
1656 check( inName );
1657
1658 Printer * printer = NULL;
1659 Printers::iterator it;
1660
1661 for ( it = m_printers.begin(); it != m_printers.end(); it++ )
1662 {
1663 if ( (*it)->name == inName )
1664 {
1665 printer = *it;
1666 break;
1667 }
1668 }
1669
1670 return printer;
1671 }
1672
1673
1674 bool
1675 CPrinterSetupWizardSheet::OrderServiceFunc( const Service * a, const Service * b )
1676 {
1677 Queue * q1, * q2;
1678
1679 q1 = (a->queues.size() > 0) ? a->queues.front() : NULL;
1680
1681 q2 = (b->queues.size() > 0) ? b->queues.front() : NULL;
1682
1683 if ( !q1 && !q2 )
1684 {
1685 return true;
1686 }
1687 else if ( q1 && !q2 )
1688 {
1689 return true;
1690 }
1691 else if ( !q1 && q2 )
1692 {
1693 return false;
1694 }
1695 else if ( q1->priority < q2->priority )
1696 {
1697 return true;
1698 }
1699 else if ( q1->priority > q2->priority )
1700 {
1701 return false;
1702 }
1703 else if ( ( a->type == kPDLServiceType ) || ( ( a->type == kLPRServiceType ) && ( b->type == kIPPServiceType ) ) )
1704 {
1705 return true;
1706 }
1707 else
1708 {
1709 return false;
1710 }
1711 }
1712
1713
1714 bool
1715 CPrinterSetupWizardSheet::OrderQueueFunc( const Queue * q1, const Queue * q2 )
1716 {
1717 return ( q1->priority <= q2->priority ) ? true : false;
1718 }
1719
1720
1721