Back to index

lightning-sunbird  0.9+nobinonly
xpnetHook.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Navigator.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 1998
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Sean Su <ssu@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <windows.h>
00039 #include <string.h>
00040 #include <time.h>
00041 #include <sys/stat.h>
00042 
00043 #ifdef __cplusplus
00044 extern "C"
00045 {
00046 #endif /* __cplusplus */
00047 
00048 #include "extern.h"
00049 #include "extra.h"
00050 #include "dialogs.h"
00051 #include "xpnetHook.h"
00052 
00053 #ifdef __cplusplus
00054 }
00055 #endif /* __cplusplus */
00056 
00057 #include "nsFTPConn.h"
00058 #include "nsHTTPConn.h"
00059 #include "nsSocket.h"
00060 
00061 #define UPDATE_INTERVAL_STATUS          1
00062 #define UPDATE_INTERVAL_PROGRESS_BAR    1
00063 
00064 /* Cancel Status */
00065 #define CS_NONE         0x00000000
00066 #define CS_CANCEL       0x00000001
00067 #define CS_PAUSE        0x00000002
00068 #define CS_RESUME       0x00000003
00069 
00070 const int  kProxySrvrLen = 1024;
00071 const char kHTTP[8]      = "http://";
00072 const char kFTP[7]       = "ftp://";
00073 const char kLoclFile[7]  = "zzzFTP";
00074 const int  kModTimeOutValue = 3;
00075 
00076 static nsHTTPConn       *connHTTP = NULL;
00077 static nsFTPConn        *connFTP = NULL;
00078 static long             glLastBytesSoFar;
00079 static long             glAbsoluteBytesSoFar;
00080 static long             glBytesResumedFrom;
00081 static long             glTotalKb;
00082 char                    gszStrCopyingFile[MAX_BUF_MEDIUM];
00083 char                    gszCurrentDownloadPath[MAX_BUF];
00084 char                    gszCurrentDownloadFilename[MAX_BUF_TINY];
00085 char                    gszCurrentDownloadFileDescription[MAX_BUF_TINY];
00086 char                    gszUrl[MAX_BUF];
00087 char                    gszTo[MAX_BUF];
00088 char                    gszFileInfo[MAX_BUF];
00089 char                    *gszConfigIniFile;
00090 BOOL                    gbDlgDownloadMinimized;
00091 BOOL                    gbDlgDownloadJustMinimized;
00092 BOOL                    gbUrlChanged;
00093 BOOL                    gbShowDownloadRetryMsg;
00094 DWORD                   gdwDownloadDialogStatus;
00095 int                     giIndex;
00096 int                     giTotalArchivesToDownload;
00097 DWORD                   gdwTickStart;
00098 BOOL                    gbStartTickCounter;
00099 
00100 double GetPercentSoFar(void);
00101 
00102 static void UpdateGaugeFileProgressBar(double value);
00103        int  ProgressCB(int aBytesSoFar, int aTotalFinalSize);
00104        void InitDownloadDlg(void);
00105        void DeInitDownloadDlg();
00106 
00107 /* local prototypes */
00108 siC *GetObjectFromArchiveName(char *szArchiveName);
00109 
00110 struct DownloadFileInfo
00111 {
00112   char szUrl[MAX_BUF];
00113   char szFile[MAX_BUF_TINY];
00114 } dlFileInfo;
00115 
00116 struct ExtractFilesDlgInfo
00117 {
00118        HWND   hWndDlg;
00119        int           nMaxFileBars;     // maximum number of bars that can be displayed
00120        int           nMaxArchiveBars;     // maximum number of bars that can be displayed
00121        int   nFileBars;           // current number of bars to display
00122        int           nArchiveBars;          // current number of bars to display
00123 } dlgInfo;
00124 
00125 struct TickInfo
00126 {
00127   DWORD dwTickBegin;
00128   DWORD dwTickEnd;
00129   DWORD dwTickDif;
00130   BOOL  bTickStarted;
00131   BOOL  bTickDownloadResumed;
00132 } gtiPaused;
00133 
00134 BOOL CheckInterval(long *lModLastValue, int iInterval)
00135 {
00136   BOOL bRv = FALSE;
00137   long lModCurrentValue;
00138 
00139   if(iInterval == 1)
00140   {
00141     lModCurrentValue = time(NULL);
00142     if(lModCurrentValue != *lModLastValue)
00143       bRv = TRUE;
00144   }
00145   else
00146   {
00147     lModCurrentValue = time(NULL) % iInterval;
00148     if((lModCurrentValue == 0) && (*lModLastValue != 0))
00149       bRv = TRUE;
00150   }
00151 
00152   *lModLastValue = lModCurrentValue;
00153   return(bRv);
00154 }
00155 
00156 char *GetTimeLeft(DWORD dwTimeLeft,
00157                   char *szTimeString,
00158                   DWORD dwTimeStringBufSize)
00159 {
00160   DWORD      dwTimeLeftPP;
00161   SYSTEMTIME stTime;
00162 
00163   ZeroMemory(&stTime, sizeof(stTime));
00164   dwTimeLeftPP         = dwTimeLeft + 1;
00165   stTime.wHour         = (unsigned)(dwTimeLeftPP / 60 / 60);
00166   stTime.wMinute       = (unsigned)((dwTimeLeftPP / 60) % 60);
00167   stTime.wSecond       = (unsigned)(dwTimeLeftPP % 60);
00168 
00169   ZeroMemory(szTimeString, dwTimeStringBufSize);
00170   /* format time string using user's local time format information */
00171   GetTimeFormat(LOCALE_USER_DEFAULT,
00172                 TIME_NOTIMEMARKER|TIME_FORCE24HOURFORMAT,
00173                 &stTime,
00174                 NULL,
00175                 szTimeString,
00176                 dwTimeStringBufSize);
00177 
00178   return(szTimeString);
00179 }
00180 
00181 DWORD AddToTick(DWORD dwTick, DWORD dwTickMoreToAdd)
00182 {
00183   DWORD dwTickLeftTillWrap = 0;
00184 
00185   /* Since GetTickCount() is the number of milliseconds since the system
00186    * has been on and the return value is a DWORD, this value will wrap
00187    * every 49.71 days or 0xFFFFFFFF milliseconds. */
00188   dwTickLeftTillWrap = 0xFFFFFFFF - dwTick;
00189   if(dwTickMoreToAdd > dwTickLeftTillWrap)
00190     dwTick = dwTickMoreToAdd - dwTickLeftTillWrap;
00191   else
00192     dwTick = dwTick + dwTickMoreToAdd;
00193 
00194   return(dwTick);
00195 }
00196 
00197 DWORD GetTickDif(DWORD dwTickEnd, DWORD dwTickStart)
00198 {
00199   DWORD dwTickDif;
00200 
00201   /* Since GetTickCount() is the number of milliseconds since the system
00202    * has been on and the return value is a DWORD, this value will wrap
00203    * every 49.71 days or 0xFFFFFFFF milliseconds. 
00204    *
00205    * Assumption: dwTickEnd has not wrapped _and_ passed dwTickStart */
00206   if(dwTickEnd < dwTickStart)
00207     dwTickDif = 0xFFFFFFFF - dwTickStart + dwTickEnd;
00208   else
00209     dwTickDif = dwTickEnd - dwTickStart;
00210 
00211   return(dwTickDif);
00212 }
00213 
00214 void InitTickInfo(void)
00215 {
00216   gtiPaused.dwTickBegin          = 0;
00217   gtiPaused.dwTickEnd            = 0;
00218   gtiPaused.dwTickDif            = 0;
00219   gtiPaused.bTickStarted         = FALSE;
00220   gtiPaused.bTickDownloadResumed = FALSE;
00221 }
00222 
00223 DWORD RoundDouble(double dValue)
00224 {
00225   if(0.5 <= (dValue - (DWORD)dValue))
00226     return((DWORD)dValue + 1);
00227   else
00228     return((DWORD)dValue);
00229 }
00230 
00231 void SetStatusStatus(void)
00232 {
00233   char        szStatusStatusLine[MAX_BUF_MEDIUM];
00234   char        szCurrentStatusInfo[MAX_BUF_MEDIUM];
00235   char        szPercentString[MAX_BUF_MEDIUM];
00236   char        szPercentageCompleted[MAX_BUF_MEDIUM];
00237   static long lModLastValue = 0;
00238   double        dRate;
00239   static double dRateCounter;
00240   DWORD         dwTickNow;
00241   DWORD         dwTickDif;
00242   DWORD         dwKBytesSoFar;
00243   DWORD         dwRoundedRate;
00244   char          szTimeLeft[MAX_BUF_TINY];
00245 
00246   /* If the user just clicked on the Resume button, then the time lapsed
00247    * between gdwTickStart and when the Resume button was clicked needs to
00248    * be subtracted taken into account when calculating dwTickDif.  So
00249    * "this" lapsed time needs to be added to gdwTickStart. */
00250   if(gtiPaused.bTickDownloadResumed)
00251   {
00252     gdwTickStart = AddToTick(gdwTickStart, gtiPaused.dwTickDif);
00253     InitTickInfo();
00254   }
00255 
00256   /* GetTickCount() returns time in milliseconds.  This is more accurate,
00257    * which will allow us to get at a 2 decimal precision value for the
00258    * download rate. */
00259   dwTickNow = GetTickCount();
00260   if((gdwTickStart == 0) && gbStartTickCounter)
00261     dwTickNow = gdwTickStart = GetTickCount();
00262 
00263   dwTickDif = GetTickDif(dwTickNow, gdwTickStart);
00264 
00265   /* Only update the UI every UPDATE_INTERVAL_STATUS interval,
00266    * which is currently set to 1 sec. */
00267   if(!CheckInterval(&lModLastValue, UPDATE_INTERVAL_STATUS))
00268     return;
00269 
00270   if(glAbsoluteBytesSoFar == 0)
00271     dRateCounter = 0.0;
00272   else
00273     dRateCounter = dwTickDif / 1000;
00274 
00275   if(dRateCounter == 0.0)
00276     dRate = 0.0;
00277   else
00278     dRate = (glAbsoluteBytesSoFar - glBytesResumedFrom) / dRateCounter / 1024;
00279 
00280   dwKBytesSoFar = glAbsoluteBytesSoFar / 1024;
00281 
00282   /* Use a rate that is rounded to the nearest integer.  If dRate used directly,
00283    * the "Time Left" will jump around quite a bit due to the rate usually 
00284    * varying up and down by quite a bit. The rounded rate give a "more linear"
00285    * count down of the "Time Left". */
00286   dwRoundedRate = RoundDouble(dRate);
00287   if(dwRoundedRate > 0)
00288     GetTimeLeft((glTotalKb - dwKBytesSoFar) / dwRoundedRate,
00289                  szTimeLeft,
00290                  sizeof(szTimeLeft));
00291   else
00292     lstrcpy(szTimeLeft, "00:00:00");
00293 
00294   if(!gbShowDownloadRetryMsg)
00295   {
00296     GetPrivateProfileString("Strings",
00297                             "Status Download",
00298                             "",
00299                             szStatusStatusLine,
00300                             sizeof(szStatusStatusLine),
00301                             szFileIniConfig);
00302     if(*szStatusStatusLine != '\0')
00303       sprintf(szCurrentStatusInfo,
00304               szStatusStatusLine,
00305               szTimeLeft,
00306               dRate,
00307               dwKBytesSoFar,
00308               glTotalKb);
00309     else
00310       sprintf(szCurrentStatusInfo,
00311               "%s at %.2fKB/sec (%uKB of %uKB downloaded)",
00312               szTimeLeft,
00313               dRate,
00314               dwKBytesSoFar,
00315               glTotalKb);
00316   }
00317   else
00318   {
00319     GetPrivateProfileString("Strings",
00320                             "Status Retry",
00321                             "",
00322                             szStatusStatusLine,
00323                             sizeof(szStatusStatusLine),
00324                             szFileIniConfig);
00325     if(*szStatusStatusLine != '\0')
00326       sprintf(szCurrentStatusInfo,
00327               szStatusStatusLine,
00328               szTimeLeft,
00329               dRate,
00330               dwKBytesSoFar,
00331               glTotalKb);
00332     else
00333       sprintf(szCurrentStatusInfo,
00334               "%s at %.2KB/sec (%uKB of %uKB downloaded)",
00335               szTimeLeft,
00336               dRate,
00337               dwKBytesSoFar,
00338               glTotalKb);
00339   }
00340 
00341   GetPrivateProfileString("Strings",
00342                           "Status Percentage Completed",
00343                           "",
00344                           szPercentageCompleted,
00345                           sizeof(szPercentageCompleted),
00346                           szFileIniConfig);
00347   wsprintf(szPercentString, szPercentageCompleted, (int)GetPercentSoFar());
00348 
00349   /* Set the download dialog title */
00350   SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_STATUS, szCurrentStatusInfo);
00351   SetDlgItemText(dlgInfo.hWndDlg, IDC_PERCENTAGE, szPercentString);
00352 }
00353 
00354 void SetStatusFile(void)
00355 {
00356   char szString[MAX_BUF];
00357 
00358   /* Set the download dialog status*/
00359   wsprintf(szString, gszFileInfo, gszCurrentDownloadFileDescription);
00360   SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_FILE, szString);
00361   SetStatusStatus();
00362 }
00363 
00364 void SetStatusUrl(void)
00365 {
00366   /* display the current url being processed */
00367   if(gbUrlChanged)
00368   {
00369     char szUrlPathBuf[MAX_BUF];
00370     char szToPathBuf[MAX_BUF];
00371     HWND hStatusUrl = NULL;
00372     HWND hStatusTo  = NULL;
00373 
00374     hStatusUrl = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS_URL);
00375     if(hStatusUrl)
00376       TruncateString(hStatusUrl, gszUrl, szUrlPathBuf, sizeof(szUrlPathBuf));
00377     else
00378       lstrcpy(szUrlPathBuf, gszUrl);
00379 
00380     hStatusTo = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS_TO);
00381     if(hStatusTo)
00382       TruncateString(hStatusTo, gszTo, szToPathBuf, sizeof(szToPathBuf));
00383     else
00384       lstrcpy(szToPathBuf, gszTo);
00385 
00386     SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_URL, szUrlPathBuf);
00387     SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_TO,  szToPathBuf);
00388     SetStatusFile();
00389     gbUrlChanged = FALSE;
00390   }
00391 }
00392 
00393 double GetPercentSoFar(void)
00394 {
00395   return((double)(((double)(glAbsoluteBytesSoFar / 1024) / (double)glTotalKb) * (double)100));
00396 }
00397 
00398 void SetMinimizedDownloadTitle(DWORD dwPercentSoFar)
00399 {
00400   static DWORD dwLastPercentSoFar = 0;
00401   char szDownloadTitle[MAX_BUF_MEDIUM];
00402   char gszCurrentDownloadInfo[MAX_BUF_MEDIUM];
00403 
00404   GetPrivateProfileString("Strings", "Dialog Download Title Minimized", "", szDownloadTitle, sizeof(szDownloadTitle), szFileIniConfig);
00405 
00406   if(*szDownloadTitle != '\0')
00407     wsprintf(gszCurrentDownloadInfo, szDownloadTitle, dwPercentSoFar, gszCurrentDownloadFilename);
00408   else
00409     wsprintf(gszCurrentDownloadInfo, "%d%% for all files", dwPercentSoFar);
00410 
00411   /* check and save the current percent so far to minimize flickering */
00412   if((dwLastPercentSoFar != dwPercentSoFar) || gbDlgDownloadJustMinimized)
00413   {
00414     /* When the dialog is has just been minimized, the title is not set
00415      * until the percentage changes, which when downloading via modem,
00416      * could take several seconds.  This variable allows us to tell when
00417      * the dialog had *just* been minimized regardless if the percentage
00418      * had changed or not. */
00419     gbDlgDownloadJustMinimized = FALSE;
00420 
00421     /* Set the download dialog title */
00422     SetWindowText(dlgInfo.hWndDlg, gszCurrentDownloadInfo);
00423     dwLastPercentSoFar = dwPercentSoFar;
00424   }
00425 }
00426 
00427 void SetRestoredDownloadTitle(void)
00428 {
00429   /* Set the download dialog title */
00430   SetWindowText(dlgInfo.hWndDlg, diDownload.szTitle);
00431 }
00432 
00433 void GetTotalArchivesToDownload(int *iTotalArchivesToDownload, DWORD *dwTotalEstDownloadSize)
00434 {
00435   int  iIndex = 0;
00436   char szUrl[MAX_BUF];
00437   char szSection[MAX_INI_SK];
00438   char szDownloadSize[MAX_ITOA];
00439 
00440   *dwTotalEstDownloadSize = 0;
00441   iIndex = 0;
00442   wsprintf(szSection, "File%d", iIndex);
00443   GetPrivateProfileString(szSection,
00444                           "url0",
00445                           "",
00446                           szUrl,
00447                           sizeof(szUrl),
00448                           gszConfigIniFile);
00449   while(*szUrl != '\0')
00450   {
00451     GetPrivateProfileString(szSection, "size", "", szDownloadSize, sizeof(szDownloadSize), gszConfigIniFile);
00452     if((lstrlen(szDownloadSize) < 32) && (*szDownloadSize != '\0'))
00453       /* size will be in kb.  31 bits (int minus the signed bit) of precision should sufice */
00454       *dwTotalEstDownloadSize += atoi(szDownloadSize);
00455 
00456     ++iIndex;
00457     wsprintf(szSection, "File%d", iIndex);
00458     GetPrivateProfileString(szSection,
00459                             "url0",
00460                             "",
00461                             szUrl,
00462                             sizeof(szUrl),
00463                             gszConfigIniFile);
00464   }
00465   *iTotalArchivesToDownload = iIndex;
00466 }
00467 
00468 /* 
00469  * Name: ProcessWndMsgCB
00470  *
00471  * Arguments: None
00472  *
00473  * Description: Callback function invoked by socket code and by FTP and HTTP layers
00474  *                          to give the UI a chance to breath while we are in a look processing
00475  *                          incoming data, or looping in select()
00476  *
00477  * Author: syd@netscape.com 5/11/2001
00478  *
00479 */
00480 
00481 int
00482 ProcessWndMsgCB()
00483 {
00484   int iRv = nsFTPConn::OK;
00485 
00486        ProcessWindowsMessages();
00487   if((gdwDownloadDialogStatus == CS_CANCEL) ||
00488      (gdwDownloadDialogStatus == CS_PAUSE))
00489     iRv = nsFTPConn::E_USER_CANCEL;
00490 
00491        return(iRv);
00492 }
00493 
00494 /* Function used only to send the message stream error */
00495 int WGet(char *szUrl,
00496          char *szFile,
00497          char *szProxyServer,
00498          char *szProxyPort,
00499          char *szProxyUser,
00500          char *szProxyPasswd)
00501 {
00502   int        rv;
00503   char       proxyURL[MAX_BUF];
00504   nsHTTPConn *conn = NULL;
00505 
00506   if((szProxyServer != NULL) && (szProxyPort != NULL) &&
00507      (*szProxyServer != '\0') && (*szProxyPort != '\0'))
00508   {
00509     /* detected proxy information, let's use it */
00510     memset(proxyURL, 0, sizeof(proxyURL));
00511     wsprintf(proxyURL, "http://%s:%s", szProxyServer, szProxyPort);
00512 
00513     conn = new nsHTTPConn(proxyURL);
00514     if(conn == NULL)
00515       return(WIZ_OUT_OF_MEMORY);
00516 
00517     if((szProxyUser != NULL) && (*szProxyUser != '\0') &&
00518        (szProxyPasswd != NULL) && (*szProxyPasswd != '\0'))
00519       /* detected user and password info */
00520       conn->SetProxyInfo(szUrl, szProxyUser, szProxyPasswd);
00521     else
00522       conn->SetProxyInfo(szUrl, NULL, NULL);
00523   }
00524   else
00525   {
00526     /* no proxy information supplied. set up normal http object */
00527     conn = new nsHTTPConn(szUrl, ProcessWndMsgCB);
00528     if(conn == NULL)
00529       return(WIZ_OUT_OF_MEMORY);
00530   }
00531   
00532   rv = conn->Open();
00533   if(rv == WIZ_OK)
00534   {
00535     rv = conn->Get(NULL, szFile);
00536     conn->Close();
00537   }
00538 
00539   if(conn)
00540     delete(conn);
00541 
00542   return(rv);
00543 }
00544 
00545 int DownloadViaProxyOpen(char *szUrl, char *szProxyServer, char *szProxyPort, char *szProxyUser, char *szProxyPasswd)
00546 {
00547   int  rv;
00548   char proxyURL[kProxySrvrLen];
00549 
00550   if((!szUrl) || (*szUrl == '\0'))
00551     return nsHTTPConn::E_PARAM;
00552 
00553   rv = nsHTTPConn::OK;
00554   memset(proxyURL, 0, kProxySrvrLen);
00555   wsprintf(proxyURL, "http://%s:%s", szProxyServer, szProxyPort);
00556 
00557   connHTTP = new nsHTTPConn(proxyURL, ProcessWndMsgCB);
00558   if(connHTTP == NULL)
00559   {
00560     char szBuf[MAX_BUF_TINY];
00561 
00562     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
00563     PrintError(szBuf, ERROR_CODE_HIDE);
00564 
00565     return(WIZ_OUT_OF_MEMORY);
00566   }
00567 
00568   if((szProxyUser != NULL) && (*szProxyUser != '\0') &&
00569      (szProxyPasswd != NULL) && (*szProxyPasswd != '\0'))
00570     connHTTP->SetProxyInfo(szUrl, szProxyUser, szProxyPasswd);
00571   else
00572     connHTTP->SetProxyInfo(szUrl, NULL, NULL);
00573 
00574   rv = connHTTP->Open();
00575   return(rv);
00576 }
00577 
00578 void DownloadViaProxyClose(void)
00579 {
00580   gbStartTickCounter = FALSE;
00581   if(connHTTP)
00582   {
00583     connHTTP->Close();
00584     delete(connHTTP);
00585     connHTTP = NULL;
00586   }
00587 }
00588 
00589 int DownloadViaProxy(char *szUrl, char *szProxyServer, char *szProxyPort, char *szProxyUser, char *szProxyPasswd)
00590 {
00591   int  rv;
00592   char *file = NULL;
00593 
00594   rv = nsHTTPConn::OK;
00595   if((!szUrl) || (*szUrl == '\0'))
00596     return nsHTTPConn::E_PARAM;
00597 
00598   if(connHTTP == NULL)
00599   {
00600     rv = DownloadViaProxyOpen(szUrl,
00601                               szProxyServer,
00602                               szProxyPort,
00603                               szProxyUser,
00604                               szProxyPasswd);
00605 
00606     if(rv != nsHTTPConn::OK)
00607     {
00608       DownloadViaProxyClose();
00609       return(rv);
00610     }
00611   }
00612 
00613   if(connHTTP == NULL)
00614   {
00615     char szBuf[MAX_BUF_TINY];
00616 
00617     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
00618     PrintError(szBuf, ERROR_CODE_HIDE);
00619 
00620     return(WIZ_OUT_OF_MEMORY);
00621   }
00622 
00623   if(strrchr(szUrl, '/') != (szUrl + strlen(szUrl)))
00624     file = strrchr(szUrl, '/') + 1; // set to leaf name
00625 
00626   gbStartTickCounter = TRUE;
00627   rv = connHTTP->Get(ProgressCB, file); // use leaf from URL
00628   DownloadViaProxyClose();
00629   return(rv);
00630 }
00631 
00632 int DownloadViaHTTPOpen(char *szUrl)
00633 {
00634   int  rv;
00635 
00636   if((!szUrl) || (*szUrl == '\0'))
00637     return nsHTTPConn::E_PARAM;
00638 
00639   rv = nsHTTPConn::OK;
00640   connHTTP = new nsHTTPConn(szUrl, ProcessWndMsgCB);
00641   if(connHTTP == NULL)
00642   {
00643     char szBuf[MAX_BUF_TINY];
00644 
00645     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), gszConfigIniFile);
00646     PrintError(szBuf, ERROR_CODE_HIDE);
00647 
00648     return(WIZ_OUT_OF_MEMORY);
00649   }
00650   
00651   rv = connHTTP->Open();
00652   return(rv);
00653 }
00654 
00655 void DownloadViaHTTPClose(void)
00656 {
00657   gbStartTickCounter = FALSE;
00658   if(connHTTP)
00659   {
00660     connHTTP->Close();
00661     delete(connHTTP);
00662     connHTTP = NULL;
00663   }
00664 }
00665 
00666 int DownloadViaHTTP(char *szUrl)
00667 {
00668   int  rv;
00669   char *file = NULL;
00670 
00671   if((!szUrl) || (*szUrl == '\0'))
00672     return nsHTTPConn::E_PARAM;
00673 
00674   if(connHTTP == NULL)
00675   {
00676     rv = DownloadViaHTTPOpen(szUrl);
00677     if(rv != nsHTTPConn::OK)
00678     {
00679       DownloadViaHTTPClose();
00680       return(rv);
00681     }
00682   }
00683 
00684   if(connHTTP == NULL)
00685   {
00686     char szBuf[MAX_BUF_TINY];
00687 
00688     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), gszConfigIniFile);
00689     PrintError(szBuf, ERROR_CODE_HIDE);
00690 
00691     return(WIZ_OUT_OF_MEMORY);
00692   }
00693   
00694   rv = nsHTTPConn::OK;
00695   if(strrchr(szUrl, '/') != (szUrl + strlen(szUrl)))
00696     file = strrchr(szUrl, '/') + 1; // set to leaf name
00697 
00698   gbStartTickCounter = TRUE;
00699   rv = connHTTP->Get(ProgressCB, file);
00700   DownloadViaHTTPClose();
00701   return(rv);
00702 }
00703 
00704 int DownloadViaFTPOpen(char *szUrl)
00705 {
00706   char *host = 0, *path = 0, *file = (char*) kLoclFile;
00707   int port = 21;
00708   int rv;
00709 
00710   if((!szUrl) || (*szUrl == '\0'))
00711     return nsFTPConn::E_PARAM;
00712 
00713   rv = nsHTTPConn::ParseURL(kFTP, szUrl, &host, &port, &path);
00714 
00715   connFTP = new nsFTPConn(host, ProcessWndMsgCB);
00716   if(connFTP == NULL)
00717   {
00718     char szBuf[MAX_BUF_TINY];
00719 
00720     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
00721     PrintError(szBuf, ERROR_CODE_HIDE);
00722 
00723     return(WIZ_OUT_OF_MEMORY);
00724   }
00725 
00726   rv = connFTP->Open();
00727   if(host)
00728     free(host);
00729   if(path)
00730     free(path);
00731 
00732   return(rv);
00733 }
00734 
00735 void DownloadViaFTPClose(void)
00736 {
00737   gbStartTickCounter = FALSE;
00738   if(connFTP)
00739   {
00740     connFTP->Close();
00741     delete(connFTP);
00742     connFTP = NULL;
00743   }
00744 }
00745 
00746 int DownloadViaFTP(char *szUrl)
00747 {
00748   char *host = 0, *path = 0, *file = (char*) kLoclFile;
00749   int port = 21;
00750   int rv;
00751 
00752   if((!szUrl) || (*szUrl == '\0'))
00753     return nsFTPConn::E_PARAM;
00754 
00755   if(connFTP == NULL)
00756   {
00757     rv = DownloadViaFTPOpen(szUrl);
00758     if(rv != nsFTPConn::OK)
00759     {
00760       DownloadViaFTPClose();
00761       return(rv);
00762     }
00763   }
00764 
00765   if(connFTP == NULL)
00766   {
00767     char szBuf[MAX_BUF_TINY];
00768 
00769     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
00770     PrintError(szBuf, ERROR_CODE_HIDE);
00771 
00772     return(WIZ_OUT_OF_MEMORY);
00773   }
00774 
00775   rv = nsHTTPConn::ParseURL(kFTP, szUrl, &host, &port, &path);
00776 
00777   if(strrchr(path, '/') != (path + strlen(path)))
00778     file = strrchr(path, '/') + 1; // set to leaf name
00779 
00780   gbStartTickCounter = TRUE;
00781   rv = connFTP->Get(path, file, nsFTPConn::BINARY, TRUE, ProgressCB);
00782 
00783   if(host)
00784     free(host);
00785   if(path)
00786     free(path);
00787 
00788   return(rv);
00789 }
00790 
00791 void PauseTheDownload(int rv, int *iFileDownloadRetries)
00792 {
00793   if(rv != nsFTPConn::E_USER_CANCEL)
00794   {
00795     SendMessage(dlgInfo.hWndDlg, WM_COMMAND, IDPAUSE, 0);
00796     --*iFileDownloadRetries;
00797   }
00798 
00799   while(gdwDownloadDialogStatus == CS_PAUSE)
00800   {
00801     SleepEx(200, FALSE);
00802     ProcessWindowsMessages();
00803   }
00804 }
00805 
00806 void CloseSocket(char *szProxyServer, char *szProxyPort)
00807 {
00808   /* Close the socket connection from the first attempt. */
00809   if((szProxyServer != NULL) && (szProxyPort != NULL) &&
00810      (*szProxyServer != '\0') && (*szProxyPort != '\0'))
00811       DownloadViaProxyClose();
00812   else
00813   {
00814     /* is this an HTTP URL? */
00815     if(strncmp(gszUrl, kHTTP, lstrlen(kHTTP)) == 0)
00816       DownloadViaHTTPClose();
00817     /* or is this an FTP URL? */
00818     else if(strncmp(gszUrl, kFTP, lstrlen(kFTP)) == 0)
00819       DownloadViaFTPClose();
00820   }
00821 }
00822 
00823 siC *GetObjectFromArchiveName(char *szArchiveName)
00824 {
00825   DWORD dwIndex;
00826   siC   *siCObject = NULL;
00827   siC   *siCNode   = NULL;
00828 
00829   dwIndex = 0;
00830   siCObject = SiCNodeGetObject(dwIndex, TRUE, AC_ALL);
00831   while(siCObject)
00832   {
00833     if(lstrcmpi(szArchiveName, siCObject->szArchiveName) == 0)
00834     {
00835       siCNode = siCObject;
00836       break;
00837     }
00838 
00839     ++dwIndex;
00840     siCObject = SiCNodeGetObject(dwIndex, TRUE, AC_ALL);
00841   }
00842 
00843   return(siCNode);
00844 }
00845 
00846 int DownloadFiles(char *szInputIniFile,
00847                   char *szDownloadDir,
00848                   char *szProxyServer,
00849                   char *szProxyPort,
00850                   char *szProxyUser,
00851                   char *szProxyPasswd,
00852                   BOOL bShowRetryMsg,
00853                   BOOL bIgnoreAllNetworkErrors,
00854                   char *szFailedFile,
00855                   DWORD dwFailedFileSize)
00856 {
00857   char      szBuf[MAX_BUF];
00858   char      szCurrentFile[MAX_BUF];
00859   char      szSection[MAX_INI_SK];
00860   char      szKey[MAX_INI_SK];
00861   char      szSavedCwd[MAX_BUF_MEDIUM];
00862   int       iCounter;
00863   int       rv;
00864   int       iFileDownloadRetries;
00865   int       iIgnoreFileNetworkError;
00866   int       iLocalTimeOutCounter;
00867   DWORD     dwTotalEstDownloadSize;
00868   char      szPartiallyDownloadedFilename[MAX_BUF];
00869   BOOL      bDownloadInitiated;
00870   char      szTempURL[MAX_BUF];
00871   char      szWorkingURLPathOnly[MAX_BUF];
00872   siC       *siCCurrentFileObj = NULL;
00873 
00874   ZeroMemory(szTempURL, sizeof(szTempURL));
00875   ZeroMemory(szWorkingURLPathOnly, sizeof(szWorkingURLPathOnly));
00876   if(szInputIniFile == NULL)
00877     return(WIZ_ERROR_UNDEFINED);
00878 
00879   if(szFailedFile)
00880     ZeroMemory(szFailedFile, dwFailedFileSize);
00881 
00882   InitTickInfo();
00883   GetCurrentDirectory(sizeof(szSavedCwd), szSavedCwd);
00884   SetCurrentDirectory(szDownloadDir);
00885 
00886   rv                        = WIZ_OK;
00887   dwTotalEstDownloadSize    = 0;
00888   giTotalArchivesToDownload = 0;
00889   glLastBytesSoFar          = 0;
00890   glAbsoluteBytesSoFar      = 0;
00891   glBytesResumedFrom        = 0;
00892   gdwTickStart              = 0; /* Initialize the counter used to
00893                                   * calculate download rate */
00894   gbStartTickCounter        = FALSE; /* used to determine when to start
00895                                       * the tick counter used to calculate
00896                                       * the download rate */
00897   gbUrlChanged              = TRUE;
00898   gbDlgDownloadMinimized    = FALSE;
00899   gbDlgDownloadJustMinimized = FALSE;
00900   gdwDownloadDialogStatus   = CS_NONE;
00901   gbShowDownloadRetryMsg    = bShowRetryMsg;
00902   gszConfigIniFile          = szInputIniFile;
00903   bDownloadInitiated        = FALSE;
00904 
00905   GetTotalArchivesToDownload(&giTotalArchivesToDownload,
00906                              &dwTotalEstDownloadSize);
00907   glTotalKb                 = dwTotalEstDownloadSize;
00908   GetSetupCurrentDownloadFile(szPartiallyDownloadedFilename,
00909                               sizeof(szPartiallyDownloadedFilename));
00910 
00911   ShowMessage(NULL, FALSE);
00912   InitDownloadDlg();
00913 
00914   for(giIndex = 0; giIndex < giTotalArchivesToDownload; giIndex++)
00915   {
00916     /* set (or reset) the counter to 0 in order to read the
00917      * next files's 0'th url from the .idi file */
00918     iCounter     = 0;
00919     gbUrlChanged = TRUE; /* Update the download dialog with new URL */
00920     wsprintf(szSection, "File%d", giIndex);
00921     wsprintf(szKey,     "url%d",  iCounter);
00922     GetPrivateProfileString(szSection,
00923                             szKey,
00924                             "",
00925                             szTempURL,
00926                             sizeof(szTempURL),
00927                             gszConfigIniFile);
00928 
00929     if(*szTempURL == '\0')
00930       continue;
00931 
00932     if(!bDownloadInitiated)
00933     {
00934       ParsePath(szTempURL,
00935                 szWorkingURLPathOnly,
00936                 sizeof(szWorkingURLPathOnly),
00937                 TRUE, //use '/' as the path delimiter
00938                 PP_PATH_ONLY);
00939     }
00940 
00941     GetPrivateProfileString(szSection,
00942                             "desc",
00943                             "",
00944                             gszCurrentDownloadFileDescription,
00945                             sizeof(gszCurrentDownloadFileDescription),
00946                             gszConfigIniFile);
00947     iIgnoreFileNetworkError = GetPrivateProfileInt(szSection,
00948                             "Ignore File Network Error",
00949                             0,
00950                             gszConfigIniFile);
00951 
00952     /* save the file name to be downloaded */
00953     ParsePath(szTempURL,
00954               szCurrentFile,
00955               sizeof(szCurrentFile),
00956               TRUE, //use '/' as the path delimiter
00957               PP_FILENAME_ONLY);
00958 
00959     RemoveSlash(szWorkingURLPathOnly);
00960     wsprintf(gszUrl, "%s/%s", szWorkingURLPathOnly, szCurrentFile);
00961 
00962     /* retrieve the file's data structure */
00963     siCCurrentFileObj = GetObjectFromArchiveName(szCurrentFile);
00964 
00965     if((*szPartiallyDownloadedFilename != 0) &&
00966        (lstrcmpi(szPartiallyDownloadedFilename, szCurrentFile) == 0))
00967     {
00968       struct stat statBuf;
00969 
00970       if(stat(szPartiallyDownloadedFilename, &statBuf) != -1)
00971       {
00972         glAbsoluteBytesSoFar += statBuf.st_size;
00973         glBytesResumedFrom    = statBuf.st_size;
00974       }
00975     }
00976 
00977     lstrcpy(gszTo, szDownloadDir);
00978     AppendBackSlash(gszTo, sizeof(gszTo));
00979     lstrcat(gszTo, szCurrentFile);
00980 
00981     if(gbDlgDownloadMinimized)
00982       SetMinimizedDownloadTitle((int)GetPercentSoFar());
00983     else
00984     {
00985       SetStatusUrl();
00986       SetRestoredDownloadTitle();
00987     }
00988 
00989     SetSetupCurrentDownloadFile(szCurrentFile);
00990     iFileDownloadRetries = 0;
00991     iLocalTimeOutCounter = 0;
00992     do
00993     {
00994       ProcessWindowsMessages();
00995       /* Download starts here */
00996       if((szProxyServer != NULL) && (szProxyPort != NULL) &&
00997          (*szProxyServer != '\0') && (*szProxyPort != '\0'))
00998         /* If proxy info is provided, use HTTP proxy */
00999         rv = DownloadViaProxy(gszUrl,
01000                               szProxyServer,
01001                               szProxyPort,
01002                               szProxyUser,
01003                               szProxyPasswd);
01004       else
01005       {
01006         /* is this an HTTP URL? */
01007         if(strncmp(gszUrl, kHTTP, lstrlen(kHTTP)) == 0)
01008           rv = DownloadViaHTTP(gszUrl);
01009         /* or is this an FTP URL? */
01010         else if(strncmp(gszUrl, kFTP, lstrlen(kFTP)) == 0)
01011           rv = DownloadViaFTP(gszUrl);
01012       }
01013 
01014       bDownloadInitiated = TRUE;
01015       if((rv == nsFTPConn::E_USER_CANCEL) ||
01016          (gdwDownloadDialogStatus == CS_PAUSE))
01017       {
01018         if(gdwDownloadDialogStatus == CS_PAUSE)
01019         {
01020           CloseSocket(szProxyServer, szProxyPort);
01021 
01022           /* rv needs to be set to something
01023            * other than E_USER_CANCEL or E_OK */
01024           rv = nsFTPConn::E_CMD_UNEXPECTED;
01025 
01026           PauseTheDownload(rv, &iFileDownloadRetries);
01027           bDownloadInitiated = FALSE; /* restart the download using
01028                                        * new socket connection */
01029         }
01030         else
01031         {
01032           /* user canceled; break out of the do loop */
01033           break;
01034         }
01035       }
01036       else if((rv != nsFTPConn::OK) &&
01037               (rv != nsFTPConn::E_CMD_FAIL) &&
01038               (rv != nsSocket::E_BIND) &&
01039               (rv != nsHTTPConn::E_HTTP_RESPONSE) &&
01040               (gdwDownloadDialogStatus != CS_CANCEL))
01041       {
01042         /* We timed out.  No response from the server, or 
01043          * we somehow lost connection. */
01044 
01045         char szTitle[MAX_BUF_SMALL];
01046         char szMsgDownloadPaused[MAX_BUF];
01047 
01048         /* Incrememt the time out counter on E_TIMEOUT */
01049         if(rv == nsSocket::E_TIMEOUT)
01050         {
01051           ++siCCurrentFileObj->iNetTimeOuts;
01052           ++iLocalTimeOutCounter;
01053         }
01054 
01055         CloseSocket(szProxyServer, szProxyPort);
01056 
01057         /* If the number of timeouts is %3 == 0, then let's pause
01058          * the download process.  Otherwise, just close the
01059          * connection and open a new one to see if the download
01060          * can be restarted automatically. */
01061         if((rv != nsSocket::E_TIMEOUT) ||
01062            (rv == nsSocket::E_TIMEOUT) && ((iLocalTimeOutCounter % kModTimeOutValue) == 0))
01063         {
01064           /* Start the pause tick counter here because we don't know how
01065            * long before the user will dismiss the MessageBox() */
01066           if(!gtiPaused.bTickStarted)
01067           {
01068             gtiPaused.dwTickBegin          = GetTickCount();
01069             gtiPaused.bTickStarted         = TRUE;
01070             gtiPaused.bTickDownloadResumed = FALSE;
01071           }
01072 
01073           /* The connection unexepectedly dropped for some reason, so inform
01074            * the user that the download will be Paused, and then update the
01075            * Download dialog to show the Paused state. */
01076           GetPrivateProfileString("Messages",
01077                                   "MB_WARNING_STR",
01078                                   "",
01079                                   szTitle,
01080                                   sizeof(szTitle),
01081                                   szFileIniInstall);
01082           GetPrivateProfileString("Strings",
01083                                   "Message Download Paused",
01084                                   "",
01085                                   szMsgDownloadPaused,
01086                                   sizeof(szMsgDownloadPaused),
01087                                   szFileIniConfig);
01088           MessageBox(dlgInfo.hWndDlg,
01089                      szMsgDownloadPaused,
01090                      szTitle,
01091                      MB_ICONEXCLAMATION);
01092 
01093           /* Let's make sure we're in a paused state */
01094           gdwDownloadDialogStatus = CS_PAUSE;
01095           PauseTheDownload(rv, &iFileDownloadRetries);
01096         }
01097         else
01098           /* Let's make sure we're _not_ in a paused state */
01099           gdwDownloadDialogStatus = CS_NONE;
01100       }
01101 
01102       /* We don't count time outs as normal failures.  We're
01103        * keeping track of time outs differently. */
01104       if(rv != nsSocket::E_TIMEOUT)
01105         ++iFileDownloadRetries;
01106 
01107       if((iFileDownloadRetries > MAX_FILE_DOWNLOAD_RETRIES) &&
01108          (rv != nsFTPConn::E_USER_CANCEL) &&
01109          (gdwDownloadDialogStatus != CS_CANCEL))
01110       {
01111         /* since the download retries maxed out, increment the counter
01112          * to read the next url for the current file */
01113         ++iCounter;
01114         wsprintf(szKey, "url%d",  iCounter);
01115         GetPrivateProfileString(szSection,
01116                                 szKey,
01117                                 "",
01118                                 szTempURL,
01119                                 sizeof(szTempURL),
01120                                 gszConfigIniFile);
01121         if(*szTempURL != '\0')
01122         {
01123           /* Found more urls to download from for the current file.
01124            * Update the dialog to show the new url and reset the
01125            * file download retries to 0 since it's a new url. */
01126           gbUrlChanged = TRUE;
01127           iFileDownloadRetries = 0;
01128           bDownloadInitiated = FALSE; // restart the download using new socket connection
01129           CloseSocket(szProxyServer, szProxyPort);
01130           ParsePath(szTempURL,
01131                     szWorkingURLPathOnly,
01132                     sizeof(szWorkingURLPathOnly),
01133                     TRUE, //use '/' as the path delimiter
01134                     PP_PATH_ONLY);
01135           RemoveSlash(szWorkingURLPathOnly);
01136           wsprintf(gszUrl, "%s/%s", szWorkingURLPathOnly, szCurrentFile);
01137           SetStatusUrl();
01138         }
01139       }
01140     } while((rv != nsFTPConn::E_USER_CANCEL) &&
01141             (rv != nsFTPConn::OK) &&
01142             (gdwDownloadDialogStatus != CS_CANCEL) &&
01143             (iFileDownloadRetries <= MAX_FILE_DOWNLOAD_RETRIES));
01144 
01145     /* Save the number of retries for each file */
01146     siCCurrentFileObj->iNetRetries = iFileDownloadRetries < 1 ? 0:iFileDownloadRetries - 1;
01147 
01148     if((rv == nsFTPConn::E_USER_CANCEL) ||
01149        (gdwDownloadDialogStatus == CS_CANCEL))
01150     {
01151       /* make sure rv is E_USER_CANCEL when gdwDownloadDialogStatus
01152        * is CS_CANCEL */
01153       rv = nsFTPConn::E_USER_CANCEL;
01154 
01155       if(szFailedFile && ((DWORD)lstrlen(szCurrentFile) <= dwFailedFileSize))
01156         lstrcpy(szFailedFile, gszCurrentDownloadFileDescription);
01157 
01158       /* break out of for() loop */
01159       break;
01160     }
01161 
01162     if((rv != nsFTPConn::OK) &&
01163        (iFileDownloadRetries > MAX_FILE_DOWNLOAD_RETRIES) &&
01164        !bIgnoreAllNetworkErrors &&
01165        !iIgnoreFileNetworkError)
01166     {
01167       /* too many retries from failed downloads */
01168       char szMsg[MAX_BUF];
01169 
01170       if(szFailedFile && ((DWORD)lstrlen(szCurrentFile) <= dwFailedFileSize))
01171         lstrcpy(szFailedFile, gszCurrentDownloadFileDescription);
01172 
01173       GetPrivateProfileString("Strings",
01174                               "Error Too Many Network Errors",
01175                               "",
01176                               szMsg,
01177                               sizeof(szMsg),
01178                               szFileIniConfig);
01179       if(*szMsg != '\0')
01180       {
01181         wsprintf(szBuf, szMsg, szCurrentFile);
01182         PrintError(szBuf, ERROR_CODE_HIDE);
01183       }
01184 
01185       iFileDownloadRetries = 0; // reset the file download retries counter since
01186                                 // we'll be restarting the download again.
01187       bDownloadInitiated = FALSE; // restart the download using new socket connection
01188       CloseSocket(szProxyServer, szProxyPort);
01189       --giIndex; // Decrement the file index counter because we'll be trying to
01190                  // download the same file again.  We don't want to go to the next
01191                  // file just yet.
01192 
01193       /* Let's make sure we're in a paused state. */
01194       /* The pause state will be unset by DownloadDlgProc(). */
01195       gdwDownloadDialogStatus = CS_PAUSE;
01196       PauseTheDownload(rv, &iFileDownloadRetries);
01197     }
01198     else if(bIgnoreAllNetworkErrors || iIgnoreFileNetworkError)
01199       rv = nsFTPConn::OK;
01200 
01201     UnsetSetupCurrentDownloadFile();
01202   }
01203 
01204   CloseSocket(szProxyServer, szProxyPort);
01205   DeInitDownloadDlg();
01206   SetCurrentDirectory(szSavedCwd);
01207   return(rv);
01208 }
01209 
01210 int ProgressCB(int aBytesSoFar, int aTotalFinalSize)
01211 {
01212   long   lBytesDiffSoFar;
01213   double dPercentSoFar;
01214   int    iRv = nsFTPConn::OK;
01215 
01216   if(sgProduct.mode != SILENT)
01217   {
01218     SetStatusUrl();
01219 
01220     if(glTotalKb == 0)
01221       glTotalKb = aTotalFinalSize;
01222 
01223     /* Calculate the difference between the last set of bytes read against
01224      * the current set of bytes read.  If the value is negative, that means
01225      * that it started a new file, so reset lBytesDiffSoFar to aBytesSoFar */
01226     lBytesDiffSoFar = ((aBytesSoFar - glLastBytesSoFar) < 1) ? aBytesSoFar : (aBytesSoFar - glLastBytesSoFar);
01227 
01228     /* Save the current bytes read as the last set of bytes read */
01229     glLastBytesSoFar = aBytesSoFar;
01230     glAbsoluteBytesSoFar += lBytesDiffSoFar;
01231 
01232     dPercentSoFar = GetPercentSoFar();
01233     if(gbDlgDownloadMinimized)
01234       SetMinimizedDownloadTitle((int)dPercentSoFar);
01235 
01236     UpdateGaugeFileProgressBar(dPercentSoFar);
01237     SetStatusStatus();
01238 
01239     if((gdwDownloadDialogStatus == CS_CANCEL) ||
01240        (gdwDownloadDialogStatus == CS_PAUSE))
01241       iRv = nsFTPConn::E_USER_CANCEL;
01242   }
01243 
01244   ProcessWindowsMessages();
01245   return(iRv);
01246 }
01247 
01248 // Window proc for dialog
01249 LRESULT CALLBACK
01250 DownloadDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
01251 {
01252   switch (msg)
01253   {
01254     case WM_INITDIALOG:
01255       GetPrivateProfileString("Strings",
01256                               "Status File Info",
01257                               "",
01258                               gszFileInfo,
01259                               sizeof(gszFileInfo),
01260                               szFileIniConfig);
01261       DisableSystemMenuItems(hWndDlg, FALSE);
01262       if(gbShowDownloadRetryMsg)
01263         SetDlgItemText(hWndDlg, IDC_MESSAGE0, diDownload.szMessageRetry0);
01264       else
01265         SetDlgItemText(hWndDlg, IDC_MESSAGE0, diDownload.szMessageDownload0);
01266 
01267       EnableWindow(GetDlgItem(hWndDlg, IDRESUME), FALSE);
01268       SetDlgItemText(hWndDlg, IDC_STATIC1, sgInstallGui.szStatus);
01269       SetDlgItemText(hWndDlg, IDC_STATIC2, sgInstallGui.szFile);
01270       SetDlgItemText(hWndDlg, IDC_STATIC4, sgInstallGui.szTo);
01271       SetDlgItemText(hWndDlg, IDC_STATIC3, sgInstallGui.szUrl);
01272       SetDlgItemText(hWndDlg, IDCANCEL, sgInstallGui.szCancel_);
01273       SetDlgItemText(hWndDlg, IDPAUSE, sgInstallGui.szPause_);
01274       SetDlgItemText(hWndDlg, IDRESUME, sgInstallGui.szResume_);
01275       SendDlgItemMessage (hWndDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01276       SendDlgItemMessage (hWndDlg, IDC_STATIC2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01277       SendDlgItemMessage (hWndDlg, IDC_STATIC3, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01278       SendDlgItemMessage (hWndDlg, IDCANCEL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01279       SendDlgItemMessage (hWndDlg, IDPAUSE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01280       SendDlgItemMessage (hWndDlg, IDRESUME, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01281       SendDlgItemMessage (hWndDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01282       SendDlgItemMessage (hWndDlg, IDC_STATUS_STATUS, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01283       SendDlgItemMessage (hWndDlg, IDC_STATUS_FILE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01284       SendDlgItemMessage (hWndDlg, IDC_STATUS_URL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01285       SendDlgItemMessage (hWndDlg, IDC_STATUS_TO, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01286       RepositionWindow(hWndDlg, BANNER_IMAGE_DOWNLOAD);
01287       ClosePreviousDialog();
01288       return FALSE;
01289 
01290     case WM_SIZE:
01291       switch(wParam)
01292       {
01293         case SIZE_MINIMIZED:
01294           SetMinimizedDownloadTitle((int)GetPercentSoFar());
01295           gbDlgDownloadMinimized = TRUE;
01296           gbDlgDownloadJustMinimized = TRUE;
01297           break;
01298 
01299         case SIZE_RESTORED:
01300           SetStatusUrl();
01301           SetRestoredDownloadTitle();
01302           gbDlgDownloadMinimized = FALSE;
01303           break;
01304       }
01305       return(FALSE);
01306 
01307     case WM_COMMAND:
01308       switch(LOWORD(wParam))
01309       {
01310         case IDCANCEL:
01311           if(AskCancelDlg(hWndDlg))
01312             gdwDownloadDialogStatus = CS_CANCEL;
01313           break;
01314 
01315         case IDPAUSE:
01316           if(!gtiPaused.bTickStarted)
01317           {
01318             gtiPaused.dwTickBegin          = GetTickCount();
01319             gtiPaused.bTickStarted         = TRUE;
01320             gtiPaused.bTickDownloadResumed = FALSE;
01321           }
01322 
01323           EnableWindow(GetDlgItem(hWndDlg, IDPAUSE),  FALSE);
01324           EnableWindow(GetDlgItem(hWndDlg, IDRESUME), TRUE);
01325           gdwDownloadDialogStatus = CS_PAUSE;
01326           break;
01327 
01328         case IDRESUME:
01329           gtiPaused.dwTickEnd = GetTickCount();
01330           gtiPaused.dwTickDif = GetTickDif(gtiPaused.dwTickEnd,
01331                                            gtiPaused.dwTickBegin);
01332           gtiPaused.bTickDownloadResumed = TRUE;
01333 
01334           EnableWindow(GetDlgItem(hWndDlg, IDRESUME), FALSE);
01335           EnableWindow(GetDlgItem(hWndDlg, IDPAUSE),  TRUE);
01336           gdwDownloadDialogStatus = CS_NONE;
01337           break;
01338 
01339         default:
01340           break;
01341       }
01342       return(TRUE);
01343   }
01344 
01345   return(FALSE);  // didn't handle the message
01346 }
01347 
01348 // This routine will update the File Gauge progress bar to the specified percentage
01349 // (value between 0 and 100)
01350 static void
01351 UpdateGaugeFileProgressBar(double value)
01352 {
01353        int            nBars;
01354   static long lModLastValue = 0;
01355 
01356   if(sgProduct.mode != SILENT)
01357   {
01358     if(!CheckInterval(&lModLastValue, UPDATE_INTERVAL_PROGRESS_BAR))
01359       return;
01360 
01361     // Figure out how many bars should be displayed
01362     nBars = (int)(dlgInfo.nMaxFileBars * value / 100);
01363 
01364     // Only paint if we need to display more bars
01365     if((nBars > dlgInfo.nFileBars) || (dlgInfo.nFileBars == 0))
01366     {
01367       HWND    hWndGauge = GetDlgItem(dlgInfo.hWndDlg, IDC_GAUGE_FILE);
01368       RECT    rect;
01369 
01370       // Update the gauge state before painting
01371       dlgInfo.nFileBars = nBars;
01372 
01373       // Only invalidate the part that needs updating
01374       GetClientRect(hWndGauge, &rect);
01375       InvalidateRect(hWndGauge, &rect, FALSE);
01376     
01377       // Update the whole extracting dialog. We do this because we don't
01378       // have a message loop to process WM_PAINT messages in case the
01379       // extracting dialog was exposed
01380       UpdateWindow(dlgInfo.hWndDlg);
01381     }
01382   }
01383 }
01384 
01385 // Draws a recessed border around the gauge
01386 static void
01387 DrawGaugeBorder(HWND hWnd)
01388 {
01389        HDC           hDC = GetWindowDC(hWnd);
01390        RECT   rect;
01391        int           cx, cy;
01392        HPEN   hShadowPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
01393        HGDIOBJ       hOldPen;
01394 
01395        GetWindowRect(hWnd, &rect);
01396        cx = rect.right - rect.left;
01397        cy = rect.bottom - rect.top;
01398 
01399        // Draw a dark gray line segment
01400        hOldPen = SelectObject(hDC, (HGDIOBJ)hShadowPen);
01401        MoveToEx(hDC, 0, cy - 1, NULL);
01402        LineTo(hDC, 0, 0);
01403        LineTo(hDC, cx - 1, 0);
01404 
01405        // Draw a white line segment
01406        SelectObject(hDC, GetStockObject(WHITE_PEN));
01407        MoveToEx(hDC, 0, cy - 1, NULL);
01408        LineTo(hDC, cx - 1, cy - 1);
01409        LineTo(hDC, cx - 1, 0);
01410 
01411        SelectObject(hDC, hOldPen);
01412        DeleteObject(hShadowPen);
01413        ReleaseDC(hWnd, hDC);
01414 }
01415 
01416 // Draws the progress bar
01417 static void
01418 DrawProgressBar(HWND hWnd, int nBars)
01419 {
01420   int         i;
01421        PAINTSTRUCT   ps;
01422        HDC         hDC;
01423        RECT        rect;
01424        HBRUSH      hBrush;
01425 
01426   hDC = BeginPaint(hWnd, &ps);
01427        GetClientRect(hWnd, &rect);
01428   if(nBars <= 0)
01429   {
01430     /* clear the bars */
01431     hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
01432     FillRect(hDC, &rect, hBrush);
01433   }
01434   else
01435   {
01436        // Draw the bars
01437     hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
01438          rect.left     = rect.top = BAR_LIBXPNET_MARGIN;
01439          rect.bottom  -= BAR_LIBXPNET_MARGIN;
01440          rect.right    = rect.left + BAR_LIBXPNET_WIDTH;
01441 
01442          for(i = 0; i < nBars; i++)
01443     {
01444                 RECT dest;
01445 
01446                 if(IntersectRect(&dest, &ps.rcPaint, &rect))
01447                        FillRect(hDC, &rect, hBrush);
01448 
01449       OffsetRect(&rect, BAR_LIBXPNET_WIDTH + BAR_LIBXPNET_SPACING, 0);
01450          }
01451   }
01452 
01453        DeleteObject(hBrush);
01454        EndPaint(hWnd, &ps);
01455 }
01456 
01457 // Adjusts the width of the gauge based on the maximum number of bars
01458 static void
01459 SizeToFitGauge(HWND hWnd, int nMaxBars)
01460 {
01461        RECT   rect;
01462        int           cx;
01463 
01464        // Get the window size in pixels
01465        GetWindowRect(hWnd, &rect);
01466 
01467        // Size the width to fit
01468        cx = 2 * GetSystemMetrics(SM_CXBORDER) + 2 * BAR_LIBXPNET_MARGIN +
01469               nMaxBars * BAR_LIBXPNET_WIDTH + (nMaxBars - 1) * BAR_LIBXPNET_SPACING;
01470 
01471        SetWindowPos(hWnd, NULL, -1, -1, cx, rect.bottom - rect.top,
01472               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
01473 }
01474 
01475 // Window proc for Download gauge
01476 BOOL CALLBACK
01477 GaugeDownloadWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
01478 {
01479        DWORD  dwStyle;
01480        RECT   rect;
01481 
01482        switch(msg)
01483   {
01484               case WM_NCCREATE:
01485                      dwStyle = GetWindowLong(hWnd, GWL_STYLE);
01486                      SetWindowLong(hWnd, GWL_STYLE, dwStyle | WS_BORDER);
01487                      return(TRUE);
01488 
01489               case WM_CREATE:
01490                      // Figure out the maximum number of bars that can be displayed
01491                      GetClientRect(hWnd, &rect);
01492                      dlgInfo.nFileBars = 0;
01493                      dlgInfo.nMaxFileBars = (rect.right - rect.left - 2 * BAR_LIBXPNET_MARGIN + BAR_LIBXPNET_SPACING) / (BAR_LIBXPNET_WIDTH + BAR_LIBXPNET_SPACING);
01494 
01495                      // Size the gauge to exactly fit the maximum number of bars
01496                      SizeToFitGauge(hWnd, dlgInfo.nMaxFileBars);
01497                      return(FALSE);
01498 
01499               case WM_NCPAINT:
01500                      DrawGaugeBorder(hWnd);
01501                      return(FALSE);
01502 
01503               case WM_PAINT:
01504                      DrawProgressBar(hWnd, dlgInfo.nFileBars);
01505                      return(FALSE);
01506        }
01507 
01508        return(DefWindowProc(hWnd, msg, wParam, lParam));
01509 }
01510 
01511 void InitDownloadDlg(void)
01512 {
01513        WNDCLASS      wc;
01514 
01515   if(sgProduct.mode != SILENT)
01516   {
01517     memset(&wc, 0, sizeof(wc));
01518     wc.style          = CS_GLOBALCLASS;
01519     wc.hInstance      = hInst;
01520     wc.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
01521     wc.lpfnWndProc    = (WNDPROC)GaugeDownloadWndProc;
01522     wc.lpszClassName  = "GaugeFile";
01523     RegisterClass(&wc);
01524 
01525     // Display the dialog box
01526     dlgInfo.hWndDlg = CreateDialog(hSetupRscInst, MAKEINTRESOURCE(DLG_DOWNLOADING), hWndMain, (DLGPROC)DownloadDlgProc);
01527     UpdateWindow(dlgInfo.hWndDlg);
01528     UpdateGaugeFileProgressBar(0);
01529   }
01530 }
01531 
01532 void DeInitDownloadDlg()
01533 {
01534   if(sgProduct.mode != SILENT)
01535   {
01536     SaveWindowPosition(dlgInfo.hWndDlg);
01537     DestroyWindow(dlgInfo.hWndDlg);
01538     UnregisterClass("GaugeFile", hInst);
01539   }
01540 }