1 //***************************************************************************** 2 // File: LeashView.cpp 3 // By: Arthur David Leather 4 // Created: 12/02/98 5 // Copyright @1998 Massachusetts Institute of Technology - All rights reserved. 6 // Description: CPP file for LeashView.h. Contains variables and functions 7 // for the Leash FormView 8 // 9 // History: 10 // 11 // MM/DD/YY Inits Description of Change 12 // 12/02/98 ADL Original 13 // 20030508 JEA Added 14 //***************************************************************************** 15 16 #include "stdafx.h" 17 #include <afxpriv.h> 18 #include "Leash.h" 19 #include "LeashDoc.h" 20 #include "LeashView.h" 21 #include "MainFrm.h" 22 #include "reminder.h" 23 #include "lglobals.h" 24 #include "LeashDebugWindow.h" 25 #include "LeashMessageBox.h" 26 #include "LeashAboutBox.h" 27 #include <krb5.h> 28 29 #ifdef _DEBUG 30 #define new DEBUG_NEW 31 #undef THIS_FILE 32 static CHAR THIS_FILE[] = __FILE__; 33 #endif 34 35 #pragma comment(lib, "uxtheme") 36 ///////////////////////////////////////////////////////////////////////////// 37 // CLeashView 38 39 IMPLEMENT_DYNCREATE(CLeashView, CListView) 40 41 BEGIN_MESSAGE_MAP(CLeashView, CListView) 42 //{{AFX_MSG_MAP(CLeashView) 43 ON_MESSAGE(WM_WARNINGPOPUP, OnWarningPopup) 44 ON_MESSAGE(WM_GOODBYE, OnGoodbye) 45 ON_MESSAGE(WM_TRAYICON, OnTrayIcon) 46 ON_NOTIFY(TVN_ITEMEXPANDED, IDC_TREEVIEW, OnItemexpandedTreeview) 47 ON_WM_CREATE() 48 ON_WM_SHOWWINDOW() 49 ON_COMMAND(ID_INIT_TICKET, OnInitTicket) 50 ON_COMMAND(ID_RENEW_TICKET, OnRenewTicket) 51 ON_COMMAND(ID_DESTROY_TICKET, OnDestroyTicket) 52 ON_COMMAND(ID_CHANGE_PASSWORD, OnChangePassword) 53 ON_COMMAND(ID_MAKE_DEFAULT, OnMakeDefault) 54 ON_COMMAND(ID_UPDATE_DISPLAY, OnUpdateDisplay) 55 ON_COMMAND(ID_SYN_TIME, OnSynTime) 56 ON_COMMAND(ID_DEBUG_MODE, OnDebugMode) 57 ON_COMMAND(ID_LARGE_ICONS, OnLargeIcons) 58 ON_COMMAND(ID_TIME_ISSUED, OnTimeIssued) 59 ON_COMMAND(ID_VALID_UNTIL, OnValidUntil) 60 ON_COMMAND(ID_RENEWABLE_UNTIL, OnRenewableUntil) 61 ON_COMMAND(ID_SHOW_TICKET_FLAGS, OnShowTicketFlags) 62 ON_COMMAND(ID_ENCRYPTION_TYPE, OnEncryptionType) 63 ON_COMMAND(ID_CCACHE_NAME, OnCcacheName) 64 ON_UPDATE_COMMAND_UI(ID_TIME_ISSUED, OnUpdateTimeIssued) 65 ON_UPDATE_COMMAND_UI(ID_VALID_UNTIL, OnUpdateValidUntil) 66 ON_UPDATE_COMMAND_UI(ID_RENEWABLE_UNTIL, OnUpdateRenewableUntil) 67 ON_UPDATE_COMMAND_UI(ID_SHOW_TICKET_FLAGS, OnUpdateShowTicketFlags) 68 ON_UPDATE_COMMAND_UI(ID_ENCRYPTION_TYPE, OnUpdateEncryptionType) 69 ON_UPDATE_COMMAND_UI(ID_CCACHE_NAME, OnUpdateCcacheName) 70 ON_COMMAND(ID_UPPERCASE_REALM, OnUppercaseRealm) 71 ON_COMMAND(ID_KILL_TIX_ONEXIT, OnKillTixOnExit) 72 ON_UPDATE_COMMAND_UI(ID_UPPERCASE_REALM, OnUpdateUppercaseRealm) 73 ON_UPDATE_COMMAND_UI(ID_KILL_TIX_ONEXIT, OnUpdateKillTixOnExit) 74 ON_WM_DESTROY() 75 ON_UPDATE_COMMAND_UI(ID_DESTROY_TICKET, OnUpdateDestroyTicket) 76 ON_UPDATE_COMMAND_UI(ID_INIT_TICKET, OnUpdateInitTicket) 77 ON_UPDATE_COMMAND_UI(ID_RENEW_TICKET, OnUpdateRenewTicket) 78 ON_COMMAND(ID_APP_ABOUT, OnAppAbout) 79 ON_UPDATE_COMMAND_UI(ID_DEBUG_MODE, OnUpdateDebugMode) 80 ON_UPDATE_COMMAND_UI(ID_CFG_FILES, OnUpdateCfgFiles) 81 ON_COMMAND(ID_LEASH_RESTORE, OnLeashRestore) 82 ON_COMMAND(ID_LEASH_MINIMIZE, OnLeashMinimize) 83 ON_COMMAND(ID_LOW_TICKET_ALARM, OnLowTicketAlarm) 84 ON_COMMAND(ID_AUTO_RENEW, OnAutoRenew) 85 ON_UPDATE_COMMAND_UI(ID_LOW_TICKET_ALARM, OnUpdateLowTicketAlarm) 86 ON_UPDATE_COMMAND_UI(ID_AUTO_RENEW, OnUpdateAutoRenew) 87 ON_UPDATE_COMMAND_UI(ID_MAKE_DEFAULT, OnUpdateMakeDefault) 88 ON_UPDATE_COMMAND_UI(ID_PROPERTIES, OnUpdateProperties) 89 ON_COMMAND(ID_HELP_KERBEROS_, OnHelpKerberos) 90 ON_COMMAND(ID_HELP_LEASH32, OnHelpLeash32) 91 ON_COMMAND(ID_HELP_WHYUSELEASH32, OnHelpWhyuseleash32) 92 ON_WM_SIZE() 93 ON_WM_LBUTTONDOWN() 94 ON_WM_CLOSE() 95 ON_WM_HSCROLL() 96 ON_WM_VSCROLL() 97 ON_WM_SYSCOLORCHANGE() 98 ON_MESSAGE(ID_OBTAIN_TGT_WITH_LPARAM, OnObtainTGTWithParam) 99 ON_NOTIFY(HDN_ITEMCHANGED, 0, OnItemChanged) 100 //}}AFX_MSG_MAP 101 102 ON_NOTIFY_REFLECT(LVN_ITEMCHANGING, &CLeashView::OnLvnItemchanging) 103 ON_NOTIFY_REFLECT(LVN_ITEMACTIVATE, &CLeashView::OnLvnItemActivate) 104 ON_NOTIFY_REFLECT(LVN_KEYDOWN, &CLeashView::OnLvnKeydown) 105 ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CLeashView::OnNMCustomdraw) 106 END_MESSAGE_MAP() 107 108 109 time_t CLeashView::m_ticketTimeLeft = 0; // # of seconds left before tickets expire 110 INT CLeashView::m_ticketStatusKrb5 = 0; // Defense Condition: are we low on tickets? 111 INT CLeashView::m_warningOfTicketTimeLeftKrb5 = 0; // Prevents warning box from coming up repeatively 112 INT CLeashView::m_warningOfTicketTimeLeftLockKrb5 = 0; 113 INT CLeashView::m_updateDisplayCount; 114 INT CLeashView::m_alreadyPlayedDisplayCount; 115 INT CLeashView::m_autoRenewTickets = 0; 116 BOOL CLeashView::m_lowTicketAlarmSound; 117 INT CLeashView::m_autoRenewalAttempted = 0; 118 LONG CLeashView::m_timerMsgNotInProgress = 1; 119 ViewColumnInfo CLeashView::sm_viewColumns[] = 120 { 121 {"Principal", true, -1, 200}, // PRINCIPAL 122 {"Issued", false, ID_TIME_ISSUED, 100}, // TIME_ISSUED 123 {"Renewable Until", false, ID_RENEWABLE_UNTIL, 100}, // RENEWABLE_UNTIL 124 {"Valid Until", true, ID_VALID_UNTIL, 100}, // VALID_UNTIL 125 {"Encryption Type", false, ID_ENCRYPTION_TYPE, 100}, // ENCRYPTION_TYPE 126 {"Flags", false, ID_SHOW_TICKET_FLAGS, 100}, // TICKET_FLAGS 127 {"Credential Cache", false, ID_CCACHE_NAME, 105}, // CACHE_NAME 128 }; 129 130 static struct TicketFlag { 131 unsigned long m_flag; 132 const LPTSTR m_description; 133 } sm_TicketFlags[] = 134 { 135 {TKT_FLG_FORWARDABLE, _T("Forwardable")}, 136 {TKT_FLG_FORWARDED, _T("Forwarded")}, 137 {TKT_FLG_PROXIABLE, _T("Proxiable")}, 138 {TKT_FLG_PROXY, _T("Proxy")}, 139 {TKT_FLG_RENEWABLE, _T("Renewable")}, 140 }; 141 142 static void krb5TicketFlagsToString(unsigned long flags, LPTSTR *outStr) 143 { 144 const int numFlags = sizeof(sm_TicketFlags) / sizeof(sm_TicketFlags[0]); 145 int strSize = 1; 146 LPTSTR str; 147 // pass 1: compute size 148 for (int i = 0; i < numFlags; i++) { 149 if (flags & sm_TicketFlags[i].m_flag) { 150 if (strSize > 1) 151 strSize += 2; 152 strSize += strlen(sm_TicketFlags[i].m_description); 153 } 154 } 155 // allocate 156 str = (LPSTR)malloc(strSize); 157 if (str != NULL) { 158 *str = 0; 159 // pass 2: construct string 160 for (int i = 0; i < numFlags; i++) { 161 if (flags & sm_TicketFlags[i].m_flag) { 162 if (str[0]) 163 _tcscat_s(str, strSize, _T(", ")); 164 _tcscat_s(str, strSize, sm_TicketFlags[i].m_description); 165 } 166 } 167 } 168 *outStr = str; 169 } 170 171 172 static HFONT CreateBoldFont(HFONT font) 173 { 174 // @TODO: Should probably enumerate fonts here instead since this 175 // does not actually seem to guarantee returning a new font 176 // distinguishable from the original. 177 LOGFONT fontAttributes = { 0 }; 178 ::GetObject(font, sizeof(fontAttributes), &fontAttributes); 179 fontAttributes.lfWeight = FW_BOLD; 180 HFONT boldFont = ::CreateFontIndirect(&fontAttributes); 181 return boldFont; 182 } 183 184 static HFONT CreateItalicFont(HFONT font) 185 { 186 LOGFONT fontAttributes = { 0 }; 187 ::GetObject(font, sizeof(fontAttributes), &fontAttributes); 188 fontAttributes.lfItalic = TRUE; 189 HFONT italicFont = ::CreateFontIndirect(&fontAttributes); 190 return italicFont; 191 } 192 193 static HFONT CreateBoldItalicFont(HFONT font) 194 { 195 LOGFONT fontAttributes = { 0 }; 196 ::GetObject(font, sizeof(fontAttributes), &fontAttributes); 197 fontAttributes.lfWeight = FW_BOLD; 198 fontAttributes.lfItalic = TRUE; 199 HFONT boldItalicFont = ::CreateFontIndirect(&fontAttributes); 200 return boldItalicFont; 201 } 202 203 bool change_icon_size = true; 204 205 void TimestampToFileTime(time_t t, LPFILETIME pft) 206 { 207 // Note that LONGLONG is a 64-bit value 208 ULONGLONG ll; 209 210 ll = UInt32x32To64((DWORD)t, 10000000) + 116444736000000000; 211 pft->dwLowDateTime = (DWORD)ll; 212 pft->dwHighDateTime = ll >> 32; 213 } 214 215 // allocate outstr 216 void TimestampToLocalizedString(time_t t, LPTSTR *outStr) 217 { 218 FILETIME ft, lft; 219 SYSTEMTIME st; 220 TimestampToFileTime(t, &ft); 221 FileTimeToLocalFileTime(&ft, &lft); 222 FileTimeToSystemTime(&lft, &st); 223 TCHAR timeFormat[80]; // 80 is max required for LOCALE_STIMEFORMAT 224 GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, 225 LOCALE_STIMEFORMAT, 226 timeFormat, 227 sizeof(timeFormat) / sizeof(timeFormat[0])); 228 229 int timeSize = GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 230 TIME_NOSECONDS, 231 &st, 232 timeFormat, 233 NULL, 234 0); 235 // Using dateFormat prevents localization of Month/day order, 236 // but there is no other way AFAICT to suppress the year 237 TCHAR * dateFormat = "MMM dd' '"; 238 int dateSize = GetDateFormat(LOCALE_SYSTEM_DEFAULT, 239 0, // flags 240 &st, 241 dateFormat, // format 242 NULL, // date string 243 0); 244 245 if (*outStr) 246 free(*outStr); 247 248 // Allocate string for combined date and time, 249 // but only need one terminating NULL 250 LPTSTR str = (LPSTR)malloc((dateSize + timeSize - 1) * sizeof(TCHAR)); 251 if (!str) { 252 // LeashWarn allocation failure 253 *outStr = NULL; 254 return; 255 } 256 GetDateFormat(LOCALE_SYSTEM_DEFAULT, 257 0, // flags 258 &st, 259 dateFormat, // format 260 &str[0], 261 dateSize); 262 263 GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 264 TIME_NOSECONDS, 265 &st, 266 timeFormat, 267 &str[dateSize - 1], 268 timeSize); 269 *outStr = str; 270 } 271 272 #define SECONDS_PER_MINUTE (60) 273 #define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) 274 #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) 275 #define MAX_DURATION_STR 255 276 // convert time in seconds to string 277 void DurationToString(long delta, LPTSTR *outStr) 278 { 279 int days; 280 int hours; 281 int minutes; 282 TCHAR minutesStr[MAX_DURATION_STR+1]; 283 TCHAR hoursStr[MAX_DURATION_STR+1]; 284 285 if (*outStr) 286 free(*outStr); 287 *outStr = (LPSTR)malloc((MAX_DURATION_STR + 1)* sizeof(TCHAR)); 288 if (!(*outStr)) 289 return; 290 291 days = delta / SECONDS_PER_DAY; 292 delta -= days * SECONDS_PER_DAY; 293 hours = delta / SECONDS_PER_HOUR; 294 delta -= hours * SECONDS_PER_HOUR; 295 minutes = delta / SECONDS_PER_MINUTE; 296 297 _snprintf(minutesStr, MAX_DURATION_STR, "%d m", minutes); 298 minutesStr[MAX_DURATION_STR] = 0; 299 300 _snprintf(hoursStr, MAX_DURATION_STR, "%d h", hours); 301 hoursStr[MAX_DURATION_STR] = 0; 302 303 if (days > 0) { 304 _snprintf(*outStr, MAX_DURATION_STR, "(%d d, %s remaining)", days, 305 hoursStr); 306 } else if (hours > 0) { 307 _snprintf(*outStr, MAX_DURATION_STR, "(%s, %s remaining)", hoursStr, 308 minutesStr); 309 } else { 310 _snprintf(*outStr, MAX_DURATION_STR, "(%s remaining)", minutesStr); 311 } 312 (*outStr)[MAX_DURATION_STR] = 0; 313 } 314 315 ///////////////////////////////////////////////////////////////////////////// 316 // CLeashView construction/destruction 317 318 CLeashView::CLeashView() 319 { 320 ////@#+Need removing as well! 321 m_startup = TRUE; 322 m_warningOfTicketTimeLeftKrb5 = 0; 323 m_warningOfTicketTimeLeftLockKrb5 = 0; 324 m_largeIcons = 0; 325 m_destroyTicketsOnExit = 0; 326 m_debugWindow = 0; 327 m_upperCaseRealm = 0; 328 m_lowTicketAlarm = 0; 329 330 m_pDebugWindow = NULL; 331 m_pDebugWindow = new CLeashDebugWindow(this); 332 if (!m_pDebugWindow) 333 { 334 AfxMessageBox("There is a problem with the Leash Debug Window!", 335 MB_OK|MB_ICONSTOP); 336 } 337 338 m_debugStartUp = TRUE; 339 m_isMinimum = FALSE; 340 m_lowTicketAlarmSound = FALSE; 341 m_alreadyPlayed = FALSE; 342 ResetTreeNodes(); 343 m_hMenu = NULL; 344 m_pApp = NULL; 345 m_ccacheDisplay = NULL; 346 m_autoRenewTickets = 0; 347 m_autoRenewalAttempted = 0; 348 m_pWarningMessage = NULL; 349 m_bIconAdded = FALSE; 350 m_bIconDeleted = FALSE; 351 m_BaseFont = NULL; 352 m_BoldFont = NULL; 353 m_ItalicFont = NULL; 354 m_aListItemInfo = NULL; 355 } 356 357 358 CLeashView::~CLeashView() 359 { 360 CCacheDisplayData *elem = m_ccacheDisplay; 361 while (elem) { 362 CCacheDisplayData *next = elem->m_next; 363 delete elem; 364 elem = next; 365 } 366 m_ccacheDisplay = NULL; 367 // destroys window if not already destroyed 368 if (m_pDebugWindow) 369 delete m_pDebugWindow; 370 if (m_BoldFont) 371 DeleteObject(m_BoldFont); 372 if (m_ItalicFont) 373 DeleteObject(m_ItalicFont); 374 if (m_aListItemInfo) 375 delete[] m_aListItemInfo; 376 } 377 378 void CLeashView::OnItemChanged(NMHDR* pNmHdr, LRESULT* pResult) 379 { 380 NMHEADER* pHdr = (NMHEADER*)pNmHdr; 381 if (!pHdr->pitem) 382 return; 383 if (!pHdr->pitem->mask & HDI_WIDTH) 384 return; 385 386 // Sync column width and save to registry 387 for (int i = 0, columnIndex = 0; i < NUM_VIEW_COLUMNS; i++) { 388 ViewColumnInfo &info = sm_viewColumns[i]; 389 if ((info.m_enabled) && (columnIndex++ == pHdr->iItem)) { 390 info.m_columnWidth = pHdr->pitem->cxy; 391 if (m_pApp) 392 m_pApp->WriteProfileInt("ColumnWidths", info.m_name, info.m_columnWidth); 393 break; 394 } 395 } 396 } 397 398 BOOL CLeashView::PreCreateWindow(CREATESTRUCT& cs) 399 { 400 // TODO: Modify the Window class or styles here by modifying 401 // the CREATESTRUCT cs 402 403 return CListView::PreCreateWindow(cs); 404 } 405 406 ///////////////////////////////////////////////////////////////////////////// 407 // CLeashView diagnostics 408 409 #ifdef _DEBUG 410 VOID CLeashView::AssertValid() const 411 { 412 CListView::AssertValid(); 413 } 414 415 VOID CLeashView::Dump(CDumpContext& dc) const 416 { 417 CListView::Dump(dc); 418 } 419 420 /* 421 LeashDoc* CLeashView::GetDocument() // non-debug version is inline 422 { 423 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(LeashDoc))); 424 return (LeashDoc*)m_pDocument; 425 } 426 */ 427 #endif //_DEBUG 428 429 ///////////////////////////////////////////////////////////////////////////// 430 // CLeashView message handlers 431 432 BOOL CLeashView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, 433 DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, 434 UINT nID, CCreateContext* pContext) 435 { 436 return CListView::Create(lpszClassName, lpszWindowName, dwStyle, rect, 437 pParentWnd, nID, pContext); 438 } 439 440 INT CLeashView::OnCreate(LPCREATESTRUCT lpCreateStruct) 441 { 442 if (CListView::OnCreate(lpCreateStruct) == -1) 443 return -1; 444 return 0; 445 } 446 447 VOID CLeashView::OnClose(void) 448 { 449 printf("OnClose\n"); 450 } 451 452 time_t CLeashView::LeashTime() 453 { 454 _tzset(); 455 return time(0); 456 } 457 458 // Call while possessing a lock to ticketinfo.lockObj 459 INT CLeashView::GetLowTicketStatus(int ver) 460 { 461 BOOL b_notix = (ver == 5 && !ticketinfo.Krb5.btickets); 462 463 if (b_notix) 464 return NO_TICKETS; 465 466 if (m_ticketTimeLeft <= 0L) 467 return ZERO_MINUTES_LEFT; 468 469 if (m_ticketTimeLeft <= 20 * 60) 470 return (INT)(m_ticketTimeLeft / 5 / 60) + 2 - 471 (m_ticketTimeLeft % (5 * 60) == 0 ? 1 : 0); 472 473 return PLENTY_OF_TIME; 474 } 475 476 VOID CLeashView::UpdateTicketTime(TICKETINFO& ti) 477 { 478 if (!ti.btickets) { 479 m_ticketTimeLeft = 0L; 480 return; 481 } 482 483 m_ticketTimeLeft = ti.valid_until - LeashTime(); 484 485 if (m_ticketTimeLeft <= 0L) 486 ti.btickets = EXPIRED_TICKETS; 487 } 488 489 490 VOID CALLBACK EXPORT CLeashView::TimerProc(HWND hWnd, UINT nMsg, 491 UINT_PTR nIDEvent, DWORD dwTime) 492 { 493 // All of the work is being done in the PreTranslateMessage method 494 // in order to have access to the object 495 } 496 497 VOID CLeashView::ApplicationInfoMissingMsg() 498 { 499 AfxMessageBox("There is a problem finding Leash application information!", 500 MB_OK|MB_ICONSTOP); 501 } 502 503 VOID CLeashView::OnShowWindow(BOOL bShow, UINT nStatus) 504 { 505 CListView::OnShowWindow(bShow, nStatus); 506 507 // Get State of Icons Size 508 m_pApp = AfxGetApp(); 509 if (!m_pApp) 510 { 511 ApplicationInfoMissingMsg(); 512 } 513 else 514 { 515 m_largeIcons = m_pApp->GetProfileInt("Settings", "LargeIcons", ON); 516 517 // Get State of Destroy Tickets On Exit 518 m_destroyTicketsOnExit = m_pApp->GetProfileInt("Settings", "DestroyTicketsOnExit", OFF); 519 520 // Get State of Low Ticket Alarm 521 m_lowTicketAlarm = m_pApp->GetProfileInt("Settings", "LowTicketAlarm", ON); 522 523 // Get State of Auto Renew Tickets 524 m_autoRenewTickets = m_pApp->GetProfileInt("Settings", "AutoRenewTickets", ON); 525 526 // Get State of Upper Case Realm 527 m_upperCaseRealm = pLeash_get_default_uppercaserealm(); 528 529 // UI main display column widths 530 for (int i=0; i<NUM_VIEW_COLUMNS; i++) { 531 ViewColumnInfo &info = sm_viewColumns[i]; 532 info.m_enabled = m_pApp->GetProfileInt("Settings", 533 info.m_name, 534 info.m_enabled); 535 info.m_columnWidth = m_pApp->GetProfileInt("ColumnWidths", 536 info.m_name, 537 info.m_columnWidth); 538 } 539 540 OnLargeIcons(); 541 } 542 543 SetTimer(1, ONE_SECOND, TimerProc); 544 545 if (!CLeashApp::m_hKrb5DLL) 546 { 547 ////Update not to mention K4 548 AfxMessageBox("Kerberos Five is not loaded!!!" 549 "\r\nYou will not be able to retrieve tickets and/or " 550 "tokens.", 551 MB_OK|MB_ICONWARNING); 552 } 553 554 SetDlgItemText(IDC_LABEL_KERB_TICKETS, 555 "Your Kerberos Tickets (Issued/Expires/[Renew]/Principal)"); 556 557 // CLeashApp::m_krbv5_context = NULL; 558 } 559 560 VOID CLeashView::OnInitTicket() 561 { 562 try { 563 InitTicket(m_hWnd); 564 } 565 catch(...) { 566 AfxMessageBox("Ticket Getting operation already in progress", MB_OK, 0); 567 } 568 } 569 570 UINT CLeashView::InitTicket(void * hWnd) 571 { 572 LSH_DLGINFO_EX ldi; 573 char username[64]; 574 char realm[192]; 575 int i=0, j=0; 576 if (WaitForSingleObject( ticketinfo.lockObj, INFINITE ) != WAIT_OBJECT_0) { 577 throw("Unable to lock ticketinfo"); 578 } 579 LeashKRB5ListDefaultTickets(&ticketinfo.Krb5); 580 char * principal = ticketinfo.Krb5.principal; 581 if (principal) 582 for (; principal[i] && principal[i] != '@'; i++) 583 username[i] = principal[i]; 584 username[i] = '\0'; 585 if (principal && principal[i]) { 586 for (i++ ; principal[i] ; i++, j++) 587 { 588 realm[j] = principal[i]; 589 } 590 } 591 realm[j] = '\0'; 592 LeashKRB5FreeTicketInfo(&ticketinfo.Krb5); 593 ReleaseMutex(ticketinfo.lockObj); 594 595 ldi.size = sizeof(ldi); 596 ldi.dlgtype = DLGTYPE_PASSWD; 597 ldi.title = ldi.in.title; 598 strcpy_s(ldi.in.title,"MIT Kerberos: Get Ticket"); 599 ldi.username = ldi.in.username; 600 strcpy(ldi.in.username,username); 601 ldi.realm = ldi.in.realm; 602 strcpy(ldi.in.realm,realm); 603 ldi.dlgtype = DLGTYPE_PASSWD; 604 ldi.use_defaults = 1; 605 606 if (!hWnd) 607 { 608 AfxMessageBox("There is a problem finding the Leash Window!", 609 MB_OK|MB_ICONSTOP); 610 return 0; 611 } 612 613 int result = pLeash_kinit_dlg_ex((HWND)hWnd, &ldi); 614 615 if (-1 == result) 616 { 617 AfxMessageBox("There is a problem getting tickets!", 618 MB_OK|MB_ICONSTOP); 619 } 620 else if ( result ) 621 { 622 if (WaitForSingleObject( ticketinfo.lockObj, INFINITE ) != WAIT_OBJECT_0) { 623 throw("Unable to lock ticketinfo"); 624 } 625 m_warningOfTicketTimeLeftKrb5 = 0; 626 m_ticketStatusKrb5 = 0; 627 ReleaseMutex(ticketinfo.lockObj); 628 m_autoRenewalAttempted = 0; 629 ::SendMessage((HWND)hWnd, WM_COMMAND, ID_UPDATE_DISPLAY, 0); 630 } 631 return 0; 632 } 633 634 static UINT krenew(void *param) 635 { 636 char *ccache_name = (char *)param; 637 krb5_context ctx = 0; 638 krb5_ccache ccache = NULL; 639 krb5_principal me = 0; 640 krb5_principal server = 0; 641 krb5_creds my_creds; 642 krb5_data *realm = 0; 643 644 memset(&my_creds, 0, sizeof(krb5_creds)); 645 if (ccache_name == NULL) 646 // Bad param 647 goto cleanup; 648 649 krb5_error_code code = pkrb5_init_context(&ctx); 650 if (code) { 651 // TODO: spew error 652 goto cleanup; 653 } 654 code = pkrb5_cc_resolve(ctx, ccache_name, &ccache); 655 if (code) { 656 // TODO: spew error 657 goto cleanup; 658 } 659 660 code = pkrb5_cc_get_principal(ctx, ccache, &me); 661 if (code) 662 goto cleanup; 663 664 realm = krb5_princ_realm(ctx, me); 665 666 code = pkrb5_build_principal_ext(ctx, &server, 667 realm->length, realm->data, 668 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, 669 realm->length, realm->data, 670 0); 671 if (code) 672 goto cleanup; 673 674 my_creds.client = me; 675 my_creds.server = server; 676 677 #ifdef KRB5_TC_NOTICKET 678 pkrb5_cc_set_flags(ctx, ccache, 0); 679 #endif 680 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, ccache, NULL); 681 #ifdef KRB5_TC_NOTICKET 682 pkrb5_cc_set_flags(ctx, ccache, KRB5_TC_NOTICKET); 683 #endif 684 if (code) { 685 /* TODO 686 if (code != KRB5KDC_ERR_ETYPE_NOSUPP || code != KRB5_KDC_UNREACH) 687 Leash_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, 688 &ccache); 689 */ 690 goto cleanup; 691 } 692 693 code = pkrb5_cc_initialize(ctx, ccache, me); 694 if (code) 695 goto cleanup; 696 697 code = pkrb5_cc_store_cred(ctx, ccache, &my_creds); 698 if (code) 699 goto cleanup; 700 701 cleanup: 702 if (my_creds.client == me) 703 my_creds.client = 0; 704 if (my_creds.server == server) 705 my_creds.server = 0; 706 pkrb5_free_cred_contents(ctx, &my_creds); 707 if (me != NULL) 708 pkrb5_free_principal(ctx, me); 709 if (server != NULL) 710 pkrb5_free_principal(ctx, server); 711 if (ccache != NULL) 712 pkrb5_cc_close(ctx, ccache); 713 if (ctx != NULL) 714 pkrb5_free_context(ctx); 715 if (ccache_name != NULL) 716 free(ccache_name); 717 718 CLeashApp::m_bUpdateDisplay = TRUE; 719 return 0; 720 } 721 722 VOID CLeashView::OnRenewTicket() 723 { 724 if ( !CLeashApp::m_hKrb5DLL ) 725 return; 726 727 // @TODO: grab list mutex 728 CCacheDisplayData *elem = m_ccacheDisplay; 729 while (elem != NULL) { 730 if (elem->m_selected) { 731 char *ccache_name = strdup(elem->m_ccacheName); 732 if (ccache_name) 733 AfxBeginThread(krenew, (void *)ccache_name); 734 } 735 elem = elem->m_next; 736 } 737 // release list mutex 738 } 739 740 UINT CLeashView::RenewTicket(void * hWnd) 741 { 742 if ( !CLeashApp::m_hKrb5DLL ) 743 return 0; 744 745 // Try to renew 746 BOOL b_renewed = pLeash_renew(); 747 if ( b_renewed ) { 748 m_warningOfTicketTimeLeftKrb5 = 0; 749 m_ticketStatusKrb5 = 0; 750 m_autoRenewalAttempted = 0; 751 ReleaseMutex(ticketinfo.lockObj); 752 ::SendMessage((HWND)hWnd, WM_COMMAND, ID_UPDATE_DISPLAY, 0); 753 return 0; 754 } 755 756 AfxBeginThread(InitTicket,hWnd); 757 758 return 0; 759 } 760 761 static void kdestroy(const char *ccache_name) 762 { 763 krb5_context ctx; 764 krb5_ccache ccache=NULL; 765 int code = pkrb5_init_context(&ctx); 766 if (code) { 767 // TODO: spew error 768 goto cleanup; 769 } 770 code = pkrb5_cc_resolve(ctx, ccache_name, &ccache); 771 if (code) { 772 // TODO: spew error 773 goto cleanup; 774 } 775 code = pkrb5_cc_destroy(ctx, ccache); 776 if (code) { 777 goto cleanup; 778 } 779 cleanup: 780 if (ctx) 781 pkrb5_free_context(ctx); 782 } 783 784 785 VOID CLeashView::OnDestroyTicket() 786 { 787 // @TODO: grab mutex 788 BOOL destroy = FALSE; 789 CCacheDisplayData *elem = m_ccacheDisplay; 790 while (elem) { 791 if (elem->m_selected) { 792 // @TODO add princ to msg text 793 destroy = TRUE; 794 } 795 elem = elem->m_next; 796 } 797 // release mutex 798 799 if (destroy) 800 { 801 INT whatToDo; 802 803 whatToDo = AfxMessageBox("Are you sure you want to destroy these tickets?", 804 MB_ICONEXCLAMATION|MB_YESNO, 0); 805 806 if (whatToDo == IDYES) 807 { 808 // grab list mutex 809 elem = m_ccacheDisplay; 810 while (elem) { 811 if (elem->m_selected) 812 kdestroy(elem->m_ccacheName); 813 elem = elem->m_next; 814 } 815 // release list mutex 816 SendMessage(WM_COMMAND, ID_UPDATE_DISPLAY, 0); 817 } 818 } 819 m_autoRenewalAttempted = 0; 820 } 821 822 VOID CLeashView::OnMakeDefault() 823 { 824 CCacheDisplayData *elem = m_ccacheDisplay; 825 int code = 0; 826 krb5_context ctx; 827 krb5_ccache cc; 828 while (elem) { 829 if (elem->m_selected) { 830 pkrb5_init_context(&ctx); 831 code = pkrb5_cc_resolve(ctx, elem->m_ccacheName, &cc); 832 if (!code) 833 code = pkrb5_cc_switch(ctx, cc); 834 if (!code) { 835 const char *cctype = pkrb5_cc_get_type(ctx, cc); 836 if (cctype != NULL) { 837 char defname[20]; 838 sprintf_s(defname, "%s:", cctype); 839 code = pkrb5int_cc_user_set_default_name(ctx, defname); 840 } 841 } 842 pkrb5_free_context(ctx); 843 CLeashApp::m_bUpdateDisplay = TRUE; 844 break; 845 } 846 elem = elem->m_next; 847 } 848 } 849 850 VOID CLeashView::OnChangePassword() 851 { 852 krb5_context ctx = 0; 853 krb5_ccache ccache = 0; 854 krb5_principal princ = 0; 855 char *pname = NULL; 856 char *username = NULL; 857 char *realm = NULL; 858 int code = 0; 859 860 CCacheDisplayData *elem = m_ccacheDisplay; 861 while (elem != NULL) { 862 if (elem->m_selected) { 863 if (elem->m_ccacheName) 864 break; 865 } 866 elem = elem->m_next; 867 } 868 if (elem != NULL) { 869 code = pkrb5_init_context(&ctx); 870 if (code) { 871 // TODO: spew error 872 goto cleanup; 873 } 874 code = pkrb5_cc_resolve(ctx, elem->m_ccacheName, &ccache); 875 if (code) { 876 // TODO: spew error 877 goto cleanup; 878 } 879 code = pkrb5_cc_get_principal(ctx, ccache, &princ); 880 if (code) { 881 goto cleanup; 882 } 883 code = pkrb5_unparse_name(ctx, princ, &pname); 884 if (code) { 885 goto cleanup; 886 } 887 } 888 889 LSH_DLGINFO_EX ldi; 890 if (pname != NULL) { 891 username = pname; 892 realm = strchr(pname, '@'); 893 if (realm != NULL) 894 *realm++ = '\0'; 895 } 896 ldi.size = sizeof(ldi); 897 ldi.dlgtype = DLGTYPE_CHPASSWD; 898 ldi.title = ldi.in.title; 899 strcpy_s(ldi.in.title, "MIT Kerberos: Change Password"); 900 ldi.username = ldi.in.username; 901 strcpy_s(ldi.in.username, username ? username : ""); 902 ldi.realm = ldi.in.realm; 903 strcpy_s(ldi.in.realm, realm ? realm : ""); 904 ldi.use_defaults = 1; 905 906 int result = pLeash_changepwd_dlg_ex(m_hWnd, &ldi); 907 if (-1 == result) { 908 AfxMessageBox("There is a problem changing password!", 909 MB_OK|MB_ICONSTOP); 910 } 911 cleanup: 912 if (pname != NULL) 913 pkrb5_free_unparsed_name(ctx, pname); 914 if (princ != NULL) 915 pkrb5_free_principal(ctx, princ); 916 if (ccache != NULL) 917 pkrb5_cc_close(ctx, ccache); 918 if (ctx != NULL) 919 pkrb5_free_context(ctx); 920 } 921 922 static CCacheDisplayData ** 923 FindCCacheDisplayData(const char * ccacheName, CCacheDisplayData **pList) 924 { 925 CCacheDisplayData *elem; 926 while ((elem = *pList)) { 927 if (strcmp(ccacheName, elem->m_ccacheName)==0) 928 return pList; 929 pList = &elem->m_next; 930 } 931 return NULL; 932 } 933 934 void CLeashView::AddDisplayItem(CListCtrl &list, 935 CCacheDisplayData *elem, 936 int iItem, 937 char *principal, 938 time_t issued, 939 time_t valid_until, 940 time_t renew_until, 941 char *encTypes, 942 unsigned long flags, 943 char *ccache_name) 944 { 945 TCHAR* localTimeStr=NULL; 946 TCHAR* durationStr=NULL; 947 TCHAR* flagsStr=NULL; 948 TCHAR tempStr[MAX_DURATION_STR+1]; 949 time_t now = LeashTime(); 950 951 list.InsertItem(iItem, principal, -1); 952 953 int iSubItem = 1; 954 if (sm_viewColumns[TIME_ISSUED].m_enabled) { 955 if (issued == 0) { 956 list.SetItemText(iItem, iSubItem++, "Unknown"); 957 } else { 958 TimestampToLocalizedString(issued, &localTimeStr); 959 list.SetItemText(iItem, iSubItem++, localTimeStr); 960 } 961 } 962 if (sm_viewColumns[RENEWABLE_UNTIL].m_enabled) { 963 if (valid_until == 0) { 964 list.SetItemText(iItem, iSubItem++, "Unknown"); 965 } else if (valid_until < now) { 966 list.SetItemText(iItem, iSubItem++, "Expired"); 967 } else if (renew_until) { 968 TimestampToLocalizedString(renew_until, &localTimeStr); 969 DurationToString(renew_until - now, &durationStr); 970 if (localTimeStr && durationStr) { 971 _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr); 972 tempStr[MAX_DURATION_STR] = 0; 973 list.SetItemText(iItem, iSubItem++, tempStr); 974 } 975 } else { 976 list.SetItemText(iItem, iSubItem++, "Not renewable"); 977 } 978 } 979 if (sm_viewColumns[VALID_UNTIL].m_enabled) { 980 if (valid_until == 0) { 981 list.SetItemText(iItem, iSubItem++, "Unknown"); 982 } else if (valid_until < now) { 983 list.SetItemText(iItem, iSubItem++, "Expired"); 984 } else { 985 TimestampToLocalizedString(valid_until, &localTimeStr); 986 DurationToString(valid_until - now, &durationStr); 987 if (localTimeStr && durationStr) { 988 _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr); 989 tempStr[MAX_DURATION_STR] = 0; 990 list.SetItemText(iItem, iSubItem++, tempStr); 991 } 992 } 993 } 994 995 if (sm_viewColumns[ENCRYPTION_TYPE].m_enabled) { 996 list.SetItemText(iItem, iSubItem++, encTypes); 997 } 998 if (sm_viewColumns[TICKET_FLAGS].m_enabled) { 999 krb5TicketFlagsToString(flags, &flagsStr); 1000 list.SetItemText(iItem, iSubItem++, flagsStr); 1001 } 1002 if (sm_viewColumns[CACHE_NAME].m_enabled) { 1003 list.SetItemText(iItem, iSubItem++, ccache_name); 1004 } 1005 if (flagsStr) 1006 free(flagsStr); 1007 if (localTimeStr) 1008 free(localTimeStr); 1009 if (durationStr) 1010 free(durationStr); 1011 } 1012 1013 BOOL CLeashView::IsExpanded(TICKETINFO *info) 1014 { 1015 CCacheDisplayData **pElem = FindCCacheDisplayData(info->ccache_name, 1016 &m_ccacheDisplay); 1017 return (pElem && (*pElem)->m_expanded) ? TRUE : FALSE; 1018 } 1019 1020 BOOL CLeashView::IsExpired(TICKETINFO *info) 1021 { 1022 return LeashTime() > info->valid_until ? TRUE : FALSE; 1023 } 1024 1025 BOOL CLeashView::IsExpired(TicketList *ticket) 1026 { 1027 return LeashTime() > ticket->valid_until ? TRUE : FALSE; 1028 } 1029 1030 CCacheDisplayData * 1031 FindCCacheDisplayElem(CCacheDisplayData *pElem, int itemIndex) 1032 { 1033 while (pElem != NULL) { 1034 if (pElem->m_index == itemIndex) 1035 return pElem; 1036 pElem = pElem->m_next; 1037 } 1038 return NULL; 1039 } 1040 1041 VOID CLeashView::OnUpdateDisplay() 1042 { 1043 CListCtrl& list = GetListCtrl(); 1044 // @TODO: there is probably a more sensible place to initialize these... 1045 if ((m_BaseFont == NULL) && (list.GetFont())) { 1046 m_BaseFont = *list.GetFont(); 1047 m_BoldFont = CreateBoldFont(m_BaseFont); 1048 m_ItalicFont = CreateItalicFont(m_BaseFont); 1049 m_BoldItalicFont = CreateBoldItalicFont(m_BaseFont); 1050 } 1051 // Determine currently focused item 1052 int focusItem = list.GetNextItem(-1, LVNI_FOCUSED); 1053 CCacheDisplayData *elem = m_ccacheDisplay; 1054 while (elem) { 1055 if (focusItem >= elem->m_index) { 1056 elem->m_focus = focusItem - elem->m_index; 1057 focusItem = -1; 1058 } else { 1059 elem->m_focus = -1; 1060 } 1061 elem = elem->m_next; 1062 } 1063 1064 list.DeleteAllItems(); 1065 ModifyStyle(LVS_TYPEMASK, LVS_REPORT); 1066 UpdateWindow(); 1067 // Delete all of the columns. 1068 while (list.DeleteColumn(0)); 1069 1070 list.SetImageList(&m_imageList, LVSIL_SMALL); 1071 1072 // Reconstruct based on current options 1073 int columnIndex = 0; 1074 int itemIndex = 0; 1075 for (int i = 0; i < NUM_VIEW_COLUMNS; i++) { 1076 ViewColumnInfo &info = sm_viewColumns[i]; 1077 if (info.m_enabled) { 1078 list.InsertColumn(columnIndex++, 1079 (info.m_name), // @LOCALIZEME! 1080 LVCFMT_LEFT, 1081 info.m_columnWidth, 1082 itemIndex++); 1083 } 1084 } 1085 1086 INT ticketIconStatusKrb5; 1087 INT ticketIconStatus_SelectedKrb5; 1088 INT iconStatusKrb5; 1089 1090 if (WaitForSingleObject( ticketinfo.lockObj, 100 ) != WAIT_OBJECT_0) 1091 throw("Unable to lock ticketinfo"); 1092 1093 // Get Kerb 5 tickets in list 1094 LeashKRB5ListDefaultTickets(&ticketinfo.Krb5); 1095 if (CLeashApp::m_hKrb5DLL && !CLeashApp::m_krbv5_profile) 1096 { 1097 CHAR confname[MAX_PATH]; 1098 if (CLeashApp::GetProfileFile(confname, sizeof(confname))) 1099 { 1100 AfxMessageBox("Can't locate Kerberos Five Config. file!", 1101 MB_OK|MB_ICONSTOP); 1102 } 1103 1104 const char *filenames[2]; 1105 filenames[0] = confname; 1106 filenames[1] = NULL; 1107 pprofile_init(filenames, &CLeashApp::m_krbv5_profile); 1108 } 1109 1110 /* 1111 * Update Ticket Status for Krb5 so that we may use their state 1112 * to select the appropriate Icon for the Parent Node 1113 */ 1114 1115 /* Krb5 */ 1116 UpdateTicketTime(ticketinfo.Krb5); 1117 m_ticketStatusKrb5 = GetLowTicketStatus(5); 1118 if ((!ticketinfo.Krb5.btickets) || 1119 EXPIRED_TICKETS == ticketinfo.Krb5.btickets || 1120 m_ticketStatusKrb5 == ZERO_MINUTES_LEFT) 1121 { 1122 ticketIconStatusKrb5 = EXPIRED_CLOCK; 1123 ticketIconStatus_SelectedKrb5 = EXPIRED_CLOCK; 1124 iconStatusKrb5 = EXPIRED_TICKET; 1125 } 1126 else if (TICKETS_LOW == ticketinfo.Krb5.btickets || 1127 m_ticketStatusKrb5 == FIVE_MINUTES_LEFT || 1128 m_ticketStatusKrb5 == TEN_MINUTES_LEFT || 1129 m_ticketStatusKrb5 == FIFTEEN_MINUTES_LEFT) 1130 { 1131 ticketIconStatusKrb5 = LOW_CLOCK; 1132 ticketIconStatus_SelectedKrb5 = LOW_CLOCK; 1133 iconStatusKrb5 = LOW_TICKET; 1134 } 1135 else if ( CLeashApp::m_hKrb5DLL ) 1136 { 1137 ticketIconStatusKrb5 = ACTIVE_CLOCK; 1138 ticketIconStatus_SelectedKrb5 = ACTIVE_CLOCK; 1139 iconStatusKrb5 = ACTIVE_TICKET; 1140 } else 1141 { 1142 ticketIconStatusKrb5 = EXPIRED_CLOCK; 1143 ticketIconStatus_SelectedKrb5 = EXPIRED_CLOCK; 1144 iconStatusKrb5 = TICKET_NOT_INSTALLED; 1145 } 1146 1147 int trayIcon = NONE_PARENT_NODE; 1148 if (CLeashApp::m_hKrb5DLL && ticketinfo.Krb5.btickets) { 1149 switch ( iconStatusKrb5 ) { 1150 case ACTIVE_TICKET: 1151 trayIcon = ACTIVE_PARENT_NODE; 1152 break; 1153 case LOW_TICKET: 1154 trayIcon = LOW_PARENT_NODE; 1155 break; 1156 case EXPIRED_TICKET: 1157 trayIcon = EXPIRED_PARENT_NODE; 1158 break; 1159 } 1160 } 1161 SetTrayIcon(NIM_MODIFY, trayIcon); 1162 1163 CCacheDisplayData* prevCCacheDisplay = m_ccacheDisplay; 1164 m_ccacheDisplay = NULL; 1165 1166 const char *def_ccache_name = ticketinfo.Krb5.ccache_name; 1167 TICKETINFO *principallist = NULL; 1168 LeashKRB5ListAllTickets(&principallist); 1169 int iItem = 0; 1170 TicketList* tempList; 1171 TICKETINFO *principal = principallist; 1172 while (principal != NULL) { 1173 CCacheDisplayData **pOldElem; 1174 pOldElem = FindCCacheDisplayData(principal->ccache_name, 1175 &prevCCacheDisplay); 1176 if (pOldElem) { 1177 // remove from old list 1178 elem = *pOldElem; 1179 *pOldElem = elem->m_next; 1180 elem->m_next = NULL; 1181 } else { 1182 elem = new CCacheDisplayData(principal->ccache_name); 1183 } 1184 elem->m_isDefault = def_ccache_name && 1185 (strcmp(def_ccache_name, elem->m_ccacheName) == 0); 1186 elem->m_isRenewable = principal->renew_until != 0; 1187 1188 elem->m_next = m_ccacheDisplay; 1189 m_ccacheDisplay = elem; 1190 elem->m_index = iItem; 1191 1192 AddDisplayItem(list, 1193 elem, 1194 iItem++, 1195 principal->principal, 1196 principal->issued, 1197 principal->valid_until, 1198 principal->renew_until, 1199 "", 1200 principal->flags, 1201 principal->ccache_name); 1202 if (elem->m_expanded) { 1203 for (tempList = principal->ticket_list; 1204 tempList != NULL; 1205 tempList = tempList->next) { 1206 AddDisplayItem(list, 1207 elem, 1208 iItem++, 1209 tempList->service, 1210 tempList->issued, 1211 tempList->valid_until, 1212 tempList->renew_until, 1213 tempList->encTypes, 1214 tempList->flags, 1215 principal->ccache_name); 1216 } 1217 } 1218 if ((elem->m_focus >= 0) && 1219 (iItem > elem->m_index + elem->m_focus)) { 1220 list.SetItemState(elem->m_index + elem->m_focus, LVIS_FOCUSED, 1221 LVIS_FOCUSED); 1222 } 1223 if (elem->m_selected) 1224 list.SetItemState(elem->m_index, LVIS_SELECTED, LVIS_SELECTED); 1225 1226 principal = principal->next; 1227 } 1228 1229 // create list item font data array 1230 if (m_aListItemInfo != NULL) 1231 delete[] m_aListItemInfo; 1232 m_aListItemInfo = new ListItemInfo[iItem]; 1233 iItem = 0; 1234 for (principal = principallist; principal != NULL; 1235 principal = principal->next) { 1236 // 1237 HFONT font, durationFont; 1238 elem = FindCCacheDisplayElem(m_ccacheDisplay, iItem); 1239 if (elem != NULL && elem->m_isDefault) { 1240 font = m_BoldFont; 1241 durationFont = IsExpired(principal) ? m_BoldItalicFont : m_BoldFont; 1242 } else { 1243 font = m_BaseFont; 1244 durationFont = IsExpired(principal) ? m_ItalicFont : m_BaseFont; 1245 } 1246 m_aListItemInfo[iItem].m_font = font; 1247 m_aListItemInfo[iItem++].m_durationFont = durationFont; 1248 1249 if (IsExpanded(principal)) { 1250 for (TicketList *ticket = principal->ticket_list; 1251 ticket != NULL; ticket = ticket->next) { 1252 font = m_BaseFont; 1253 durationFont = IsExpired(ticket) ? m_ItalicFont : m_BaseFont; 1254 m_aListItemInfo[iItem].m_font = font; 1255 m_aListItemInfo[iItem++].m_durationFont = durationFont; 1256 } 1257 } 1258 } 1259 1260 // delete ccache items that no longer exist 1261 while (prevCCacheDisplay != NULL) { 1262 CCacheDisplayData *next = prevCCacheDisplay->m_next; 1263 delete prevCCacheDisplay; 1264 prevCCacheDisplay = next; 1265 } 1266 1267 LeashKRB5FreeTicketInfo(&ticketinfo.Krb5); 1268 LeashKRB5FreeTickets(&principallist); 1269 1270 ReleaseMutex(ticketinfo.lockObj); 1271 } 1272 1273 VOID CLeashView::OnSynTime() 1274 { 1275 LONG returnValue; 1276 returnValue = pLeash_timesync(1); 1277 } 1278 1279 VOID CLeashView::OnActivateView(BOOL bActivate, CView* pActivateView, 1280 CView* pDeactiveView) 1281 { 1282 UINT check = NULL; 1283 1284 if (m_alreadyPlayed) 1285 { 1286 CListView::OnActivateView(bActivate, pActivateView, pDeactiveView); 1287 return; 1288 } 1289 1290 // The following code has put here because at the time 1291 // 'checking and unchecking' a menuitem with the 1292 // 'OnUpdate.....(CCmdUI* pCmdUI) functions' were unreliable 1293 // in CLeashView -->> Better done in CMainFrame 1294 if( CLeashApp::m_hProgram != 0 ) 1295 { 1296 m_hMenu = ::GetMenu(CLeashApp::m_hProgram); 1297 } else { 1298 return; 1299 } 1300 1301 if (m_hMenu) { 1302 if (!m_largeIcons) 1303 check = CheckMenuItem(m_hMenu, ID_LARGE_ICONS, MF_CHECKED); 1304 else 1305 check = CheckMenuItem(m_hMenu, ID_LARGE_ICONS, MF_UNCHECKED); 1306 1307 if( check != MF_CHECKED || check != MF_UNCHECKED ) 1308 { 1309 m_debugStartUp = 1; 1310 } 1311 1312 if (!m_destroyTicketsOnExit) 1313 check = CheckMenuItem(m_hMenu, ID_KILL_TIX_ONEXIT, MF_UNCHECKED); 1314 else 1315 check = CheckMenuItem(m_hMenu, ID_KILL_TIX_ONEXIT, MF_CHECKED); 1316 1317 if (!m_upperCaseRealm) 1318 check = CheckMenuItem(m_hMenu, ID_UPPERCASE_REALM, MF_UNCHECKED); 1319 else 1320 check = CheckMenuItem(m_hMenu, ID_UPPERCASE_REALM, MF_CHECKED); 1321 1322 for (int i=0; i<NUM_VIEW_COLUMNS; i++) { 1323 ViewColumnInfo &info = sm_viewColumns[i]; 1324 if (info.m_id >= 0) 1325 CheckMenuItem(m_hMenu, info.m_id, 1326 info.m_enabled ? MF_CHECKED : MF_UNCHECKED); 1327 } 1328 1329 if (!m_lowTicketAlarm) 1330 CheckMenuItem(m_hMenu, ID_LOW_TICKET_ALARM, MF_UNCHECKED); 1331 else 1332 CheckMenuItem(m_hMenu, ID_LOW_TICKET_ALARM, MF_CHECKED); 1333 1334 if (!m_autoRenewTickets) 1335 CheckMenuItem(m_hMenu, ID_AUTO_RENEW, MF_UNCHECKED); 1336 else 1337 CheckMenuItem(m_hMenu, ID_AUTO_RENEW, MF_CHECKED); 1338 1339 m_debugWindow = m_pApp->GetProfileInt("Settings", "DebugWindow", 0); 1340 if (!m_debugWindow) 1341 check = CheckMenuItem(m_hMenu, ID_DEBUG_MODE, MF_UNCHECKED); 1342 else 1343 check = CheckMenuItem(m_hMenu, ID_DEBUG_MODE, MF_CHECKED); 1344 } 1345 m_lowTicketAlarmSound = !!m_lowTicketAlarm; 1346 m_alreadyPlayed = TRUE; 1347 if (m_pApp) 1348 { 1349 m_debugWindow = m_pApp->GetProfileInt("Settings", "DebugWindow", 0); 1350 1351 if (m_hMenu) 1352 { 1353 if (!m_debugWindow) 1354 { 1355 CheckMenuItem(m_hMenu, ID_DEBUG_MODE, MF_UNCHECKED); 1356 } 1357 else 1358 { 1359 CheckMenuItem(m_hMenu, ID_DEBUG_MODE, MF_CHECKED); 1360 } 1361 } 1362 } 1363 else 1364 { 1365 ApplicationInfoMissingMsg(); 1366 } 1367 1368 m_alreadyPlayed = TRUE; 1369 1370 if (m_debugStartUp) 1371 { 1372 OnDebugMode(); 1373 } 1374 1375 m_debugStartUp = FALSE; 1376 1377 CListView::OnActivateView(bActivate, pActivateView, pDeactiveView); 1378 } 1379 1380 ////@#+Is this KRB4 only? 1381 VOID CLeashView::OnDebugMode() 1382 { 1383 if (!m_pDebugWindow) 1384 { 1385 AfxMessageBox("There is a problem with the Leash Debug Window!", 1386 MB_OK|MB_ICONSTOP); 1387 return; 1388 } 1389 1390 1391 // Check all possible 'KRB' system variables, then delete debug file 1392 CHAR* Env[] = {"TEMP", "TMP", "HOME", NULL}; 1393 CHAR** pEnv = Env; 1394 CHAR debugFilePath[MAX_PATH]; 1395 *debugFilePath = 0; 1396 1397 while (*pEnv) 1398 { 1399 CHAR* ptestenv = getenv(*pEnv); 1400 if (ptestenv) 1401 { 1402 // reset debug file 1403 strcpy(debugFilePath, ptestenv); 1404 strcat(debugFilePath, "\\LshDebug.log"); 1405 remove(debugFilePath); 1406 break; 1407 } 1408 1409 pEnv++; 1410 } 1411 1412 if (!m_debugStartUp) 1413 { 1414 if (m_debugWindow%2 == 0) 1415 m_debugWindow = ON; 1416 else 1417 m_debugWindow = OFF; 1418 } 1419 1420 if (!m_pApp) 1421 { 1422 ApplicationInfoMissingMsg(); 1423 } 1424 else if (!m_debugWindow) 1425 { 1426 if (m_hMenu) 1427 CheckMenuItem(m_hMenu, ID_DEBUG_MODE, MF_UNCHECKED); 1428 1429 m_pApp->WriteProfileInt("Settings", "DebugWindow", FALSE_FLAG); 1430 m_pDebugWindow->DestroyWindow(); 1431 return; 1432 } 1433 else 1434 { 1435 if (m_hMenu) 1436 CheckMenuItem(m_hMenu, ID_DEBUG_MODE, MF_CHECKED); 1437 1438 m_pApp->WriteProfileInt("Settings", "DebugWindow", TRUE_FLAG); 1439 } 1440 1441 // Creates the Debug dialog if not created already 1442 if (m_pDebugWindow->GetSafeHwnd() == 0) 1443 { // displays the Debug Window 1444 m_pDebugWindow->Create(debugFilePath); 1445 } 1446 } 1447 1448 void CLeashView::ToggleViewColumn(eViewColumn viewOption) 1449 { 1450 if ((viewOption < 0) || (viewOption >= NUM_VIEW_COLUMNS)) { 1451 //LeashWarn("ToggleViewColumn(): invalid view option index %i", viewOption); 1452 return; 1453 } 1454 ViewColumnInfo &info = sm_viewColumns[viewOption]; 1455 info.m_enabled = !info.m_enabled; 1456 if (m_pApp) 1457 m_pApp->WriteProfileInt("Settings", info.m_name, info.m_enabled); 1458 // Don't update display immediately; wait for next idle so our 1459 // checkbox controls will be more responsive 1460 CLeashApp::m_bUpdateDisplay = TRUE; 1461 } 1462 1463 VOID CLeashView::OnRenewableUntil() 1464 { 1465 ToggleViewColumn(RENEWABLE_UNTIL); 1466 } 1467 1468 VOID CLeashView::OnUpdateRenewableUntil(CCmdUI *pCmdUI) 1469 { 1470 pCmdUI->SetCheck(sm_viewColumns[RENEWABLE_UNTIL].m_enabled); 1471 } 1472 1473 VOID CLeashView::OnShowTicketFlags() 1474 { 1475 ToggleViewColumn(TICKET_FLAGS); 1476 } 1477 1478 VOID CLeashView::OnUpdateShowTicketFlags(CCmdUI *pCmdUI) 1479 { 1480 pCmdUI->SetCheck(sm_viewColumns[TICKET_FLAGS].m_enabled); 1481 } 1482 1483 VOID CLeashView::OnTimeIssued() 1484 { 1485 ToggleViewColumn(TIME_ISSUED); 1486 } 1487 1488 VOID CLeashView::OnUpdateTimeIssued(CCmdUI *pCmdUI) 1489 { 1490 pCmdUI->SetCheck(sm_viewColumns[TIME_ISSUED].m_enabled); 1491 } 1492 1493 VOID CLeashView::OnValidUntil() 1494 { 1495 ToggleViewColumn(VALID_UNTIL); 1496 } 1497 1498 VOID CLeashView::OnUpdateValidUntil(CCmdUI *pCmdUI) 1499 { 1500 pCmdUI->SetCheck(sm_viewColumns[VALID_UNTIL].m_enabled); 1501 } 1502 1503 VOID CLeashView::OnEncryptionType() 1504 { 1505 ToggleViewColumn(ENCRYPTION_TYPE); 1506 } 1507 1508 VOID CLeashView::OnUpdateEncryptionType(CCmdUI *pCmdUI) 1509 { 1510 pCmdUI->SetCheck(sm_viewColumns[ENCRYPTION_TYPE].m_enabled); 1511 } 1512 1513 VOID CLeashView::OnCcacheName() 1514 { 1515 ToggleViewColumn(CACHE_NAME); 1516 } 1517 1518 VOID CLeashView::OnUpdateCcacheName(CCmdUI *pCmdUI) 1519 { 1520 pCmdUI->SetCheck(sm_viewColumns[CACHE_NAME].m_enabled); 1521 } 1522 1523 VOID CLeashView::OnLargeIcons() 1524 { 1525 INT x, y, n; 1526 1527 if (change_icon_size) 1528 { 1529 if (m_largeIcons%2 == 0) 1530 m_largeIcons = ON; 1531 else 1532 m_largeIcons = OFF; 1533 } 1534 else 1535 { 1536 if (m_largeIcons%2 == 0) 1537 m_largeIcons = OFF; 1538 else 1539 m_largeIcons = ON; 1540 } 1541 1542 x = y = SMALL_ICONS; 1543 1544 if (!m_pApp) 1545 ApplicationInfoMissingMsg(); 1546 else 1547 { 1548 if (!m_largeIcons) 1549 { 1550 if (m_hMenu) 1551 CheckMenuItem(m_hMenu, ID_LARGE_ICONS, MF_CHECKED); 1552 1553 x = y = LARGE_ICONS; 1554 1555 if (!m_startup) 1556 { 1557 m_pApp->WriteProfileInt("Settings", "LargeIcons", TRUE_FLAG); 1558 } 1559 } 1560 else 1561 { 1562 if (m_hMenu) 1563 CheckMenuItem(m_hMenu, ID_LARGE_ICONS, MF_UNCHECKED); 1564 1565 x = y = SMALL_ICONS; 1566 1567 if (!m_startup) 1568 { 1569 m_pApp->WriteProfileInt("Settings", "LargeIcons", FALSE_FLAG); 1570 } 1571 } 1572 } 1573 1574 HICON hIcon[IMAGE_COUNT]; 1575 for (n = 0; n < IMAGE_COUNT; n++) 1576 { 1577 hIcon[n] = NULL; 1578 } 1579 1580 m_imageList.DeleteImageList( ); 1581 1582 UINT bitsPerPixel = GetDeviceCaps( ::GetDC(::GetDesktopWindow()), BITSPIXEL); 1583 UINT ilcColor; 1584 if ( bitsPerPixel >= 32 ) 1585 ilcColor = ILC_COLOR32; 1586 else if ( bitsPerPixel >= 24 ) 1587 ilcColor = ILC_COLOR24; 1588 else if ( bitsPerPixel >= 16 ) 1589 ilcColor = ILC_COLOR16; 1590 else if ( bitsPerPixel >= 8 ) 1591 ilcColor = ILC_COLOR8; 1592 else 1593 ilcColor = ILC_COLOR; 1594 m_imageList.Create(x, y, ilcColor | ILC_MASK, IMAGE_COUNT, 1); 1595 m_imageList.SetBkColor(GetSysColor(COLOR_WINDOW)); 1596 1597 hIcon[ACTIVE_TRAY_ICON] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_GOOD); 1598 hIcon[LOW_TRAY_ICON] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_LOW); 1599 hIcon[EXPIRED_TRAY_ICON] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_EXPIRED); 1600 hIcon[NONE_TRAY_ICON] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_NONE); 1601 hIcon[ACTIVE_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_PRINCIPAL_GOOD); 1602 hIcon[LOW_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_PRINCIPAL_LOW); 1603 hIcon[EXPIRED_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_PRINCIPAL_EXPIRED); 1604 hIcon[NONE_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_PRINCIPAL_NONE); 1605 hIcon[ACTIVE_TICKET] = AfxGetApp()->LoadIcon(IDI_TICKETTYPE_GOOD); 1606 hIcon[LOW_TICKET] = AfxGetApp()->LoadIcon(IDI_TICKETTYPE_LOW); 1607 hIcon[EXPIRED_TICKET] = AfxGetApp()->LoadIcon(IDI_TICKETTYPE_EXPIRED); 1608 hIcon[TICKET_NOT_INSTALLED] = AfxGetApp()->LoadIcon(IDI_TICKETTYPE_NOTINSTALLED); 1609 hIcon[ACTIVE_CLOCK] = AfxGetApp()->LoadIcon(IDI_TICKET_GOOD); 1610 hIcon[LOW_CLOCK] = AfxGetApp()->LoadIcon(IDI_TICKET_LOW); 1611 hIcon[EXPIRED_CLOCK] = AfxGetApp()->LoadIcon(IDI_TICKET_EXPIRED); 1612 hIcon[TKT_ADDRESS] = AfxGetApp()->LoadIcon(IDI_LEASH_TICKET_ADDRESS); 1613 hIcon[TKT_SESSION] = AfxGetApp()->LoadIcon(IDI_LEASH_TICKET_SESSION); 1614 hIcon[TKT_ENCRYPTION] = AfxGetApp()->LoadIcon(IDI_LEASH_TICKET_ENCRYPTION); 1615 1616 for (n = 0; n < IMAGE_COUNT; n++) 1617 { 1618 if ( !hIcon[n] ) { 1619 AfxMessageBox("Can't find one or more images in the Leash Ticket Tree!", 1620 MB_OK|MB_ICONSTOP); 1621 return; 1622 } 1623 m_imageList.Add(hIcon[n]); 1624 } 1625 1626 if (!m_startup) 1627 SendMessage(WM_COMMAND, ID_UPDATE_DISPLAY, 0); 1628 } 1629 1630 VOID CLeashView::OnKillTixOnExit() 1631 { 1632 m_destroyTicketsOnExit = !m_destroyTicketsOnExit; 1633 1634 if (m_pApp) 1635 m_pApp->WriteProfileInt("Settings", "DestroyTicketsOnExit", 1636 m_destroyTicketsOnExit); 1637 } 1638 1639 VOID CLeashView::OnUpdateKillTixOnExit(CCmdUI *pCmdUI) 1640 { 1641 pCmdUI->SetCheck(m_destroyTicketsOnExit); 1642 } 1643 1644 VOID CLeashView::OnUppercaseRealm() 1645 { 1646 m_upperCaseRealm = !m_upperCaseRealm; 1647 1648 pLeash_set_default_uppercaserealm(m_upperCaseRealm); 1649 } 1650 1651 VOID CLeashView::OnUpdateUppercaseRealm(CCmdUI *pCmdUI) 1652 { 1653 // description is now 'allow mixed case', so reverse logic 1654 pCmdUI->SetCheck(!m_upperCaseRealm); 1655 } 1656 1657 VOID CLeashView::ResetTreeNodes() 1658 { 1659 m_hPrincipalState = 0; 1660 m_hKerb5State = 0; 1661 } 1662 1663 VOID CLeashView::OnDestroy() 1664 { 1665 CCacheDisplayData *elem; 1666 SetTrayIcon(NIM_DELETE); 1667 1668 if (m_destroyTicketsOnExit) { 1669 elem = m_ccacheDisplay; 1670 while (elem != NULL) { 1671 kdestroy(elem->m_ccacheName); 1672 elem = elem->m_next; 1673 } 1674 } 1675 CListView::OnDestroy(); 1676 } 1677 1678 VOID CLeashView::OnUpdateDestroyTicket(CCmdUI* pCmdUI) 1679 { 1680 // @TODO: mutex 1681 BOOL enable = FALSE; 1682 CCacheDisplayData *elem = m_ccacheDisplay; 1683 while (elem != NULL) { 1684 if (elem->m_selected) { 1685 enable = TRUE; 1686 break; 1687 } 1688 elem = elem->m_next; 1689 } 1690 1691 pCmdUI->Enable(enable); 1692 } 1693 1694 VOID CLeashView::OnUpdateInitTicket(CCmdUI* pCmdUI) 1695 { 1696 if (!CLeashApp::m_hKrb5DLL) 1697 pCmdUI->Enable(FALSE); 1698 else 1699 pCmdUI->Enable(TRUE); 1700 } 1701 1702 VOID CLeashView::OnUpdateRenewTicket(CCmdUI* pCmdUI) 1703 { 1704 // @TODO: mutex 1705 BOOL enable = FALSE; 1706 CCacheDisplayData *elem = m_ccacheDisplay; 1707 while (elem != NULL) { 1708 if (elem->m_selected) { // @TODO: && elem->m_renewable 1709 enable = TRUE; 1710 break; 1711 } 1712 elem = elem->m_next; 1713 } 1714 1715 pCmdUI->Enable(enable); 1716 } 1717 1718 LRESULT CLeashView::OnGoodbye(WPARAM wParam, LPARAM lParam) 1719 { 1720 m_pDebugWindow->DestroyWindow(); 1721 return 0L; 1722 } 1723 1724 VOID CLeashView::OnLeashRestore() 1725 { 1726 if ( CMainFrame::m_isMinimum ) { 1727 CMainFrame * frame = (CMainFrame *)GetParentFrame(); 1728 frame->ShowTaskBarButton(TRUE); 1729 frame->ShowWindow(SW_SHOWNORMAL); 1730 } 1731 } 1732 1733 VOID CLeashView::OnLeashMinimize() 1734 { 1735 if ( !CMainFrame::m_isMinimum ) { 1736 CMainFrame * frame = (CMainFrame *)GetParentFrame(); 1737 // frame->ShowTaskBarButton(FALSE); 1738 frame->ShowWindow(SW_HIDE); 1739 frame->ShowWindow(SW_MINIMIZE); 1740 } 1741 } 1742 1743 LRESULT CLeashView::OnTrayIcon(WPARAM wParam, LPARAM lParam) 1744 { 1745 switch ( lParam ) { 1746 case WM_LBUTTONDOWN: 1747 if ( CMainFrame::m_isMinimum ) 1748 OnLeashRestore(); 1749 else 1750 OnLeashMinimize(); 1751 break; 1752 case WM_RBUTTONDOWN: 1753 { 1754 int nFlags; 1755 CMenu * menu = new CMenu(); 1756 menu->CreatePopupMenu(); 1757 if ( !CMainFrame::m_isMinimum ) 1758 menu->AppendMenu(MF_STRING, ID_LEASH_MINIMIZE, "&Close MIT Kerberos Window"); 1759 else 1760 menu->AppendMenu(MF_STRING, ID_LEASH_RESTORE, "&Open MIT Kerberos Window"); 1761 menu->AppendMenu(MF_SEPARATOR); 1762 menu->AppendMenu(MF_STRING, ID_INIT_TICKET, "&Get Tickets"); 1763 if (WaitForSingleObject( ticketinfo.lockObj, INFINITE ) != WAIT_OBJECT_0) 1764 throw("Unable to lock ticketinfo"); 1765 if (!ticketinfo.Krb5.btickets || 1766 !CLeashApp::m_hKrb5DLL) 1767 nFlags = MF_STRING | MF_GRAYED; 1768 else 1769 nFlags = MF_STRING; 1770 menu->AppendMenu(nFlags, ID_RENEW_TICKET, "&Renew Tickets"); 1771 if (!ticketinfo.Krb5.btickets) 1772 nFlags = MF_STRING | MF_GRAYED; 1773 else 1774 nFlags = MF_STRING; 1775 ReleaseMutex(ticketinfo.lockObj); 1776 menu->AppendMenu(MF_STRING, ID_DESTROY_TICKET, "&Destroy Tickets"); 1777 menu->AppendMenu(MF_STRING, ID_CHANGE_PASSWORD, "&Change Password"); 1778 1779 menu->AppendMenu(MF_SEPARATOR); 1780 if ( m_autoRenewTickets ) 1781 nFlags = MF_STRING | MF_CHECKED; 1782 else 1783 nFlags = MF_STRING | MF_UNCHECKED; 1784 menu->AppendMenu(nFlags, ID_AUTO_RENEW, "&Automatic Ticket Renewal"); 1785 if ( m_lowTicketAlarm ) 1786 nFlags = MF_STRING | MF_CHECKED; 1787 else 1788 nFlags = MF_STRING | MF_UNCHECKED; 1789 menu->AppendMenu(nFlags, ID_LOW_TICKET_ALARM, "&Expiration Alarm"); 1790 menu->AppendMenu(MF_SEPARATOR); 1791 menu->AppendMenu(MF_STRING, ID_APP_EXIT, "E&xit"); 1792 menu->SetDefaultItem(ID_LEASH_RESTORE); 1793 1794 POINT pt; 1795 GetCursorPos(&pt); 1796 1797 SetForegroundWindow(); 1798 menu->TrackPopupMenu(TPM_RIGHTALIGN | TPM_RIGHTBUTTON, 1799 pt.x, pt.y, GetParentFrame()); 1800 PostMessage(WM_NULL, 0, 0); 1801 menu->DestroyMenu(); 1802 delete menu; 1803 } 1804 break; 1805 case WM_MOUSEMOVE: 1806 // SendMessage(WM_COMMAND, ID_UPDATE_DISPLAY, 0); 1807 break; 1808 } 1809 return 0L; 1810 } 1811 1812 VOID CLeashView::OnAppAbout() 1813 { 1814 CLeashAboutBox leashAboutBox; 1815 // To debug loaded dlls: 1816 // leashAboutBox.m_bListModules = TRUE; 1817 leashAboutBox.DoModal(); 1818 } 1819 1820 1821 VOID CLeashView::OnInitialUpdate() 1822 { 1823 CListView::OnInitialUpdate(); 1824 CLeashApp::m_hProgram = ::FindWindow(_T("LEASH.0WNDCLASS"), NULL); 1825 EnableToolTips(); 1826 } 1827 1828 VOID CLeashView::OnItemexpandedTreeview(NMHDR* pNMHDR, LRESULT* pResult) 1829 { 1830 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; 1831 1832 if (m_hPrincipal == pNMTreeView->itemNew.hItem) 1833 m_hPrincipalState = pNMTreeView->action; 1834 else if (m_hKerb5 == pNMTreeView->itemNew.hItem) 1835 m_hKerb5State = pNMTreeView->action; 1836 1837 CMainFrame::m_isBeingResized = TRUE; 1838 *pResult = 0; 1839 } 1840 1841 VOID CLeashView::OnUpdateDebugMode(CCmdUI* pCmdUI) 1842 { 1843 pCmdUI->Enable(FALSE); 1844 } 1845 1846 VOID CLeashView::OnUpdateCfgFiles(CCmdUI* pCmdUI) 1847 { 1848 pCmdUI->Enable(FALSE); 1849 } 1850 1851 /* 1852 void CLeashView::GetRowWidthHeight(CDC* pDC, LPCSTR theString, int& nRowWidth, 1853 int& nRowHeight, int& nCharWidth) 1854 { 1855 TEXTMETRIC tm; 1856 1857 //CEx29aDoc* pDoc = GetDocument(); 1858 pDC->GetTextMetrics(&tm); 1859 nCharWidth = tm.tmAveCharWidth + 1; 1860 nRowWidth = strlen(theString); 1861 1862 //int nFields = theString.GetLength(); 1863 1864 //for(int i = 0; i < nFields; i++) 1865 //{ 1866 // nRowWidth += nCharWidth; 1867 //} 1868 1869 nRowWidth *= nCharWidth; 1870 nRowHeight = tm.tmHeight; 1871 } 1872 */ 1873 1874 void CLeashView::SetTrayText(int nim, CString tip) 1875 { 1876 if ( (nim == NIM_MODIFY) && (m_bIconDeleted) ) 1877 return; 1878 if ( (nim == NIM_MODIFY) && (!m_bIconAdded) ) 1879 nim = NIM_ADD; 1880 1881 if ( (nim != NIM_DELETE) || IsWindow(m_hWnd) ) 1882 { 1883 NOTIFYICONDATA nid; 1884 memset (&nid, 0x00, sizeof(NOTIFYICONDATA)); 1885 nid.cbSize = sizeof(NOTIFYICONDATA); 1886 nid.hWnd = m_hWnd; 1887 nid.uID = 0; 1888 nid.uFlags = NIF_MESSAGE | NIF_TIP; 1889 nid.uCallbackMessage = WM_TRAYICON; 1890 strncpy(nid.szTip, (LPCTSTR) tip, sizeof(nid.szTip)); 1891 nid.szTip[sizeof(nid.szTip)-1] = '\0'; 1892 Shell_NotifyIcon (nim, &nid); 1893 } 1894 1895 if ( nim == NIM_ADD ) 1896 m_bIconAdded = TRUE; 1897 if ( nim == NIM_DELETE ) 1898 m_bIconDeleted = TRUE; 1899 } 1900 1901 void CLeashView::SetTrayIcon(int nim, int state) 1902 { 1903 static HICON hIcon[IMAGE_COUNT]; 1904 static BOOL bIconInit = FALSE; 1905 1906 if ( (nim == NIM_MODIFY) && (m_bIconDeleted) ) 1907 return; 1908 if ( (nim == NIM_MODIFY) && (!m_bIconAdded) ) 1909 nim = NIM_ADD; 1910 1911 if ( (nim != NIM_DELETE) || IsWindow(m_hWnd) ) 1912 { 1913 if ( !bIconInit ) { 1914 // The state is reported as the parent node value although 1915 // we want to use the Tray Version of the icons 1916 hIcon[ACTIVE_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_GOOD); 1917 hIcon[LOW_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_LOW); 1918 hIcon[EXPIRED_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_EXPIRED); 1919 hIcon[NONE_PARENT_NODE] = AfxGetApp()->LoadIcon(IDI_LEASH_TRAY_NONE); 1920 bIconInit = TRUE; 1921 } 1922 1923 NOTIFYICONDATA nid; 1924 memset (&nid, 0x00, sizeof(NOTIFYICONDATA)); 1925 nid.cbSize = sizeof(NOTIFYICONDATA); 1926 nid.hWnd = m_hWnd; 1927 nid.uID = 0; 1928 nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 1929 nid.uCallbackMessage = WM_TRAYICON; 1930 nid.hIcon = hIcon[state]; 1931 Shell_NotifyIcon (nim, &nid); 1932 } 1933 1934 if ( nim == NIM_ADD ) 1935 m_bIconAdded = TRUE; 1936 if ( nim == NIM_DELETE ) 1937 m_bIconDeleted = TRUE; 1938 } 1939 1940 BOOL CLeashView::PostWarningMessage(const CString& message) 1941 { 1942 if (m_pWarningMessage) 1943 { 1944 return FALSE; // can't post more than one warning at a time 1945 } 1946 m_pWarningMessage = new CString(message); 1947 PostMessage(WM_WARNINGPOPUP); 1948 return TRUE; 1949 } 1950 1951 LRESULT CLeashView::OnWarningPopup(WPARAM wParam, LPARAM lParam) 1952 { 1953 CLeashMessageBox leashMessageBox(CMainFrame::m_isMinimum ? GetDesktopWindow() : NULL, 1954 *m_pWarningMessage, 100000); 1955 leashMessageBox.DoModal(); 1956 delete m_pWarningMessage; 1957 m_pWarningMessage = NULL; 1958 return 0L; 1959 } 1960 1961 BOOL CLeashView::PreTranslateMessage(MSG* pMsg) 1962 { 1963 if ( pMsg->message == ID_OBTAIN_TGT_WITH_LPARAM ) 1964 { 1965 OutputDebugString("Obtain TGT with LParam\n"); 1966 } 1967 1968 if ( pMsg->message == WM_TIMER ) { 1969 try { 1970 if (InterlockedDecrement(&m_timerMsgNotInProgress) == 0) { 1971 1972 CString ticketStatusKrb5 = TCHAR(NOT_INSTALLED); 1973 CString strTimeDate; 1974 CString lowTicketWarningKrb5; 1975 1976 timer_start: 1977 if (WaitForSingleObject( ticketinfo.lockObj, 100 ) != WAIT_OBJECT_0) 1978 throw("Unable to lock ticketinfo"); 1979 if (CLeashApp::m_hKrb5DLL) 1980 { 1981 // KRB5 1982 UpdateTicketTime(ticketinfo.Krb5); 1983 1984 if (!ticketinfo.Krb5.btickets) 1985 { 1986 ticketStatusKrb5 = "Kerb-5: No Tickets"; 1987 } 1988 else if (EXPIRED_TICKETS == ticketinfo.Krb5.btickets) 1989 { 1990 ticketStatusKrb5 = "Kerb-5: Expired Ticket(s)"; 1991 m_ticketTimeLeft = 0; 1992 lowTicketWarningKrb5 = "Your Kerberos Five ticket(s) have expired"; 1993 if (!m_warningOfTicketTimeLeftLockKrb5) 1994 m_warningOfTicketTimeLeftKrb5 = 0; 1995 m_warningOfTicketTimeLeftLockKrb5 = ZERO_MINUTES_LEFT; 1996 } 1997 else 1998 { 1999 m_ticketStatusKrb5 = GetLowTicketStatus(5); 2000 switch (m_ticketStatusKrb5) 2001 { 2002 case TWENTY_MINUTES_LEFT: 2003 break; 2004 case FIFTEEN_MINUTES_LEFT: 2005 ticketinfo.Krb5.btickets = TICKETS_LOW; 2006 lowTicketWarningKrb5 = "Less then 15 minutes left on your Kerberos Five ticket(s)"; 2007 break; 2008 case TEN_MINUTES_LEFT: 2009 ticketinfo.Krb5.btickets = TICKETS_LOW; 2010 lowTicketWarningKrb5 = "Less then 10 minutes left on your Kerberos Five ticket(s)"; 2011 if (!m_warningOfTicketTimeLeftLockKrb5) 2012 m_warningOfTicketTimeLeftKrb5 = 0; 2013 m_warningOfTicketTimeLeftLockKrb5 = TEN_MINUTES_LEFT; 2014 break; 2015 case FIVE_MINUTES_LEFT: 2016 ticketinfo.Krb5.btickets = TICKETS_LOW; 2017 if (m_warningOfTicketTimeLeftLockKrb5 == TEN_MINUTES_LEFT) 2018 m_warningOfTicketTimeLeftKrb5 = 0; 2019 m_warningOfTicketTimeLeftLockKrb5 = FIVE_MINUTES_LEFT; 2020 lowTicketWarningKrb5 = "Less then 5 minutes left on your Kerberos Five ticket(s)"; 2021 break; 2022 default: 2023 m_ticketStatusKrb5 = 0; 2024 break; 2025 } 2026 } 2027 2028 if (CMainFrame::m_isMinimum) 2029 { 2030 // minimized display 2031 ticketStatusKrb5.Format("Kerb-5: %02d:%02d Left", 2032 (m_ticketTimeLeft / 60L / 60L), 2033 (m_ticketTimeLeft / 60L % 60L)); 2034 } 2035 else 2036 { 2037 // normal display 2038 if (GOOD_TICKETS == ticketinfo.Krb5.btickets || TICKETS_LOW == ticketinfo.Krb5.btickets) 2039 { 2040 if ( m_ticketTimeLeft >= 60 ) { 2041 ticketStatusKrb5.Format("Kerb-5 Ticket Life: %02d:%02d", 2042 (m_ticketTimeLeft / 60L / 60L), 2043 (m_ticketTimeLeft / 60L % 60L)); 2044 } else { 2045 ticketStatusKrb5.Format("Kerb-5 Ticket Life: < 1 min"); 2046 } 2047 } 2048 #ifndef NO_STATUS_BAR 2049 if (CMainFrame::m_wndStatusBar) 2050 { 2051 CMainFrame::m_wndStatusBar.SetPaneInfo(1, 111112, SBPS_NORMAL, 130); 2052 CMainFrame::m_wndStatusBar.SetPaneText(1, ticketStatusKrb5, SBT_POPOUT); 2053 } 2054 #endif 2055 } 2056 } 2057 else 2058 { 2059 // not installed 2060 ticketStatusKrb5.Format("Kerb-5: Not Available"); 2061 #ifndef NO_STATUS_BAR 2062 if (CMainFrame::m_wndStatusBar) 2063 { 2064 CMainFrame::m_wndStatusBar.SetPaneInfo(1, 111112, SBPS_NORMAL, 130); 2065 CMainFrame::m_wndStatusBar.SetPaneText(1, ticketStatusKrb5, SBT_POPOUT); 2066 } 2067 #endif 2068 } 2069 //KRB5 2070 2071 if ( m_ticketStatusKrb5 == TWENTY_MINUTES_LEFT && 2072 m_autoRenewTickets && !m_autoRenewalAttempted && ticketinfo.Krb5.renew_until && 2073 (ticketinfo.Krb5.renew_until - LeashTime() > 20 * 60)) 2074 { 2075 m_autoRenewalAttempted = 1; 2076 ReleaseMutex(ticketinfo.lockObj); 2077 AfxBeginThread(RenewTicket,m_hWnd); 2078 goto timer_start; 2079 } 2080 2081 BOOL warningKrb5 = m_ticketStatusKrb5 > NO_TICKETS && 2082 m_ticketStatusKrb5 < TWENTY_MINUTES_LEFT && 2083 !m_warningOfTicketTimeLeftKrb5; 2084 2085 // Play warning message only once per each case statement above 2086 if (warningKrb5) 2087 { 2088 2089 CString lowTicketWarning = ""; 2090 int warnings = 0; 2091 2092 if (warningKrb5) { 2093 lowTicketWarning += lowTicketWarningKrb5; 2094 m_warningOfTicketTimeLeftKrb5 = ON; 2095 warnings++; 2096 } 2097 2098 ReleaseMutex(ticketinfo.lockObj); 2099 AlarmBeep(); 2100 PostWarningMessage(lowTicketWarning); 2101 if (WaitForSingleObject( ticketinfo.lockObj, 100 ) != WAIT_OBJECT_0) 2102 throw("Unable to lock ticketinfo"); 2103 } 2104 2105 CTime tTimeDate = CTime::GetCurrentTime(); 2106 2107 if (CMainFrame::m_isMinimum) 2108 { 2109 strTimeDate = ( "MIT Kerberos - " 2110 "[" + ticketStatusKrb5 + "] - " + 2111 "[" + ticketinfo.Krb5.principal + "]" + " - " + 2112 tTimeDate.Format("%A, %B %d, %Y %H:%M ")); 2113 } 2114 else 2115 { 2116 strTimeDate = ("MIT Kerberos - " + 2117 tTimeDate.Format("%A, %B %d, %Y %H:%M ") 2118 //timeDate.Format("%d %b %y %H:%M:%S - ") 2119 ); 2120 } 2121 ::SetWindowText(CLeashApp::m_hProgram, strTimeDate); 2122 2123 if (CLeashApp::m_hKrb5DLL) { 2124 if ( ticketinfo.Krb5.btickets ) 2125 strTimeDate = ( "MIT Kerberos: " 2126 "[" + ticketStatusKrb5 + "]" + 2127 " - [" + ticketinfo.Krb5.principal + "]"); 2128 else 2129 strTimeDate = "MIT Kerberos: No Tickets"; 2130 } 2131 ReleaseMutex(ticketinfo.lockObj); 2132 2133 SetTrayText(NIM_MODIFY, strTimeDate); 2134 2135 m_updateDisplayCount++; 2136 m_alreadyPlayedDisplayCount++; 2137 } 2138 } catch (...) { 2139 } 2140 InterlockedIncrement(&m_timerMsgNotInProgress); 2141 } // WM_TIMER 2142 2143 2144 if (UPDATE_DISPLAY_TIME == m_updateDisplayCount) 2145 { 2146 m_updateDisplayCount = 0; 2147 SendMessage(WM_COMMAND, ID_UPDATE_DISPLAY, 0); 2148 } 2149 2150 if (m_alreadyPlayedDisplayCount > 2) 2151 { 2152 m_alreadyPlayedDisplayCount = 0; 2153 m_alreadyPlayed = FALSE; 2154 } 2155 2156 if (CMainFrame::m_isBeingResized) 2157 { 2158 m_startup = FALSE; 2159 2160 UpdateWindow(); 2161 2162 CMainFrame::m_isBeingResized = FALSE; 2163 } 2164 2165 if (::IsWindow(pMsg->hwnd)) 2166 return CListView::PreTranslateMessage(pMsg); 2167 else 2168 return FALSE; 2169 } 2170 2171 VOID CLeashView::OnLowTicketAlarm() 2172 { 2173 m_lowTicketAlarm = !m_lowTicketAlarm; 2174 2175 if (m_pApp) 2176 m_pApp->WriteProfileInt("Settings", "LowTicketAlarm", m_lowTicketAlarm); 2177 } 2178 2179 VOID CLeashView::OnUpdateLowTicketAlarm(CCmdUI* pCmdUI) 2180 { 2181 pCmdUI->SetCheck(m_lowTicketAlarm); 2182 } 2183 2184 VOID CLeashView::OnAutoRenew() 2185 { 2186 m_autoRenewTickets = !m_autoRenewTickets; 2187 2188 if (m_pApp) 2189 m_pApp->WriteProfileInt("Settings", "AutoRenewTickets", m_autoRenewTickets); 2190 2191 m_autoRenewalAttempted = 0; 2192 } 2193 2194 VOID CLeashView::OnUpdateAutoRenew(CCmdUI* pCmdUI) 2195 { 2196 pCmdUI->SetCheck(m_autoRenewTickets); 2197 } 2198 2199 VOID CLeashView::OnUpdateMakeDefault(CCmdUI* pCmdUI) 2200 { 2201 // enable if exactly one principal is selected and that principal is not 2202 // the default principal 2203 BOOL enable = FALSE; 2204 CCacheDisplayData *elem = m_ccacheDisplay; 2205 while (elem != NULL) { 2206 if (elem->m_selected) { 2207 if (enable) { 2208 // multiple selection; disable button 2209 enable = FALSE; 2210 break; 2211 } 2212 if (elem->m_isDefault) 2213 break; 2214 2215 enable = TRUE; 2216 } 2217 elem = elem->m_next; 2218 } 2219 pCmdUI->Enable(enable); 2220 } 2221 2222 VOID CLeashView::AlarmBeep() 2223 { 2224 if (m_lowTicketAlarmSound) 2225 { 2226 ::Beep(2000, 200); 2227 ::Beep(200, 200); 2228 ::Beep(700, 200); 2229 } 2230 } 2231 2232 VOID CLeashView::OnUpdateProperties(CCmdUI* pCmdUI) 2233 { 2234 if (CLeashApp::m_hKrb5DLL) 2235 pCmdUI->Enable(); 2236 else 2237 pCmdUI->Enable(FALSE); 2238 } 2239 2240 void CLeashView::OnHelpLeash32() 2241 { 2242 #ifdef CALL_HTMLHELP 2243 AfxGetApp()->HtmlHelp(HID_LEASH_PROGRAM); 2244 #else 2245 AfxGetApp()->WinHelp(HID_LEASH_PROGRAM); 2246 #endif 2247 } 2248 2249 void CLeashView::OnHelpKerberos() 2250 { 2251 #ifdef CALL_HTMLHELP 2252 AfxGetApp()->HtmlHelp(HID_ABOUT_KERBEROS); 2253 #else 2254 AfxGetApp()->WinHelp(HID_ABOUT_KERBEROS); 2255 #endif 2256 } 2257 2258 void CLeashView::OnHelpWhyuseleash32() 2259 { 2260 #ifdef CALL_HTMLHELP 2261 AfxGetApp()->HtmlHelp(HID_WHY_USE_LEASH32); 2262 #else 2263 AfxGetApp()->WinHelp(HID_WHY_USE_LEASH32); 2264 #endif 2265 } 2266 2267 void CLeashView::OnSysColorChange() 2268 { 2269 change_icon_size = FALSE; 2270 CWnd::OnSysColorChange(); 2271 OnLargeIcons(); 2272 m_imageList.SetBkColor(GetSysColor(COLOR_WINDOW)); 2273 change_icon_size = TRUE; 2274 } 2275 2276 2277 LRESULT 2278 CLeashView::OnObtainTGTWithParam(WPARAM wParam, LPARAM lParam) 2279 { 2280 LRESULT res = 0; 2281 char *param = 0; 2282 LSH_DLGINFO_EX ldi; 2283 ldi.size = sizeof(ldi); 2284 ldi.dlgtype = DLGTYPE_PASSWD; 2285 ldi.use_defaults = 1; 2286 ldi.title = ldi.in.title; 2287 ldi.username = ldi.in.username; 2288 ldi.realm = ldi.in.realm; 2289 2290 if (lParam) 2291 param = (char *) MapViewOfFile((HANDLE)lParam, 2292 FILE_MAP_ALL_ACCESS, 2293 0, 2294 0, 2295 4096); 2296 2297 if ( param ) { 2298 if ( *param ) 2299 strcpy_s(ldi.in.title,param); 2300 param += strlen(param) + 1; 2301 if ( *param ) 2302 strcpy_s(ldi.in.username,param); 2303 param += strlen(param) + 1; 2304 if ( *param ) 2305 strcpy_s(ldi.in.realm,param); 2306 param += strlen(param) + 1; 2307 if ( *param ) 2308 strcpy_s(ldi.in.ccache,param); 2309 } else { 2310 strcpy_s(ldi.in.title, "MIT Kerberos: Get Ticket"); 2311 } 2312 2313 if (strlen(ldi.username) > 0 && strlen(ldi.realm) > 0) 2314 ldi.dlgtype |= DLGFLAG_READONLYPRINC; 2315 2316 res = pLeash_kinit_dlg_ex(m_hWnd, &ldi); 2317 if (param) 2318 UnmapViewOfFile(param); 2319 if (lParam) 2320 CloseHandle((HANDLE )lParam); 2321 ::SendMessage(m_hWnd, WM_COMMAND, ID_UPDATE_DISPLAY, 0); 2322 return res; 2323 } 2324 2325 2326 // Find the CCacheDisplayData corresponding to the specified item, if it exists 2327 static CCacheDisplayData * 2328 FindCCacheDisplayData(int item, CCacheDisplayData *elem) 2329 { 2330 while (elem != NULL) { 2331 if (elem->m_index == item) 2332 break; 2333 elem = elem->m_next; 2334 } 2335 return elem; 2336 } 2337 2338 2339 void CLeashView::OnLvnItemActivate(NMHDR *pNMHDR, LRESULT *pResult) 2340 { 2341 LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR); 2342 // TODO: Add your control notification handler code here 2343 CCacheDisplayData *elem = FindCCacheDisplayData(pNMIA->iItem, 2344 m_ccacheDisplay); 2345 if (elem != NULL) { 2346 elem->m_expanded = !elem->m_expanded; 2347 OnUpdateDisplay(); 2348 } 2349 *pResult = 0; 2350 } 2351 2352 2353 void CLeashView::OnLvnKeydown(NMHDR *pNMHDR, LRESULT *pResult) 2354 { 2355 LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR); 2356 int expand = -1; // -1 = unchanged; 0 = collapse; 1 = expand 2357 switch (pLVKeyDow->wVKey) { 2358 case VK_RIGHT: 2359 // expand focus item 2360 expand = 1; 2361 break; 2362 case VK_LEFT: 2363 // collapse focus item 2364 expand = 0; 2365 break; 2366 default: 2367 break; 2368 } 2369 if (expand >= 0) { 2370 int focusedItem = GetListCtrl().GetNextItem(-1, LVNI_FOCUSED); 2371 if (focusedItem >= 0) { 2372 CCacheDisplayData *elem = FindCCacheDisplayData(focusedItem, 2373 m_ccacheDisplay); 2374 if (elem != NULL) { 2375 if (elem->m_expanded != expand) { 2376 elem->m_expanded = expand; 2377 OnUpdateDisplay(); 2378 } 2379 } 2380 } 2381 } 2382 *pResult = 0; 2383 } 2384 2385 void CLeashView::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult) 2386 { 2387 CCacheDisplayData *elem; 2388 LRESULT result = 0; 2389 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); 2390 // TODO: Add your control notification handler code here 2391 if ((pNMLV->uNewState ^ pNMLV->uOldState) & LVIS_SELECTED) { 2392 // selection state changing 2393 elem = FindCCacheDisplayData(pNMLV->iItem, m_ccacheDisplay); 2394 if (elem == NULL) { 2395 // this is an individual ticket, not a cache, so prevent selection 2396 if (pNMLV->uNewState & LVIS_SELECTED) { 2397 unsigned int newState = pNMLV->uNewState & ~LVIS_SELECTED; 2398 result = 1; // suppress changes 2399 if (newState != pNMLV->uOldState) { 2400 // but need to make other remaining changes still 2401 GetListCtrl().SetItemState(pNMLV->iItem, newState, 2402 newState ^ pNMLV->uOldState); 2403 } 2404 } 2405 } else { 2406 elem->m_selected = (pNMLV->uNewState & LVIS_SELECTED) ? 1 : 0; 2407 } 2408 } 2409 *pResult = result; 2410 } 2411 2412 HFONT CLeashView::GetSubItemFont(int iItem, int iSubItem) 2413 { 2414 HFONT retval = m_BaseFont; 2415 int iColumn, columnSubItem = 0; 2416 2417 // Translate subitem to column index 2418 for (iColumn = 0; iColumn < NUM_VIEW_COLUMNS; iColumn++) { 2419 if (sm_viewColumns[iColumn].m_enabled) { 2420 if (columnSubItem == iSubItem) 2421 break; 2422 else 2423 columnSubItem++; 2424 } 2425 } 2426 switch (iColumn) { 2427 case RENEWABLE_UNTIL: 2428 case VALID_UNTIL: 2429 retval = m_aListItemInfo[iItem].m_durationFont; 2430 break; 2431 default: 2432 retval = m_aListItemInfo[iItem].m_font; 2433 break; 2434 } 2435 return retval; 2436 } 2437 2438 void CLeashView::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult) 2439 { 2440 HFONT font; 2441 CCacheDisplayData *pElem; 2442 *pResult = CDRF_DODEFAULT; 2443 int iItem; 2444 2445 LPNMLVCUSTOMDRAW pNMLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR); 2446 switch (pNMLVCD->nmcd.dwDrawStage) { 2447 case CDDS_PREPAINT: 2448 *pResult = CDRF_NOTIFYITEMDRAW; 2449 break; 2450 case CDDS_ITEMPREPAINT: 2451 *pResult = CDRF_NOTIFYSUBITEMDRAW; 2452 break; 2453 case CDDS_SUBITEM | CDDS_ITEMPREPAINT: 2454 iItem = pNMLVCD->nmcd.dwItemSpec; 2455 pElem = FindCCacheDisplayElem(m_ccacheDisplay, iItem); 2456 font = GetSubItemFont(iItem, pNMLVCD->iSubItem); 2457 SelectObject(pNMLVCD->nmcd.hdc, font); 2458 if (pElem != NULL && pNMLVCD->iSubItem == 0) { 2459 CListCtrl &list = GetListCtrl(); 2460 CRect drawRect, nextRect; 2461 if (list.GetSubItemRect(iItem, 0, LVIR_BOUNDS, drawRect)) { 2462 HTHEME hTheme = OpenThemeData(pNMLVCD->nmcd.hdr.hwndFrom, 2463 L"Explorer::TreeView"); 2464 drawRect.right = drawRect.left + 2465 (drawRect.bottom - drawRect.top); 2466 // @TODO: need hot states, too: TVP_HOTGLYPH, HGLPS_OPENED, 2467 // HGLPS_CLOSED 2468 int state = pElem->m_expanded ? GLPS_OPENED : GLPS_CLOSED; 2469 DrawThemeBackground(hTheme, 2470 pNMLVCD->nmcd.hdc, 2471 TVP_GLYPH, state, 2472 &drawRect, NULL); 2473 } 2474 } 2475 *pResult = CDRF_NEWFONT; 2476 break; 2477 default: 2478 break; 2479 } 2480 } 2481