Back to index

lightning-sunbird  0.9+nobinonly
nsSetupTypeDlg.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nscore.h"
00041 #include "nsSetupTypeDlg.h"
00042 #include "nsXInstaller.h"
00043 
00044 
00045 // need these for statfs 
00046 
00047 #ifdef HAVE_SYS_STATVFS_H
00048 #include <sys/statvfs.h>
00049 #endif
00050 
00051 #ifdef HAVE_SYS_STATFS_H
00052 #include <sys/statfs.h>
00053 #endif
00054 
00055 #ifdef HAVE_STATVFS
00056 #define STATFS statvfs
00057 #else
00058 #define STATFS statfs
00059 #endif
00060 
00061 
00062 static GtkWidget        *sBrowseBtn;
00063 static gint             sBrowseBtnID;
00064 static GtkWidget        *sFolder;
00065 static int              sFilePickerUp = FALSE;
00066 
00067 nsSetupTypeDlg::nsSetupTypeDlg() :
00068     mBox(NULL),
00069     mExistingMsg(NULL),
00070     mMsg0(NULL),
00071     mSetupTypeList(NULL)
00072 {
00073 }
00074 
00075 nsSetupTypeDlg::~nsSetupTypeDlg()
00076 {
00077     FreeSetupTypeList();
00078 
00079     XI_IF_FREE(mMsg0);
00080     XI_IF_FREE(mExistingMsg);
00081 }
00082 
00083 void
00084 nsSetupTypeDlg::Back(GtkWidget *aWidget, gpointer aData)
00085 {
00086     DUMP("Back");
00087     if (aData != gCtx->sdlg) return;
00088 
00089     // hide this notebook page
00090     gCtx->sdlg->Hide(nsXInstallerDlg::BACKWARD_MOVE);
00091 
00092     // disconnect this dlg's nav btn signal handlers
00093     gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
00094     gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
00095     gtk_signal_disconnect(GTK_OBJECT(sBrowseBtn), sBrowseBtnID);
00096 
00097     // show the next dlg
00098     gCtx->ldlg->Show(nsXInstallerDlg::BACKWARD_MOVE);
00099 }
00100 
00101 void 
00102 nsSetupTypeDlg::Next(GtkWidget *aWidget, gpointer aData)
00103 {
00104     DUMP("Next");
00105     if (aData != gCtx->sdlg) return;
00106 
00107     GSList *s = gCtx->sdlg->mRadioGroup;
00108     gCtx->opt->mSetupType = 0;
00109     while (s) {
00110       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->data)))
00111         break;
00112 
00113       ++gCtx->opt->mSetupType;
00114       s = s->next;
00115     }
00116 
00117     // verify selected destination directory exists
00118     if (OK != nsSetupTypeDlg::VerifyDestination())
00119         return;
00120 
00121     // old installation may exist: delete it
00122     if (OK != nsSetupTypeDlg::DeleteOldInst())
00123         return;
00124 
00125     // if not custom setup type verify disk space
00126     if (gCtx->opt->mSetupType != (gCtx->sdlg->GetNumSetupTypes() - 1))
00127     {
00128         if (OK != nsSetupTypeDlg::VerifyDiskSpace())
00129             return;
00130     }
00131 
00132     // hide this notebook page
00133     gCtx->sdlg->Hide(nsXInstallerDlg::FORWARD_MOVE);
00134 
00135     // disconnect this dlg's nav btn signal handlers
00136     gtk_signal_disconnect(GTK_OBJECT(gCtx->back), gCtx->backID);
00137     gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
00138     gtk_signal_disconnect(GTK_OBJECT(sBrowseBtn), sBrowseBtnID);
00139 
00140     // show the last dlg
00141     if (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1))
00142         gCtx->cdlg->Show(nsXInstallerDlg::FORWARD_MOVE);
00143     else
00144         gCtx->idlg->Show(nsXInstallerDlg::FORWARD_MOVE);
00145 }
00146 
00147 nsComponent*
00148 nsSetupTypeDlg::ParseComponent(nsINIParser *aParser, char *aCompName)
00149 {
00150   char *descShort = NULL, *descLong = NULL, *archive = NULL,
00151     *installSize = NULL, *archiveSize = NULL, *attr = NULL;
00152   int bufsize = 0, err;
00153   nsComponent *comp = NULL;
00154 
00155   err = aParser->GetStringAlloc(aCompName, DESC_SHORT, &descShort, &bufsize);
00156   if (err != OK)
00157     goto bail;
00158 
00159   err = aParser->GetStringAlloc(aCompName, DESC_LONG, &descLong, &bufsize);
00160   if (err != OK)
00161     goto bail;
00162 
00163   err = aParser->GetStringAlloc(aCompName, ARCHIVE, &archive, &bufsize);
00164   if (err != OK)
00165     goto bail;
00166 
00167   err = aParser->GetStringAlloc(aCompName, INSTALL_SIZE,
00168                                 &installSize, &bufsize);
00169   if (err != OK)
00170     goto bail;
00171 
00172   err = aParser->GetStringAlloc(aCompName, ARCHIVE_SIZE,
00173                                 &archiveSize, &bufsize);
00174   if (err != OK)
00175     goto bail;
00176 
00177   err = aParser->GetStringAlloc(aCompName, ATTRIBUTES, &attr, &bufsize);
00178   if (err != OK && err != nsINIParser::E_NO_KEY) // this is optional
00179     goto bail;
00180 
00181   comp = new nsComponent();
00182   if (!comp)
00183     goto bail;
00184 
00185   comp->SetDescShort(descShort);
00186   comp->SetDescLong(descLong);
00187   comp->SetArchive(archive);
00188   comp->SetInstallSize(atoi(installSize));
00189   comp->SetArchiveSize(atoi(archiveSize));
00190 
00191   if (strstr(attr, SELECTED_ATTR)) {
00192     comp->SetSelected();
00193     comp->DepAddRef();
00194   }
00195   else {
00196     comp->SetUnselected();
00197   }
00198 
00199   if (strstr(attr, INVISIBLE_ATTR))
00200     comp->SetInvisible();
00201   else
00202     comp->SetVisible();
00203 
00204   if (strstr(attr, LAUNCHAPP_ATTR))
00205     comp->SetLaunchApp();
00206   else
00207     comp->SetDontLaunchApp();
00208 
00209   if (strstr(attr, DOWNLOAD_ONLY_ATTR))
00210     comp->SetDownloadOnly();
00211 
00212   if (strstr(attr, MAIN_COMPONENT_ATTR))
00213     comp->SetMainComponent();
00214 
00215   for (int i = 0; i < MAX_URLS; ++i) {
00216     char urlKey[MAX_URL_LEN], *currURL;
00217     sprintf(urlKey, URLd, i);
00218     err = aParser->GetStringAlloc(aCompName, urlKey, &currURL, &bufsize);
00219     if (err != OK)
00220       break;
00221 
00222     comp->SetURL(currURL, i);
00223   }
00224 
00225   for (int j = 0; j < MAX_COMPONENTS; ++j) {
00226     char *currDep = NULL;
00227     char key[MAX_DEPENDEE_KEY_LEN];
00228 
00229     sprintf(key, DEPENDEEd, j);
00230 
00231     err = aParser->GetStringAlloc(aCompName, key, &currDep, &bufsize);
00232     if (bufsize == 0 || err != OK)
00233       break; // no more dependees
00234 
00235     comp->AddDependee(currDep); // we will scan for invalid dependencies later
00236   }
00237 
00238   return comp;
00239  bail:
00240   return NULL;
00241 }
00242 
00243 int
00244 nsSetupTypeDlg::Parse(nsINIParser *aParser)
00245 {
00246     int err = OK;
00247     int bufsize = 0;
00248     char *showDlg = NULL;
00249     int i, j;
00250     char *currSec = (char *) malloc(strlen(SETUP_TYPE) + 3); // e.g. SetupType12
00251     if (!currSec) return E_MEM;
00252     char *currKey = (char *) malloc(1 + 3); // e.g. C0, C1, C12
00253     if (!currKey) return E_MEM;
00254     char *currVal = NULL;
00255     nsComponent *currComp = NULL;
00256     int currNumComps = 0;
00257     nsSetupType *currST = NULL;
00258     char *currDescShort = NULL;
00259     char *currDescLong = NULL;
00260 
00261     XI_VERIFY(gCtx);
00262 
00263     XI_ERR_BAIL(aParser->GetStringAlloc(DLG_SETUP_TYPE, MSGEXISTING,
00264                                         &mExistingMsg, &bufsize));
00265     if (bufsize == 0)
00266       XI_IF_FREE(mExistingMsg);
00267 
00268     /* optional keys */
00269     err = aParser->GetStringAlloc(DLG_SETUP_TYPE, MSG0, &mMsg0, &bufsize);
00270     if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
00271 
00272     bufsize = 5;
00273     err = aParser->GetStringAlloc(DLG_SETUP_TYPE, SHOW_DLG, &showDlg, &bufsize);
00274     if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
00275     if (bufsize != 0 && showDlg)
00276     {
00277         if (0 == strncmp(showDlg, "TRUE", 4))
00278             mShowDlg = nsXInstallerDlg::SHOW_DIALOG;
00279         else if (0 == strncmp(showDlg, "FALSE", 5))
00280             mShowDlg = nsXInstallerDlg::SKIP_DIALOG;
00281     }
00282 
00283     bufsize = 0;
00284     err = aParser->GetStringAlloc(DLG_SETUP_TYPE, TITLE, &mTitle, &bufsize);
00285     if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
00286     if (bufsize == 0)
00287       XI_IF_FREE(mTitle); 
00288 
00289     aParser->GetStringAlloc(DLG_SETUP_TYPE, SUBTITLE, &mSubTitle, &bufsize);
00290     if (bufsize == 0)
00291       XI_IF_FREE(mSubTitle);
00292 
00293     /* setup types */
00294     for (i=0; i<MAX_SETUP_TYPES; i++)
00295     {
00296         sprintf(currSec, SETUP_TYPEd, i);
00297 
00298         bufsize = 0;
00299         err = aParser->GetStringAlloc(currSec, DESC_SHORT, &currDescShort,
00300                                       &bufsize);
00301         if (err != OK && err != nsINIParser::E_NO_SEC) goto fin_iter;
00302         if (bufsize == 0 || err == nsINIParser::E_NO_SEC) // no more setup types
00303         {
00304             err = OK;
00305             break;
00306         }
00307 
00308         bufsize = 0;
00309         err = aParser->GetStringAlloc(currSec, DESC_LONG, &currDescLong,
00310                                       &bufsize);
00311         if (err != OK || bufsize == 0) goto fin_iter;
00312 
00313         currST = new nsSetupType();
00314         if (!currST) goto fin_iter;
00315 
00316         // The short description may contain mnemonics by prefixing
00317         // characters with "&".  We need to change these to "_" for GTK.
00318         for (char *c = currDescShort; *c != '\0'; ++c) {
00319           if (*c == '&')  // XXX this doesn't quite handle "&&"
00320             *c = '_';
00321         }
00322 
00323         currST->SetDescShort(currDescShort);
00324         currST->SetDescLong(currDescLong);
00325 
00326         currNumComps = 0;
00327         for (j=0; j<MAX_COMPONENTS; j++)
00328         {
00329             sprintf(currKey, Cd, j);
00330             
00331             bufsize = 0;
00332             err = aParser->GetStringAlloc(currSec, currKey, &currVal, 
00333                                           &bufsize);
00334             if (err != OK && err != nsINIParser::E_NO_KEY) continue;
00335             if (bufsize == 0 || err == nsINIParser::E_NO_KEY) 
00336             {
00337                 err = OK;
00338                 break;
00339             }
00340         
00341             currComp = ParseComponent(aParser, currVal);
00342             if (currComp) {
00343               currST->SetComponent(currComp);
00344               ++currNumComps;
00345             }
00346         }
00347 
00348         if (currNumComps > 0)
00349         {
00350             AddSetupType(currST);
00351             currST = NULL;
00352         }
00353 
00354 fin_iter:
00355         XI_IF_DELETE(currST);
00356     }
00357 
00358     err = OK;
00359 
00360 BAIL:
00361     XI_IF_FREE(currSec);
00362     XI_IF_FREE(currKey);
00363 
00364     return err;
00365 }
00366 
00367 int
00368 nsSetupTypeDlg::Show(int aDirection)
00369 {
00370     int err = OK;
00371     int numSetupTypes = 0;
00372     GtkWidget *radbtn;
00373     nsSetupType *currST = NULL;
00374     GtkWidget *frame = NULL;
00375 
00376     XI_VERIFY(gCtx);
00377     XI_VERIFY(gCtx->notebook);
00378 
00379     if (mWidgetsInit == FALSE)
00380     {
00381       // add a vbox as a page of the notebook
00382       mBox = gtk_vbox_new(FALSE, 0);
00383       gtk_container_set_border_width(GTK_CONTAINER(mBox), 12);
00384       gtk_notebook_append_page(GTK_NOTEBOOK(gCtx->notebook), mBox, NULL);
00385       mPageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(gCtx->notebook));
00386 
00387       // add the top text label
00388       GtkWidget *msg0 = gtk_label_new(mMsg0);
00389       gtk_misc_set_alignment(GTK_MISC(msg0), 0.0, 0.5);
00390       gtk_box_pack_start(GTK_BOX(mBox), msg0, FALSE, FALSE, 12);
00391 
00392       // for each setup type, pack into the vbox:
00393       //  an hbox containing:  (this is to pad the radio button on the right)
00394       //   the radio button with short description
00395       //  a label with the long description
00396 
00397       numSetupTypes = GetNumSetupTypes();
00398       currST = GetSetupTypeList();
00399 
00400       for (int i = 0; i < numSetupTypes; ++i, currST = currST->GetNext()) {
00401         if (i == 0) {
00402           radbtn = gtk_radio_button_new_with_mnemonic(NULL,
00403                                                       currST->GetDescShort());
00404           mRadioGroup = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radbtn));
00405         } else {
00406           radbtn = gtk_radio_button_new_with_mnemonic(mRadioGroup,
00407                                                       currST->GetDescShort());
00408         }
00409 
00410         
00411         GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
00412         gtk_box_pack_start(GTK_BOX(hbox), radbtn, FALSE, FALSE, 0);
00413         gtk_box_pack_start(GTK_BOX(mBox), hbox, FALSE, FALSE, 6);
00414 
00415         GtkWidget *desc = gtk_label_new(currST->GetDescLong());
00416         gtk_label_set_line_wrap(GTK_LABEL(desc), TRUE);
00417         gtk_misc_set_alignment(GTK_MISC(desc), 0.0, 0.5);
00418 
00419         // Pad the labels so that they line up with the radio button text
00420         gint ind_size, ind_spacing;
00421         gtk_widget_style_get(radbtn,
00422                              "indicator_size", &ind_size,
00423                              "indicator_spacing", &ind_spacing,
00424                              NULL);
00425 
00426         gtk_misc_set_padding(GTK_MISC(desc), ind_size + ind_spacing * 3, 0);
00427         gtk_box_pack_start(GTK_BOX(mBox), desc, FALSE, FALSE, 6);
00428       }
00429 
00430 
00431       frame = gtk_frame_new(gCtx->Res("DEST_DIR"));
00432       gtk_box_pack_start(GTK_BOX(mBox), frame, FALSE, FALSE, 12);
00433 
00434       GtkWidget *frame_hbox = gtk_hbox_new(FALSE, 6);
00435       gtk_container_set_border_width(GTK_CONTAINER(frame_hbox), 6);
00436       gtk_container_add(GTK_CONTAINER(frame), frame_hbox);
00437 
00438       if (!gCtx->opt->mDestination) {
00439         gCtx->opt->mDestination = (char*)malloc(MAXPATHLEN * sizeof(char));
00440         getcwd(gCtx->opt->mDestination, MAXPATHLEN);
00441       }
00442 
00443       sFolder = gtk_label_new(gCtx->opt->mDestination);
00444       gtk_label_set_line_wrap(GTK_LABEL(sFolder), TRUE);
00445       gtk_misc_set_alignment(GTK_MISC(sFolder), 0.0, 0.5);
00446       gtk_box_pack_start(GTK_BOX(frame_hbox), sFolder, TRUE, TRUE, 0);
00447 
00448       sBrowseBtn = gtk_button_new_with_label(gCtx->Res("BROWSE"));
00449       gtk_box_pack_start(GTK_BOX(frame_hbox), sBrowseBtn, FALSE, FALSE, 0);
00450 
00451       mWidgetsInit = TRUE;
00452     } else {
00453         gtk_notebook_set_page(GTK_NOTEBOOK(gCtx->notebook), mPageNum);
00454     }
00455 
00456     // <b>title</b>\0
00457     char *titleBuf = new char[strlen(mTitle) + 9];
00458     sprintf(titleBuf, "<b>%s</b>", mTitle);
00459 
00460     gtk_label_set_markup(GTK_LABEL(gCtx->header_title), titleBuf);
00461     gtk_label_set_text(GTK_LABEL(gCtx->header_subtitle), mSubTitle);
00462 
00463     delete[] titleBuf;
00464 
00465     gtk_widget_show_all(mBox);
00466 
00467     // signal connect the buttons
00468     // NOTE: back button disfunctional in this dlg since user accepted license
00469     gCtx->backID = gtk_signal_connect(GTK_OBJECT(gCtx->back), "clicked",
00470                    GTK_SIGNAL_FUNC(nsSetupTypeDlg::Back), gCtx->sdlg);
00471     gCtx->nextID = gtk_signal_connect(GTK_OBJECT(gCtx->next), "clicked",
00472                    GTK_SIGNAL_FUNC(nsSetupTypeDlg::Next), gCtx->sdlg);
00473     sBrowseBtnID = gtk_signal_connect(GTK_OBJECT(sBrowseBtn), "clicked",
00474                    GTK_SIGNAL_FUNC(nsSetupTypeDlg::SelectFolder), NULL);  
00475 
00476     if (aDirection == nsXInstallerDlg::FORWARD_MOVE)
00477     {
00478         // change the button titles back to Back/Next
00479       gtk_button_set_label(GTK_BUTTON(gCtx->next), GTK_STOCK_GO_FORWARD);
00480       gtk_button_set_label(GTK_BUTTON(gCtx->back), GTK_STOCK_GO_BACK);
00481     }
00482         // from install dlg
00483     if (aDirection == nsXInstallerDlg::BACKWARD_MOVE && 
00484         // not custom setup type
00485         gCtx->opt->mSetupType != (gCtx->sdlg->GetNumSetupTypes() - 1))
00486     {
00487         DUMP("Back from Install to Setup Type");
00488         gtk_button_set_label(GTK_BUTTON(gCtx->next), GTK_STOCK_GO_FORWARD);
00489     }     
00490 
00491     gtk_widget_set_sensitive(gCtx->back, FALSE);
00492 
00493     return err;
00494 }
00495 
00496 int
00497 nsSetupTypeDlg::Hide(int aDirection)
00498 {
00499   //    gtk_widget_hide(mTable);
00500   gtk_widget_hide(mBox);
00501 
00502     return OK;
00503 }
00504 
00505 int
00506 nsSetupTypeDlg::SetMsg0(char *aMsg)
00507 {
00508     if (!aMsg)
00509         return E_PARAM;
00510 
00511     mMsg0 = aMsg;
00512 
00513     return OK;
00514 }
00515 
00516 char *
00517 nsSetupTypeDlg::GetMsg0()
00518 {
00519     if (mMsg0)
00520         return mMsg0;
00521 
00522     return NULL;
00523 }
00524 
00525 int
00526 nsSetupTypeDlg::AddSetupType(nsSetupType *aSetupType)
00527 {
00528     if (!aSetupType)
00529         return E_PARAM;
00530 
00531     if (!mSetupTypeList)
00532     {
00533         mSetupTypeList = aSetupType;
00534         return OK;
00535     }
00536 
00537     nsSetupType *curr = mSetupTypeList;
00538     nsSetupType *next;
00539     while (curr)
00540     {
00541         next = NULL;
00542         next = curr->GetNext();
00543     
00544         if (!next)
00545         {
00546             return curr->SetNext(aSetupType);
00547         }
00548 
00549         curr = next;
00550     }
00551 
00552     return OK;
00553 }
00554 
00555 nsSetupType *
00556 nsSetupTypeDlg::GetSetupTypeList()
00557 {
00558     if (mSetupTypeList)
00559         return mSetupTypeList;
00560 
00561     return NULL;
00562 }
00563 
00564 int
00565 nsSetupTypeDlg::GetNumSetupTypes()
00566 {
00567     int num = 0;
00568     nsSetupType *curr = NULL;
00569 
00570     if (!mSetupTypeList)
00571         return 0;
00572     
00573     curr = mSetupTypeList;
00574     while(curr)
00575     {
00576         num++;
00577         curr = curr->GetNext();
00578     }
00579 
00580     return num;
00581 }
00582 
00583 nsSetupType *
00584 nsSetupTypeDlg::GetSelectedSetupType()
00585 {
00586     nsSetupType *curr = NULL;
00587     int numSetupTypes = GetNumSetupTypes();
00588     int setupTypeCount = 0;
00589 
00590     curr = GetSetupTypeList();
00591     while (curr && setupTypeCount < numSetupTypes)  // paranoia!
00592     {
00593         if (setupTypeCount == gCtx->opt->mSetupType)
00594             return curr;        
00595 
00596         setupTypeCount++;
00597         curr = curr->GetNext();
00598     }
00599 
00600     return NULL;
00601 }
00602 
00603 void
00604 nsSetupTypeDlg::FreeSetupTypeList()
00605 {
00606     nsSetupType *curr = mSetupTypeList;
00607     nsSetupType *prev;
00608     
00609     while (curr)
00610     {
00611         prev = curr;
00612         curr = curr->GetNext();
00613 
00614         XI_IF_DELETE(prev);
00615     }
00616 }
00617 
00618 void
00619 nsSetupTypeDlg::SelectFolder(GtkWidget *aWidget, gpointer aData)
00620 {
00621     DUMP("SelectFolder");
00622 
00623     if (sFilePickerUp)
00624         return;
00625 
00626     GtkWidget *fileSel = NULL;
00627     char *selDir = gCtx->opt->mDestination;
00628 
00629     fileSel = gtk_file_selection_new(gCtx->Res("SELECT_DIR"));
00630     gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileSel), selDir);
00631     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileSel)->ok_button),
00632                        "clicked", (GtkSignalFunc) SelectFolderOK, fileSel);
00633     gtk_signal_connect_object(GTK_OBJECT(
00634                                 GTK_FILE_SELECTION(fileSel)->cancel_button),
00635                                 "clicked", (GtkSignalFunc) SelectFolderCancel,
00636                                 GTK_OBJECT(fileSel));
00637     gtk_widget_show(fileSel); 
00638     sFilePickerUp = TRUE;
00639 }
00640 
00641 void
00642 nsSetupTypeDlg::SelectFolderOK(GtkWidget *aWidget, GtkFileSelection *aFileSel)
00643 {
00644     DUMP("SelectFolderOK");
00645 
00646     struct stat destStat;
00647     const gchar *selDir =
00648       gtk_file_selection_get_filename(GTK_FILE_SELECTION(aFileSel));
00649 
00650     // put the candidate file name in the global variable, then verify it
00651 
00652     strcpy(gCtx->opt->mDestination, selDir);
00653 
00654     if (0 == stat(selDir, &destStat))
00655         if (!S_ISDIR(destStat.st_mode) || VerifyDestination() != OK ) /* not a directory, or we don't have access permissions, so don't tear down */
00656             return;
00657 
00658     // update folder path displayed
00659     gtk_label_set_text(GTK_LABEL(sFolder), gCtx->opt->mDestination);
00660     gtk_widget_show(sFolder);
00661 
00662     // tear down file sel dlg
00663     gtk_object_destroy(GTK_OBJECT(aFileSel)); 
00664     sFilePickerUp = FALSE;
00665 }
00666 
00667 void
00668 nsSetupTypeDlg::SelectFolderCancel(GtkWidget *aWidget, 
00669                                    GtkFileSelection *aFileSel)
00670 {
00671     // tear down file sel dlg
00672     gtk_object_destroy(GTK_OBJECT(aWidget)); 
00673     gtk_object_destroy(GTK_OBJECT(aFileSel)); 
00674     sFilePickerUp = FALSE;
00675 }
00676 
00677 int
00678 nsSetupTypeDlg::VerifyDestination()
00679 {
00680     int stat_err = 0;
00681     struct stat stbuf; 
00682   
00683     stat_err = stat(gCtx->opt->mDestination, &stbuf);
00684     if (stat_err == 0)
00685     {
00686       if (access(gCtx->opt->mDestination, R_OK | W_OK | X_OK ) != 0)
00687       {
00688         GtkWidget *noPermsDlg =
00689           gtk_message_dialog_new(GTK_WINDOW(gCtx->window),
00690              GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
00691                                  GTK_MESSAGE_ERROR,
00692                                  GTK_BUTTONS_OK,
00693                                  gCtx->Res("NO_PERMS"),
00694                                  gCtx->opt->mDestination);
00695 
00696         gtk_dialog_run(GTK_DIALOG(noPermsDlg));
00697         gtk_widget_destroy(noPermsDlg);
00698 
00699         return E_NO_PERMS;
00700       }
00701       else
00702       {
00703         // perms OK, we can proceed
00704         return OK;
00705       }
00706     }
00707 
00708     // destination doesn't exist so ask user if we should create it
00709     GtkWidget *createDestDlg =
00710       gtk_message_dialog_new(GTK_WINDOW(gCtx->window),
00711                GtkDialogFlags(GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT),
00712                              GTK_MESSAGE_QUESTION,
00713                              GTK_BUTTONS_YES_NO,
00714                              gCtx->Res("DOESNT_EXIST"),
00715                              gCtx->opt->mDestination);
00716 
00717     gint result = gtk_dialog_run(GTK_DIALOG(createDestDlg));
00718     gtk_widget_destroy(createDestDlg);
00719 
00720     if (result == GTK_RESPONSE_YES) {
00721       // Create the destination directory.
00722       char path[PATH_MAX + 1];
00723       int  pathLen = strlen(gCtx->opt->mDestination);
00724       int  dirErr = 0;
00725 
00726       if (pathLen > PATH_MAX)
00727         pathLen = PATH_MAX;
00728       memcpy(path, gCtx->opt->mDestination, pathLen);
00729       path[pathLen] = '/';  // for uniform handling
00730 
00731       struct stat buf;
00732       mode_t oldPerms = umask(022);
00733 
00734       for (int i = 1; !dirErr && i <= pathLen; i++) {
00735         if (path[i] == '/') {
00736           path[i] = '\0';
00737           if (stat(path, &buf) != 0) {
00738             dirErr = mkdir(path, (0777 & ~oldPerms));
00739           }
00740           path[i] = '/';
00741         }
00742       }
00743 
00744       umask(oldPerms); // restore original umask
00745       if (dirErr != 0)
00746         ErrorHandler(E_MKDIR_FAIL);
00747       else
00748         return OK;
00749     }
00750 
00751     return E_NO_DEST;
00752 }
00753 
00754 int
00755 nsSetupTypeDlg::DeleteOldInst()
00756 {
00757     DUMP("DeleteOldInst");
00758 
00759     int err = OK;
00760     struct stat dummy;
00761     char path[MAXPATHLEN];
00762 
00763     memset(path, 0, MAXPATHLEN);
00764     ConstructPath(path, gCtx->opt->mDestination, gCtx->opt->mProgramName);
00765 
00766     DUMP(path);
00767 
00768     // check if old installation exists
00769     if (0 == stat(path, &dummy)) {
00770       // throw up delete dialog 
00771       GtkWidget *delInstDlg =
00772         gtk_message_dialog_new(GTK_WINDOW(gCtx->window),
00773              GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
00774                                GTK_MESSAGE_QUESTION,
00775                                GTK_BUTTONS_NONE,
00776                                gCtx->sdlg->mExistingMsg,
00777                                gCtx->opt->mDestination);
00778 
00779       gtk_dialog_add_buttons(GTK_DIALOG(delInstDlg),
00780                              GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
00781                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
00782                             
00783       gint result = gtk_dialog_run(GTK_DIALOG(delInstDlg));
00784       if (result == GTK_RESPONSE_ACCEPT) {
00785         // Delete the old installation
00786         char cwd[MAXPATHLEN];
00787         getcwd(cwd, MAXPATHLEN);
00788         chdir(gCtx->opt->mDestination);
00789         system("rm -rf *");
00790         chdir(cwd);
00791         err = OK;
00792       } else {
00793         err = E_OLD_INST;
00794       }
00795 
00796       gtk_widget_destroy(delInstDlg);
00797     }
00798     
00799     return err;
00800 }
00801 
00802 int
00803 nsSetupTypeDlg::ConstructPath(char *aDest, char *aTrunk, char *aLeaf)
00804 {
00805     int err = OK;
00806     int trunkLen;
00807     char *lastSlash = NULL;
00808     
00809     if (!aDest || !aTrunk || !aLeaf)
00810         return E_PARAM;
00811 
00812     trunkLen = strlen(aTrunk);
00813     lastSlash = strrchr(aTrunk, '/');
00814     
00815     strcpy(aDest, aTrunk);
00816     if (lastSlash != aTrunk + (trunkLen - 1))
00817     {
00818         // need to tack on a slash
00819         strcat(aDest, "/");
00820     }
00821     strcat(aDest, aLeaf);
00822 
00823     return err;
00824 }
00825 
00826 int
00827 nsSetupTypeDlg::VerifyDiskSpace(void)
00828 {
00829     int err = OK;
00830     int dsAvail, dsReqd;
00831     char dsAvailStr[128], dsReqdStr[128];
00832     char message[512];
00833     GtkWidget *noDSDlg, *label;
00834 
00835     // find disk space available at destination
00836     dsAvail = DSAvailable();
00837     if (dsAvail < 0)
00838         return OK; // optimistic when statfs failed
00839                    // or we don't have statfs
00840 
00841     // get disk space required
00842     dsReqd = DSRequired();
00843 
00844     if (dsReqd > dsAvail)
00845     {
00846         // throw up not enough ds dlg
00847         sprintf(dsAvailStr, gCtx->Res("DS_AVAIL"), dsAvail);
00848         sprintf(dsReqdStr, gCtx->Res("DS_REQD"), dsReqd);
00849         sprintf(message, "%s\n%s\n\n%s", dsAvailStr, dsReqdStr, 
00850                 gCtx->Res("NO_DISK_SPACE"));
00851 
00852         noDSDlg = gtk_dialog_new_with_buttons(gCtx->opt->mTitle,
00853                                               NULL, (GtkDialogFlags) 0,
00854                                               GTK_STOCK_OK,
00855                                               GTK_RESPONSE_NONE,
00856                                               NULL);
00857         label = gtk_label_new(message);
00858 
00859         g_signal_connect_swapped(GTK_OBJECT(noDSDlg), "response",
00860                                  G_CALLBACK(NoDiskSpaceOK),
00861                                  GTK_OBJECT(noDSDlg));
00862 
00863         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(noDSDlg)->vbox), label);
00864         gtk_widget_show_all(noDSDlg);
00865         err = E_NO_DISK_SPACE;
00866     }
00867 
00868     return err;
00869 }
00870 
00871 int
00872 nsSetupTypeDlg::DSAvailable(void)
00873 {
00874     // returns disk space available in kilobytes
00875 
00876     int dsAvail = -1;
00877 
00878 #if defined(HAVE_SYS_STATVFS_H) || defined(HAVE_SYS_STATFS_H)
00879     struct STATFS buf;
00880     int rv;
00881 
00882     if (gCtx->opt->mDestination)
00883     {
00884         rv = STATFS(gCtx->opt->mDestination, &buf);
00885         if (rv == 0)
00886         {
00887             if (buf.f_bsize > 1024 && (buf.f_bsize%1024 == 0))
00888             {
00889                 // normally the block size is >= 1024 and a multiple
00890                 // so we can shave off the last three digits before 
00891                 // finding the product of the block size and num blocks
00892                 // which is important for large disks
00893 
00894                 dsAvail = (buf.f_bsize/1024) * (buf.f_bavail);
00895             }
00896             else
00897             {
00898                 // attempt to stuff into a 32 bit int even though
00899                 // we convert from bytes -> kilobytes later
00900                 // (may fail to compute on very large disks whose
00901                 // block size is not a multiple of 1024 -- highly 
00902                 // improbable)
00903 
00904                 dsAvail = (buf.f_bsize * buf.f_bavail)/1024;
00905             }
00906         }
00907     }
00908 #endif // HAVE_SYS_STATVFS_H -or- HAVE_SYS_STATFS_H 
00909 
00910     return dsAvail;
00911 }
00912 
00913 int 
00914 nsSetupTypeDlg::DSRequired(void)
00915 {
00916     // returns disk space required in kilobytes 
00917 
00918     int dsReqd = 0;
00919     nsComponentList *comps;
00920     int bCus;
00921 
00922     // find setup type's component list
00923     bCus = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
00924     comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
00925 
00926     // loop through all components
00927     nsComponent *currComp = comps->GetHead();
00928     while (currComp)
00929     {
00930         if ( (bCus == TRUE && currComp->IsSelected()) || (bCus == FALSE) )
00931         {
00932             // add to disk space required 
00933             dsReqd += currComp->GetInstallSize();
00934             dsReqd += currComp->GetArchiveSize();
00935         }
00936 
00937         currComp = currComp->GetNext();
00938     }
00939 
00940     return dsReqd;
00941 }
00942 
00943 void
00944 nsSetupTypeDlg::NoDiskSpaceOK(GtkWidget *aWidget, gpointer aData)
00945 {
00946     GtkWidget *noDSDlg = (GtkWidget *) aData;
00947 
00948     if (!noDSDlg)
00949         return;
00950 
00951     gtk_widget_destroy(noDSDlg);
00952 }
00953