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