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 "AppAccessRequestWindow.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 <MenuField.h> 16 #include <MenuItem.h> 17 #include <NetworkDevice.h> 18 #include <PopUpMenu.h> 19 #include <SpaceLayoutItem.h> 20 #include <TextView.h> 21 #include <View.h> 22 23 #include <new> 24 25 26 static const uint32 kMessageDisallow = 'btda'; 27 static const uint32 kMessageOnce = 'btao'; 28 static const uint32 kMessageAlways = 'btaa'; 29 30 31 class AppAccessRequestView : public BView { 32 public: 33 AppAccessRequestView(const char* keyringName, const char* signature, 34 const char* path, const char* accessString, bool appIsNew, 35 bool appWasUpdated) 36 : 37 BView("AppAccessRequestView", B_WILL_DRAW) 38 { 39 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 40 41 BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL); 42 if (rootLayout == NULL) 43 return; 44 45 SetLayout(rootLayout); 46 47 float inset = ceilf(be_plain_font->Size() * 0.7); 48 rootLayout->SetInsets(inset, inset, inset, inset); 49 rootLayout->SetSpacing(inset); 50 51 BTextView* message = new(std::nothrow) BTextView("Message"); 52 if (message == NULL) 53 return; 54 55 BString details; 56 details << "The application:\n" 57 << signature << " (" << path << ")\n\n"; 58 59 if (keyringName != NULL) { 60 details << "requests access to keyring:\n" 61 << keyringName << "\n\n"; 62 } 63 64 if (accessString != NULL) { 65 details << "to perform the following action:\n" 66 << accessString << "\n\n"; 67 } 68 69 if (appIsNew) 70 details << "This application hasn't been granted access before."; 71 else if (appWasUpdated) { 72 details << "This application has been updated since it was last" 73 << " granted access."; 74 } else { 75 details << "This application doesn't yet have the required" 76 " privileges."; 77 } 78 79 message->SetText(details); 80 message->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 81 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 82 message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); 83 message->MakeEditable(false); 84 message->MakeSelectable(false); 85 message->SetWordWrap(true); 86 87 message->SetExplicitMinSize(BSize(message->StringWidth( 88 "01234567890123456789012345678901234567890123456789") + inset, 89 B_SIZE_UNSET)); 90 91 BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL); 92 if (buttons == NULL) 93 return; 94 95 fDisallowButton = new(std::nothrow) BButton("Disallow", 96 new BMessage(kMessageDisallow)); 97 buttons->GroupLayout()->AddView(fDisallowButton); 98 99 buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); 100 101 fOnceButton = new(std::nothrow) BButton("Allow Once", 102 new BMessage(kMessageOnce)); 103 buttons->GroupLayout()->AddView(fOnceButton); 104 105 fAlwaysButton = new(std::nothrow) BButton("Allow Always", 106 new BMessage(kMessageAlways)); 107 buttons->GroupLayout()->AddView(fAlwaysButton); 108 109 rootLayout->AddView(message); 110 rootLayout->AddView(buttons); 111 } 112 113 virtual void 114 AttachedToWindow() 115 { 116 fDisallowButton->SetTarget(Window()); 117 fOnceButton->SetTarget(Window()); 118 fAlwaysButton->SetTarget(Window()); 119 120 // TODO: Decide for a sane default button (or none at all). 121 //fButton->MakeDefault(true); 122 } 123 124 private: 125 BButton* fDisallowButton; 126 BButton* fOnceButton; 127 BButton* fAlwaysButton; 128 }; 129 130 131 AppAccessRequestWindow::AppAccessRequestWindow(const char* keyringName, 132 const char* signature, const char* path, const char* accessString, 133 bool appIsNew, bool appWasUpdated) 134 : 135 BWindow(BRect(50, 50, 269, 302), "Application Keyring Access", 136 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS 137 | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), 138 fRequestView(NULL), 139 fDoneSem(-1), 140 fResult(kMessageDisallow) 141 { 142 fDoneSem = create_sem(0, "application keyring access dialog"); 143 if (fDoneSem < 0) 144 return; 145 146 BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL); 147 if (layout == NULL) 148 return; 149 150 SetLayout(layout); 151 152 fRequestView = new(std::nothrow) AppAccessRequestView(keyringName, 153 signature, path, accessString, appIsNew, appWasUpdated); 154 if (fRequestView == NULL) 155 return; 156 157 layout->AddView(fRequestView); 158 } 159 160 161 AppAccessRequestWindow::~AppAccessRequestWindow() 162 { 163 if (fDoneSem >= 0) 164 delete_sem(fDoneSem); 165 } 166 167 168 void 169 AppAccessRequestWindow::DispatchMessage(BMessage* message, BHandler* handler) 170 { 171 int8 key; 172 if (message->what == B_KEY_DOWN 173 && message->FindInt8("byte", 0, &key) == B_OK 174 && key == B_ESCAPE) { 175 PostMessage(kMessageDisallow); 176 } 177 178 BWindow::DispatchMessage(message, handler); 179 } 180 181 182 void 183 AppAccessRequestWindow::MessageReceived(BMessage* message) 184 { 185 switch (message->what) { 186 case kMessageDisallow: 187 case kMessageOnce: 188 case kMessageAlways: 189 fResult = message->what; 190 release_sem(fDoneSem); 191 return; 192 } 193 194 BWindow::MessageReceived(message); 195 } 196 197 198 status_t 199 AppAccessRequestWindow::RequestAppAccess(bool& allowAlways) 200 { 201 CenterOnScreen(); 202 Show(); 203 204 while (acquire_sem(fDoneSem) == B_INTERRUPTED) 205 ; 206 207 status_t result; 208 switch (fResult) { 209 default: 210 case kMessageDisallow: 211 result = B_NOT_ALLOWED; 212 allowAlways = false; 213 break; 214 case kMessageOnce: 215 result = B_OK; 216 allowAlways = false; 217 break; 218 case kMessageAlways: 219 result = B_OK; 220 allowAlways = true; 221 break; 222 } 223 224 LockLooper(); 225 Quit(); 226 return result; 227 } 228