RetroZilla/xpinstall/wizard/unix/src2/nsInstallDlg.cpp
2015-10-20 23:03:22 -04:00

1483 lines
42 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Samir Gehani <sgehani@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSocket.h"
#include "nsHTTPConn.h"
#include "nsInstallDlg.h"
#include "nsXInstaller.h"
#include "nsXIEngine.h"
#include <signal.h>
#include <sys/wait.h>
#include <gtk/gtk.h>
#include <errno.h>
#define NUM_PS_ENTRIES 4
typedef struct _DLProgress
{
// progress widgets
GtkWidget *vbox;
GtkWidget *compName;
GtkWidget *URL;
GtkWidget *localPath;
GtkWidget *status;
GtkWidget *progBar;
// progress info
int downloadedBytes;
int totalKB;
}
DLProgress;
static char *sXPInstallEngine;
static nsRunApp *sRunAppList = NULL;
static nsRunApp *sPostInstallRun = NULL;
static DLProgress sDLProgress;
static GtkWidget *sDLTable = NULL;
static GtkWidget *sMsg0Label;
static GtkWidget *sMajorLabel;
static GtkWidget *sMinorLabel;
static GtkWidget *sRateLabel;
static GtkWidget *sMajorProgBar;
static GtkWidget *sMinorProgBar;
static GtkWidget *sPSTextEntry[NUM_PS_ENTRIES];
static int bDownload = FALSE;
static struct timeval sDLStartTime;
static int bDLPause = FALSE;
static int bDLCancel = FALSE;
nsInstallDlg::nsInstallDlg() :
mMsg0(NULL)
{
}
nsInstallDlg::~nsInstallDlg()
{
XI_IF_FREE(mMsg0);
}
void
nsInstallDlg::Back(GtkWidget *aWidget, gpointer aData)
{
DUMP("Back");
if (aData != gCtx->idlg) return;
#ifdef MOZ_WIDGET_GTK
if (gCtx->bMoving)
{
gCtx->bMoving = FALSE;
return;
}
#endif
// hide this notebook page
gCtx->idlg->Hide();
// show the last dlg
if (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1))
{
gCtx->cdlg->Show();
// only set bMoving for component dlg since setuptype has no "back"
#ifdef MOZ_WIDGET_GTK
gCtx->bMoving = TRUE;
#endif
}
else
{
gCtx->sdlg->Show();
}
}
void
nsInstallDlg::Next(GtkWidget *aWidget, gpointer aData)
{
DUMP("Next");
GtkWidget *pauseLabel, *resumeLabel;
if (aData != gCtx->idlg) return;
#ifdef MOZ_WIDGET_GTK
if (gCtx->bMoving)
{
gCtx->bMoving = FALSE;
DUMP("Moving done!");
return;
}
#endif
// initialize progress bar cleanly
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT) {
gtk_progress_set_activity_mode(GTK_PROGRESS(sMajorProgBar), FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMajorProgBar), (gfloat) 0);
gtk_label_set_text(GTK_LABEL(sMajorLabel), "");
if (bDownload)
{
InitDLProgress( TRUE );
pauseLabel = gtk_label_new(gCtx->Res("PAUSE"));
resumeLabel = gtk_label_new(gCtx->Res("RESUME"));
gtk_container_remove(GTK_CONTAINER(gCtx->back), gCtx->backLabel);
gtk_container_remove(GTK_CONTAINER(gCtx->next), gCtx->installLabel);
gtk_container_add(GTK_CONTAINER(gCtx->back), pauseLabel);
gtk_container_add(GTK_CONTAINER(gCtx->next), resumeLabel);
gtk_widget_show(pauseLabel);
gtk_widget_show(resumeLabel);
gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->cancel), gCtx->cancelID);
// disable resume button
gtk_widget_set_sensitive(gCtx->next, FALSE);
XI_GTK_UPDATE_UI();
// hook up buttons with callbacks
gCtx->backID = gtk_signal_connect(GTK_OBJECT(gCtx->back), "clicked",
GTK_SIGNAL_FUNC(DLPause), NULL);
gCtx->nextID = gtk_signal_connect(GTK_OBJECT(gCtx->next), "clicked",
GTK_SIGNAL_FUNC(DLResume), NULL);
gCtx->cancelID = gtk_signal_connect(GTK_OBJECT(gCtx->cancel), "clicked",
GTK_SIGNAL_FUNC(DLCancel), NULL);
}
else
{
gtk_widget_show(sMajorLabel);
gtk_widget_show(sMajorProgBar);
gtk_widget_hide(gCtx->back);
gtk_widget_hide(gCtx->next);
gtk_widget_hide(gCtx->cancel);
}
gtk_widget_hide(sMsg0Label);
if (bDownload && sDLTable)
gtk_widget_hide(sDLTable);
XI_GTK_UPDATE_UI();
}
PerformInstall();
while (bDLPause) {
// event loop ends with resume or cancel
gtk_main();
if (!bDLCancel)
PerformInstall();
}
// mode auto has no call to gtk_main()
if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
gtk_main_quit();
#ifdef MOZ_WIDGET_GTK
gCtx->bMoving = TRUE;
#endif
return;
}
int
nsInstallDlg::Parse(nsINIParser *aParser)
{
int err = OK;
int bufsize = 0;
char *showDlg = NULL;
char secName[64];
int i;
char *app = NULL, *args = NULL;
nsRunApp *newRunApp = NULL;
/* compulsory keys*/
XI_ERR_BAIL(aParser->GetStringAlloc(DLG_START_INSTALL,
XPINSTALL_ENGINE, &sXPInstallEngine, &bufsize));
if (bufsize == 0 || !sXPInstallEngine)
return E_INVALID_KEY;
/* optional keys */
bufsize = 0;
err = aParser->GetStringAlloc(DLG_START_INSTALL, MSG0, &mMsg0, &bufsize);
if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
bufsize = 5;
XI_ERR_BAIL(aParser->GetStringAlloc(DLG_START_INSTALL, SHOW_DLG,
&showDlg, &bufsize));
if (bufsize != 0 && showDlg)
{
if (0 == strncmp(showDlg, "TRUE", 4))
mShowDlg = nsXInstallerDlg::SHOW_DIALOG;
else if (0 == strncmp(showDlg, "FALSE", 5))
mShowDlg = nsXInstallerDlg::SKIP_DIALOG;
}
bufsize = 0;
XI_ERR_BAIL(aParser->GetStringAlloc(DLG_START_INSTALL, TITLE,
&mTitle, &bufsize));
if (bufsize == 0)
XI_IF_FREE(mTitle);
for (i = 0; err == OK; i++)
{
/* construct PostInstallRunX section name */
sprintf(secName, POSTINSTALLRUNd, i);
err = aParser->GetStringAlloc(secName, TARGET, &app, &bufsize);
if (err == OK && bufsize > 0)
{
/* "args" is optional: this may return E_NO_KEY which we ignore */
aParser->GetStringAlloc(secName, ARGS, &args, &bufsize);
newRunApp = new nsRunApp(app, args);
if (!newRunApp)
return E_MEM;
err = AppendRunApp(&sPostInstallRun, newRunApp);
}
}
err = OK; /* reset error since PostInstallRunX sections are optional
and we could have gotten a parse error (E_NO_SEC) */
for (i = 0; err == OK; i++)
{
/* construct RunAppX section name */
sprintf(secName, RUNAPPd, i);
err = aParser->GetStringAlloc(secName, TARGET, &app, &bufsize);
if (err == OK && bufsize > 0)
{
/* "args" is optional: this may return E_NO_KEY which we ignore */
aParser->GetStringAlloc(secName, ARGS, &args, &bufsize);
newRunApp = new nsRunApp(app, args);
if (!newRunApp)
return E_MEM;
err = AppendRunApp(&sRunAppList, newRunApp);
}
}
err = OK; /* reset error since RunAppX sections are optional
and we could have gotten a parse error (E_NO_SEC) */
BAIL:
return err;
}
int
nsInstallDlg::AppendRunApp(nsRunApp **aRunAppList, nsRunApp *aNewRunApp)
{
int err = OK;
nsRunApp *currRunApp = NULL, *nextRunApp = NULL;
/* param check */
if (!aNewRunApp)
return E_PARAM;
/* special case: list is empty */
if (!*aRunAppList)
{
*aRunAppList = aNewRunApp;
return OK;
}
/* list has at least one element */
currRunApp = *aRunAppList;
while (currRunApp)
{
if (!(nextRunApp = currRunApp->GetNext()))
{
currRunApp->SetNext(aNewRunApp);
break;
}
currRunApp = nextRunApp;
}
return err;
}
void
nsInstallDlg::FreeRunAppList(nsRunApp *aRunAppList)
{
nsRunApp *currRunApp = aRunAppList, *nextRunApp = NULL;
while (currRunApp)
{
nextRunApp = currRunApp->GetNext();
delete currRunApp;
currRunApp = nextRunApp;
}
}
void
nsInstallDlg::RunApps(nsRunApp *aRunAppList, int aSequential)
{
nsRunApp *currRunApp = aRunAppList;
char *argv[3], *dest;
char apppath[MAXPATHLEN];
extern NS_IMPORT_(char **) environ; /* globally available to all processes */
dest = gCtx->opt->mDestination;
if (chdir(dest) < 0)
fprintf(stderr,"chdir(%s): %s\n",dest,strerror(errno));
while (currRunApp)
{
/* run application with supplied args */
sprintf(apppath, "%s/%s", dest, currRunApp->GetApp());
argv[0] = apppath;
argv[1] = currRunApp->GetArgs();
argv[2] = NULL; /* null-terminate arg vector */
if (!fork())
{
/* child */
execve(apppath, argv, environ);
/* shouldn't reach this but in case execve fails we will */
_exit(0);
}
/* parent continues running to finish installation */
if (aSequential)
{
wait(NULL);
}
currRunApp = currRunApp->GetNext();
}
}
int
nsInstallDlg::Show()
{
int err = OK;
GtkWidget *hbox = NULL;
GtkWidget *vbox = NULL;
GtkWidget *dlFrame, *dlCheckbox, *dlProxyBtn;
int bCus;
nsComponentList *comps = NULL;
XI_VERIFY(gCtx);
XI_VERIFY(gCtx->notebook);
if (mWidgetsInit == FALSE)
{
// create a new table and add it as a page of the notebook
mTable = gtk_table_new(4, 1, FALSE);
gtk_notebook_append_page(GTK_NOTEBOOK(gCtx->notebook), mTable, NULL);
mPageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(gCtx->notebook));
gtk_widget_show(mTable);
// insert a static text widget in the first row
sMsg0Label = gtk_label_new(mMsg0);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), sMsg0Label, FALSE, FALSE, 0);
gtk_widget_show(hbox);
gtk_table_attach(GTK_TABLE(mTable), hbox, 0, 1, 0, 1,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GTK_FILL, 20, 20);
gtk_widget_show(sMsg0Label);
// Proxy Settings
// insert a [ x ] heterogenous table
sDLTable = gtk_table_new(2, 2, FALSE);
gtk_table_attach(GTK_TABLE(mTable), sDLTable, 0, 1, 1, 4,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GTK_FILL, 20, 20);
// download settings groupbox
dlFrame = gtk_frame_new(gCtx->Res("DL_SETTINGS"));
gtk_table_attach_defaults(GTK_TABLE(sDLTable), dlFrame, 0, 2, 0, 2);
gtk_widget_show(dlFrame);
// save installer modules checkbox and label
dlCheckbox = gtk_check_button_new_with_label(
gCtx->Res("SAVE_MODULES"));
gtk_widget_show(dlCheckbox);
gtk_table_attach(GTK_TABLE(sDLTable), dlCheckbox, 0, 2, 0, 1,
GTK_FILL, GTK_FILL, 10, 20);
gtk_signal_connect(GTK_OBJECT(dlCheckbox), "toggled",
GTK_SIGNAL_FUNC(SaveModulesToggled), NULL);
// proxy settings button
dlProxyBtn = gtk_button_new_with_label(gCtx->Res("PROXY_SETTINGS"));
gtk_widget_show(dlProxyBtn);
gtk_table_attach(GTK_TABLE(sDLTable), dlProxyBtn, 0, 1, 1, 2,
GTK_FILL, GTK_FILL, 10, 10);
gtk_signal_connect(GTK_OBJECT(dlProxyBtn), "clicked",
GTK_SIGNAL_FUNC(ShowProxySettings), NULL);
// vbox with two widgets packed in: label0 / progmeter0 (major)
vbox = gtk_vbox_new(FALSE, 0);
hbox = gtk_hbox_new(FALSE, 0);
sMajorLabel = gtk_label_new("");
sRateLabel = gtk_label_new("");
gtk_box_pack_start(GTK_BOX(hbox), sMajorLabel, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), sRateLabel, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
gtk_widget_show(sMajorLabel);
gtk_widget_show(sRateLabel);
sMajorProgBar = gtk_progress_bar_new();
gtk_box_pack_start(GTK_BOX(vbox), sMajorProgBar, FALSE, FALSE, 0);
// gtk_widget_show(sMajorProgBar);
gtk_table_attach(GTK_TABLE(mTable), vbox, 0, 1, 2, 3,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GTK_FILL, 20, 20);
gtk_widget_show(vbox);
// vbox with two widgets packed in: label1 / progmeter1 (minor)
vbox = gtk_vbox_new(FALSE, 0);
hbox = gtk_hbox_new(FALSE, 0);
sMinorLabel = gtk_label_new("");
gtk_box_pack_start(GTK_BOX(hbox), sMinorLabel, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
gtk_widget_show(sMinorLabel);
sMinorProgBar = gtk_progress_bar_new();
gtk_box_pack_start(GTK_BOX(vbox), sMinorProgBar, FALSE, FALSE, 0);
// gtk_widget_show(sMinorProgBar);
gtk_table_attach(GTK_TABLE(mTable), vbox, 0, 1, 3, 4,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
GTK_FILL, 20, 20);
gtk_widget_show(vbox);
mWidgetsInit = TRUE;
}
else
{
gtk_notebook_set_page(GTK_NOTEBOOK(gCtx->notebook), mPageNum);
gtk_widget_show(mTable);
}
bCus = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
if (!nsXIEngine::ExistAllXPIs(bCus, comps))
{
bDownload = TRUE;
gtk_widget_show(sDLTable);
}
else
{
bDownload = FALSE;
}
// signal connect the buttons
gCtx->backID = gtk_signal_connect(GTK_OBJECT(gCtx->back), "clicked",
GTK_SIGNAL_FUNC(nsInstallDlg::Back), gCtx->idlg);
gCtx->nextID = gtk_signal_connect(GTK_OBJECT(gCtx->next), "clicked",
GTK_SIGNAL_FUNC(nsInstallDlg::Next), gCtx->idlg);
if (gCtx->opt->mSetupType != (gCtx->sdlg->GetNumSetupTypes() - 1))
{
// show back btn again after setup type dlg where we couldn't go back
gtk_widget_show(gCtx->back);
}
GTK_WIDGET_SET_FLAGS(gCtx->next, GTK_CAN_DEFAULT);
gtk_widget_grab_default(gCtx->next);
gtk_widget_grab_focus(gCtx->next);
// show back and next button, but make title of next button "Install"
gCtx->backLabel = gtk_label_new(gCtx->Res("BACK"));
gCtx->installLabel = gtk_label_new(gCtx->Res("INSTALL"));
gtk_container_add(GTK_CONTAINER(gCtx->back), gCtx->backLabel);
gtk_container_add(GTK_CONTAINER(gCtx->next), gCtx->installLabel);
gtk_widget_show(gCtx->backLabel);
gtk_widget_show(gCtx->installLabel);
gtk_widget_show(gCtx->back);
gtk_widget_show(gCtx->next);
if (!mShowDlg)
{
gCtx->bMoving = FALSE;
nsInstallDlg::Next((GtkWidget *)NULL, gCtx->idlg);
return err;
}
return err;
}
int
nsInstallDlg::Hide()
{
if (bDownload && sDLTable)
gtk_widget_hide(sDLTable);
gtk_widget_hide(mTable);
// disconnect and remove this dlg's nav btns
gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
gtk_container_remove(GTK_CONTAINER(gCtx->back), gCtx->backLabel);
gtk_container_remove(GTK_CONTAINER(gCtx->next), gCtx->installLabel);
gtk_widget_hide(gCtx->back);
gtk_widget_hide(gCtx->next);
return OK;
}
int
nsInstallDlg::ShowTable()
{
if (!mTable)
return E_PARAM;
gtk_widget_show(mTable);
return OK;
}
int
nsInstallDlg::HideTable()
{
if (!mTable)
return E_PARAM;
gtk_widget_hide(mTable);
return OK;
}
int
nsInstallDlg::SetMsg0(char *aMsg)
{
if (!aMsg)
return E_PARAM;
mMsg0 = aMsg;
return OK;
}
char *
nsInstallDlg::GetMsg0()
{
if (mMsg0)
return mMsg0;
return NULL;
}
int
nsInstallDlg::PerformInstall()
{
DUMP("PerformInstall");
int err = OK;
// perform the installation
nsXIEngine *engine = new nsXIEngine();
if (!engine)
{
ErrorHandler(E_MEM);
return E_MEM;
}
// get the component list for the current setup type
nsComponentList *comps = NULL;
nsComponent *xpiengine = NULL;
int bCus = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
if (!sXPInstallEngine) return E_PARAM;
xpiengine = comps->GetCompByArchive(sXPInstallEngine);
// 1> download
if (bDownload)
{
err = engine->Download(bCus, comps);
if (err == E_DL_DROP_CXN)
{
ShowCxnDroppedDlg();
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
DLPause(NULL, NULL);
return err;
}
else if (err == E_CRC_FAILED)
{
ErrorHandler(err);
goto BAIL;
}
else if (err == E_DL_PAUSE || err == E_DL_CANCEL)
{
DUMP("Pause or Cancel pressed");
goto BAIL;
}
else if (err != OK)
{
DUMP("dammit... hopped into the wrong hole!");
ErrorHandler(err);
goto BAIL;
}
}
// prepare install UI
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
{
InitInstallProgress();
HideNavButtons();
}
// 2> extract engine
XI_ERR_BAIL(engine->Extract(xpiengine));
// 3> install .xpis
XI_ERR_BAIL(engine->Install(bCus, comps, gCtx->opt->mDestination));
// delete xpis if user didn't request saving them
if (bDownload && !gCtx->opt->mSaveModules)
{
engine->DeleteXPIs(bCus, comps);
}
// destroy installer engine thread object
XI_IF_DELETE(engine);
// run post-install applications to complete installation
if (sPostInstallRun)
{
if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
MajorProgressCB("", 1, 1, ACT_COMPLETE);
RunApps(sPostInstallRun, 1);
FreeRunAppList(sPostInstallRun);
}
// run all specified applications after installation
if (sRunAppList)
{
if (gCtx->opt->mShouldRunApps)
RunApps(sRunAppList, 0);
FreeRunAppList(sRunAppList);
}
return OK;
BAIL:
// destroy installer engine thread object
XI_IF_DELETE(engine);
return err;
}
void
nsInstallDlg::XPIProgressCB(const char *aMsg, int aVal, int aMax)
{
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT)
return;
// DUMP("XPIProgressCB");
if (!aMsg)
return;
static int updates = 0;
char msg[64];
const char *colon = NULL, *lastSlash = NULL;
if (aMax > 0)
{
// reset for next component
if (updates)
updates = 0;
gfloat percent = (gfloat)((gfloat)aVal/(gfloat)aMax);
#if 0
printf("progress percent: %f\taVal: %d\taMax: %d\n", percent, aVal, aMax);
#endif
gtk_progress_set_activity_mode(GTK_PROGRESS(sMinorProgBar), FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMinorProgBar), percent);
gtk_widget_show(sMinorProgBar);
sprintf(msg, gCtx->Res("PROCESSING_FILE"), aVal, aMax);
}
else
{
updates++;
if (updates > 5)
updates = 0;
gfloat percent = (gfloat)((gfloat)updates/(gfloat)5);
gtk_progress_set_activity_mode(GTK_PROGRESS(sMinorProgBar), TRUE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMinorProgBar), percent);
gtk_widget_show(sMinorProgBar);
/* tack on XPInstall action */
memset(msg, 0, 64);
colon = strchr(aMsg, ':');
if (colon)
strncpy(msg, aMsg, colon - aMsg);
strncat(msg, " ", 1);
/* tack on leaf name */
lastSlash = strrchr(aMsg, '/');
if (lastSlash)
strncat(msg, lastSlash + 1, strlen(lastSlash) - 1);
strncat(msg, "\0", 1);
}
gtk_label_set_text(GTK_LABEL(sMinorLabel), msg);
gtk_widget_draw(sMinorLabel, NULL);
XI_GTK_UPDATE_UI();
}
void
nsInstallDlg::MajorProgressCB(char *aName, int aNum, int aTotal, int aActivity)
{
// DUMP("MajorProgressCB");
char msg[256];
if (!aName)
return;
#ifdef DEBUG
printf("%s %d: Name = %s\tNum = %d\tTotal = %d\tAct = %d\n",
__FILE__, __LINE__, aName, aNum, aTotal, aActivity);
#endif
switch (aActivity)
{
case ACT_DOWNLOAD:
if (!bDownload)
sprintf(msg, gCtx->Res("PREPARING"), aName);
break;
case ACT_EXTRACT:
sprintf(msg, gCtx->Res("EXTRACTING"), aName);
break;
case ACT_INSTALL:
sprintf(msg, gCtx->Res("INSTALLING_XPI"), aName);
break;
case ACT_COMPLETE:
sprintf(msg, gCtx->Res("COMPLETING_INSTALL"));
break;
default:
break;
}
gtk_label_set_text(GTK_LABEL(sMajorLabel), msg);
gtk_widget_show(sMajorLabel);
if (aTotal <= 0)
{
XI_ASSERT(0, "aTotal was <= 0");
XI_GTK_UPDATE_UI();
return;
}
gfloat percent = (gfloat)((gfloat)aNum/(gfloat)aTotal);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMajorProgBar), percent);
gtk_widget_show(sMajorProgBar);
// reset minor progress ui
if (aActivity == ACT_INSTALL)
{
gtk_label_set_text(GTK_LABEL(sMinorLabel), "");
gtk_progress_bar_update(GTK_PROGRESS_BAR(sMinorProgBar), (gfloat)0);
gtk_widget_show(sMinorLabel);
gtk_widget_show(sMinorProgBar);
}
else if (aActivity == ACT_COMPLETE)
gtk_label_set_text(GTK_LABEL(sMinorLabel), "");
XI_GTK_UPDATE_UI();
}
const int kCharsInDLLabel = 50;
void
nsInstallDlg::SetDownloadComp(nsComponent *aComp, int aURLIndex,
int aNum, int aTotal)
{
static char xpiDir[MAXPATHLEN];
static int bHaveXPIDir = FALSE;
char label[MAXPATHLEN];
char localPath[MAXPATHLEN];
if (!aComp)
return;
if (!bHaveXPIDir)
{
getcwd(xpiDir, MAXPATHLEN);
strcat(xpiDir, "/xpi");
bHaveXPIDir = TRUE;
}
// update comp name
sprintf(label, "%s [%d/%d]", aComp->GetDescShort(), aNum, aTotal);
gtk_label_set_text(GTK_LABEL(sDLProgress.compName), label);
// update from URL
label[0] = 0;
CompressToFit(aComp->GetURL(aURLIndex), label, kCharsInDLLabel);
gtk_label_set_text(GTK_LABEL(sDLProgress.URL), label);
// to local path
label[0] = 0;
sprintf(localPath, "%s/%s", xpiDir, aComp->GetArchive());
CompressToFit(localPath, label, kCharsInDLLabel);
gtk_label_set_text(GTK_LABEL(sDLProgress.localPath), label);
gettimeofday(&sDLStartTime, NULL);
}
#define SHOW_EVERY_N_KB 16
int
nsInstallDlg::DownloadCB(int aBytesRd, int aTotal)
{
struct timeval now;
char label[64];
int rate;
gfloat percent = 0;
static int timesCalled = 0;
static int activityCount = 0;
int dlKB;
static int lastTotal = 0;
static int lastBytesRd = 0;
// new component being downloaded
if (lastTotal != aTotal)
{
lastBytesRd = 0; // reset
lastTotal = aTotal;
}
if ((aBytesRd - lastBytesRd) > 0)
{
sDLProgress.downloadedBytes += aBytesRd - lastBytesRd;
lastBytesRd = aBytesRd;
}
if (bDLPause || bDLCancel)
{
return nsHTTPConn::E_USER_CANCEL;
}
if (++timesCalled < SHOW_EVERY_N_KB)
return 0;
else
timesCalled = 0;
gettimeofday(&now, NULL);
rate = (int) nsSocket::CalcRate(&sDLStartTime, &now, aBytesRd);
// update the status -- bytes thus far, rate, percent in prog bar
dlKB = sDLProgress.downloadedBytes/1024;
sprintf(label, gCtx->Res("DL_STATUS_STR"), dlKB, sDLProgress.totalKB, rate);
gtk_label_set_text(GTK_LABEL(sDLProgress.status), label);
/*
// only update rate in major label line
XXX remove this: DLRATE no longer exists
sprintf(label, gCtx->Res("DLRATE"), rate);
gtk_label_set_text(GTK_LABEL(sRateLabel), label);
*/
if (sDLProgress.totalKB <= 0)
{
// show some activity
if (activityCount >= 5) activityCount = 0;
percent = (gfloat)( (gfloat)activityCount++/ (gfloat)5 );
gtk_progress_set_activity_mode(GTK_PROGRESS(sDLProgress.progBar), TRUE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sDLProgress.progBar), percent);
}
else
{
percent = (gfloat)dlKB/(gfloat)sDLProgress.totalKB;
#ifdef DEBUG
printf("DLProgress: %d of %d (%f percent) at %d KB/sec\n", dlKB,
sDLProgress.totalKB, percent, rate);
#endif
gtk_progress_set_activity_mode(GTK_PROGRESS(sDLProgress.progBar),
FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sDLProgress.progBar), percent);
}
XI_GTK_UPDATE_UI();
return 0;
}
void
nsInstallDlg::ClearRateLabel()
{
gtk_label_set_text(GTK_LABEL(sRateLabel), "");
gtk_progress_set_activity_mode(GTK_PROGRESS(sMajorProgBar), FALSE);
XI_GTK_UPDATE_UI();
}
void
nsInstallDlg::SaveModulesToggled(GtkWidget *aWidget, gpointer aData)
{
if (GTK_TOGGLE_BUTTON(aWidget)->active)
{
DUMP("Save modules toggled on");
gCtx->opt->mSaveModules = TRUE;
}
else
{
DUMP("Save modules toggled off");
gCtx->opt->mSaveModules = FALSE;
}
}
void
nsInstallDlg::ShowProxySettings(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *psDlg, *psTable;
GtkWidget *okButton, *cancelButton;
GtkWidget *psLabel[NUM_PS_ENTRIES];
int i;
char resName[16], *text = nsnull;
psDlg = gtk_dialog_new();
gtk_window_set_modal(GTK_WINDOW(psDlg), TRUE);
gtk_window_set_title(GTK_WINDOW(psDlg), gCtx->opt->mTitle);
gtk_window_set_position(GTK_WINDOW(psDlg), GTK_WIN_POS_CENTER);
psTable = gtk_table_new(5, 2, FALSE);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(psDlg)->vbox), psTable);
gtk_widget_show(psTable);
// create labels
for (i = 0; i < NUM_PS_ENTRIES; ++i)
{
sprintf(resName, "PS_LABEL%d", i);
psLabel[i] = gtk_label_new(gCtx->Res(resName));
gtk_widget_show(psLabel[i]);
gtk_misc_set_alignment(GTK_MISC(psLabel[i]), 1, 0.5);
gtk_table_attach(GTK_TABLE(psTable), psLabel[i], 0, 1, i, i + 1,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), 5, 5);
}
// create text entry fields
for (i = 0; i < NUM_PS_ENTRIES; ++i)
{
sPSTextEntry[i] = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(sPSTextEntry[i]), TRUE);
// reset text if we already opened this dlg before
if (i == 0) text = gCtx->opt->mProxyHost;
if (i == 1) text = gCtx->opt->mProxyPort;
if (i == 2) text = gCtx->opt->mProxyUser;
if (i == 3) text = gCtx->opt->mProxyPswd;
if (text)
gtk_entry_set_text(GTK_ENTRY(sPSTextEntry[i]), text);
// password field
if (i + 1 == NUM_PS_ENTRIES)
gtk_entry_set_visibility(GTK_ENTRY(sPSTextEntry[i]), FALSE);
gtk_widget_show(sPSTextEntry[i]);
gtk_table_attach(GTK_TABLE(psTable), sPSTextEntry[i],
1, 2, i, i + 1,
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), 5, 5);
}
// pre-populate text entry fields if data already stored
okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(psDlg)->action_area),
okButton);
gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
GTK_SIGNAL_FUNC(PSDlgOK), psDlg);
GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
gtk_widget_grab_default(okButton);
gtk_widget_show(okButton);
cancelButton = gtk_button_new_with_label(gCtx->Res("CANCEL_LABEL"));
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(psDlg)->action_area),
cancelButton);
gtk_signal_connect(GTK_OBJECT(cancelButton), "clicked",
GTK_SIGNAL_FUNC(PSDlgCancel), psDlg);
gtk_widget_show(cancelButton);
gtk_widget_show(psDlg);
}
void
nsInstallDlg::PSDlgOK(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *dlg = (GtkWidget *) aData;
char *text;
char *proxyHost=NULL, *proxyPort=NULL, *proxyUser=NULL, *proxyPswd=NULL;
// grab proxy host field
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[0]), 0, -1);
if (text && *text)
proxyHost = text;
else
XI_IF_FREE(text);
// grab proxy port field
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[1]), 0, -1);
if (text && *text)
proxyPort = text;
else
XI_IF_FREE(text);
// grab proxy user field
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[2]), 0, -1);
if (text && *text)
proxyUser = text;
else
XI_IF_FREE(text);
// grab proxy pswd field
text = gtk_editable_get_chars(GTK_EDITABLE(sPSTextEntry[3]), 0, -1);
if (text && *text)
proxyPswd = text;
else
XI_IF_FREE(text);
if ( (proxyHost || proxyPort || proxyUser || proxyPswd)
&& (!proxyHost || !proxyPort) )
{
XI_IF_FREE(proxyHost);
XI_IF_FREE(proxyPort);
XI_IF_FREE(proxyUser);
XI_IF_FREE(proxyPswd);
ErrorHandler(E_INVALID_PROXY);
}
else
{
XI_IF_FREE(gCtx->opt->mProxyHost);
XI_IF_FREE(gCtx->opt->mProxyPort);
XI_IF_FREE(gCtx->opt->mProxyUser);
XI_IF_FREE(gCtx->opt->mProxyPswd);
gCtx->opt->mProxyHost = proxyHost;
gCtx->opt->mProxyPort = proxyPort;
gCtx->opt->mProxyUser = proxyUser;
gCtx->opt->mProxyPswd = proxyPswd;
gtk_widget_destroy(dlg);
}
}
void
nsInstallDlg::PSDlgCancel(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *dlg = (GtkWidget *) aData;
if (dlg)
gtk_widget_destroy(dlg);
}
void
nsInstallDlg::DLPause(GtkWidget *aWidget, gpointer aData)
{
DUMP("DLPause");
// set pause for download callback to return to libxpnet
bDLPause = TRUE;
// disbale pause button
gtk_widget_set_sensitive(gCtx->back, FALSE);
// enable resume button
gtk_widget_set_sensitive(gCtx->next, TRUE);
}
void
nsInstallDlg::DLResume(GtkWidget *aWidget, gpointer aData)
{
DUMP("DLResume");
if (!bDLPause)
{
DUMP("Not paused");
return;
}
DUMP("Unsetting bDLPause");
bDLPause = FALSE;
// disable resume button
gtk_widget_set_sensitive(gCtx->next, FALSE);
// enable pause button
gtk_widget_set_sensitive(gCtx->back, TRUE);
gtk_main_quit();
}
void
nsInstallDlg::DLCancel(GtkWidget *aWidget, gpointer aData)
{
DUMP("DLCancel");
// show cancellation confirm dialog
// XXX TO DO
// set cancel for download callback to return to libxpnet
bDLCancel = TRUE;
#ifdef DEBUG
printf("%s %d: bDLPause: %d\tbDLCancel: %d\n", __FILE__, __LINE__,
bDLPause, bDLCancel);
#endif
// already paused then take explicit action to quit
if (bDLPause)
{
bDLPause = FALSE;
gtk_main_quit();
}
}
int
nsInstallDlg::CancelOrPause()
{
int err = OK;
if (bDLPause)
{
err = E_DL_PAUSE;
}
else if (bDLCancel)
{
err = E_DL_CANCEL;
}
return err;
}
static GtkWidget *crcDlg = (GtkWidget *) NULL;
void
nsInstallDlg::ShowCRCDlg()
{
GtkWidget *label, *okButton;
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT) {
ErrorHandler(E_CRC_FAILED);
return;
}
if ( crcDlg == (GtkWidget *) NULL ) {
// throw up dialog informing user to press resume
// or to cancel out
crcDlg = gtk_dialog_new();
gtk_window_set_modal(GTK_WINDOW(crcDlg), TRUE);
label = gtk_label_new(gCtx->Res("CRC_CHECK"));
okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
if (crcDlg && label && okButton )
{
gtk_misc_set_padding(GTK_MISC(label), 20, 20);
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 1);
gtk_window_set_title(GTK_WINDOW(crcDlg), gCtx->opt->mTitle);
gtk_window_set_position(GTK_WINDOW(crcDlg), GTK_WIN_POS_CENTER);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(crcDlg)->vbox),
label);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(crcDlg)->action_area),
okButton);
gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
GTK_SIGNAL_FUNC(CRCOKCb), crcDlg);
GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
gtk_widget_grab_default(okButton);
gtk_widget_show_all(crcDlg);
}
}
XI_GTK_UPDATE_UI();
}
int
nsInstallDlg::ShowCxnDroppedDlg()
{
GtkWidget *cxnDroppedDlg, *label, *okButton;
// throw up dialog informing user to press resume
// or to cancel out
if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT) {
ErrorHandler(E_NO_DOWNLOAD);
return OK;
}
cxnDroppedDlg = gtk_dialog_new();
gtk_window_set_modal(GTK_WINDOW(cxnDroppedDlg), TRUE);
label = gtk_label_new(gCtx->Res("CXN_DROPPED"));
okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
if (cxnDroppedDlg && label && okButton )
{
gtk_misc_set_padding(GTK_MISC(label), 20, 20);
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 1);
gtk_window_set_modal(GTK_WINDOW(cxnDroppedDlg), TRUE);
gtk_window_set_title(GTK_WINDOW(cxnDroppedDlg), gCtx->opt->mTitle);
gtk_window_set_position(GTK_WINDOW(cxnDroppedDlg), GTK_WIN_POS_CENTER);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(cxnDroppedDlg)->vbox),
label);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(cxnDroppedDlg)->action_area),
okButton);
gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
GTK_SIGNAL_FUNC(CxnDroppedOK), cxnDroppedDlg);
GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
gtk_widget_grab_default(okButton);
gtk_widget_show_all(cxnDroppedDlg);
}
XI_GTK_UPDATE_UI();
return OK;
}
void
nsInstallDlg::DestroyCRCDlg()
{
CRCOKCb( (GtkWidget *) NULL, (gpointer) NULL );
}
void
nsInstallDlg::CRCOKCb(GtkWidget *aWidget, gpointer aData)
{
if (crcDlg != (GtkWidget *) NULL)
gtk_widget_destroy(crcDlg);
crcDlg = (GtkWidget *) NULL;
return;
}
void
nsInstallDlg::CxnDroppedOK(GtkWidget *aWidget, gpointer aData)
{
GtkWidget *cxnDroppedDlg = (GtkWidget *) aData;
if (cxnDroppedDlg)
gtk_widget_destroy(cxnDroppedDlg);
return;
}
void
nsInstallDlg::HideNavButtons()
{
gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
gtk_signal_disconnect(GTK_OBJECT(gCtx->cancel), gCtx->cancelID);
gtk_widget_hide(gCtx->back);
gtk_widget_hide(gCtx->next);
gtk_widget_hide(gCtx->cancel);
}
void
nsInstallDlg::InitDLProgress( int isFirst )
{
GtkWidget *titles[4];
GtkWidget *hbox;
GtkWidget *table;
gCtx->idlg->HideTable();
if ( isFirst == TRUE ) {
sDLProgress.vbox = gtk_vbox_new(FALSE, 10);
gtk_notebook_append_page(GTK_NOTEBOOK(gCtx->notebook),
sDLProgress.vbox, NULL);
gtk_widget_show(sDLProgress.vbox);
table = gtk_table_new(5, 2, FALSE);
gtk_box_pack_start(GTK_BOX(sDLProgress.vbox), table, FALSE,
FALSE, 0);
gtk_widget_show(table);
// setup static title progress labels in table left column
titles[0] = gtk_label_new(gCtx->Res("DOWNLOADING"));
titles[1] = gtk_label_new(gCtx->Res("FROM"));
titles[2] = gtk_label_new(gCtx->Res("TO"));
titles[3] = gtk_label_new(gCtx->Res("STATUS"));
// setup dynamic progress labels in right column
sDLProgress.compName = gtk_label_new(gCtx->Res("UNKNOWN"));
sDLProgress.URL = gtk_label_new(gCtx->Res("UNKNOWN"));
sDLProgress.localPath = gtk_label_new(gCtx->Res("UNKNOWN"));
sDLProgress.status = gtk_label_new(gCtx->Res("UNKNOWN"));
// pack and show titles
for (int i = 0; i < 4; ++i)
{
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_end(GTK_BOX(hbox), titles[i], FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox,
0, 1, i, i + 1, GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(titles[i]);
gtk_widget_show(hbox);
}
// pack and show dynamic labels
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.compName, FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 0, 1,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.compName);
gtk_widget_show(hbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.URL, FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 1, 2,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.URL);
gtk_widget_show(hbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.localPath, FALSE,
FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 2, 3,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.localPath);
gtk_widget_show(hbox);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.status, FALSE,
FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 3, 4,
GTK_FILL, GTK_FILL, 5, 5);
gtk_widget_show(sDLProgress.status);
gtk_widget_show(hbox);
// init and show prog bar
sDLProgress.progBar = gtk_progress_bar_new();
// show prog bar
hbox = gtk_hbox_new(TRUE, 10);
gtk_box_pack_start(GTK_BOX(hbox), sDLProgress.progBar, FALSE,
TRUE, 0);
gtk_box_pack_start(GTK_BOX(sDLProgress.vbox), hbox, FALSE,
FALSE, 0);
gtk_widget_show(sDLProgress.progBar);
gtk_widget_show(hbox);
}
// set to non-activity mode and initialize
gtk_progress_set_activity_mode(GTK_PROGRESS(sDLProgress.progBar), FALSE);
gtk_progress_bar_update(GTK_PROGRESS_BAR(sDLProgress.progBar), (gfloat) 0);
// compute total download size
sDLProgress.downloadedBytes = 0;
sDLProgress.totalKB = TotalDLSize();
XI_GTK_UPDATE_UI();
}
void
nsInstallDlg::InitInstallProgress()
{
if ( sDLProgress.vbox )
gtk_widget_hide(sDLProgress.vbox);
gCtx->idlg->ShowTable();
}
int
nsInstallDlg::TotalDLSize()
{
int total = 0; // in KB
int bCustom;
nsComponentList *comps;
nsComponent *currComp;
int archiveSize, currentSize;
bCustom = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
currComp = comps->GetHead();
// loop through all components
while (currComp)
{
if ((bCustom && currComp->IsSelected()) || (!bCustom))
{
// if still have to download
if (!currComp->IsDownloaded())
{
// find archive size - amount downloaded already
archiveSize = currComp->GetArchiveSize();
currentSize = currComp->GetCurrentSize();
#ifdef DEBUG
printf("%s ar sz = %d cu sz = %d\n", currComp->GetArchive(),
archiveSize, currentSize);
#endif
total += (archiveSize - currentSize);
}
}
currComp = comps->GetNext();
}
return total;
}
void
nsInstallDlg::CompressToFit(char *aOrigStr, char *aOutStr, int aOutStrLen)
{
int origStrLen;
int halfOutStrLen;
char *lastPart; // last aOrigStr part start
if (!aOrigStr || !aOutStr || aOutStrLen <= 0)
return;
origStrLen = strlen(aOrigStr);
halfOutStrLen = (aOutStrLen/2) - 2; // minus 2 since ellipsis is 3 chars
lastPart = aOrigStr + origStrLen - halfOutStrLen;
strncpy(aOutStr, aOrigStr, halfOutStrLen);
*(aOutStr + halfOutStrLen) = 0;
strcat(aOutStr, "...");
strncat(aOutStr, lastPart, strlen(lastPart));
*(aOutStr + aOutStrLen + 1) = 0;
}
void
nsInstallDlg::ReInitUI( void )
{
InitDLProgress( FALSE );
}