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