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