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 <Catalog.h>
10#include <LayoutBuilder.h>
11#include <LayoutUtils.h>
12#include <NodeInfo.h>
13#include <Roster.h>
14#include <SpaceLayoutItem.h>
15#include <TextView.h>
16
17#include <new>
18
19#undef B_TRANSLATION_CONTEXT
20#define B_TRANSLATION_CONTEXT "AppAccessRequestWindow"
21
22
23static const uint32 kMessageDisallow = 'btda';
24static const uint32 kMessageOnce = 'btao';
25static const uint32 kMessageAlways = 'btaa';
26
27
28AppAccessRequestWindow::AppAccessRequestWindow(const char* keyringName,
29	const char* signature, const char* path, const char* accessString,
30	bool appIsNew, bool appWasUpdated)
31	:
32	BWindow(BRect(50, 50, 100, 100), B_TRANSLATE("Application keyring access"),
33		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS
34			| B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS
35			| B_CLOSE_ON_ESCAPE),
36	fDoneSem(-1),
37	fResult(kMessageDisallow)
38{
39	fDoneSem = create_sem(0, "application keyring access dialog");
40	if (fDoneSem < 0)
41		return;
42
43
44	BBitmap icon = GetIcon(32 * icon_layout_scale());
45	fStripeView = new BStripeView(icon);
46
47	float inset = ceilf(be_plain_font->Size() * 0.7);
48
49	BTextView* message = new(std::nothrow) BTextView("Message");
50	if (message == NULL)
51		return;
52
53	BString details;
54	details <<  B_TRANSLATE("The application:\n"
55		"%signature% (%path%)\n\n");
56	details.ReplaceFirst("%signature%", signature);
57	details.ReplaceFirst("%path%", path);
58
59	if (keyringName != NULL) {
60		details <<  B_TRANSLATE("requests access to keyring:\n"
61			"%keyringName%\n\n");
62		details.ReplaceFirst("%keyringName%", keyringName);
63	}
64
65	if (accessString != NULL) {
66		details <<  B_TRANSLATE("to perform the following action:\n"
67			"%accessString%\n\n");
68		details.ReplaceFirst("%accessString%", accessString);
69	}
70
71	if (appIsNew)
72		details <<  B_TRANSLATE("This application hasn't been granted "
73		"access before.");
74	else if (appWasUpdated) {
75		details <<  B_TRANSLATE("This application has been updated since "
76		"it was last granted access.");
77	} else {
78		details <<  B_TRANSLATE("This application doesn't yet have the "
79		"required privileges.");
80	}
81
82	message->SetText(details);
83	message->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
84	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
85	message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
86	message->MakeEditable(false);
87	message->MakeSelectable(false);
88	message->SetWordWrap(true);
89
90	message->SetExplicitMinSize(BSize(message->StringWidth(
91		"01234567890123456789012345678901234567890123456789") + inset,
92		B_SIZE_UNSET));
93
94	fDisallowButton = new(std::nothrow) BButton(B_TRANSLATE("Disallow"),
95		new BMessage(kMessageDisallow));
96	fOnceButton = new(std::nothrow) BButton(B_TRANSLATE("Allow once"),
97		new BMessage(kMessageOnce));
98	fAlwaysButton = new(std::nothrow) BButton(B_TRANSLATE("Allow always"),
99		new BMessage(kMessageAlways));
100
101	BLayoutBuilder::Group<>(this, B_HORIZONTAL, B_USE_ITEM_SPACING)
102		.Add(fStripeView)
103		.AddGroup(B_VERTICAL, 0)
104			.SetInsets(0, B_USE_WINDOW_SPACING,
105				B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING)
106			.AddGroup(new BGroupView(B_VERTICAL, B_USE_ITEM_SPACING))
107				.Add(message)
108			.End()
109			.AddStrut(B_USE_SMALL_SPACING)
110			.AddGroup(new BGroupView(B_HORIZONTAL))
111				.Add(fDisallowButton)
112				.AddGlue()
113				.Add(fOnceButton)
114				.Add(fAlwaysButton)
115			.End()
116		.End()
117	.End();
118}
119
120
121AppAccessRequestWindow::~AppAccessRequestWindow()
122{
123	if (fDoneSem >= 0)
124		delete_sem(fDoneSem);
125}
126
127
128bool
129AppAccessRequestWindow::QuitRequested()
130{
131	fResult = kMessageDisallow;
132	release_sem(fDoneSem);
133	return false;
134}
135
136
137void
138AppAccessRequestWindow::MessageReceived(BMessage* message)
139{
140	switch (message->what) {
141		case kMessageDisallow:
142		case kMessageOnce:
143		case kMessageAlways:
144			fResult = message->what;
145			release_sem(fDoneSem);
146			return;
147	}
148
149	BWindow::MessageReceived(message);
150}
151
152
153status_t
154AppAccessRequestWindow::RequestAppAccess(bool& allowAlways)
155{
156	ResizeToPreferred();
157	CenterOnScreen();
158	Show();
159
160	while (acquire_sem(fDoneSem) == B_INTERRUPTED)
161		;
162
163	status_t result;
164	switch (fResult) {
165		default:
166		case kMessageDisallow:
167			result = B_NOT_ALLOWED;
168			allowAlways = false;
169			break;
170		case kMessageOnce:
171			result = B_OK;
172			allowAlways = false;
173			break;
174		case kMessageAlways:
175			result = B_OK;
176			allowAlways = true;
177			break;
178	}
179
180	LockLooper();
181	Quit();
182	return result;
183}
184
185
186BBitmap
187AppAccessRequestWindow::GetIcon(int32 iconSize)
188{
189	BBitmap icon(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32);
190	team_info teamInfo;
191	get_team_info(B_CURRENT_TEAM, &teamInfo);
192	app_info appInfo;
193	be_roster->GetRunningAppInfo(teamInfo.team, &appInfo);
194	BNodeInfo::GetTrackerIcon(&appInfo.ref, &icon, icon_size(iconSize));
195	return icon;
196}
197