xref: /haiku/src/servers/keystore/KeyRequestWindow.cpp (revision ca8ed5ea660fb6275799a3b7f138b201c41a667b)
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 
34 static const uint32 kMessageCancel = 'btcl';
35 static const uint32 kMessageUnlock = 'btul';
36 
37 
38 class KeyRequestView : public BView {
39 public:
40 	KeyRequestView()
41 		:
42 		BView("KeyRequestView", B_WILL_DRAW),
43 		fPassword(NULL)
44 	{
45 		SetViewColor(ui_color(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->SetViewColor(ui_color(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 
145 private:
146 	BStringView* fKeyringName;
147 	BTextControl* fPassword;
148 	BButton* fCancelButton;
149 	BButton* fUnlockButton;
150 };
151 
152 
153 KeyRequestWindow::KeyRequestWindow()
154 	:
155 	BWindow(BRect(50, 50, 269, 302), 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 	fRequestView(NULL),
159 	fDoneSem(-1),
160 	fResult(B_ERROR)
161 {
162 	fDoneSem = create_sem(0, "keyring unlock dialog");
163 	if (fDoneSem < 0)
164 		return;
165 
166 	BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL);
167 	if (layout == NULL)
168 		return;
169 
170 	SetLayout(layout);
171 
172 	fRequestView = new(std::nothrow) KeyRequestView();
173 	if (fRequestView == NULL)
174 		return;
175 
176 	layout->AddView(fRequestView);
177 }
178 
179 
180 KeyRequestWindow::~KeyRequestWindow()
181 {
182 	if (fDoneSem >= 0)
183 		delete_sem(fDoneSem);
184 }
185 
186 
187 void
188 KeyRequestWindow::DispatchMessage(BMessage* message, BHandler* handler)
189 {
190 	int8 key;
191 	if (message->what == B_KEY_DOWN
192 		&& message->FindInt8("byte", 0, &key) == B_OK
193 		&& key == B_ESCAPE) {
194 		PostMessage(kMessageCancel);
195 	}
196 
197 	BWindow::DispatchMessage(message, handler);
198 }
199 
200 
201 void
202 KeyRequestWindow::MessageReceived(BMessage* message)
203 {
204 	switch (message->what) {
205 		case kMessageCancel:
206 		case kMessageUnlock:
207 			fResult = message->what == kMessageUnlock ? B_OK : B_CANCELED;
208 			release_sem(fDoneSem);
209 			return;
210 	}
211 
212 	BWindow::MessageReceived(message);
213 }
214 
215 
216 status_t
217 KeyRequestWindow::RequestKey(const BString& keyringName, BMessage& keyMessage)
218 {
219 	fRequestView->SetUp(keyringName);
220 
221 	CenterOnScreen();
222 	Show();
223 
224 	while (acquire_sem(fDoneSem) == B_INTERRUPTED)
225 		;
226 
227 	status_t result = fResult;
228 	if (result == B_OK)
229 		result = fRequestView->Complete(keyMessage);
230 
231 	LockLooper();
232 	Quit();
233 	return result;
234 }
235