Back to index

lightning-sunbird  0.9+nobinonly
nsXIEngine.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  *   Syd Logan syd@netscape.com
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsFTPConn.h"
00042 #include "nsHTTPConn.h"
00043 #include "nsXIEngine.h"
00044 
00045 #include <errno.h>
00046 #include <stdlib.h>
00047 
00048 #define CORE_LIB_COUNT 13
00049 
00050 const char kHTTPProto[] = "http://";
00051 const char kFTPProto[] = "ftp://";
00052 const char kDLMarkerPath[] = "./xpi/.current_download";
00053 
00054 nsXIEngine::nsXIEngine() :
00055     mTmp(NULL),
00056     mOriginalDir(NULL)
00057 {
00058 }
00059 
00060 #define RM_PREFIX "rm -rf "
00061 
00062 nsXIEngine::~nsXIEngine()   
00063 {
00064     DUMP("~nsXIEngine");
00065 
00066     // reset back to original directory
00067     chdir(mOriginalDir);
00068 
00069     if ( mTmp != (char *) NULL ) {
00070 
00071       // blow away the temp dir 
00072 
00073       char *buf;
00074       buf = (char *) malloc( strlen(RM_PREFIX) + strlen( mTmp ) + 1 );
00075       if ( buf != (char *) NULL ) {
00076         strcpy( buf, RM_PREFIX );
00077         strcat( buf, mTmp );
00078         system( buf ); 
00079         XI_IF_FREE(mTmp);
00080         free( buf );
00081       }
00082     }
00083     XI_IF_FREE(mOriginalDir);
00084 }
00085 
00086 int     
00087 EventPumpCB(void)
00088 {
00089     return 0;
00090 }
00091 
00092 #define MAXCRC 4
00093 
00094 int     
00095 nsXIEngine::Download(int aCustom, nsComponentList *aComps)
00096 {
00097     DUMP("Download");
00098 
00099     if (!aComps)
00100         return E_PARAM;
00101 
00102     int err = OK;
00103     nsComponent *currComp = NULL, *markedComp = NULL;
00104     char *currURL = NULL;
00105     char *currHost = NULL;
00106     char *currPath = NULL;
00107     char localPath[MAXPATHLEN];
00108     char *srvPath = NULL;
00109     char *proxyURL = NULL;
00110     char *qualURL = NULL;
00111     int i, crcPass, bDone;
00112     int currPort;
00113     struct stat stbuf;
00114     int resPos = 0;
00115     int fileSize = 0;
00116     int currCompNum = 1;
00117     int numToDL = 0; // num xpis to download
00118     CONN myConn;
00119     
00120     err = GetDLMarkedComp(aComps, &markedComp);
00121     if (err == OK && markedComp)
00122     {
00123         sprintf(localPath, "%s/%s", XPI_DIR, markedComp->GetArchive());
00124         markedComp->SetResumePos(GetFileSize(localPath));
00125     }
00126 
00127     // check if ./xpi dir exists else create it
00128     if (0 != stat(XPI_DIR, &stbuf))
00129     {
00130         if (0 != mkdir(XPI_DIR, 0755))
00131             return E_MKDIR_FAIL;
00132     }
00133 
00134     numToDL = TotalToDownload(aCustom, aComps);
00135 
00136     currComp = aComps->GetHead();
00137 
00138     myConn.URL = (char *) NULL;
00139     myConn.type = TYPE_UNDEF;
00140 
00141     crcPass = 0;
00142     bDone = 0;
00143     while ( bDone == 0 && crcPass < MAXCRC ) {
00144       while (currComp)
00145       {
00146         if ( (aCustom == TRUE && currComp->IsSelected()) || (aCustom == FALSE) )
00147         {
00148             // in case we are resuming inter- or intra-installer session
00149             if (currComp->IsDownloaded())
00150             {
00151                 currComp = aComps->GetNext();
00152                 continue;
00153             }
00154 
00155             SetDLMarker(currComp->GetArchive());
00156 
00157             for (i = 0; i < MAX_URLS; i++)
00158             {
00159                 currURL = currComp->GetURL(i);
00160                 if (!currURL) break;
00161                 
00162                 if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
00163                     nsInstallDlg::SetDownloadComp(currComp, i, 
00164                         currCompNum, numToDL);
00165 
00166                 // restore resume position
00167                 resPos = currComp->GetResumePos();
00168 
00169                 // has a proxy server been specified?
00170                 if (gCtx->opt->mProxyHost && gCtx->opt->mProxyPort)
00171                 {
00172                     // URL of the proxy server
00173                     proxyURL = (char *) malloc(strlen(kHTTPProto) + 
00174                                         strlen(gCtx->opt->mProxyHost) + 1 +
00175                                         strlen(gCtx->opt->mProxyPort) + 1);
00176                     if (!proxyURL)
00177                     {
00178                         err = E_MEM;
00179                         break;
00180                     }
00181 
00182                     sprintf(proxyURL, "%s%s:%s", kHTTPProto,
00183                             gCtx->opt->mProxyHost, gCtx->opt->mProxyPort);
00184 
00185                     nsHTTPConn *conn = new nsHTTPConn(proxyURL, EventPumpCB);
00186                     if (!conn)
00187                     {
00188                         err = E_MEM;
00189                         break;
00190                     }
00191 
00192                     // URL of the actual file to download
00193                     qualURL = (char *) malloc(strlen(currURL) + 
00194                                        strlen(currComp->GetArchive()) + 1);
00195                     if (!qualURL)
00196                     {
00197                         err = E_MEM;
00198                         break;
00199                     }
00200                     sprintf(qualURL, "%s%s", currURL, currComp->GetArchive());
00201 
00202                     if (*gCtx->opt->mProxyUser || *gCtx->opt->mProxyPswd)
00203                     {
00204                       conn->SetProxyInfo(qualURL, gCtx->opt->mProxyUser,
00205                                                   gCtx->opt->mProxyPswd);
00206                     }
00207                     else
00208                     {
00209                       conn->SetProxyInfo(qualURL, NULL, NULL);
00210                     }
00211 
00212                     err = conn->Open();
00213                     if (err == nsHTTPConn::OK)
00214                     {
00215                         sprintf(localPath, "%s/%s", XPI_DIR,
00216                             currComp->GetArchive());
00217                         if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT)
00218                           err = conn->Get(NULL, localPath, resPos);
00219                         else
00220                           err = conn->Get(nsInstallDlg::DownloadCB, localPath,
00221                                           resPos);
00222                         conn->Close();
00223                     }
00224                     
00225                     XI_IF_FREE(proxyURL);
00226                     XI_IF_FREE(qualURL);
00227                     XI_IF_DELETE(conn);
00228                 }
00229             
00230                 // is this an HTTP URL?
00231                 else if (strncmp(currURL, kHTTPProto, strlen(kHTTPProto)) == 0)
00232                 {
00233                     // URL of the actual file to download
00234                     qualURL = (char *) malloc(strlen(currURL) + 
00235                                        strlen(currComp->GetArchive()) + 1);
00236                     if (!qualURL)
00237                     {
00238                         err = E_MEM;
00239                         break;
00240                     }
00241                     sprintf(qualURL, "%s%s", currURL, currComp->GetArchive());
00242 
00243                     nsHTTPConn *conn = new nsHTTPConn(qualURL, EventPumpCB);
00244                     if (!conn)
00245                     {
00246                         err = E_MEM;
00247                         break;
00248                     }
00249     
00250                     err = conn->Open();
00251                     if (err == nsHTTPConn::OK)
00252                     {
00253                         sprintf(localPath, "%s/%s", XPI_DIR,
00254                             currComp->GetArchive());
00255                         if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT)
00256                           err = conn->Get(NULL, localPath, resPos);
00257                         else
00258                           err = conn->Get(nsInstallDlg::DownloadCB, localPath,
00259                                           resPos);
00260                         conn->Close();
00261                     }
00262 
00263                     XI_IF_FREE(qualURL);
00264                     XI_IF_DELETE(conn);
00265                 }
00266 
00267                 // or is this an FTP URL? 
00268                 else if (strncmp(currURL, kFTPProto, strlen(kFTPProto)) == 0)
00269                 {
00270                     PRBool isNewConn;
00271 
00272                     err = nsHTTPConn::ParseURL(kFTPProto, currURL, &currHost, 
00273                             &currPort, &currPath);
00274                     if (err != nsHTTPConn::OK)
00275                         break;
00276     
00277                     // path on the remote server
00278                     srvPath = (char *) malloc(strlen(currPath) +
00279                                         strlen(currComp->GetArchive()) + 1);
00280                     if (!srvPath)
00281                     {
00282                         err = E_MEM;
00283                         break;
00284                     }
00285                     sprintf(srvPath, "%s%s", currPath, currComp->GetArchive());
00286 
00287                     // closes the old connection if any
00288 
00289                     isNewConn = CheckConn( currHost, TYPE_FTP, &myConn, PR_FALSE ); 
00290                     err = nsFTPConn::OK;
00291 
00292                     nsFTPConn *conn;
00293                     if ( isNewConn == PR_TRUE ) {
00294                       conn = new nsFTPConn(currHost, EventPumpCB);
00295                       if (!conn) {
00296                         err = E_MEM;
00297                         break;
00298                       }
00299                       err = conn->Open();
00300                       myConn.conn = (void *) conn;
00301                       myConn.type = TYPE_FTP;
00302                       myConn.URL = (char *) calloc(strlen(currHost) + 1, sizeof(char));
00303                       if ( myConn.URL != (char *) NULL )
00304                         strcpy( myConn.URL, currHost );
00305                     } else
00306                       conn = (nsFTPConn *) myConn.conn;
00307 
00308                     if (isNewConn == PR_FALSE || err == nsFTPConn::OK)
00309                     {
00310                         sprintf(localPath, "%s/%s", XPI_DIR,
00311                             currComp->GetArchive());
00312                         if (gCtx->opt->mMode == nsXIOptions::MODE_SILENT)
00313                           err = conn->Get(srvPath, localPath, nsFTPConn::BINARY, 
00314                               resPos, 1, NULL);
00315                         else
00316                           err = conn->Get(srvPath, localPath, nsFTPConn::BINARY, 
00317                               resPos, 1, nsInstallDlg::DownloadCB);
00318                     }
00319 
00320                     XI_IF_FREE(currHost);
00321                     XI_IF_FREE(currPath);
00322                     XI_IF_FREE(srvPath);
00323                 }
00324 
00325                 // else error: malformed URL
00326                 else
00327                 {
00328                     err = nsHTTPConn::E_MALFORMED_URL;
00329                 }
00330 
00331                 if (err == nsHTTPConn::E_USER_CANCEL)
00332                     err = nsInstallDlg::CancelOrPause();
00333 
00334                 // user hit pause and subsequently resumed
00335                 if (err == nsInstallDlg::E_DL_PAUSE)
00336                 {
00337                     currComp->SetResumePos(GetFileSize(localPath));
00338                     return err;
00339                 }
00340 
00341                 // user cancelled during download
00342                 else if (err == nsInstallDlg::E_DL_CANCEL)
00343                     return err;
00344 
00345                 // user didn't cancel or pause: some other dl error occured
00346                 else if (err != OK)
00347                 {
00348                     fileSize = GetFileSize(localPath);
00349 
00350                     if (fileSize > 0)
00351                     {
00352                         // assume dropped connection if file size > 0
00353                         currComp->SetResumePos(fileSize);
00354                         return nsInstallDlg::E_DL_DROP_CXN;
00355                     }
00356                     else
00357                     {
00358                         // failover
00359                         continue;
00360                     }
00361                 }
00362 
00363                 if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
00364                     nsInstallDlg::ClearRateLabel(); // clean after ourselves
00365 
00366                 if (err == OK) 
00367                 {
00368                     currComp->SetDownloaded(TRUE);
00369                     currCompNum++;
00370                     break;  // no need to failover
00371                 }
00372             }
00373         }
00374         
00375         currComp = aComps->GetNext();
00376       }
00377    
00378       CheckConn( "", TYPE_UNDEF, &myConn, true );
00379  
00380       bDone = CRCCheckDownloadedArchives(XPI_DIR, strlen(XPI_DIR), 
00381                 aComps, aCustom);
00382       crcPass++;
00383       if ( bDone == 0 && crcPass < MAXCRC ) {
00384         // reset ourselves
00385         numToDL = TotalToDownload(aCustom, aComps);
00386         currComp = aComps->GetHead();
00387         currCompNum = 1;
00388         if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
00389           gCtx->idlg->ReInitUI(); 
00390         gCtx->idlg->ShowCRCDlg(); 
00391       }
00392     }
00393     gCtx->idlg->DestroyCRCDlg(); // destroy the CRC dialog if showing
00394     if ( crcPass < MAXCRC ) {
00395       // download complete: remove marker
00396       DelDLMarker();
00397       return OK;
00398     } else {
00399       return E_CRC_FAILED;
00400     }
00401 }
00402 
00403 /* 
00404  * Name: CheckConn
00405  *
00406  * Arguments: 
00407  *
00408  * char *URL; -- URL of connection we need to have established
00409  * int type; -- connection type (TYPE_HTTP, etc.)
00410  * CONN *myConn; -- connection state (info about currently established 
00411  *                   connection)
00412  * PRBool force; -- force closing of connection
00413  *
00414  * Description:
00415  *
00416  * This function determines if the caller should open a connection based upon 
00417  * the current connection that is open (if any), and the type of connection 
00418  * desired. If no previous connection was established, the function returns 
00419  * true. If the connection is for a different protocol, then true is also 
00420  * returned (and the previous connection is closed). If the connection is for 
00421  * the same protocol and the URL is different, the previous connection is 
00422  * closed and true is returned. Otherwise, the connection has already been
00423  * established, and false is returned.
00424  *
00425  * Return Value: If a new connection needs to be opened, true. Otherwise, 
00426  * false is returned.
00427  *
00428  * Original Code: Syd Logan (syd@netscape.com) 6/24/2001
00429  *
00430 */
00431 
00432 PRBool
00433 nsXIEngine::CheckConn( char *URL, int type, CONN *myConn, PRBool force )
00434 {
00435        nsFTPConn *fconn;
00436        nsHTTPConn *hconn;
00437        PRBool retval = false;
00438 
00439        if ( myConn->type == TYPE_UNDEF )
00440               retval = PR_TRUE;                                // first time
00441        else if ( ( myConn->type != type || myConn->URL == (char *) NULL || strcmp( URL, myConn->URL ) || force == PR_TRUE ) /* && gControls->state != ePaused */) {
00442               retval = PR_TRUE;
00443               switch ( myConn->type ) {
00444               case TYPE_HTTP:
00445               case TYPE_PROXY:
00446                      hconn = (nsHTTPConn *) myConn->conn;
00447                      hconn->Close();
00448                      break;
00449               case TYPE_FTP:
00450                      fconn = (nsFTPConn *) myConn->conn;
00451       if ( fconn != (nsFTPConn *) NULL ) {
00452         fconn->Close();
00453         XI_IF_DELETE(fconn);
00454         myConn->conn = NULL;
00455       }
00456                      break;
00457               }
00458        }
00459        
00460        if ( retval == PR_TRUE && myConn->URL != (char *) NULL ) {
00461     free( myConn->URL );
00462     myConn->URL = (char *) NULL;
00463   }
00464 
00465        return retval;
00466 }
00467 
00468 int     
00469 nsXIEngine::Extract(nsComponent *aXPIEngine)
00470 {
00471     int rv;
00472 
00473     if (!aXPIEngine)
00474         return E_PARAM;
00475 
00476     mTmp = NULL;
00477     rv = MakeUniqueTmpDir();
00478     if (!mTmp || rv != OK)
00479         return E_DIR_CREATE;
00480 
00481     nsZipExtractor *unzip = new nsZipExtractor(XPI_DIR, mTmp);
00482     rv = unzip->Extract(aXPIEngine, CORE_LIB_COUNT);
00483     XI_IF_DELETE(unzip);
00484 
00485     return rv;
00486 }
00487 
00488 int     
00489 nsXIEngine::Install(int aCustom, nsComponentList *aComps, char *aDestination)
00490 {
00491     DUMP("Install");
00492 
00493     int err = OK;
00494     xpistub_t stub;
00495     char *old_LD_LIBRARY_PATH = NULL;
00496     char new_LD_LIBRARY_PATH[MAXPATHLEN];
00497     int i;
00498     int compNum = 1;
00499     int numComps;
00500     nsComponent *currComp = NULL;
00501 
00502     if (!aComps || !aDestination)
00503         return E_PARAM;
00504 
00505     numComps = aCustom ? aComps->GetLengthSelected() : aComps->GetLength();
00506 
00507     // handle LD_LIBRARY_PATH settings
00508 #if defined (SOLARIS) || defined (IRIX)
00509     sprintf(new_LD_LIBRARY_PATH, "LD_LIBRARY_PATH=%s/bin:.", mTmp);
00510 #else
00511     sprintf(new_LD_LIBRARY_PATH, "%s/bin:.", mTmp);
00512 #endif
00513     DUMP(new_LD_LIBRARY_PATH);
00514     old_LD_LIBRARY_PATH = getenv("LD_LIBRARY_PATH");
00515 #if defined (SOLARIS) || defined (IRIX)
00516     putenv(new_LD_LIBRARY_PATH);
00517 #else
00518     setenv("LD_LIBRARY_PATH", new_LD_LIBRARY_PATH, 1);
00519 #endif 
00520     currComp = aComps->GetHead();
00521     err = LoadXPIStub(&stub, aDestination);
00522     if (err == OK)
00523     {
00524         for (i = 0; i < MAX_COMPONENTS; i++)
00525         {
00526             if (!currComp)
00527                 break;
00528 
00529             if (  (aCustom && currComp->IsSelected()) ||
00530                   (!aCustom)  )
00531             {
00532 #ifdef DEBUG
00533                 printf("%s %d: DOWNLOAD_ONLY for %s is %d\n", __FILE__, __LINE__, 
00534                     currComp->GetArchive(), currComp->IsDownloadOnly());
00535 #endif
00536                 if (!currComp->IsDownloadOnly())
00537                 {
00538                     if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
00539                         nsInstallDlg::MajorProgressCB(currComp->GetDescShort(),
00540                             compNum, numComps, nsInstallDlg::ACT_INSTALL);
00541                     err = InstallXPI(currComp, &stub);
00542                     if (err != OK)
00543                     if (err == E_INSTALL)
00544                         ErrorHandler(err, currComp->GetArchive()); //handle E_INSTALL separately
00545                     else
00546                         ErrorHandler(err); //handle and continue 
00547                     compNum++;
00548                 }
00549             }
00550 
00551             currComp = aComps->GetNext();
00552         }
00553         UnloadXPIStub(&stub);
00554     }
00555 
00556     // restore LD_LIBRARY_PATH settings
00557 #if defined (SOLARIS) || defined (IRIX)
00558     char old_LD_env[MAXPATHLEN];
00559 
00560     sprintf(old_LD_env, "LD_LIBRARY_PATH=%s", old_LD_LIBRARY_PATH);
00561     putenv(old_LD_env);
00562 #else
00563     setenv("LD_LIBRARY_PATH", old_LD_LIBRARY_PATH, 1);
00564 #endif
00565 
00566     return err;
00567 }
00568 
00569 int
00570 nsXIEngine::MakeUniqueTmpDir()
00571 {
00572     int err = E_DIR_CREATE;
00573     char tmpnam[MAXPATHLEN];
00574     char *tmpdir = getenv("TMPDIR");
00575     if (!tmpdir) tmpdir = getenv("TMP");
00576     if (!tmpdir) tmpdir = getenv("TEMP");
00577     if (!tmpdir) tmpdir = P_tmpdir;
00578     snprintf(tmpnam, sizeof(tmpnam), "%s/xpi.XXXXXX", tmpdir);
00579 #ifdef HAVE_MKDTEMP
00580     if (mkdtemp(tmpnam)) {
00581       mTmp = strdup(tmpnam);
00582       if (mTmp) err = OK;
00583     }
00584 #else
00585     int fd = mkstemp(tmpnam);
00586     if (fd < 0) return err;
00587     close(fd);
00588     if (unlink(tmpnam) < 0) return err;
00589     mTmp = strdup(tmpnam);
00590     if (!mTmp) return err;
00591     if (mkdir(mTmp, 0755) < 0) return err;
00592     err = OK;
00593 #endif
00594     return err;
00595 }
00596 
00597 int
00598 nsXIEngine::LoadXPIStub(xpistub_t *aStub, char *aDestination)
00599 {
00600     int err = OK;
00601 
00602     char libpath[MAXPATHLEN];
00603     char libloc[MAXPATHLEN];
00604        char *dlerr;
00605     nsresult rv = 0;
00606 
00607        DUMP("LoadXPIStub");
00608 
00609     /* param check */
00610     if (!aStub || !aDestination)
00611         return E_PARAM;
00612 
00613     /* save original directory to reset it after installing */
00614     mOriginalDir = (char *) malloc(MAXPATHLEN * sizeof(char));
00615     getcwd(mOriginalDir, MAXPATHLEN);
00616 
00617     /* chdir to library location for dll deps resolution */
00618     sprintf(libloc, "%s/bin", mTmp);
00619     chdir(libloc);
00620     
00621     /* open the library */
00622     getcwd(libpath, MAXPATHLEN);
00623     sprintf(libpath, "%s/%s", libpath, XPISTUB);
00624 
00625 #ifdef DEBUG
00626 printf("DEBUG: libpath = >>%s<<\n", libpath);
00627 #endif
00628 
00629     aStub->handle = NULL;
00630     aStub->handle = dlopen(libpath, RTLD_LAZY);
00631     if (!aStub->handle)
00632     {
00633         dlerr = dlerror();
00634         DUMP(dlerr);
00635         ErrorHandler(E_LIB_OPEN, dlerr);
00636         return E_LIB_OPEN;
00637     }
00638     DUMP("xpistub opened");
00639 
00640     /* read and store symbol addresses */
00641     aStub->fn_init    = (pfnXPI_Init) dlsym(aStub->handle, FN_INIT);
00642     aStub->fn_install = (pfnXPI_Install) dlsym(aStub->handle, FN_INSTALL);
00643     aStub->fn_exit    = (pfnXPI_Exit) dlsym(aStub->handle, FN_EXIT);
00644     if (!aStub->fn_init || !aStub->fn_install || !aStub->fn_exit)
00645     {
00646         dlerr = dlerror();
00647         DUMP(dlerr);
00648         err = E_LIB_SYM;
00649         goto BAIL;
00650     }
00651     DUMP("xpistub symbols loaded");
00652 
00653     rv = aStub->fn_init(aDestination, NULL, ProgressCallback);
00654 
00655 #ifdef DEBUG
00656 printf("DEBUG: XPI_Init returned 0x%.8X\n", rv);
00657 #endif
00658 
00659     DUMP("XPI_Init called");
00660        if (NS_FAILED(rv))
00661        {
00662               err = E_XPI_FAIL;
00663         goto BAIL;
00664        }
00665 
00666     return err;
00667 
00668 BAIL:
00669     return err;
00670 }
00671 
00672 int
00673 nsXIEngine::InstallXPI(nsComponent *aXPI, xpistub_t *aStub)
00674 {
00675     int err = OK;
00676     char xpipath[MAXPATHLEN];
00677     nsresult rv = 0;
00678 
00679     if (!aStub || !aXPI || !mOriginalDir)
00680         return E_PARAM;
00681 
00682     sprintf(xpipath, "%s/%s/%s", mOriginalDir, XPI_DIR, aXPI->GetArchive());
00683     DUMP(xpipath);
00684 
00685 #define XPI_NO_NEW_THREAD 0x1000
00686 
00687     rv = aStub->fn_install(xpipath, "", XPI_NO_NEW_THREAD);
00688 
00689 #ifdef DEBUG
00690 printf("DEBUG: XPI_Install %s returned %d\n", aXPI->GetArchive(), rv);
00691 #endif
00692 
00693     if (NS_FAILED(rv))
00694         err = E_INSTALL;
00695 
00696     return err;
00697 }
00698 
00699 int
00700 nsXIEngine::UnloadXPIStub(xpistub_t *aStub)
00701 {
00702     int err = OK;
00703 
00704     /* param check */
00705     if (!aStub)
00706         return E_PARAM;
00707 
00708        /* release XPCOM and XPInstall */
00709     XI_ASSERT(aStub->fn_exit, "XPI_Exit is NULL and wasn't called!");
00710        if (aStub->fn_exit)
00711        {
00712               aStub->fn_exit();
00713               DUMP("XPI_Exit called");
00714        }
00715 
00716 #if 0
00717     /* NOTE:
00718      * ----
00719      *      Don't close the stub: it'll be released on exit.
00720      *      This fixes the seg fault on exit bug,
00721      *      Apparently, the global destructors are no longer
00722      *      around when the app exits (since xpcom etc. was 
00723      *      unloaded when the stub was unloaded).  To get 
00724      *      around this we don't close the stub (which is 
00725      *      apparently safe on Linux/Unix).
00726      */
00727 
00728        /* close xpistub library */
00729        if (aStub->handle)
00730        {
00731               dlclose(aStub->handle);
00732               DUMP("xpistub closed");
00733        }
00734 #endif
00735 
00736     return err;
00737 }
00738 
00739 void
00740 nsXIEngine::ProgressCallback(const char* aMsg, PRInt32 aVal, PRInt32 aMax)
00741 {
00742     // DUMP("ProgressCallback");
00743     
00744     nsInstallDlg::XPIProgressCB(aMsg, (int)aVal, (int)aMax);
00745 }
00746 
00747 int 
00748 nsXIEngine::ExistAllXPIs(int aCustom, nsComponentList *aComps)
00749 {
00750     DUMP("ExistAllXPIs");
00751 
00752     int bAllExist = TRUE;
00753     nsComponent *currComp = aComps->GetHead();
00754     char currArchivePath[256];
00755     struct stat dummy;
00756 
00757     while (currComp)
00758     {
00759         if ( (aCustom == TRUE && currComp->IsSelected()) || (aCustom == FALSE) )
00760         {
00761             sprintf(currArchivePath, "%s/%s", XPI_DIR, currComp->GetArchive());
00762             DUMP(currArchivePath);
00763             
00764             if (0 != stat(currArchivePath, &dummy)
00765                   || VerifyArchive(currArchivePath) != ZIP_OK)
00766                 bAllExist = FALSE;
00767             else
00768                 currComp->SetDownloaded(TRUE);
00769         }
00770         
00771         currComp = aComps->GetNext();
00772     }
00773 
00774     return bAllExist;
00775 }
00776 
00777 int
00778 nsXIEngine::DeleteXPIs(int aCustom, nsComponentList *aComps)
00779 {
00780     int err = OK;
00781     nsComponent *currComp = aComps->GetHead();
00782     char currXPIPath[MAXPATHLEN];
00783 
00784     if (!aComps || !mOriginalDir)
00785         return E_PARAM;
00786 
00787     while (currComp)
00788     {
00789         if ( (aCustom == TRUE && currComp->IsSelected()) || (aCustom == FALSE) )
00790         {
00791             sprintf(currXPIPath, "%s/%s/%s", mOriginalDir, XPI_DIR, 
00792                     currComp->GetArchive());
00793             
00794             // delete the xpi
00795             err = unlink(currXPIPath);
00796 
00797 #ifdef DEBUG
00798             printf("%s %d: unlink %s returned: %d\n", __FILE__, __LINE__, 
00799                 currXPIPath, err); 
00800 #endif
00801         }
00802 
00803         currComp = aComps->GetNext();
00804     }
00805 
00806     // all xpi should be deleted so delete the ./xpi dir
00807     sprintf(currXPIPath, "%s/xpi", mOriginalDir);
00808     err = rmdir(currXPIPath);
00809 
00810 #ifdef DEBUG
00811     printf("%s %d: rmdir %s returned: %d\n", __FILE__, __LINE__, 
00812         currXPIPath, err);
00813 #endif
00814     
00815     return err;
00816 }
00817 
00818 int
00819 nsXIEngine::GetFileSize(char *aPath)
00820 {
00821     struct stat stbuf;
00822 
00823     if (!aPath)
00824         return 0;
00825 
00826     if (0 == stat(aPath, &stbuf))
00827     {
00828         return stbuf.st_size;
00829     }
00830 
00831     return 0;
00832 }
00833 
00834 int
00835 nsXIEngine::SetDLMarker(char *aCompName)
00836 {
00837     int rv = OK;
00838     FILE *dlMarkerFD;
00839     int compNameLen;
00840 
00841     if (!aCompName)
00842         return E_PARAM;
00843 
00844     // open the marker file
00845     dlMarkerFD = fopen(kDLMarkerPath, "w");
00846     if (!dlMarkerFD)
00847         return E_OPEN_MKR;
00848 
00849     // write out the current comp name
00850     compNameLen = strlen(aCompName);
00851     if (compNameLen > 0)
00852     {
00853         rv = fwrite((void *) aCompName, sizeof(char), compNameLen, dlMarkerFD);
00854         if (rv != compNameLen)
00855             rv = E_WRITE_MKR;
00856         else
00857             rv = OK;
00858     }
00859 
00860     // close the marker file
00861     fclose(dlMarkerFD);
00862         
00863 #ifdef DEBUG
00864     printf("%s %d: SetDLMarker rv = %d\n", __FILE__, __LINE__, rv);
00865 #endif
00866     return rv;
00867 }
00868 
00869 int
00870 nsXIEngine::GetDLMarkedComp(nsComponentList *aComps, nsComponent **aOutComp)
00871 {
00872     int rv = OK;
00873     FILE *dlMarkerFD = NULL;
00874     struct stat stbuf;
00875     char *compNameInFile = NULL;
00876     nsComponent *currComp = NULL;
00877 
00878     if (!aComps || !aOutComp)
00879         return E_PARAM;
00880 
00881     *aOutComp = NULL;
00882     currComp = aComps->GetHead();
00883 
00884     // open the marker file
00885     dlMarkerFD = fopen(kDLMarkerPath, "r");
00886     if (!dlMarkerFD)
00887         return E_OPEN_MKR;
00888 
00889     // find it's length 
00890     if (0 != stat(kDLMarkerPath, &stbuf))
00891     {
00892         rv = E_STAT;
00893         goto BAIL;
00894     }
00895     if (stbuf.st_size <= 0)
00896     {
00897         rv = E_FIND_COMP;
00898         goto BAIL;
00899     }
00900 
00901     // allocate a buffer the length of the file
00902     compNameInFile = (char *) malloc(sizeof(char) * (stbuf.st_size + 1));
00903     if (!compNameInFile)
00904     {
00905         rv = E_MEM;
00906         goto BAIL;
00907     }
00908     memset(compNameInFile, 0 , (stbuf.st_size + 1));
00909 
00910     // read in the file contents
00911     rv = fread((void *) compNameInFile, sizeof(char), 
00912                stbuf.st_size, dlMarkerFD);
00913     if (rv != stbuf.st_size)
00914         rv = E_READ_MKR;
00915     else
00916         rv = OK; 
00917 
00918     if (rv == OK)
00919     {
00920         // compare the comp name read in with all those in the components list
00921         while (currComp)
00922         {
00923             if (strcmp(currComp->GetArchive(), compNameInFile) == 0)
00924             {
00925                 *aOutComp = currComp;
00926                 break;
00927             }
00928 
00929             currComp = aComps->GetNext();
00930         }
00931     }
00932 
00933 BAIL:
00934     if (dlMarkerFD)
00935         fclose(dlMarkerFD);
00936 
00937     XI_IF_FREE(compNameInFile);
00938 
00939     return rv;
00940 }
00941 
00942 int
00943 nsXIEngine::DelDLMarker()
00944 {
00945     return unlink(kDLMarkerPath);
00946 }
00947 
00948 int
00949 nsXIEngine::TotalToDownload(int aCustom, nsComponentList *aComps)
00950 {
00951     int total = 0;
00952     nsComponent *currComp;
00953 
00954     if (!aComps)
00955         return 0;
00956 
00957     currComp = aComps->GetHead();
00958     while (currComp)
00959     {
00960         if ( (aCustom == TRUE && currComp->IsSelected()) || (aCustom == FALSE) )
00961         {
00962             if (!currComp->IsDownloaded())
00963                 total++;
00964         }
00965         currComp = aComps->GetNext();
00966     }
00967 
00968     return total;
00969 }
00970 
00971 /* 
00972  * Name: CRCCheckDownloadedArchives
00973  *
00974  * Arguments: 
00975  *
00976  * Handle dlPath;     -- a handle to the location of the XPI files on disk
00977  * short dlPathlen;    -- length, in bytes, of dlPath
00978  *
00979  * Description:
00980  *
00981  * This function iterates the XPI files and calls VerifyArchive() on each to 
00982  * determine which archives pass checksum checks. 
00983  *
00984  * Return Value: if all archives pass, true. Otherwise, false.
00985  *
00986  * Original Code: Syd Logan (syd@netscape.com) 6/24/2001
00987  *
00988 */
00989 
00990 PRBool 
00991 nsXIEngine::CRCCheckDownloadedArchives(char *dlPath, short dlPathlen, 
00992   nsComponentList *aComps, int aCustom)
00993 {
00994   int i;
00995   PRBool isClean;
00996   char buf[ 1024 ];
00997   nsComponent *currComp = aComps->GetHead();
00998   int numComps = aCustom ? aComps->GetLengthSelected() : aComps->GetLength();
00999 
01000   isClean = PR_TRUE;
01001 
01002   for(i = 0; currComp != (nsComponent *) NULL && i < MAX_COMPONENTS; i++) {
01003     strncpy( buf, (const char *) dlPath, dlPathlen );
01004     buf[ dlPathlen ] = '\0';
01005     strcat( buf, "/" );
01006     strcat( buf, currComp->GetArchive() );
01007     if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT) {
01008        nsInstallDlg::MajorProgressCB(buf, i, numComps, 
01009              nsInstallDlg::ACT_INSTALL);
01010     }
01011     if (((aCustom == TRUE && currComp->IsSelected()) || 
01012         (aCustom == FALSE)) && IsArchiveFile(buf) == TRUE && 
01013         VerifyArchive( buf ) != ZIP_OK) {
01014       currComp->SetDownloaded(FALSE); // VerifyArchive has unlinked it
01015       isClean = PR_FALSE;
01016     }
01017     currComp = aComps->GetNext();
01018   }
01019   return isClean;
01020 }
01021 
01022 /* 
01023  * Name: IsArchiveFile( char *path )
01024  * 
01025  * Arguments:
01026  * 
01027  * char *path -- NULL terminated pathname 
01028  *
01029  * Description: 
01030  *  
01031  * This function extracts the file extension of filename pointed to by path 
01032  * and then checks it against a table of extensions. If a match occurs, the 
01033  * file is considered to be an archive file that has a checksum we can 
01034  * validate, and we return PR_TRUE.
01035  * Otherwise, PR_FALSE is returned.
01036  *
01037  * Return Value: true if the file extension matches one of those we are 
01038  * looking for, and false otherwise.
01039  *
01040  * Original Code: Syd Logan 7/28/2001
01041  *
01042 */
01043 
01044 static char *extensions[] = { "ZIP", "XPI", "JAR" };  // must be uppercase
01045 
01046 PRBool
01047 nsXIEngine::IsArchiveFile( char *buf ) 
01048 {
01049     PRBool ret = false;
01050     char lbuf[1024];
01051     char *p;
01052     int i, max;
01053     
01054     // if we have a string and it contains a '.'
01055     
01056     if ( buf != (char *) NULL && ( p = strrchr( buf, '.' ) ) != (char *) NULL ) {
01057         p++;
01058         
01059         // if there are characters after the '.' then see if there is a match
01060         
01061         if ( *p != '\0' ) {
01062             
01063             // make a copy of the extension, and fold to uppercase, since mac has no strcasecmp
01064             // and we need to ensure we are comparing strings of chars that have the same case. 
01065 
01066             strcpy( lbuf, p );
01067             for ( i = 0; i < (int) strlen( lbuf ); i++ )
01068               lbuf[i] = toupper(lbuf[i]);
01069             
01070             // search
01071               
01072             max = sizeof( extensions ) / sizeof ( char * );
01073             for ( i = 0; i < max; i++ ) 
01074                 if ( !strcmp( lbuf, extensions[i] ) ) {
01075                     ret = true;
01076                     break;
01077                 }
01078         }   
01079     }
01080     return ( ret );
01081 }
01082 
01083 /*
01084  * Name: VerifyArchive
01085  *
01086  * Arguments:
01087  *
01088  * char *szArchive;     -- path of archive to verify
01089  *
01090  * Description:
01091  *
01092  * This function verifies that the specified path exists, that it is a XPI 
01093  * file, and that it has a valid checksum.
01094  *
01095  * Return Value: If all tests pass, ZIP_OK. Otherwise, !ZIP_OK
01096  *
01097  * Original Code: Syd Logan (syd@netscape.com) 6/25/2001
01098  *
01099 */
01100 
01101 int
01102 nsXIEngine::VerifyArchive(char *szArchive)
01103 {
01104   void *vZip;
01105   int  iTestRv;
01106   char *penv;
01107 
01108   if((iTestRv = ZIP_OpenArchive(szArchive, &vZip)) == ZIP_OK)
01109   {
01110     /* 1st parameter should be NULL or it will fail */
01111     /* It indicates extract the entire archive */
01112     iTestRv = ZIP_TestArchive(vZip);
01113     ZIP_CloseArchive(&vZip);
01114   }
01115  
01116   // for testing, this will cause about half of the CRCs to fail. Since 
01117   // randomly selecting which fail, likely next pass the same file will 
01118   // end up a success.
01119  
01120   penv = getenv("MOZ_INSTALL_TEST_CRC");
01121   if ( penv != (char *) NULL ) { 
01122     if ( random() < RAND_MAX / 2 ) 
01123       iTestRv = !ZIP_OK;
01124   }
01125 
01126   if ( iTestRv != ZIP_OK )
01127     unlink( szArchive );
01128   return(iTestRv);
01129 }
01130