xref: /haiku/src/servers/keystore/AppAccessRequestWindow.cpp (revision 894526b51a3d931c423878fc0eb8da610fa1fb2a)
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, 100, 100), 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 			| B_CLOSE_ON_ESCAPE),
149 	fRequestView(NULL),
150 	fDoneSem(-1),
151 	fResult(kMessageDisallow)
152 {
153 	fDoneSem = create_sem(0, "application keyring access dialog");
154 	if (fDoneSem < 0)
155 		return;
156 
157 	BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL);
158 	if (layout == NULL)
159 		return;
160 
161 	SetLayout(layout);
162 
163 	fRequestView = new(std::nothrow) AppAccessRequestView(keyringName,
164 		signature, path, accessString, appIsNew, appWasUpdated);
165 	if (fRequestView == NULL)
166 		return;
167 
168 	layout->AddView(fRequestView);
169 }
170 
171 
172 AppAccessRequestWindow::~AppAccessRequestWindow()
173 {
174 	if (fDoneSem >= 0)
175 		delete_sem(fDoneSem);
176 }
177 
178 
179 bool
180 AppAccessRequestWindow::QuitRequested()
181 {
182 	fResult = kMessageDisallow;
183 	release_sem(fDoneSem);
184 	return false;
185 }
186 
187 
188 void
189 AppAccessRequestWindow::MessageReceived(BMessage* message)
190 {
191 	switch (message->what) {
192 		case kMessageDisallow:
193 		case kMessageOnce:
194 		case kMessageAlways:
195 			fResult = message->what;
196 			release_sem(fDoneSem);
197 			return;
198 	}
199 
200 	BWindow::MessageReceived(message);
201 }
202 
203 
204 status_t
205 AppAccessRequestWindow::RequestAppAccess(bool& allowAlways)
206 {
207 	ResizeToPreferred();
208 	CenterOnScreen();
209 	Show();
210 
211 	while (acquire_sem(fDoneSem) == B_INTERRUPTED)
212 		;
213 
214 	status_t result;
215 	switch (fResult) {
216 		default:
217 		case kMessageDisallow:
218 			result = B_NOT_ALLOWED;
219 			allowAlways = false;
220 			break;
221 		case kMessageOnce:
222 			result = B_OK;
223 			allowAlways = false;
224 			break;
225 		case kMessageAlways:
226 			result = B_OK;
227 			allowAlways = true;
228 			break;
229 	}
230 
231 	LockLooper();
232 	Quit();
233 	return result;
234 }
235