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 of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or 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 #include <sys/types.h>
00045 #include <dirent.h>
00046 
00047 // need these for statfs 
00048 
00049 #ifdef HAVE_SYS_STATVFS_H
00050 #include <sys/statvfs.h>
00051 #endif
00052 
00053 #ifdef HAVE_SYS_STATFS_H
00054 #include <sys/statfs.h>
00055 #endif
00056 
00057 #ifdef HAVE_STATVFS
00058 #define STATFS statvfs
00059 #else
00060 #define STATFS statfs
00061 #endif
00062 
00063 #include <sys/wait.h>
00064 
00065 
00066 static GtkWidget        *sBrowseBtn;
00067 static gint             sBrowseBtnID;
00068 static GtkWidget        *sFolder;
00069 static GSList           *sGroup;
00070 static GtkWidget        *sCreateDestDlg;
00071 static GtkWidget        *sDelInstDlg;
00072 static nsLegacyCheck    *sLegacyChecks = NULL;
00073 static nsObjectIgnore   *sObjectsToIgnore = NULL;
00074 
00075 nsSetupTypeDlg::nsSetupTypeDlg() :
00076     mMsg0(NULL),
00077     mSetupTypeList(NULL)
00078 {
00079 }
00080 
00081 nsSetupTypeDlg::~nsSetupTypeDlg()
00082 {
00083     FreeSetupTypeList();
00084     FreeLegacyChecks();
00085 
00086     XI_IF_FREE(mMsg0)
00087 }
00088 
00089 void 
00090 nsSetupTypeDlg::Next(GtkWidget *aWidget, gpointer aData)
00091 {
00092     DUMP("Next");
00093     if (aData && aData != gCtx->sdlg) return;
00094 #ifdef MOZ_WIDGET_GTK
00095     if (gCtx->bMoving)
00096     {
00097         gCtx->bMoving = FALSE;
00098         return;
00099     }
00100 #endif
00101 
00102     // verify selected destination directory exists
00103     if (OK != nsSetupTypeDlg::VerifyDestination())
00104         return;
00105 
00106     // old installation may exist: delete it
00107     if (OK != nsSetupTypeDlg::DeleteOldInst())
00108         return;
00109 
00110     // make sure destination directory is empty
00111     if (OK != nsSetupTypeDlg::CheckDestEmpty())
00112         return;
00113 
00114     // if not custom setup type verify disk space
00115     if (gCtx->opt->mSetupType != (gCtx->sdlg->GetNumSetupTypes() - 1))
00116     {
00117         if (OK != nsSetupTypeDlg::VerifyDiskSpace())
00118             return;
00119     }
00120 
00121     if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
00122     {
00123         // hide this notebook page
00124         gCtx->sdlg->Hide();
00125     }
00126 
00127     // show the last dlg
00128     if (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1))
00129     {
00130         gCtx->cdlg->Show();
00131     }
00132     else
00133     {
00134         if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
00135         {
00136             gCtx->idlg->Show();
00137         }
00138         if (gCtx->opt->mMode != nsXIOptions::MODE_DEFAULT)
00139         {
00140             gCtx->idlg->Next((GtkWidget *)NULL, (gpointer) gCtx->idlg);
00141         }
00142     }
00143 
00144 #ifdef MOZ_WIDGET_GTK
00145     // When Next() is not invoked from a signal handler, the caller passes
00146     // aData as NULL so we know not to do the bMoving hack. 
00147     if (aData)
00148     {
00149         gCtx->bMoving = TRUE;
00150     }
00151 #endif
00152 }
00153 
00154 int
00155 nsSetupTypeDlg::Parse(nsINIParser *aParser)
00156 {
00157     int err = OK;
00158     int bufsize = 0;
00159     char *showDlg = NULL;
00160     int i, j;
00161     char *defSec = NULL; // default Setup Type
00162     char *currSec = (char *) malloc(strlen(SETUP_TYPEd) + 1); // e.g. SetupType12
00163     if (!currSec) return E_MEM;
00164     char *currKey = (char *) malloc(1 + 3); // e.g. C0, C1, C12
00165     if (!currKey) return E_MEM;
00166     char *currOIKey = (char *) malloc(strlen(OBJECT_IGNOREd) + 1);
00167     if (!currOIKey) return E_MEM;
00168     char *currLCSec = (char *) malloc(strlen(LEGACY_CHECKd) + 1);
00169     if (!currLCSec) return E_MEM;
00170     char *currVal = NULL;
00171     nsObjectIgnore *currOI = NULL, *nextOI = NULL;
00172     char *currFile = NULL, *currMsg = NULL;
00173     nsLegacyCheck *currLC = NULL, *nextLC = NULL;
00174     nsComponent *currComp = NULL;
00175     int currIndex;
00176     int currNumComps = 0;
00177 
00178     nsComponentList *compList = gCtx->cdlg->GetCompList();
00179     DUMP("Pre-verification of comp list")
00180     XI_VERIFY(compList);
00181     DUMP("Post-verification of comp list")
00182 
00183     nsSetupType *currST = NULL;
00184     char *currDescShort = NULL;
00185     char *currDescLong = NULL;
00186 
00187     XI_VERIFY(gCtx);
00188 
00189     /* optional keys */
00190     err = aParser->GetStringAlloc(GENERAL, DEFAULT_SETUP_TYPE, &defSec, &bufsize);
00191     if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
00192 
00193     bufsize = 0;
00194     err = aParser->GetStringAlloc(DLG_SETUP_TYPE, MSG0, &mMsg0, &bufsize);
00195     if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
00196 
00197     bufsize = 0;
00198     err = aParser->GetStringAlloc(DLG_SETUP_TYPE, TITLE, &mTitle, &bufsize);
00199     if (err != OK && err != nsINIParser::E_NO_KEY) goto BAIL; else err = OK;
00200     if (bufsize == 0)
00201             XI_IF_FREE(mTitle); 
00202 
00203     /* Objects to Ignore */
00204     for (i = 0; i < MAX_LEGACY_CHECKS; i++)
00205     {
00206         // construct key name based on index
00207         memset(currOIKey, 0, (strlen(OBJECT_IGNOREd) + 1));
00208         sprintf(currOIKey, OBJECT_IGNOREd, i);
00209 
00210         // get ObjectToIgnore key
00211         bufsize = 0;
00212         err = aParser->GetStringAlloc(CLEAN_UPGRADE, currOIKey, &currFile, &bufsize);
00213         if (err != OK) 
00214         { 
00215             if (err != nsINIParser::E_NO_SEC &&
00216                 err != nsINIParser::E_NO_KEY) goto BAIL; 
00217             else 
00218             {
00219                 err = OK; 
00220                 break; 
00221             } 
00222         }
00223         nextOI = new nsObjectIgnore(currFile);
00224 
00225         if (currOI)
00226         {
00227            currOI->SetNext(nextOI);
00228         }
00229         else if (!sObjectsToIgnore)
00230         {
00231            sObjectsToIgnore = nextOI;
00232         }
00233 
00234         currOI = nextOI;
00235     }
00236 
00237     /* legacy check */
00238     for (i = 0; i < MAX_LEGACY_CHECKS; i++)
00239     {
00240         // construct section name based on index
00241         memset(currLCSec, 0, (strlen(LEGACY_CHECKd) + 1));
00242         sprintf(currLCSec, LEGACY_CHECKd, i);
00243 
00244         // get "Filename" and "Message" keys
00245         bufsize = 0;
00246         err = aParser->GetStringAlloc(currLCSec, FILENAME, &currFile, &bufsize);
00247         if (err != OK) 
00248         { 
00249             if (err != nsINIParser::E_NO_SEC &&
00250                 err != nsINIParser::E_NO_KEY) goto BAIL; 
00251             else 
00252             {
00253                 err = OK; 
00254                 break; 
00255             } 
00256         }
00257 
00258         bufsize = 0;
00259         err = aParser->GetStringAlloc(currLCSec, MSG, &currMsg, &bufsize);
00260         if (err != OK)
00261         {
00262             if (err != nsINIParser::E_NO_SEC &&
00263                 err != nsINIParser::E_NO_KEY) goto BAIL; 
00264             else 
00265             {
00266                 err = OK; 
00267                 break; 
00268             } 
00269         }
00270         nextLC = new nsLegacyCheck(currFile, currMsg);
00271 
00272         if (currLC)
00273         {
00274            currLC->SetNext(nextLC);
00275         }
00276         else if (!sLegacyChecks)
00277         {
00278            sLegacyChecks = nextLC;
00279         }
00280 
00281         currLC = nextLC;
00282     }
00283 
00284     /* setup types */
00285     gCtx->opt->mSetupType = 0;
00286     for (i=0; i<MAX_SETUP_TYPES; i++)
00287     {
00288         sprintf(currSec, SETUP_TYPEd, i);
00289 
00290         bufsize = 0;
00291         err = aParser->GetStringAlloc(currSec, DESC_SHORT, &currDescShort,
00292                                       &bufsize);
00293         if (err != OK && err != nsINIParser::E_NO_SEC) goto fin_iter;
00294         if (bufsize == 0 || err == nsINIParser::E_NO_SEC) // no more setup types
00295         {
00296             err = OK;
00297             break;
00298         }
00299 
00300         if (defSec && strcasecmp(currDescShort, defSec) == 0)
00301             gCtx->opt->mSetupType = i;
00302 
00303         bufsize = 0;
00304         err = aParser->GetStringAlloc(currSec, DESC_LONG, &currDescLong,
00305                                       &bufsize);
00306         if (err != OK || bufsize == 0) goto fin_iter;
00307 
00308         currST = new nsSetupType();
00309         if (!currST) goto fin_iter;
00310 
00311         currST->SetDescShort(currDescShort);
00312         currST->SetDescLong(currDescLong);
00313 
00314         currNumComps = 0;
00315         for (j=0; j<MAX_COMPONENTS; j++)
00316         {
00317             sprintf(currKey, Cd, j);
00318             
00319             bufsize = 0;
00320             err = aParser->GetStringAlloc(currSec, currKey, &currVal, 
00321                                           &bufsize);
00322             if (err != OK && err != nsINIParser::E_NO_KEY) continue;
00323             if (bufsize == 0 || err == nsINIParser::E_NO_KEY) 
00324             {
00325                 err = OK;
00326                 break;
00327             }
00328         
00329             currIndex = atoi(currVal + strlen(COMPONENT));
00330             currComp = compList->GetCompByIndex(currIndex);
00331             if (!currComp)
00332             {
00333                 err = E_OUT_OF_BOUNDS;
00334                 goto BAIL;
00335             }
00336 
00337             currST->SetComponent(currComp);
00338             currNumComps++;
00339         }
00340         if (currNumComps > 0)
00341         {
00342             AddSetupType(currST);
00343             currST = NULL;
00344         }
00345 
00346 fin_iter:
00347         XI_IF_DELETE(currST);
00348     }
00349 
00350     err = OK;
00351 
00352 BAIL:
00353     XI_IF_FREE(currSec);
00354     XI_IF_FREE(currKey);
00355     XI_IF_FREE(currOIKey);
00356     XI_IF_FREE(currLCSec);
00357 
00358     return err;
00359 }
00360 
00361 int
00362 nsSetupTypeDlg::Show()
00363 {
00364     int err = OK;
00365     int numSetupTypes = 0;
00366     int i;
00367     GtkWidget *stTable = NULL;
00368     GtkWidget *radbtns[MAX_SETUP_TYPES];
00369     GtkWidget *desc[MAX_SETUP_TYPES];
00370     nsSetupType *currST = NULL;
00371     GtkWidget *destTable = NULL;
00372     GtkWidget *frame = NULL;
00373     GtkWidget *hbox = NULL;
00374 
00375     XI_VERIFY(gCtx);
00376     XI_VERIFY(gCtx->notebook);
00377 
00378     if (mWidgetsInit == FALSE)
00379     {
00380         // create a new table and add it as a page of the notebook
00381         mTable = gtk_table_new(4, 1, FALSE);
00382         gtk_notebook_append_page(GTK_NOTEBOOK(gCtx->notebook), mTable, NULL);
00383         mPageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(gCtx->notebook));
00384         gtk_widget_show(mTable);
00385 
00386         // insert a static text widget in the first row
00387         GtkWidget *msg0 = gtk_label_new(mMsg0);
00388         hbox = gtk_hbox_new(FALSE, 0);
00389         gtk_box_pack_start(GTK_BOX(hbox), msg0, FALSE, FALSE, 0);
00390         gtk_widget_show(hbox);
00391         gtk_table_attach(GTK_TABLE(mTable), hbox, 0, 1, 1, 2,
00392             static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
00393             GTK_FILL, 20, 20);
00394         gtk_widget_show(msg0);
00395 
00396         // insert a [n x 2] heterogeneous table in the second row
00397         // where n = numSetupTypes
00398         numSetupTypes = GetNumSetupTypes();
00399         stTable = gtk_table_new(numSetupTypes, 4, FALSE);
00400         gtk_widget_show(stTable);
00401         gtk_table_attach(GTK_TABLE(mTable), stTable, 0, 1, 2, 3,
00402             static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL),
00403             static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL),
00404             20, 0);
00405 
00406         currST = GetSetupTypeList();
00407         if (!currST) return E_NO_SETUPTYPES;
00408 
00409         sGroup=NULL;
00410 
00411         // radio buttons
00412         for (i = 0; i < numSetupTypes; i++)
00413         {
00414             radbtns[i] = gtk_radio_button_new_with_label(sGroup,
00415                             currST->GetDescShort());
00416             sGroup = gtk_radio_button_group(GTK_RADIO_BUTTON(radbtns[i]));
00417             gtk_table_attach(GTK_TABLE(stTable), radbtns[i], 0, 1, i, i+1,
00418                 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
00419                 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), 0, 0);
00420             gtk_signal_connect(GTK_OBJECT(radbtns[i]), "toggled",
00421                                GTK_SIGNAL_FUNC(RadBtnToggled),
00422                                reinterpret_cast<void *>(i));
00423             gtk_widget_show(radbtns[i]);
00424 
00425             desc[i] = gtk_label_new(currST->GetDescLong());
00426             gtk_label_set_justify(GTK_LABEL(desc[i]), GTK_JUSTIFY_LEFT);
00427             gtk_label_set_line_wrap(GTK_LABEL(desc[i]), TRUE);
00428             hbox = gtk_hbox_new(FALSE, 0);
00429             gtk_box_pack_start(GTK_BOX(hbox), desc[i], FALSE, FALSE, 0);
00430             gtk_widget_show(hbox);
00431             gtk_table_attach_defaults(GTK_TABLE(stTable), hbox, 1, 2, i, i+1);
00432             gtk_widget_show(desc[i]);
00433 
00434             currST = currST->GetNext();
00435         }
00436 
00437         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
00438                                         radbtns[gCtx->opt->mSetupType]), TRUE);
00439 
00440         // insert a [1 x 2] heterogeneous table in the third row
00441         destTable = gtk_table_new(1, 2, FALSE);
00442         gtk_widget_show(destTable); 
00443 
00444         gtk_table_attach(GTK_TABLE(mTable), destTable, 0, 1, 3, 4,
00445             static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL),
00446             static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL),
00447             20, 5);
00448         frame = gtk_frame_new(gCtx->Res("DEST_DIR"));
00449         gtk_table_attach_defaults(GTK_TABLE(destTable), frame, 0, 2, 0, 1);
00450         gtk_widget_show(frame);
00451 
00452         if (!gCtx->opt->mDestination)
00453         {
00454             gCtx->opt->mDestination = (char*)malloc(MAXPATHLEN * sizeof(char));
00455             getcwd(gCtx->opt->mDestination, MAXPATHLEN);
00456         }
00457         sFolder = gtk_label_new(gCtx->opt->mDestination);
00458         gtk_label_set_line_wrap(GTK_LABEL(sFolder), TRUE);
00459         gtk_widget_show(sFolder);
00460         gtk_table_attach_defaults(GTK_TABLE(destTable), sFolder, 0, 1, 0, 1);
00461 
00462         sBrowseBtn = gtk_button_new_with_label(gCtx->Res("BROWSE"));
00463         gtk_widget_show(sBrowseBtn);
00464         gtk_table_attach(GTK_TABLE(destTable), sBrowseBtn, 1, 2, 0, 1,
00465             static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL),
00466             GTK_SHRINK, 10, 10);
00467 
00468         mWidgetsInit = TRUE;
00469     }
00470     else
00471     {
00472         gtk_notebook_set_page(GTK_NOTEBOOK(gCtx->notebook), mPageNum);
00473         gtk_widget_show(mTable);
00474     }
00475 
00476     // signal connect the buttons
00477     // NOTE: back button disfunctional in this dlg since user accepted license
00478     gCtx->nextID = gtk_signal_connect(GTK_OBJECT(gCtx->next), "clicked",
00479                    GTK_SIGNAL_FUNC(nsSetupTypeDlg::Next), gCtx->sdlg);
00480     sBrowseBtnID = gtk_signal_connect(GTK_OBJECT(sBrowseBtn), "clicked",
00481                    GTK_SIGNAL_FUNC(nsSetupTypeDlg::SelectFolder), NULL);  
00482 
00483     GTK_WIDGET_SET_FLAGS(gCtx->next, GTK_CAN_DEFAULT);
00484     gtk_widget_grab_default(gCtx->next);
00485     gtk_widget_grab_focus(gCtx->next);
00486 
00487     // set up the next button.
00488     gCtx->nextLabel = gtk_label_new(gCtx->Res("NEXT"));
00489     gtk_widget_show(gCtx->nextLabel);
00490     gtk_container_add(GTK_CONTAINER(gCtx->next), gCtx->nextLabel);
00491     gtk_widget_show(gCtx->next);
00492 
00493     return err;
00494 }
00495 
00496 int
00497 nsSetupTypeDlg::Hide()
00498 {
00499     gtk_widget_hide(mTable);
00500 
00501     // disconnect and remove this dlg's nav btn
00502     gtk_signal_disconnect(GTK_OBJECT(sBrowseBtn), sBrowseBtnID);
00503     gtk_signal_disconnect(GTK_OBJECT(gCtx->next), gCtx->nextID);
00504     gtk_container_remove(GTK_CONTAINER(gCtx->next), gCtx->nextLabel); 
00505     gtk_widget_hide(gCtx->next);
00506 
00507     return OK;
00508 }
00509 
00510 int
00511 nsSetupTypeDlg::SetMsg0(char *aMsg)
00512 {
00513     if (!aMsg)
00514         return E_PARAM;
00515 
00516     mMsg0 = aMsg;
00517 
00518     return OK;
00519 }
00520 
00521 char *
00522 nsSetupTypeDlg::GetMsg0()
00523 {
00524     if (mMsg0)
00525         return mMsg0;
00526 
00527     return NULL;
00528 }
00529 
00530 int
00531 nsSetupTypeDlg::AddSetupType(nsSetupType *aSetupType)
00532 {
00533     if (!aSetupType)
00534         return E_PARAM;
00535 
00536     if (!mSetupTypeList)
00537     {
00538         mSetupTypeList = aSetupType;
00539         return OK;
00540     }
00541 
00542     nsSetupType *curr = mSetupTypeList;
00543     nsSetupType *next;
00544     while (curr)
00545     {
00546         next = NULL;
00547         next = curr->GetNext();
00548     
00549         if (!next)
00550         {
00551             return curr->SetNext(aSetupType);
00552         }
00553 
00554         curr = next;
00555     }
00556 
00557     return OK;
00558 }
00559 
00560 nsSetupType *
00561 nsSetupTypeDlg::GetSetupTypeList()
00562 {
00563     if (mSetupTypeList)
00564         return mSetupTypeList;
00565 
00566     return NULL;
00567 }
00568 
00569 int
00570 nsSetupTypeDlg::GetNumSetupTypes()
00571 {
00572     int num = 0;
00573     nsSetupType *curr = NULL;
00574 
00575     if (!mSetupTypeList)
00576         return 0;
00577     
00578     curr = mSetupTypeList;
00579     while(curr)
00580     {
00581         num++;
00582         curr = curr->GetNext();
00583     }
00584 
00585     return num;
00586 }
00587 
00588 nsSetupType *
00589 nsSetupTypeDlg::GetSelectedSetupType()
00590 {
00591     nsSetupType *curr = NULL;
00592     int numSetupTypes = GetNumSetupTypes();
00593     int setupTypeCount = 0;
00594 
00595     curr = GetSetupTypeList();
00596     while (curr && setupTypeCount < numSetupTypes)  // paranoia!
00597     {
00598         if (setupTypeCount == gCtx->opt->mSetupType)
00599             return curr;        
00600 
00601         setupTypeCount++;
00602         curr = curr->GetNext();
00603     }
00604 
00605     return NULL;
00606 }
00607 
00608 void
00609 nsSetupTypeDlg::FreeSetupTypeList()
00610 {
00611     nsSetupType *curr = mSetupTypeList;
00612     nsSetupType *prev;
00613     
00614     while (curr)
00615     {
00616         prev = curr;
00617         curr = curr->GetNext();
00618 
00619         XI_IF_DELETE(prev);
00620     }
00621 }
00622 
00623 void
00624 nsSetupTypeDlg::FreeLegacyChecks()
00625 {
00626     nsLegacyCheck *curr = NULL;
00627     nsLegacyCheck *last = NULL;
00628 
00629     if (sLegacyChecks)
00630     {
00631         curr = sLegacyChecks;
00632 
00633         while(curr)
00634         {
00635             last = curr;
00636             curr = last->GetNext();
00637 
00638             XI_IF_DELETE(last);
00639         }
00640     }
00641 }
00642 
00643 void
00644 nsSetupTypeDlg::SelectFolder(GtkWidget *aWidget, gpointer aData)
00645 {
00646     DUMP("SelectFolder");
00647 
00648     GtkWidget *fileSel = NULL;
00649     char *selDir = gCtx->opt->mDestination;
00650 
00651     fileSel = gtk_file_selection_new(gCtx->Res("SELECT_DIR"));
00652     gtk_window_set_modal(GTK_WINDOW(fileSel), TRUE);
00653     gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileSel), selDir);
00654     gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileSel)->ok_button),
00655                        "clicked", (GtkSignalFunc) SelectFolderOK, fileSel);
00656     gtk_signal_connect_object(GTK_OBJECT(
00657                                 GTK_FILE_SELECTION(fileSel)->cancel_button),
00658                                 "clicked", (GtkSignalFunc) SelectFolderCancel,
00659                                 GTK_OBJECT(fileSel));
00660     gtk_widget_show(fileSel); 
00661 }
00662 
00663 void
00664 nsSetupTypeDlg::SelectFolderOK(GtkWidget *aWidget, GtkFileSelection *aFileSel)
00665 {
00666     DUMP("SelectFolderOK");
00667 
00668     struct stat destStat;
00669     const char *selDir = gtk_file_selection_get_filename(
00670                     GTK_FILE_SELECTION(aFileSel));
00671 
00672     // put the candidate file name in the global variable, then verify it
00673 
00674     strcpy(gCtx->opt->mDestination, selDir);
00675 
00676     if (0 == stat(selDir, &destStat))
00677         if (!S_ISDIR(destStat.st_mode) || VerifyDestination() != OK ) /* not a directory, or we don't have access permissions, so don't tear down */
00678             return;
00679 
00680     // update folder path displayed
00681     gtk_label_set_text(GTK_LABEL(sFolder), gCtx->opt->mDestination);
00682     gtk_widget_show(sFolder);
00683 
00684     // tear down file sel dlg
00685     gtk_object_destroy(GTK_OBJECT(aFileSel)); 
00686 }
00687 
00688 void
00689 nsSetupTypeDlg::SelectFolderCancel(GtkWidget *aWidget, 
00690                                    GtkFileSelection *aFileSel)
00691 {
00692     // tear down file sel dlg
00693     gtk_object_destroy(GTK_OBJECT(aWidget)); 
00694     gtk_object_destroy(GTK_OBJECT(aFileSel)); 
00695 }
00696 
00697 void
00698 nsSetupTypeDlg::RadBtnToggled(GtkWidget *aWidget, gpointer aData)
00699 {
00700     DUMP("RadBtnToggled");
00701     
00702     gCtx->opt->mSetupType = NS_PTR_TO_INT32(aData);
00703 }
00704 
00705 int
00706 nsSetupTypeDlg::VerifyDestination()
00707 {
00708     int stat_err = 0;
00709     struct stat stbuf; 
00710     GtkWidget *yesButton, *noButton, *label;
00711     GtkWidget *noPermsDlg, *okButton;
00712     char message[MAXPATHLEN];
00713   
00714     stat_err = stat(gCtx->opt->mDestination, &stbuf);
00715     if (stat_err == 0)
00716     {
00717       if (access(gCtx->opt->mDestination, R_OK | W_OK | X_OK ) != 0)
00718       {
00719         if (gCtx->opt->mMode != nsXIOptions::MODE_DEFAULT) {
00720           ErrorHandler(E_NO_PERMS);
00721           return E_NO_PERMS;
00722         }
00723         sprintf(message, gCtx->Res("NO_PERMS"), gCtx->opt->mDestination);
00724 
00725         noPermsDlg = gtk_dialog_new();
00726         gtk_window_set_modal(GTK_WINDOW(noPermsDlg), TRUE);
00727         label = gtk_label_new(message);
00728         okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
00729 
00730         if (noPermsDlg && label && okButton)
00731         {
00732           gtk_window_set_title(GTK_WINDOW(noPermsDlg), gCtx->opt->mTitle);
00733           gtk_window_set_position(GTK_WINDOW(noPermsDlg), 
00734             GTK_WIN_POS_CENTER);
00735           gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
00736           gtk_box_pack_start(GTK_BOX(
00737             GTK_DIALOG(noPermsDlg)->action_area), okButton, FALSE, FALSE, 10);
00738           gtk_signal_connect(GTK_OBJECT(okButton), "clicked", 
00739             GTK_SIGNAL_FUNC(NoPermsOK), noPermsDlg);
00740           gtk_box_pack_start(GTK_BOX(
00741             GTK_DIALOG(noPermsDlg)->vbox), label, FALSE, FALSE, 10);
00742 
00743           GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
00744           gtk_widget_grab_default(okButton);
00745 
00746           gtk_widget_show_all(noPermsDlg);
00747         }
00748 
00749         return E_NO_PERMS;
00750       }
00751       else
00752       {
00753         // perms OK, we can proceed
00754         return OK;
00755       }
00756     }
00757 
00758     if (gCtx->opt->mMode != nsXIOptions::MODE_DEFAULT)
00759     {
00760       CreateDestYes((GtkWidget *)NULL, (gpointer) gCtx->sdlg);
00761       return E_NO_DEST;
00762     }
00763     // destination doesn't exist so ask user if we should create it
00764     sprintf(message, gCtx->Res("DOESNT_EXIST"), gCtx->opt->mDestination);
00765 
00766     sCreateDestDlg = gtk_dialog_new();
00767     gtk_window_set_modal(GTK_WINDOW(sCreateDestDlg), TRUE);
00768     label = gtk_label_new(message);
00769     yesButton = gtk_button_new_with_label(gCtx->Res("YES_LABEL"));
00770     noButton = gtk_button_new_with_label(gCtx->Res("NO_LABEL"));
00771 
00772     gtk_window_set_title(GTK_WINDOW(sCreateDestDlg), gCtx->opt->mTitle);
00773     gtk_window_set_position(GTK_WINDOW(sCreateDestDlg), GTK_WIN_POS_CENTER);
00774     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sCreateDestDlg)->action_area),
00775                       yesButton);
00776     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sCreateDestDlg)->action_area),
00777                       noButton);
00778     gtk_signal_connect(GTK_OBJECT(yesButton), "clicked",
00779                        GTK_SIGNAL_FUNC(CreateDestYes), sCreateDestDlg);
00780     gtk_signal_connect(GTK_OBJECT(noButton), "clicked",
00781                        GTK_SIGNAL_FUNC(CreateDestNo), sCreateDestDlg);
00782 
00783     GTK_WIDGET_SET_FLAGS(yesButton, GTK_CAN_DEFAULT);
00784     gtk_widget_grab_default(yesButton);
00785 
00786     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sCreateDestDlg)->vbox), label);
00787     
00788     gtk_widget_show_all(sCreateDestDlg);
00789 
00790     return E_NO_DEST;
00791 }
00792 
00793 void
00794 nsSetupTypeDlg::NoPermsOK(GtkWidget *aWidget, gpointer aData)
00795 {
00796     GtkWidget *noPermsDlg = (GtkWidget *) aData;
00797 
00798     if (!noPermsDlg)
00799         return;
00800 
00801     gtk_widget_destroy(noPermsDlg);
00802 }
00803 
00804 void
00805 nsSetupTypeDlg::CreateDestYes(GtkWidget *aWidget, gpointer aData)
00806 {
00807     DUMP("CreateDestYes");
00808     int err = 0; 
00809     char path[PATH_MAX + 1];
00810     int  pathLen = strlen(gCtx->opt->mDestination);
00811 
00812     if (pathLen > PATH_MAX)
00813         pathLen = PATH_MAX;
00814     memcpy(path, gCtx->opt->mDestination, pathLen);
00815     path[pathLen] = '/';  // for uniform handling
00816 
00817     struct stat buf;
00818 
00819     for (int i = 1; !err && i <= pathLen; i++) 
00820     {
00821         if (path[i] == '/') 
00822         {
00823             path[i] = '\0';
00824             if (stat(path, &buf) != 0) 
00825             {
00826                 err = mkdir(path, 0755);
00827             }
00828             path[i] = '/';
00829         }
00830     }
00831 
00832     if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
00833     {
00834         gtk_widget_destroy(sCreateDestDlg);
00835     }
00836 
00837     if (err != 0)
00838     {
00839         ErrorHandler(E_MKDIR_FAIL);
00840     }
00841     else
00842     {
00843         // try to move forward to installer dialog again
00844         nsSetupTypeDlg::Next((GtkWidget *)NULL, NULL);
00845     }
00846 }
00847 
00848 void
00849 nsSetupTypeDlg::CreateDestNo(GtkWidget *aWidget, gpointer aData)
00850 {
00851     DUMP("CreateDestNo");
00852 
00853     gtk_widget_destroy(sCreateDestDlg);
00854 }
00855 
00856 int
00857 nsSetupTypeDlg::DeleteOldInst()
00858 {
00859     DUMP("DeleteOldInst");
00860 
00861     const int MAXCHARS = 64; // Maximum chars per line in Delete Dialog
00862     const int MAXLINES = 20; // Maximum lines in Delete Dialog
00863     int err = OK;
00864     struct stat dummy;
00865     char path[MAXPATHLEN];
00866     GtkWidget *label = NULL;
00867     GtkWidget *deleteBtn = NULL; /* delete button */
00868     GtkWidget *cancelBtn = NULL; /* cancel button */
00869     char *msgPtr = NULL, *msgChunkPtr = NULL, *msgEndPtr = NULL;
00870     char msgChunk[MAXCHARS+1];
00871     char msg[MAXPATHLEN+512];
00872     nsLegacyCheck *currLC = NULL;
00873 
00874     currLC = sLegacyChecks;
00875     while (currLC)
00876     {
00877       memset(path, 0, MAXPATHLEN);
00878       ConstructPath(path, gCtx->opt->mDestination, currLC->GetFilename());
00879       DUMP(path);
00880 
00881       // check if old installation exists
00882       if (0 == stat(path, &dummy))
00883       {
00884           if (gCtx->opt->mMode != nsXIOptions::MODE_DEFAULT)
00885           {
00886               DeleteInstDelete((GtkWidget *)NULL, (gpointer) gCtx->sdlg);
00887               return OK;
00888           }
00889 
00890           // throw up delete dialog 
00891           sDelInstDlg = gtk_dialog_new();
00892           gtk_window_set_modal(GTK_WINDOW(sDelInstDlg), TRUE);
00893           gtk_window_set_title(GTK_WINDOW(sDelInstDlg), gCtx->opt->mTitle);
00894           gtk_window_set_position(GTK_WINDOW(sDelInstDlg), GTK_WIN_POS_CENTER);
00895 
00896           deleteBtn = gtk_button_new_with_label(gCtx->Res("DELETE_LABEL"));
00897           cancelBtn = gtk_button_new_with_label(gCtx->Res("CANCEL_LABEL"));
00898 
00899           gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sDelInstDlg)->action_area), 
00900               deleteBtn);
00901           gtk_container_add(GTK_CONTAINER(GTK_DIALOG(sDelInstDlg)->action_area),
00902               cancelBtn);
00903           gtk_signal_connect(GTK_OBJECT(deleteBtn), "clicked",
00904                          GTK_SIGNAL_FUNC(DeleteInstDelete), sDelInstDlg);
00905           gtk_signal_connect(GTK_OBJECT(cancelBtn), "clicked",
00906                          GTK_SIGNAL_FUNC(DeleteInstCancel), sDelInstDlg);
00907 
00908           GTK_WIDGET_SET_FLAGS(cancelBtn, GTK_CAN_DEFAULT);
00909           gtk_widget_grab_default(cancelBtn);
00910 
00911           snprintf(msg, sizeof(msg), currLC->GetMessage(), gCtx->opt->mDestination);
00912           msgPtr = msg;
00913           msgEndPtr = msg + strlen(msg);
00914           // wrap message at MAXCHARS colums (or last space inside MAXCHARS)
00915           // stop at MAXLINES rows or stop after last char is reached
00916           for (int i = 0; i < MAXLINES && msgPtr < msgEndPtr; i++)
00917           {
00918               // get the next MAXCHARS chars
00919               memset(msgChunk, 0, MAXCHARS+1);
00920               strncpy(msgChunk, msgPtr, MAXCHARS);
00921 
00922               // find last space
00923               msgChunkPtr = strrchr(msgChunk, ' ');
00924               if (msgChunkPtr)
00925               {
00926                   *msgChunkPtr = '\0';
00927                   msgPtr += (msgChunkPtr - msgChunk + 1);
00928               }
00929               else
00930               {
00931                   msgPtr += MAXCHARS;
00932               }
00933               label = gtk_label_new(msgChunk);
00934               gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sDelInstDlg)->vbox), label,
00935                   FALSE, FALSE, 0);
00936           }
00937           gtk_widget_show_all(sDelInstDlg);
00938       
00939           err = E_OLD_INST;
00940           break;
00941       }
00942       currLC = currLC->GetNext();    
00943     }
00944 
00945     return err;
00946 }
00947 
00948 void         
00949 nsSetupTypeDlg::DeleteInstDelete(GtkWidget *aWidget, gpointer aData)
00950 {
00951     DUMP("DeleteInstDelete");
00952 
00953     if (!fork())
00954     {
00955         execlp("rm", "rm", "-rf", gCtx->opt->mDestination, NULL);
00956         /* execlp shouldn't return, we need to exit in case it does */
00957         _exit(0);
00958     }
00959     wait(NULL);
00960 
00961     if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
00962     {
00963        gtk_widget_destroy(sDelInstDlg);
00964     }
00965 
00966     // We just deleted the directory, so the parent exists
00967     // and we have appropriate perms.
00968     mkdir(gCtx->opt->mDestination, 0755);
00969 
00970     if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
00971     {
00972         // Try to move forward to installer dialog again.
00973         nsSetupTypeDlg::Next((GtkWidget *)NULL, NULL);
00974     }
00975 }
00976 
00977 void         
00978 nsSetupTypeDlg::DeleteInstCancel(GtkWidget *aWidget, gpointer aData)
00979 {
00980     DUMP("DeleteInstCancel");
00981 
00982     gtk_widget_destroy(sDelInstDlg);
00983 }
00984 
00985 int
00986 nsSetupTypeDlg::ConstructPath(char *aDest, char *aTrunk, char *aLeaf)
00987 {
00988     int err = OK;
00989     int trunkLen;
00990     char *lastSlash = NULL;
00991     
00992     if (!aDest || !aTrunk || !aLeaf)
00993         return E_PARAM;
00994 
00995     trunkLen = strlen(aTrunk);
00996     lastSlash = strrchr(aTrunk, '/');
00997     
00998     strcpy(aDest, aTrunk);
00999     if (lastSlash != aTrunk + (trunkLen - 1))
01000     {
01001         // need to tack on a slash
01002         strcat(aDest, "/");
01003     }
01004     strcat(aDest, aLeaf);
01005 
01006     return err;
01007 }
01008 
01009 int
01010 nsSetupTypeDlg::CheckDestEmpty()
01011 {
01012     DUMP("CheckDestEmpty");
01013 
01014     DIR *destDirD;
01015     struct dirent *de;
01016     nsObjectIgnore *currOI = NULL;
01017 
01018     /* check if the destination directory is empty */
01019     destDirD = opendir(gCtx->opt->mDestination);
01020     while (de = readdir(destDirD))
01021     {
01022         if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
01023         {
01024             currOI = sObjectsToIgnore;
01025             while (currOI)
01026             {
01027                 // check if this is an Object To Ignore
01028                 if (!strcmp(currOI->GetFilename(),de->d_name))
01029                     break;
01030 
01031                 currOI = currOI->GetNext();    
01032             }
01033             if (!currOI)
01034             {
01035                 closedir(destDirD);
01036                 ErrorHandler(E_DIR_NOT_EMPTY);
01037                 return E_DIR_NOT_EMPTY;
01038             }
01039         }
01040     }
01041     
01042     closedir(destDirD);
01043     return OK;
01044 }
01045 
01046 int
01047 nsSetupTypeDlg::VerifyDiskSpace(void)
01048 {
01049     int err = OK;
01050     int dsAvail, dsReqd;
01051     char dsAvailStr[128], dsReqdStr[128];
01052     char message[512];
01053     GtkWidget *noDSDlg, *label, *okButton;
01054 
01055     // find disk space available at destination
01056     dsAvail = DSAvailable();
01057     if (dsAvail < 0)
01058         return OK; // optimistic when statfs failed
01059                    // or we don't have statfs
01060 
01061     // get disk space required
01062     dsReqd = DSRequired();
01063 
01064     if (dsReqd > dsAvail)
01065     {
01066         if (gCtx->opt->mMode == nsXIOptions::MODE_DEFAULT)
01067         {
01068             // throw up not enough ds dlg
01069             sprintf(dsAvailStr, gCtx->Res("DS_AVAIL"), dsAvail);
01070             sprintf(dsReqdStr, gCtx->Res("DS_REQD"), dsReqd);
01071             sprintf(message, "%s\n%s\n\n%s", dsAvailStr, dsReqdStr, 
01072                     gCtx->Res("NO_DISK_SPACE"));
01073 
01074             noDSDlg = gtk_dialog_new();
01075             gtk_window_set_modal(GTK_WINDOW(noDSDlg), TRUE);
01076             label = gtk_label_new(message);
01077             okButton = gtk_button_new_with_label(gCtx->Res("OK_LABEL"));
01078 
01079             if (noDSDlg && label && okButton)
01080             {
01081                 gtk_window_set_title(GTK_WINDOW(noDSDlg), gCtx->opt->mTitle);
01082                 gtk_window_set_position(GTK_WINDOW(noDSDlg), 
01083                         GTK_WIN_POS_CENTER);
01084                 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
01085                 gtk_misc_set_padding(GTK_MISC(label), 20, 20);
01086                 gtk_misc_set_alignment(GTK_MISC(label), 0.5, 1);
01087                 gtk_box_pack_start(GTK_BOX(
01088                         GTK_DIALOG(noDSDlg)->action_area), okButton,
01089                         FALSE, FALSE, 10);
01090                 gtk_signal_connect(GTK_OBJECT(okButton), "clicked", 
01091                         GTK_SIGNAL_FUNC(NoDiskSpaceOK), noDSDlg);
01092                 gtk_box_pack_start(GTK_BOX(
01093                         GTK_DIALOG(noDSDlg)->vbox), label, FALSE, FALSE, 10);
01094 
01095                 GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
01096                 gtk_widget_grab_default(okButton);
01097 
01098                 gtk_widget_show_all(noDSDlg);
01099             }
01100         }
01101 
01102         err = E_NO_DISK_SPACE;
01103     }
01104 
01105     return err;
01106 }
01107 
01108 int
01109 nsSetupTypeDlg::DSAvailable(void)
01110 {
01111     // returns disk space available in kilobytes
01112 
01113     int dsAvail = -1;
01114 
01115 #if defined(HAVE_SYS_STATVFS_H) || defined(HAVE_SYS_STATFS_H)
01116     struct STATFS buf;
01117     int rv;
01118 
01119     if (gCtx->opt->mDestination)
01120     {
01121         rv = STATFS(gCtx->opt->mDestination, &buf);
01122         if (rv == 0)
01123         {
01124             if (buf.f_bsize > 1024 && (buf.f_bsize%1024 == 0))
01125             {
01126                 // normally the block size is >= 1024 and a multiple
01127                 // so we can shave off the last three digits before 
01128                 // finding the product of the block size and num blocks
01129                 // which is important for large disks
01130 
01131                 dsAvail = (buf.f_bsize/1024) * (buf.f_bavail);
01132             }
01133             else
01134             {
01135                 // attempt to stuff into a 32 bit int even though
01136                 // we convert from bytes -> kilobytes later
01137                 // (may fail to compute on very large disks whose
01138                 // block size is not a multiple of 1024 -- highly 
01139                 // improbable)
01140 
01141                 dsAvail = (buf.f_bsize * buf.f_bavail)/1024;
01142             }
01143         }
01144     }
01145 #endif // HAVE_SYS_STATVFS_H -or- HAVE_SYS_STATFS_H 
01146 
01147     return dsAvail;
01148 }
01149 
01150 int 
01151 nsSetupTypeDlg::DSRequired(void)
01152 {
01153     // returns disk space required in kilobytes 
01154 
01155     int dsReqd = 0;
01156     nsComponentList *comps;
01157     int bCus;
01158 
01159     // find setup type's component list
01160     bCus = (gCtx->opt->mSetupType == (gCtx->sdlg->GetNumSetupTypes() - 1));
01161     comps = gCtx->sdlg->GetSelectedSetupType()->GetComponents();
01162 
01163     // loop through all components
01164     nsComponent *currComp = comps->GetHead();
01165     while (currComp)
01166     {
01167         if ( (bCus == TRUE && currComp->IsSelected()) || (bCus == FALSE) )
01168         {
01169             // add to disk space required 
01170             dsReqd += currComp->GetInstallSize();
01171             dsReqd += currComp->GetArchiveSize();
01172         }
01173 
01174         currComp = comps->GetNext();
01175     }
01176 
01177     return dsReqd;
01178 }
01179 
01180 void
01181 nsSetupTypeDlg::NoDiskSpaceOK(GtkWidget *aWidget, gpointer aData)
01182 {
01183     GtkWidget *noDSDlg = (GtkWidget *) aData;
01184 
01185     if (!noDSDlg)
01186         return;
01187 
01188     gtk_widget_destroy(noDSDlg);
01189 }
01190