Back to index

lightning-sunbird  0.9+nobinonly
nsInstallExecute.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  *   Daniel Veditz <dveditz@netscape.com>
00025  *   Douglas Turner <dougt@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 
00042 
00043 #include "nsCRT.h"
00044 #include "prmem.h"
00045 #include "VerReg.h"
00046 #include "nsInstallExecute.h"
00047 #include "nsInstallResources.h"
00048 #include "ScheduledTasks.h"
00049 
00050 #include "nsInstall.h"
00051 #include "nsIDOMInstallVersion.h"
00052 #include "nsProcess.h"
00053 #include "nsReadableUtils.h"
00054 
00055 static NS_DEFINE_CID(kIProcessCID, NS_PROCESS_CID); 
00056 
00057 MOZ_DECL_CTOR_COUNTER(nsInstallExecute)
00058 
00059 // Chop the command-line up in place into an array of arguments
00060 //   by replacing spaces in the command-line string with null
00061 //   terminators and pointing the array elements to the 
00062 //   characters following the null terminators.
00063 //
00064 // aArgsString is a string containing the complete command-line.
00065 // aArgs points to an array which will be filled with the 
00066 //   individual arguments from the command-line.
00067 // aArgsAvailable is the size of aArgs, i.e. the maximum number of
00068 //   individual command-line arguments which can be stored in the array.
00069 //
00070 // Returns the count of the number of command-line arguments actually 
00071 //   stored into the array aArgs or -1 if it fails.
00072 PRInt32 xpi_PrepareProcessArguments(const char *aArgsString, char **aArgs, PRInt32 aArgsAvailable)
00073 {
00074    int   argc;
00075    char *c;
00076    char *p; // look ahead
00077    PRBool quoted = PR_FALSE;
00078 
00079    aArgs[0] = (char *)aArgsString;
00080    if (!aArgs[0])
00081       return -1;
00082 
00083    // Strip leading spaces from command-line string.
00084    argc = 0;
00085    c = aArgs[argc];
00086    while (*c == ' ') ++c;
00087    aArgs[argc++] = c;
00088 
00089    for (; *c && argc < aArgsAvailable; ++c) 
00090    {
00091       switch(*c) {
00092 
00093       // Only handle escaped double quote and escaped backslash.
00094       case '\\':
00095          // See if next character is backslash or dquote
00096          if ( *(c+1) == '\\' || *(c+1) == '\"' )
00097          {
00098             // Eat escape character (i.e., backslash) by
00099             //   shifting all characters to the left one.
00100             for (p=c; *p != 0; ++p)
00101                *p = *(p+1);
00102          }
00103          break;
00104 
00105       case '\"':
00106          *c = 0; // terminate current arg
00107          if (quoted) 
00108          {
00109             p = c+1; // look ahead
00110             while (*p == ' ')
00111                ++p; // eat spaces
00112             if (*p)
00113                aArgs[argc++] = p; //not at end, set next arg
00114             c = p-1;
00115 
00116             quoted = PR_FALSE;
00117          }
00118          else 
00119          {
00120             quoted = PR_TRUE;
00121 
00122             if (aArgs[argc-1] == c)
00123               // Quote is at beginning so 
00124               //   start current argument after the quote.
00125               aArgs[argc-1] = c+1;
00126             else
00127               // Quote is embedded so 
00128               //   start a new argument after the quote.
00129               aArgs[argc++] = c+1;
00130          }
00131          break;
00132 
00133       case ' ':
00134          if (!quoted) 
00135          {
00136             *c = 0; // terminate current arg
00137             p = c+1; // look ahead
00138             while (*p == ' ')
00139                ++p; // eat spaces
00140             if (*p)
00141                aArgs[argc++] = p; //not at end, set next arg
00142             c = p-1;
00143          }
00144          break;
00145 
00146       default:
00147          break;  // nothing to do
00148       }
00149    }
00150    return argc;
00151 }
00152 
00153 nsInstallExecute:: nsInstallExecute(  nsInstall* inInstall,
00154                                       const nsString& inJarLocation,
00155                                       const nsString& inArgs,
00156                                       const PRBool inBlocking,
00157                                       PRInt32 *error)
00158 
00159 : nsInstallObject(inInstall)
00160 {
00161     MOZ_COUNT_CTOR(nsInstallExecute);
00162 
00163     if ((inInstall == nsnull) || (inJarLocation.IsEmpty()) )
00164     {
00165         *error = nsInstall::INVALID_ARGUMENTS;
00166         return;
00167     }
00168 
00169     mJarLocation        = inJarLocation;
00170     mArgs               = inArgs;
00171     mExecutableFile     = nsnull;
00172     mBlocking           = inBlocking;
00173     mPid                = nsnull;
00174 }
00175 
00176 
00177 nsInstallExecute::~nsInstallExecute()
00178 {
00179 
00180     MOZ_COUNT_DTOR(nsInstallExecute);
00181 }
00182 
00183 
00184 
00185 PRInt32 nsInstallExecute::Prepare()
00186 {
00187     if (mInstall == NULL || mJarLocation.IsEmpty()) 
00188         return nsInstall::INVALID_ARGUMENTS;
00189 
00190     return mInstall->ExtractFileFromJar(mJarLocation, nsnull, getter_AddRefs(mExecutableFile));
00191 }
00192 
00193 PRInt32 nsInstallExecute::Complete()
00194 {
00195    #define ARG_SLOTS       256
00196 
00197    PRInt32 result = NS_OK;
00198    PRInt32 rv = nsInstall::SUCCESS;
00199    char *cArgs[ARG_SLOTS];
00200    int   argcount = 0;
00201 
00202    if (mExecutableFile == nsnull)
00203       return nsInstall::INVALID_ARGUMENTS;
00204 
00205    nsCOMPtr<nsIProcess> process = do_CreateInstance(kIProcessCID);
00206 
00207    char *arguments = nsnull;
00208    if (!mArgs.IsEmpty())
00209    {
00210       arguments = ToNewCString(mArgs);
00211       argcount = xpi_PrepareProcessArguments(arguments, cArgs, ARG_SLOTS);
00212    }
00213    if (argcount >= 0)
00214    {
00215       result = process->Init(mExecutableFile);
00216       if (NS_SUCCEEDED(result))
00217       {
00218          result = process->Run(mBlocking, (const char**)&cArgs, argcount, mPid);
00219          if (NS_SUCCEEDED(result))
00220          {
00221             if (mBlocking)
00222             {
00223                process->GetExitValue(&result);
00224                if (result != 0)
00225                   rv = nsInstall::EXECUTION_ERROR;
00226 
00227                // should be OK to delete now since execution done
00228                DeleteFileNowOrSchedule( mExecutableFile );
00229             }
00230             else
00231             {
00232                // don't try to delete now since execution is async
00233                ScheduleFileForDeletion( mExecutableFile );
00234             }
00235          }
00236          else
00237             rv = nsInstall::EXECUTION_ERROR;
00238       }
00239       else
00240          rv = nsInstall::EXECUTION_ERROR;
00241    }
00242    else
00243       rv = nsInstall::UNEXPECTED_ERROR;
00244 
00245    if(arguments)
00246       Recycle(arguments);
00247 
00248    return rv;
00249 }
00250 
00251 void nsInstallExecute::Abort()
00252 {
00253     /* Get the names */
00254     if (mExecutableFile == nsnull) 
00255         return;
00256 
00257     DeleteFileNowOrSchedule(mExecutableFile);
00258 }
00259 
00260 char* nsInstallExecute::toString()
00261 {
00262     char* buffer = new char[1024];
00263     char* rsrcVal = nsnull;
00264 
00265     if (buffer == nsnull || !mInstall)
00266         return nsnull;
00267 
00268     // if the FileSpec is NULL, just us the in jar file name.
00269 
00270     if (mExecutableFile == nsnull)
00271     {
00272         char *tempString = ToNewCString(mJarLocation);
00273         rsrcVal = mInstall->GetResourcedString(NS_LITERAL_STRING("Execute"));
00274 
00275         if (rsrcVal)
00276         {
00277             sprintf( buffer, rsrcVal, tempString);
00278             nsCRT::free(rsrcVal);
00279         }
00280         
00281         if (tempString)
00282             Recycle(tempString);
00283     }
00284     else
00285     {
00286         rsrcVal = mInstall->GetResourcedString(NS_LITERAL_STRING("Execute"));
00287 
00288         if (rsrcVal)
00289         {
00290             nsCAutoString temp;
00291             mExecutableFile->GetNativePath(temp);
00292             sprintf( buffer, rsrcVal, temp.get());
00293             nsCRT::free(rsrcVal);
00294         }
00295     }
00296     return buffer;
00297 }
00298 
00299 
00300 PRBool
00301 nsInstallExecute::CanUninstall()
00302 {
00303     return PR_FALSE;
00304 }
00305 
00306 PRBool
00307 nsInstallExecute::RegisterPackageNode()
00308 {
00309     return PR_FALSE;
00310 }
00311