haiku/src/servers/keystore/KeyRequestWindow.cpp

232 lines
5.3 KiB
C++

/*
* Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#include "KeyRequestWindow.h"
#include <Button.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <GridLayout.h>
#include <GridView.h>
#include <GroupLayout.h>
#include <GroupView.h>
#include <Key.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <NetworkDevice.h>
#include <PopUpMenu.h>
#include <SpaceLayoutItem.h>
#include <StringView.h>
#include <TextControl.h>
#include <TextView.h>
#include <View.h>
#include <new>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "KeyRequestWindow"
static const uint32 kMessageCancel = 'btcl';
static const uint32 kMessageUnlock = 'btul';
class KeyRequestView : public BView {
public:
KeyRequestView()
:
BView("KeyRequestView", B_WILL_DRAW),
fPassword(NULL)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL);
if (rootLayout == NULL)
return;
SetLayout(rootLayout);
BGridView* controls = new(std::nothrow) BGridView();
if (controls == NULL)
return;
BGridLayout* layout = controls->GridLayout();
float inset = ceilf(be_plain_font->Size() * 0.7);
rootLayout->SetInsets(inset, inset, inset, inset);
rootLayout->SetSpacing(inset);
layout->SetSpacing(inset, inset);
BStringView* label = new(std::nothrow) BStringView("keyringLabel",
B_TRANSLATE("Keyring:"));
if (label == NULL)
return;
int32 row = 0;
layout->AddView(label, 0, row);
fKeyringName = new(std::nothrow) BStringView("keyringName", "");
if (fKeyringName == NULL)
return;
layout->AddView(fKeyringName, 1, row++);
fPassword = new(std::nothrow) BTextControl(B_TRANSLATE("Password:"), "", NULL);
if (fPassword == NULL)
return;
BLayoutItem* layoutItem = fPassword->CreateTextViewLayoutItem();
layoutItem->SetExplicitMinSize(BSize(fPassword->StringWidth(
"0123456789012345678901234567890123456789") + inset,
B_SIZE_UNSET));
layout->AddItem(fPassword->CreateLabelLayoutItem(), 0, row);
layout->AddItem(layoutItem, 1, row++);
BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL);
if (buttons == NULL)
return;
fCancelButton = new(std::nothrow) BButton(B_TRANSLATE("Cancel"),
new BMessage(kMessageCancel));
buttons->GroupLayout()->AddView(fCancelButton);
buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
fUnlockButton = new(std::nothrow) BButton(B_TRANSLATE("Unlock"),
new BMessage(kMessageUnlock));
buttons->GroupLayout()->AddView(fUnlockButton);
BTextView* message = new(std::nothrow) BTextView("message");
message->SetText(B_TRANSLATE("An application wants to access the "
"keyring below, but it is locked with a passphrase. Please enter "
"the passphrase to unlock the keyring.\n"
"If you unlock the keyring, it stays unlocked until the system is "
"shut down or the keyring is manually locked again.\n"
"If you cancel this dialog the keyring will remain locked."));
message->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
message->MakeEditable(false);
message->MakeSelectable(false);
message->SetWordWrap(true);
rootLayout->AddView(message);
rootLayout->AddView(controls);
rootLayout->AddView(buttons);
}
virtual void
AttachedToWindow()
{
fCancelButton->SetTarget(Window());
fUnlockButton->SetTarget(Window());
fUnlockButton->MakeDefault(true);
fPassword->MakeFocus();
}
void
SetUp(const BString& keyringName)
{
fKeyringName->SetText(keyringName);
}
status_t
Complete(BMessage& keyMessage)
{
BPasswordKey password(fPassword->Text(), B_KEY_PURPOSE_KEYRING, "");
return password.Flatten(keyMessage);
}
private:
BStringView* fKeyringName;
BTextControl* fPassword;
BButton* fCancelButton;
BButton* fUnlockButton;
};
KeyRequestWindow::KeyRequestWindow()
:
BWindow(BRect(50, 50, 100, 100), B_TRANSLATE("Unlock keyring"),
B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS
| B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS
| B_CLOSE_ON_ESCAPE),
fRequestView(NULL),
fDoneSem(-1),
fResult(B_ERROR)
{
fDoneSem = create_sem(0, "keyring unlock dialog");
if (fDoneSem < 0)
return;
BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL);
if (layout == NULL)
return;
SetLayout(layout);
fRequestView = new(std::nothrow) KeyRequestView();
if (fRequestView == NULL)
return;
layout->AddView(fRequestView);
}
KeyRequestWindow::~KeyRequestWindow()
{
if (fDoneSem >= 0)
delete_sem(fDoneSem);
}
bool
KeyRequestWindow::QuitRequested()
{
fResult = B_CANCELED;
release_sem(fDoneSem);
return false;
}
void
KeyRequestWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMessageCancel:
case kMessageUnlock:
fResult = message->what == kMessageUnlock ? B_OK : B_CANCELED;
release_sem(fDoneSem);
return;
}
BWindow::MessageReceived(message);
}
status_t
KeyRequestWindow::RequestKey(const BString& keyringName, BMessage& keyMessage)
{
fRequestView->SetUp(keyringName);
ResizeToPreferred();
CenterOnScreen();
Show();
while (acquire_sem(fDoneSem) == B_INTERRUPTED)
;
status_t result = fResult;
if (result == B_OK)
result = fRequestView->Complete(keyMessage);
LockLooper();
Quit();
return result;
}