Added handling of password protected archives (bug #4879), only tested with zip archives.

* switch stdin to a tty in ExpanderThread (had to use fork() and execv)
* anytime an error message contains the word "password", an alert with a textcontrol is presented to the user.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38876 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2010-10-03 19:45:27 +00:00
parent 1d2ce8b8dc
commit e8c006b9ac
6 changed files with 330 additions and 32 deletions

View File

@ -3,15 +3,20 @@
* Distributed under the terms of the MIT License.
* Original code from ZipOMatic by jonas.sundstrom@kirilla.com
*/
#include <Messenger.h>
#include <Path.h>
#include "ExpanderThread.h"
#include <errno.h>
#include <image.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
const char * ExpanderThreadName = "ExpanderThread";
#include <Messenger.h>
#include <Path.h>
const char * ExpanderThreadName = "ExpanderThread";
ExpanderThread::ExpanderThread(BMessage * refs_message, BMessenger * messenger)
: GenericThread(ExpanderThreadName, B_NORMAL_PRIORITY, refs_message),
@ -84,7 +89,7 @@ ExpanderThread::ThreadStartup()
flags = fcntl(fStdErr, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fStdErr, F_SETFL, flags);
fExpanderOutput = fdopen(fStdOut, "r");
fExpanderError = fdopen(fStdErr, "r");
@ -127,6 +132,14 @@ ExpanderThread::ExecuteUnit(void)
}
void
ExpanderThread::PushInput(BString text)
{
text += "\n";
write(fStdIn, text.String(), text.Length());
}
status_t
ExpanderThread::ThreadShutdown(void)
{
@ -184,32 +197,60 @@ ExpanderThread::PipeCommand(int argc, const char **argv, int &in, int &out, int
// http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209
// Save current FDs
int old_in = dup(0);
int old_out = dup(1);
int old_err = dup(2);
int old_out = dup(1);
int old_err = dup(2);
int filedes[2];
/* Create new pipe FDs as stdin, stdout, stderr */
pipe(filedes); dup2(filedes[0], 0); close(filedes[0]);
in = filedes[1]; // Write to in, appears on cmd's stdin
/* Create new pipe FDs as stdout, stderr */
pipe(filedes); dup2(filedes[1], 1); close(filedes[1]);
out = filedes[0]; // Read from out, taken from cmd's stdout
pipe(filedes); dup2(filedes[1], 2); close(filedes[1]);
err = filedes[0]; // Read from err, taken from cmd's stderr
// "load" command.
thread_id ret = load_image(argc, argv, envp);
// taken from pty.cpp
// Create a tty for stdin, as utilities don't generally use stdin
int master = posix_openpt(O_RDWR);
if (master < 0)
return -1;
if (ret < B_OK)
return ret;
int slave;
const char *ttyName;
if (grantpt(master) != 0 || unlockpt(master) != 0
|| (ttyName = ptsname(master)) == NULL
|| (slave = open(ttyName, O_RDWR | O_NOCTTY)) < 0) {
close(master);
return -1;
}
int pid = fork();
if (pid < 0) {
close(master);
close(slave);
return -1;
}
// child
if (pid == 0) {
close(master);
setsid();
if (ioctl(slave, TIOCSCTTY, NULL) != 0)
return -1;
dup2(slave, 0);
close(slave);
// "load" command.
execv(argv[0], (char *const *)argv);
// thread ret is now suspended.
setpgid(ret, ret);
// shouldn't return
return -1;
}
// parent
close (slave);
in = master;
// Restore old FDs
close(0); dup(old_in); close(old_in);
close(1); dup(old_out); close(old_out);
close(2); dup(old_err); close(old_err);
@ -217,7 +258,7 @@ ExpanderThread::PipeCommand(int argc, const char **argv, int &in, int &out, int
the calls aren't very likely to fail, and that would
muddy up the example quite a bit. YMMV. */
return ret;
return pid;
}

View File

@ -28,6 +28,7 @@ class ExpanderThread : public GenericThread
status_t ResumeExternalExpander();
status_t InterruptExternalExpander();
status_t WaitOnExternalExpander();
void PushInput(BString text);
private:

View File

@ -5,14 +5,9 @@
*/
#include "ExpanderApp.h"
#include "ExpanderWindow.h"
#include "ExpanderThread.h"
#include "ExpanderPreferences.h"
#include <Alert.h>
#include <Application.h>
#include <Box.h>
#include <Button.h>
#include <Catalog.h>
@ -32,6 +27,11 @@
#include <StringView.h>
#include <TextView.h>
#include "ExpanderApp.h"
#include "ExpanderThread.h"
#include "ExpanderPreferences.h"
#include "PasswordAlert.h"
const uint32 MSG_SOURCE = 'mSOU';
const uint32 MSG_DEST = 'mDES';
@ -344,14 +344,22 @@ ExpanderWindow::MessageReceived(BMessage* msg)
if (msg->FindString("error", &string) == B_OK
&& fExpandingStarted) {
fExpandingThread->SuspendExternalExpander();
BAlert* alert = new BAlert("stopAlert", string,
B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL,
B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
if (alert->Go() == 0) {
fExpandingThread->ResumeExternalExpander();
StopExpanding();
} else
if (strstr(string.String(), "password") != NULL) {
BString password;
PasswordAlert* alert = new PasswordAlert("passwordAlert", string);
alert->Go(password);
fExpandingThread->ResumeExternalExpander();
fExpandingThread->PushInput(password);
} else {
BAlert* alert = new BAlert("stopAlert", string,
B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL,
B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
if (alert->Go() == 0) {
fExpandingThread->ResumeExternalExpander();
StopExpanding();
} else
fExpandingThread->ResumeExternalExpander();
}
}
break;
}

View File

@ -1,5 +1,7 @@
SubDir HAIKU_TOP src apps expander ;
UseLibraryHeaders icon ;
Application Expander :
ExpanderApp.cpp
ExpanderWindow.cpp
@ -9,6 +11,7 @@ Application Expander :
ExpanderPreferences.cpp
DirectoryFilePanel.cpp
ExpanderRules.cpp
PasswordAlert.cpp
: be tracker $(HAIKU_LOCALE_LIBS) $(TARGET_LIBSUPC++)
: Expander.rdef
;

View File

@ -0,0 +1,212 @@
/*
* Copyright 2003-2010 Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#include "PasswordAlert.h"
#include <string.h>
#include <File.h>
#include <FindDirectory.h>
#include <IconUtils.h>
#include <Path.h>
#include <Resources.h>
#include <Screen.h>
#include <View.h>
static const int kWindowIconOffset = 27;
static const int kIconStripeWidth = 30;
static const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2;
static const int kTextTopOffset = 6;
static const int kSemTimeOut = 50000;
class TAlertView : public BView {
public:
TAlertView(BRect frame);
TAlertView(BMessage* archive);
~TAlertView();
virtual void Draw(BRect updateRect);
void SetBitmap(BBitmap* Icon) { fIconBitmap = Icon; }
BBitmap* Bitmap() { return fIconBitmap; }
private:
BBitmap* fIconBitmap;
};
PasswordAlert::PasswordAlert(const char* title, const char* text)
:
BWindow(BRect(0, 0, 450, 45), title, B_MODAL_WINDOW, B_NOT_CLOSABLE | B_NOT_RESIZABLE),
fTextControl(NULL),
fAlertSem(-1)
{
// Set up the "_master_" view
TAlertView* masterView = new TAlertView(Bounds());
masterView->SetBitmap(InitIcon());
AddChild(masterView);
// Set up the text view
BRect textControlRect(kTextIconOffset, kTextTopOffset,
Bounds().right - 5, Bounds().bottom);
fTextControl = new BTextControl(textControlRect, "_password_", text, NULL, new BMessage('pass'),
B_FOLLOW_ALL);
fTextControl->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fTextControl->TextView()->HideTyping(true);
fTextControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
fTextControl->SetDivider(10 + fTextControl->StringWidth(text));
masterView->AddChild(fTextControl);
BRect screenFrame = BScreen(B_MAIN_SCREEN_ID).Frame();
BPoint pt;
pt.x = screenFrame.Width() / 2 - Bounds().Width() / 2;
pt.y = screenFrame.Height() / 2 - Bounds().Height() / 2;
if (screenFrame.Contains(pt))
MoveTo(pt);
fTextControl->MakeFocus();
}
PasswordAlert::~PasswordAlert()
{
}
BBitmap*
PasswordAlert::InitIcon()
{
// The alert icons are in the app_server resources
BBitmap* icon = NULL;
BPath path;
if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) == B_OK) {
path.Append("app_server");
BFile file;
if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK) {
BResources resources;
if (resources.SetTo(&file) == B_OK) {
// Which icon are we trying to load?
const char* iconName = "warn";
// Load the raw icon data
size_t size;
const void* rawIcon =
resources.LoadResource(B_VECTOR_ICON_TYPE, iconName, &size);
if (rawIcon != NULL) {
// Now build the bitmap
icon = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
if (BIconUtils::GetVectorIcon((const uint8*)rawIcon, size,
icon) != B_OK) {
delete icon;
return NULL;
}
}
}
}
}
return icon;
}
void
PasswordAlert::Go(BString &password)
{
fAlertSem = create_sem(0, "AlertSem");
if (fAlertSem < B_OK) {
Quit();
return;
}
// Get the originating window, if it exists
BWindow* window =
dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
Show();
// Heavily modified from TextEntryAlert code; the original didn't let the
// blocked window ever draw.
if (window) {
status_t err;
for (;;) {
do {
err = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT,
kSemTimeOut);
// We've (probably) had our time slice taken away from us
} while (err == B_INTERRUPTED);
if (err == B_BAD_SEM_ID) {
// Semaphore was finally nuked in MessageReceived
break;
}
window->UpdateIfNeeded();
}
} else {
// No window to update, so just hang out until we're done.
while (acquire_sem(fAlertSem) == B_INTERRUPTED) {
}
}
// Have to cache the value since we delete on Quit()
password = fTextControl->Text();
if (Lock())
Quit();
}
void
PasswordAlert::MessageReceived(BMessage* msg)
{
if (msg->what != 'pass')
return BWindow::MessageReceived(msg);
delete_sem(fAlertSem);
fAlertSem = -1;
}
// #pragma mark - TAlertView
TAlertView::TAlertView(BRect frame)
:
BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
fIconBitmap(NULL)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
TAlertView::~TAlertView()
{
delete fIconBitmap;
}
void
TAlertView::Draw(BRect updateRect)
{
// Here's the fun stuff
if (fIconBitmap) {
BRect stripeRect = Bounds();
stripeRect.right = kIconStripeWidth;
SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
FillRect(stripeRect);
SetDrawingMode(B_OP_ALPHA);
DrawBitmapAsync(fIconBitmap, BPoint(18, 6));
SetDrawingMode(B_OP_COPY);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2003-2010 Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#ifndef _PASSWORDALERT_H
#define _PASSWORDALERT_H
#include <Bitmap.h>
#include <String.h>
#include <TextControl.h>
#include <Window.h>
class PasswordAlert : public BWindow
{
public:
PasswordAlert(const char* title,
const char* text);
virtual ~PasswordAlert();
void Go(BString &password);
virtual void MessageReceived(BMessage* msg);
private:
BBitmap* InitIcon();
BTextControl* fTextControl;
sem_id fAlertSem;
};
#endif // _PASSWORDALERT_H