1 /* 2 * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "KeyRequestWindow.h" 8 9 #include <Button.h> 10 #include <CheckBox.h> 11 #include <GridLayout.h> 12 #include <GridView.h> 13 #include <GroupLayout.h> 14 #include <GroupView.h> 15 #include <Key.h> 16 #include <MenuField.h> 17 #include <MenuItem.h> 18 #include <NetworkDevice.h> 19 #include <PopUpMenu.h> 20 #include <SpaceLayoutItem.h> 21 #include <StringView.h> 22 #include <TextControl.h> 23 #include <TextView.h> 24 #include <View.h> 25 26 #include <new> 27 28 29 static const uint32 kMessageCancel = 'btcl'; 30 static const uint32 kMessageUnlock = 'btul'; 31 32 33 class KeyRequestView : public BView { 34 public: 35 KeyRequestView() 36 : 37 BView("KeyRequestView", B_WILL_DRAW), 38 fPassword(NULL) 39 { 40 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 41 42 BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL); 43 if (rootLayout == NULL) 44 return; 45 46 SetLayout(rootLayout); 47 48 BGridView* controls = new(std::nothrow) BGridView(); 49 if (controls == NULL) 50 return; 51 52 BGridLayout* layout = controls->GridLayout(); 53 54 float inset = ceilf(be_plain_font->Size() * 0.7); 55 rootLayout->SetInsets(inset, inset, inset, inset); 56 rootLayout->SetSpacing(inset); 57 layout->SetSpacing(inset, inset); 58 59 BStringView* label = new(std::nothrow) BStringView("keyringLabel", 60 "Keyring:"); 61 if (label == NULL) 62 return; 63 64 int32 row = 0; 65 layout->AddView(label, 0, row); 66 67 fKeyringName = new(std::nothrow) BStringView("keyringName", ""); 68 if (fKeyringName == NULL) 69 return; 70 71 layout->AddView(fKeyringName, 1, row++); 72 73 fPassword = new(std::nothrow) BTextControl("Password:", "", NULL); 74 if (fPassword == NULL) 75 return; 76 77 BLayoutItem* layoutItem = fPassword->CreateTextViewLayoutItem(); 78 layoutItem->SetExplicitMinSize(BSize(fPassword->StringWidth( 79 "0123456789012345678901234567890123456789") + inset, 80 B_SIZE_UNSET)); 81 82 layout->AddItem(fPassword->CreateLabelLayoutItem(), 0, row); 83 layout->AddItem(layoutItem, 1, row++); 84 85 BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL); 86 if (buttons == NULL) 87 return; 88 89 fCancelButton = new(std::nothrow) BButton("Cancel", 90 new BMessage(kMessageCancel)); 91 buttons->GroupLayout()->AddView(fCancelButton); 92 93 buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); 94 95 fUnlockButton = new(std::nothrow) BButton("Unlock", 96 new BMessage(kMessageUnlock)); 97 buttons->GroupLayout()->AddView(fUnlockButton); 98 99 BTextView* message = new(std::nothrow) BTextView("message"); 100 message->SetText("An application wants to access the keyring below, " 101 "but it is locked with a passphrase. Please enter the passphrase " 102 "to unlock the keyring.\n" 103 "If you unlock the keyring, it stays unlocked until the system is " 104 "shut down or the keyring is manually locked again.\n" 105 "If you cancel this dialog the keyring will remain locked."); 106 message->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 107 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 108 message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); 109 message->MakeEditable(false); 110 message->MakeSelectable(false); 111 message->SetWordWrap(true); 112 113 rootLayout->AddView(message); 114 rootLayout->AddView(controls); 115 rootLayout->AddView(buttons); 116 } 117 118 virtual void 119 AttachedToWindow() 120 { 121 fCancelButton->SetTarget(Window()); 122 fUnlockButton->SetTarget(Window()); 123 fUnlockButton->MakeDefault(true); 124 fPassword->MakeFocus(); 125 } 126 127 void 128 SetUp(const BString& keyringName) 129 { 130 fKeyringName->SetText(keyringName); 131 } 132 133 status_t 134 Complete(BMessage& keyMessage) 135 { 136 BPasswordKey password(fPassword->Text(), B_KEY_PURPOSE_KEYRING, ""); 137 return password.Flatten(keyMessage); 138 } 139 140 private: 141 BStringView* fKeyringName; 142 BTextControl* fPassword; 143 BButton* fCancelButton; 144 BButton* fUnlockButton; 145 }; 146 147 148 KeyRequestWindow::KeyRequestWindow() 149 : 150 BWindow(BRect(50, 50, 269, 302), "Unlock Keyring", 151 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS 152 | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), 153 fRequestView(NULL), 154 fDoneSem(-1), 155 fResult(B_ERROR) 156 { 157 fDoneSem = create_sem(0, "keyring unlock dialog"); 158 if (fDoneSem < 0) 159 return; 160 161 BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL); 162 if (layout == NULL) 163 return; 164 165 SetLayout(layout); 166 167 fRequestView = new(std::nothrow) KeyRequestView(); 168 if (fRequestView == NULL) 169 return; 170 171 layout->AddView(fRequestView); 172 } 173 174 175 KeyRequestWindow::~KeyRequestWindow() 176 { 177 if (fDoneSem >= 0) 178 delete_sem(fDoneSem); 179 } 180 181 182 void 183 KeyRequestWindow::DispatchMessage(BMessage* message, BHandler* handler) 184 { 185 int8 key; 186 if (message->what == B_KEY_DOWN 187 && message->FindInt8("byte", 0, &key) == B_OK 188 && key == B_ESCAPE) { 189 PostMessage(kMessageCancel); 190 } 191 192 BWindow::DispatchMessage(message, handler); 193 } 194 195 196 void 197 KeyRequestWindow::MessageReceived(BMessage* message) 198 { 199 switch (message->what) { 200 case kMessageCancel: 201 case kMessageUnlock: 202 fResult = message->what == kMessageUnlock ? B_OK : B_CANCELED; 203 release_sem(fDoneSem); 204 return; 205 } 206 207 BWindow::MessageReceived(message); 208 } 209 210 211 status_t 212 KeyRequestWindow::RequestKey(const BString& keyringName, BMessage& keyMessage) 213 { 214 fRequestView->SetUp(keyringName); 215 216 CenterOnScreen(); 217 Show(); 218 219 while (acquire_sem(fDoneSem) == B_INTERRUPTED) 220 ; 221 222 status_t result = fResult; 223 if (result == B_OK) 224 result = fRequestView->Complete(keyMessage); 225 226 LockLooper(); 227 Quit(); 228 return result; 229 } 230