1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include "SecondPage.h" 19 #include "resource.h" 20 21 #include "ConfigPropertySheet.h" 22 #include "SharedSecret.h" 23 24 #include <WinServices.h> 25 26 #define MAX_KEY_LENGTH 255 27 28 IMPLEMENT_DYNCREATE(CSecondPage, CPropertyPage) 29 30 31 //--------------------------------------------------------------------------------------------------------------------------- 32 // CSecondPage::CSecondPage 33 //--------------------------------------------------------------------------------------------------------------------------- 34 35 CSecondPage::CSecondPage() 36 : 37 CPropertyPage(CSecondPage::IDD), 38 m_setupKey( NULL ) 39 { 40 //{{AFX_DATA_INIT(CSecondPage) 41 //}}AFX_DATA_INIT 42 43 OSStatus err; 44 45 err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0, 46 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &m_setupKey, NULL ); 47 check_noerr( err ); 48 } 49 50 51 //--------------------------------------------------------------------------------------------------------------------------- 52 // CSecondPage::~CSecondPage 53 //--------------------------------------------------------------------------------------------------------------------------- 54 55 CSecondPage::~CSecondPage() 56 { 57 if ( m_setupKey ) 58 { 59 RegCloseKey( m_setupKey ); 60 m_setupKey = NULL; 61 } 62 } 63 64 65 //--------------------------------------------------------------------------------------------------------------------------- 66 // CSecondPage::DoDataExchange 67 //--------------------------------------------------------------------------------------------------------------------------- 68 69 void CSecondPage::DoDataExchange(CDataExchange* pDX) 70 { 71 CPropertyPage::DoDataExchange(pDX); 72 //{{AFX_DATA_MAP(CSecondPage) 73 //}}AFX_DATA_MAP 74 DDX_Control(pDX, IDC_CHECK1, m_advertiseServicesButton); 75 DDX_Control(pDX, IDC_BUTTON1, m_sharedSecretButton); 76 DDX_Control(pDX, IDC_COMBO2, m_regDomainsBox); 77 } 78 79 BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage) 80 //{{AFX_MSG_MAP(CSecondPage) 81 //}}AFX_MSG_MAP 82 ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSharedSecret) 83 ON_BN_CLICKED(IDC_CHECK1, OnBnClickedAdvertise) 84 ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelChange) 85 ON_CBN_EDITCHANGE(IDC_COMBO1, OnCbnEditChange) 86 ON_CBN_EDITCHANGE(IDC_COMBO2, OnCbnEditChange) 87 ON_CBN_SELCHANGE(IDC_COMBO2, OnCbnSelChange) 88 89 END_MESSAGE_MAP() 90 91 92 //--------------------------------------------------------------------------------------------------------------------------- 93 // CSecondPage::SetModified 94 //--------------------------------------------------------------------------------------------------------------------------- 95 96 void CSecondPage::SetModified( BOOL bChanged ) 97 { 98 m_modified = bChanged; 99 100 CPropertyPage::SetModified( bChanged ); 101 } 102 103 104 //--------------------------------------------------------------------------------------------------------------------------- 105 // CSecondPage::OnSetActive 106 //--------------------------------------------------------------------------------------------------------------------------- 107 108 BOOL 109 CSecondPage::OnSetActive() 110 { 111 CConfigPropertySheet * psheet; 112 DWORD err; 113 BOOL b = CPropertyPage::OnSetActive(); 114 115 psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent()); 116 require_quiet( psheet, exit ); 117 118 m_modified = FALSE; 119 120 // Clear out what's there 121 122 EmptyComboBox( m_regDomainsBox ); 123 124 // Now populate the registration domain box 125 126 err = Populate( m_regDomainsBox, m_setupKey, psheet->m_regDomains ); 127 check_noerr( err ); 128 129 exit: 130 131 return b; 132 } 133 134 135 //--------------------------------------------------------------------------------------------------------------------------- 136 // CSecondPage::OnOK 137 //--------------------------------------------------------------------------------------------------------------------------- 138 139 void 140 CSecondPage::OnOK() 141 { 142 if ( m_modified ) 143 { 144 Commit(); 145 } 146 } 147 148 149 150 //--------------------------------------------------------------------------------------------------------------------------- 151 // CSecondPage::Commit 152 //--------------------------------------------------------------------------------------------------------------------------- 153 154 void 155 CSecondPage::Commit() 156 { 157 DWORD err; 158 159 if ( m_setupKey != NULL ) 160 { 161 err = Commit( m_regDomainsBox, m_setupKey, m_advertiseServicesButton.GetCheck() == BST_CHECKED ); 162 check_noerr( err ); 163 } 164 } 165 166 167 //--------------------------------------------------------------------------------------------------------------------------- 168 // CSecondPage::Commit 169 //--------------------------------------------------------------------------------------------------------------------------- 170 171 OSStatus 172 CSecondPage::Commit( CComboBox & box, HKEY key, DWORD enabled ) 173 { 174 CString selected; 175 HKEY subKey = NULL; 176 TCHAR subKeyName[MAX_KEY_LENGTH]; 177 DWORD cSubKeys = 0; 178 DWORD cbMaxSubKey; 179 DWORD cchMaxClass; 180 DWORD dwSize; 181 int i; 182 OSStatus err = kNoErr; 183 184 // First, remove all the entries that are there 185 186 err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL ); 187 require_noerr( err, exit ); 188 189 for ( i = 0; i < (int) cSubKeys; i++ ) 190 { 191 dwSize = MAX_KEY_LENGTH; 192 193 err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL ); 194 require_noerr( err, exit ); 195 196 err = RegDeleteKey( key, subKeyName ); 197 require_noerr( err, exit ); 198 } 199 200 // Get selected text 201 202 box.GetWindowText( selected ); 203 204 // If we haven't seen this string before, add the string to the box and 205 // the registry 206 207 if ( ( selected.GetLength() > 0 ) && ( box.FindStringExact( -1, selected ) == CB_ERR ) ) 208 { 209 CString string; 210 211 box.AddString( selected ); 212 213 err = RegQueryString( key, L"UserDefined", string ); 214 check_noerr( err ); 215 216 if ( string.GetLength() ) 217 { 218 string += L"," + selected; 219 } 220 else 221 { 222 string = selected; 223 } 224 225 err = RegSetValueEx( key, L"UserDefined", 0, REG_SZ, (LPBYTE) (LPCTSTR) string, ( string.GetLength() + 1) * sizeof( TCHAR ) ); 226 check_noerr ( err ); 227 } 228 229 // Save selected text in registry. This will trigger mDNSResponder to setup 230 // DynDNS config again 231 232 err = RegCreateKeyEx( key, selected, 0, 233 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &subKey, NULL ); 234 require_noerr( err, exit ); 235 236 err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) ); 237 check_noerr( err ); 238 239 exit: 240 241 if ( subKey ) 242 { 243 RegCloseKey( subKey ); 244 subKey = NULL; 245 } 246 247 return err; 248 } 249 250 251 //--------------------------------------------------------------------------------------------------------------------------- 252 // CSecondPage::OnBnClickedSharedSecret 253 //--------------------------------------------------------------------------------------------------------------------------- 254 255 void CSecondPage::OnBnClickedSharedSecret() 256 { 257 CString name; 258 259 m_regDomainsBox.GetWindowText( name ); 260 261 CSharedSecret dlg; 262 263 dlg.Load( name ); 264 265 if ( dlg.DoModal() == IDOK ) 266 { 267 DWORD wakeup = 0; 268 DWORD dwSize = sizeof( DWORD ); 269 OSStatus err; 270 271 dlg.Commit( name ); 272 273 // We have now updated the secret, however the system service 274 // doesn't know about it yet. So we're going to update the 275 // registry with a dummy value which will cause the system 276 // service to re-initialize it's DynDNS setup 277 // 278 279 RegQueryValueEx( m_setupKey, L"Wakeup", NULL, NULL, (LPBYTE) &wakeup, &dwSize ); 280 281 wakeup++; 282 283 err = RegSetValueEx( m_setupKey, L"Wakeup", 0, REG_DWORD, (LPBYTE) &wakeup, sizeof( DWORD ) ); 284 require_noerr( err, exit ); 285 } 286 287 exit: 288 289 return; 290 } 291 292 293 //--------------------------------------------------------------------------------------------------------------------------- 294 // CSecondPage::OnBnClickedAdvertise 295 //--------------------------------------------------------------------------------------------------------------------------- 296 297 void CSecondPage::OnBnClickedAdvertise() 298 { 299 int state; 300 301 state = m_advertiseServicesButton.GetCheck(); 302 303 m_regDomainsBox.EnableWindow( state ); 304 m_sharedSecretButton.EnableWindow( state ); 305 306 SetModified( TRUE ); 307 } 308 309 310 //--------------------------------------------------------------------------------------------------------------------------- 311 // CSecondPage::OnCbnSelChange 312 //--------------------------------------------------------------------------------------------------------------------------- 313 314 void CSecondPage::OnCbnSelChange() 315 { 316 SetModified( TRUE ); 317 } 318 319 320 //--------------------------------------------------------------------------------------------------------------------------- 321 // CSecondPage::OnCbnEditChange 322 //--------------------------------------------------------------------------------------------------------------------------- 323 324 void CSecondPage::OnCbnEditChange() 325 { 326 SetModified( TRUE ); 327 } 328 329 330 331 //--------------------------------------------------------------------------------------------------------------------------- 332 // CSecondPage::OnAddRegistrationDomain 333 //--------------------------------------------------------------------------------------------------------------------------- 334 335 void 336 CSecondPage::OnAddRegistrationDomain( CString & domain ) 337 { 338 int index = m_regDomainsBox.FindStringExact( -1, domain ); 339 340 if ( index == CB_ERR ) 341 { 342 m_regDomainsBox.AddString( domain ); 343 } 344 } 345 346 347 //--------------------------------------------------------------------------------------------------------------------------- 348 // CSecondPage::OnRemoveRegistrationDomain 349 //--------------------------------------------------------------------------------------------------------------------------- 350 351 void 352 CSecondPage::OnRemoveRegistrationDomain( CString & domain ) 353 { 354 int index = m_regDomainsBox.FindStringExact( -1, domain ); 355 356 if ( index != CB_ERR ) 357 { 358 m_regDomainsBox.DeleteString( index ); 359 } 360 } 361 362 363 //--------------------------------------------------------------------------------------------------------------------------- 364 // CSecondPage::EmptyComboBox 365 //--------------------------------------------------------------------------------------------------------------------------- 366 367 void 368 CSecondPage::EmptyComboBox( CComboBox & box ) 369 { 370 while ( box.GetCount() > 0 ) 371 { 372 box.DeleteString( 0 ); 373 } 374 } 375 376 377 //--------------------------------------------------------------------------------------------------------------------------- 378 // CSecondPage::Populate 379 //--------------------------------------------------------------------------------------------------------------------------- 380 381 OSStatus 382 CSecondPage::Populate( CComboBox & box, HKEY key, StringList & l ) 383 { 384 CString string; 385 HKEY subKey = NULL; 386 DWORD dwSize; 387 DWORD enabled = 0; 388 TCHAR subKeyName[MAX_KEY_LENGTH]; 389 DWORD cSubKeys = 0; 390 DWORD cbMaxSubKey; 391 DWORD cchMaxClass; 392 OSStatus err; 393 394 err = RegQueryString( key, L"UserDefined", string ); 395 396 if ( !err && string.GetLength() ) 397 { 398 bool done = false; 399 400 while ( !done ) 401 { 402 CString tok; 403 404 tok = string.SpanExcluding( L"," ); 405 406 box.AddString( tok ); 407 408 if ( tok != string ) 409 { 410 // Get rid of that string and comma 411 412 string = string.Right( string.GetLength() - tok.GetLength() - 1 ); 413 } 414 else 415 { 416 done = true; 417 } 418 } 419 } 420 421 StringList::iterator it; 422 423 for ( it = l.begin(); it != l.end(); it++ ) 424 { 425 if ( box.FindStringExact( -1, *it ) == CB_ERR ) 426 { 427 box.AddString( *it ); 428 } 429 } 430 431 err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL ); 432 require_noerr( err, exit ); 433 434 if ( cSubKeys > 0 ) 435 { 436 dwSize = MAX_KEY_LENGTH; 437 438 err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL ); 439 require_noerr( err, exit ); 440 441 err = RegOpenKey( key, subKeyName, &subKey ); 442 require_noerr( err, exit ); 443 444 dwSize = sizeof( DWORD ); 445 err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize ); 446 require_noerr( err, exit ); 447 448 // See if it's there 449 450 if ( box.SelectString( -1, subKeyName ) == CB_ERR ) 451 { 452 // If not, add it 453 454 box.AddString( subKeyName ); 455 } 456 457 box.SelectString( -1, subKeyName ); 458 459 RegCloseKey( subKey ); 460 subKey = NULL; 461 } 462 463 exit: 464 465 m_advertiseServicesButton.SetCheck( ( !err && enabled ) ? BST_CHECKED : BST_UNCHECKED ); 466 m_regDomainsBox.EnableWindow( ( !err && enabled ) ); 467 m_sharedSecretButton.EnableWindow( (!err && enabled ) ); 468 469 return err; 470 } 471 472 473 //--------------------------------------------------------------------------------------------------------------------------- 474 // CSecondPage::CreateKey 475 //--------------------------------------------------------------------------------------------------------------------------- 476 477 OSStatus 478 CSecondPage::CreateKey( CString & name, DWORD enabled ) 479 { 480 HKEY key = NULL; 481 OSStatus err; 482 483 err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, (LPCTSTR) name, 0, 484 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL ); 485 require_noerr( err, exit ); 486 487 err = RegSetValueEx( key, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) ); 488 check_noerr( err ); 489 490 exit: 491 492 if ( key ) 493 { 494 RegCloseKey( key ); 495 } 496 497 return err; 498 } 499 500 501 //--------------------------------------------------------------------------------------------------------------------------- 502 // CSecondPage::RegQueryString 503 //--------------------------------------------------------------------------------------------------------------------------- 504 505 OSStatus 506 CSecondPage::RegQueryString( HKEY key, CString valueName, CString & value ) 507 { 508 TCHAR * string; 509 DWORD stringLen; 510 int i; 511 OSStatus err; 512 513 stringLen = 1024; 514 string = NULL; 515 i = 0; 516 517 do 518 { 519 if ( string ) 520 { 521 free( string ); 522 } 523 524 string = (TCHAR*) malloc( stringLen ); 525 require_action( string, exit, err = kUnknownErr ); 526 *string = '\0'; 527 528 err = RegQueryValueEx( key, valueName, 0, NULL, (LPBYTE) string, &stringLen ); 529 530 i++; 531 } 532 while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) ); 533 534 value = string; 535 536 exit: 537 538 if ( string ) 539 { 540 free( string ); 541 } 542 543 return err; 544 } 545