diff --git a/src/apps/expander/ExpanderThread.cpp b/src/apps/expander/ExpanderThread.cpp index cffe2817ce..6ad90b563a 100644 --- a/src/apps/expander/ExpanderThread.cpp +++ b/src/apps/expander/ExpanderThread.cpp @@ -3,15 +3,20 @@ * Distributed under the terms of the MIT License. * Original code from ZipOMatic by jonas.sundstrom@kirilla.com */ -#include -#include #include "ExpanderThread.h" + +#include #include #include +#include #include -#include -const char * ExpanderThreadName = "ExpanderThread"; +#include +#include + + +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; } diff --git a/src/apps/expander/ExpanderThread.h b/src/apps/expander/ExpanderThread.h index 75d121917f..5b0c70c026 100644 --- a/src/apps/expander/ExpanderThread.h +++ b/src/apps/expander/ExpanderThread.h @@ -28,6 +28,7 @@ class ExpanderThread : public GenericThread status_t ResumeExternalExpander(); status_t InterruptExternalExpander(); status_t WaitOnExternalExpander(); + void PushInput(BString text); private: diff --git a/src/apps/expander/ExpanderWindow.cpp b/src/apps/expander/ExpanderWindow.cpp index b8b15b2ebc..2fd63bc681 100644 --- a/src/apps/expander/ExpanderWindow.cpp +++ b/src/apps/expander/ExpanderWindow.cpp @@ -5,14 +5,9 @@ */ -#include "ExpanderApp.h" #include "ExpanderWindow.h" -#include "ExpanderThread.h" -#include "ExpanderPreferences.h" - #include -#include #include #include #include @@ -32,6 +27,11 @@ #include #include +#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; } diff --git a/src/apps/expander/Jamfile b/src/apps/expander/Jamfile index 860359abcf..cd30f68ab8 100644 --- a/src/apps/expander/Jamfile +++ b/src/apps/expander/Jamfile @@ -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 ; diff --git a/src/apps/expander/PasswordAlert.cpp b/src/apps/expander/PasswordAlert.cpp new file mode 100644 index 0000000000..566172c1ec --- /dev/null +++ b/src/apps/expander/PasswordAlert.cpp @@ -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 + +#include +#include +#include +#include +#include +#include +#include + + +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(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); + } +} diff --git a/src/apps/expander/PasswordAlert.h b/src/apps/expander/PasswordAlert.h new file mode 100644 index 0000000000..35eadae2b3 --- /dev/null +++ b/src/apps/expander/PasswordAlert.h @@ -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 +#include +#include +#include + + +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 +