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-2001
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 the GNU General Public License Version 2 or later (the "GPL"), or
00026  * 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     GetConfigIniProfileString("Strings", "Status Download", "",
00297                             szStatusStatusLine, sizeof(szStatusStatusLine));
00298     if(*szStatusStatusLine != '\0')
00299       sprintf(szCurrentStatusInfo,
00300               szStatusStatusLine,
00301               szTimeLeft,
00302               dRate,
00303               dwKBytesSoFar,
00304               glTotalKb);
00305     else
00306       sprintf(szCurrentStatusInfo,
00307               "%s at %.2fKB/sec (%uKB of %uKB downloaded)",
00308               szTimeLeft,
00309               dRate,
00310               dwKBytesSoFar,
00311               glTotalKb);
00312   }
00313   else
00314   {
00315     GetConfigIniProfileString("Strings", "Status Retry", "",
00316                            szStatusStatusLine, sizeof(szStatusStatusLine));
00317     if(*szStatusStatusLine != '\0')
00318       sprintf(szCurrentStatusInfo,
00319               szStatusStatusLine,
00320               szTimeLeft,
00321               dRate,
00322               dwKBytesSoFar,
00323               glTotalKb);
00324     else
00325       sprintf(szCurrentStatusInfo,
00326               "%s at %.2KB/sec (%uKB of %uKB downloaded)",
00327               szTimeLeft,
00328               dRate,
00329               dwKBytesSoFar,
00330               glTotalKb);
00331   }
00332 
00333   GetConfigIniProfileString("Strings", "Status Percentage Completed", "",
00334                          szPercentageCompleted, sizeof(szPercentageCompleted));
00335   wsprintf(szPercentString, szPercentageCompleted, (int)GetPercentSoFar());
00336 
00337   /* Set the download dialog title */
00338   SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_STATUS, szCurrentStatusInfo);
00339   SetDlgItemText(dlgInfo.hWndDlg, IDC_PERCENTAGE, szPercentString);
00340 }
00341 
00342 void SetStatusFile(void)
00343 {
00344   char szString[MAX_BUF];
00345 
00346   /* Set the download dialog status*/
00347   wsprintf(szString, gszFileInfo, gszCurrentDownloadFileDescription);
00348   SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_FILE, szString);
00349   SetStatusStatus();
00350 }
00351 
00352 void SetStatusUrl(void)
00353 {
00354   /* display the current url being processed */
00355   if(gbUrlChanged)
00356   {
00357     char szUrlPathBuf[MAX_BUF];
00358     char szToPathBuf[MAX_BUF];
00359     HWND hStatusUrl = NULL;
00360     HWND hStatusTo  = NULL;
00361 
00362     hStatusUrl = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS_URL);
00363     if(hStatusUrl)
00364       TruncateString(hStatusUrl, gszUrl, szUrlPathBuf, sizeof(szUrlPathBuf));
00365     else
00366       lstrcpy(szUrlPathBuf, gszUrl);
00367 
00368     hStatusTo = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS_TO);
00369     if(hStatusTo)
00370       TruncateString(hStatusTo, gszTo, szToPathBuf, sizeof(szToPathBuf));
00371     else
00372       lstrcpy(szToPathBuf, gszTo);
00373 
00374     SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_URL, szUrlPathBuf);
00375     SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_TO,  szToPathBuf);
00376     SetStatusFile();
00377     gbUrlChanged = FALSE;
00378   }
00379 }
00380 
00381 double GetPercentSoFar(void)
00382 {
00383   return((double)(((double)(glAbsoluteBytesSoFar / 1024) / (double)glTotalKb) * (double)100));
00384 }
00385 
00386 void SetMinimizedDownloadTitle(DWORD dwPercentSoFar)
00387 {
00388   static DWORD dwLastPercentSoFar = 0;
00389   char szDownloadTitle[MAX_BUF_MEDIUM];
00390   char gszCurrentDownloadInfo[MAX_BUF_MEDIUM];
00391 
00392   GetConfigIniProfileString("Strings", "Dialog Download Title Minimized", "", szDownloadTitle, sizeof(szDownloadTitle));
00393 
00394   if(*szDownloadTitle != '\0')
00395     wsprintf(gszCurrentDownloadInfo, szDownloadTitle, dwPercentSoFar, gszCurrentDownloadFilename);
00396   else
00397     wsprintf(gszCurrentDownloadInfo, "%d%% for all files", dwPercentSoFar);
00398 
00399   /* check and save the current percent so far to minimize flickering */
00400   if((dwLastPercentSoFar != dwPercentSoFar) || gbDlgDownloadJustMinimized)
00401   {
00402     /* When the dialog is has just been minimized, the title is not set
00403      * until the percentage changes, which when downloading via modem,
00404      * could take several seconds.  This variable allows us to tell when
00405      * the dialog had *just* been minimized regardless if the percentage
00406      * had changed or not. */
00407     gbDlgDownloadJustMinimized = FALSE;
00408 
00409     /* Set the download dialog title */
00410     SetWindowText(dlgInfo.hWndDlg, gszCurrentDownloadInfo);
00411     dwLastPercentSoFar = dwPercentSoFar;
00412   }
00413 }
00414 
00415 void SetRestoredDownloadTitle(void)
00416 {
00417   /* Set the download dialog title */
00418   SetWindowText(dlgInfo.hWndDlg, diDownload.szTitle);
00419 }
00420 
00421 void GetTotalArchivesToDownload(int *iTotalArchivesToDownload, DWORD *dwTotalEstDownloadSize)
00422 {
00423   int  iIndex = 0;
00424   char szUrl[MAX_BUF];
00425   char szSection[MAX_INI_SK];
00426   char szDownloadSize[MAX_ITOA];
00427 
00428   *dwTotalEstDownloadSize = 0;
00429   iIndex = 0;
00430   wsprintf(szSection, "File%d", iIndex);
00431   GetPrivateProfileString(szSection,
00432                           "url0",
00433                           "",
00434                           szUrl,
00435                           sizeof(szUrl),
00436                           gszConfigIniFile);
00437   while(*szUrl != '\0')
00438   {
00439     GetPrivateProfileString(szSection, "size", "", szDownloadSize, sizeof(szDownloadSize), gszConfigIniFile);
00440     if((lstrlen(szDownloadSize) < 32) && (*szDownloadSize != '\0'))
00441       /* size will be in kb.  31 bits (int minus the signed bit) of precision should sufice */
00442       *dwTotalEstDownloadSize += atoi(szDownloadSize);
00443 
00444     ++iIndex;
00445     wsprintf(szSection, "File%d", iIndex);
00446     GetPrivateProfileString(szSection,
00447                             "url0",
00448                             "",
00449                             szUrl,
00450                             sizeof(szUrl),
00451                             gszConfigIniFile);
00452   }
00453   *iTotalArchivesToDownload = iIndex;
00454 }
00455 
00456 /* 
00457  * Name: ProcessWndMsgCB
00458  *
00459  * Arguments: None
00460  *
00461  * Description: Callback function invoked by socket code and by FTP and HTTP layers
00462  *                          to give the UI a chance to breath while we are in a look processing
00463  *                          incoming data, or looping in select()
00464  *
00465  * Author: syd@netscape.com 5/11/2001
00466  *
00467 */
00468 
00469 int
00470 ProcessWndMsgCB()
00471 {
00472   int iRv = nsFTPConn::OK;
00473 
00474        ProcessWindowsMessages();
00475   if((gdwDownloadDialogStatus == CS_CANCEL) ||
00476      (gdwDownloadDialogStatus == CS_PAUSE))
00477     iRv = nsFTPConn::E_USER_CANCEL;
00478 
00479        return(iRv);
00480 }
00481 
00482 /* Function used only to send the message stream error */
00483 int WGet(char *szUrl,
00484          char *szFile,
00485          char *szProxyServer,
00486          char *szProxyPort,
00487          char *szProxyUser,
00488          char *szProxyPasswd)
00489 {
00490   int        rv;
00491   char       proxyURL[MAX_BUF];
00492   nsHTTPConn *conn = NULL;
00493 
00494   if((szProxyServer != NULL) && (szProxyPort != NULL) &&
00495      (*szProxyServer != '\0') && (*szProxyPort != '\0'))
00496   {
00497     /* detected proxy information, let's use it */
00498     memset(proxyURL, 0, sizeof(proxyURL));
00499     wsprintf(proxyURL, "http://%s:%s", szProxyServer, szProxyPort);
00500 
00501     conn = new nsHTTPConn(proxyURL);
00502     if(conn == NULL)
00503       return(WIZ_OUT_OF_MEMORY);
00504 
00505     if((szProxyUser != NULL) && (*szProxyUser != '\0') &&
00506        (szProxyPasswd != NULL) && (*szProxyPasswd != '\0'))
00507       /* detected user and password info */
00508       conn->SetProxyInfo(szUrl, szProxyUser, szProxyPasswd);
00509     else
00510       conn->SetProxyInfo(szUrl, NULL, NULL);
00511   }
00512   else
00513   {
00514     /* no proxy information supplied. set up normal http object */
00515     conn = new nsHTTPConn(szUrl, ProcessWndMsgCB);
00516     if(conn == NULL)
00517       return(WIZ_OUT_OF_MEMORY);
00518   }
00519   
00520   rv = conn->Open();
00521   if(rv == WIZ_OK)
00522   {
00523     rv = conn->Get(NULL, szFile);
00524     conn->Close();
00525   }
00526 
00527   if(conn)
00528     delete(conn);
00529 
00530   return(rv);
00531 }
00532 
00533 int DownloadViaProxyOpen(char *szUrl, char *szProxyServer, char *szProxyPort, char *szProxyUser, char *szProxyPasswd)
00534 {
00535   int  rv;
00536   char proxyURL[kProxySrvrLen];
00537 
00538   if((!szUrl) || (*szUrl == '\0'))
00539     return nsHTTPConn::E_PARAM;
00540 
00541   rv = nsHTTPConn::OK;
00542   memset(proxyURL, 0, kProxySrvrLen);
00543   wsprintf(proxyURL, "http://%s:%s", szProxyServer, szProxyPort);
00544 
00545   connHTTP = new nsHTTPConn(proxyURL, ProcessWndMsgCB);
00546   if(connHTTP == NULL)
00547   {
00548     char szBuf[MAX_BUF_TINY];
00549 
00550     GetConfigIniProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf));
00551     PrintError(szBuf, ERROR_CODE_HIDE);
00552 
00553     return(WIZ_OUT_OF_MEMORY);
00554   }
00555 
00556   if((szProxyUser != NULL) && (*szProxyUser != '\0') &&
00557      (szProxyPasswd != NULL) && (*szProxyPasswd != '\0'))
00558     connHTTP->SetProxyInfo(szUrl, szProxyUser, szProxyPasswd);
00559   else
00560     connHTTP->SetProxyInfo(szUrl, NULL, NULL);
00561 
00562   rv = connHTTP->Open();
00563   return(rv);
00564 }
00565 
00566 void DownloadViaProxyClose(void)
00567 {
00568   gbStartTickCounter = FALSE;
00569   if(connHTTP)
00570   {
00571     connHTTP->Close();
00572     delete(connHTTP);
00573     connHTTP = NULL;
00574   }
00575 }
00576 
00577 int DownloadViaProxy(char *szUrl, char *szProxyServer, char *szProxyPort, char *szProxyUser, char *szProxyPasswd)
00578 {
00579   int  rv;
00580   char *file = NULL;
00581 
00582   rv = nsHTTPConn::OK;
00583   if((!szUrl) || (*szUrl == '\0'))
00584     return nsHTTPConn::E_PARAM;
00585 
00586   if(connHTTP == NULL)
00587   {
00588     rv = DownloadViaProxyOpen(szUrl,
00589                               szProxyServer,
00590                               szProxyPort,
00591                               szProxyUser,
00592                               szProxyPasswd);
00593 
00594     if(rv != nsHTTPConn::OK)
00595     {
00596       DownloadViaProxyClose();
00597       return(rv);
00598     }
00599   }
00600 
00601   if(connHTTP == NULL)
00602   {
00603     char szBuf[MAX_BUF_TINY];
00604 
00605     GetConfigIniProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf));
00606     PrintError(szBuf, ERROR_CODE_HIDE);
00607 
00608     return(WIZ_OUT_OF_MEMORY);
00609   }
00610 
00611   if(strrchr(szUrl, '/') != (szUrl + strlen(szUrl)))
00612     file = strrchr(szUrl, '/') + 1; // set to leaf name
00613 
00614   gbStartTickCounter = TRUE;
00615   rv = connHTTP->Get(ProgressCB, file); // use leaf from URL
00616   DownloadViaProxyClose();
00617   return(rv);
00618 }
00619 
00620 int DownloadViaHTTPOpen(char *szUrl)
00621 {
00622   int  rv;
00623 
00624   if((!szUrl) || (*szUrl == '\0'))
00625     return nsHTTPConn::E_PARAM;
00626 
00627   rv = nsHTTPConn::OK;
00628   connHTTP = new nsHTTPConn(szUrl, ProcessWndMsgCB);
00629   if(connHTTP == NULL)
00630   {
00631     char szBuf[MAX_BUF_TINY];
00632 
00633     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), gszConfigIniFile);
00634     PrintError(szBuf, ERROR_CODE_HIDE);
00635 
00636     return(WIZ_OUT_OF_MEMORY);
00637   }
00638   
00639   rv = connHTTP->Open();
00640   return(rv);
00641 }
00642 
00643 void DownloadViaHTTPClose(void)
00644 {
00645   gbStartTickCounter = FALSE;
00646   if(connHTTP)
00647   {
00648     connHTTP->Close();
00649     delete(connHTTP);
00650     connHTTP = NULL;
00651   }
00652 }
00653 
00654 int DownloadViaHTTP(char *szUrl)
00655 {
00656   int  rv;
00657   char *file = NULL;
00658 
00659   if((!szUrl) || (*szUrl == '\0'))
00660     return nsHTTPConn::E_PARAM;
00661 
00662   if(connHTTP == NULL)
00663   {
00664     rv = DownloadViaHTTPOpen(szUrl);
00665     if(rv != nsHTTPConn::OK)
00666     {
00667       DownloadViaHTTPClose();
00668       return(rv);
00669     }
00670   }
00671 
00672   if(connHTTP == NULL)
00673   {
00674     char szBuf[MAX_BUF_TINY];
00675 
00676     GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), gszConfigIniFile);
00677     PrintError(szBuf, ERROR_CODE_HIDE);
00678 
00679     return(WIZ_OUT_OF_MEMORY);
00680   }
00681   
00682   rv = nsHTTPConn::OK;
00683   if(strrchr(szUrl, '/') != (szUrl + strlen(szUrl)))
00684     file = strrchr(szUrl, '/') + 1; // set to leaf name
00685 
00686   gbStartTickCounter = TRUE;
00687   rv = connHTTP->Get(ProgressCB, file);
00688   DownloadViaHTTPClose();
00689   return(rv);
00690 }
00691 
00692 int DownloadViaFTPOpen(char *szUrl)
00693 {
00694   char *host = 0, *path = 0, *file = (char*) kLoclFile;
00695   int port = 21;
00696   int rv;
00697 
00698   if((!szUrl) || (*szUrl == '\0'))
00699     return nsFTPConn::E_PARAM;
00700 
00701   rv = nsHTTPConn::ParseURL(kFTP, szUrl, &host, &port, &path);
00702 
00703   connFTP = new nsFTPConn(host, ProcessWndMsgCB);
00704   if(connFTP == NULL)
00705   {
00706     char szBuf[MAX_BUF_TINY];
00707 
00708     GetConfigIniProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf));
00709     PrintError(szBuf, ERROR_CODE_HIDE);
00710 
00711     return(WIZ_OUT_OF_MEMORY);
00712   }
00713 
00714   rv = connFTP->Open();
00715   if(host)
00716     free(host);
00717   if(path)
00718     free(path);
00719 
00720   return(rv);
00721 }
00722 
00723 void DownloadViaFTPClose(void)
00724 {
00725   gbStartTickCounter = FALSE;
00726   if(connFTP)
00727   {
00728     connFTP->Close();
00729     delete(connFTP);
00730     connFTP = NULL;
00731   }
00732 }
00733 
00734 int DownloadViaFTP(char *szUrl)
00735 {
00736   char *host = 0, *path = 0, *file = (char*) kLoclFile;
00737   int port = 21;
00738   int rv;
00739 
00740   if((!szUrl) || (*szUrl == '\0'))
00741     return nsFTPConn::E_PARAM;
00742 
00743   if(connFTP == NULL)
00744   {
00745     rv = DownloadViaFTPOpen(szUrl);
00746     if(rv != nsFTPConn::OK)
00747     {
00748       DownloadViaFTPClose();
00749       return(rv);
00750     }
00751   }
00752 
00753   if(connFTP == NULL)
00754   {
00755     char szBuf[MAX_BUF_TINY];
00756 
00757     GetConfigIniProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf));
00758     PrintError(szBuf, ERROR_CODE_HIDE);
00759 
00760     return(WIZ_OUT_OF_MEMORY);
00761   }
00762 
00763   rv = nsHTTPConn::ParseURL(kFTP, szUrl, &host, &port, &path);
00764 
00765   if(strrchr(path, '/') != (path + strlen(path)))
00766     file = strrchr(path, '/') + 1; // set to leaf name
00767 
00768   gbStartTickCounter = TRUE;
00769   rv = connFTP->Get(path, file, nsFTPConn::BINARY, TRUE, ProgressCB);
00770 
00771   if(host)
00772     free(host);
00773   if(path)
00774     free(path);
00775 
00776   return(rv);
00777 }
00778 
00779 void PauseTheDownload(int rv, int *iFileDownloadRetries)
00780 {
00781   if(rv != nsFTPConn::E_USER_CANCEL)
00782   {
00783     SendMessage(dlgInfo.hWndDlg, WM_COMMAND, IDPAUSE, 0);
00784     --*iFileDownloadRetries;
00785   }
00786 
00787   while(gdwDownloadDialogStatus == CS_PAUSE)
00788   {
00789     SleepEx(200, FALSE);
00790     ProcessWindowsMessages();
00791   }
00792 }
00793 
00794 void CloseSocket(char *szProxyServer, char *szProxyPort)
00795 {
00796   /* Close the socket connection from the first attempt. */
00797   if((szProxyServer != NULL) && (szProxyPort != NULL) &&
00798      (*szProxyServer != '\0') && (*szProxyPort != '\0'))
00799       DownloadViaProxyClose();
00800   else
00801   {
00802     /* is this an HTTP URL? */
00803     if(strncmp(gszUrl, kHTTP, lstrlen(kHTTP)) == 0)
00804       DownloadViaHTTPClose();
00805     /* or is this an FTP URL? */
00806     else if(strncmp(gszUrl, kFTP, lstrlen(kFTP)) == 0)
00807       DownloadViaFTPClose();
00808   }
00809 }
00810 
00811 siC *GetObjectFromArchiveName(char *szArchiveName)
00812 {
00813   DWORD dwIndex;
00814   siC   *siCObject = NULL;
00815   siC   *siCNode   = NULL;
00816 
00817   dwIndex = 0;
00818   siCObject = SiCNodeGetObject(dwIndex, TRUE, AC_ALL);
00819   while(siCObject)
00820   {
00821     if(lstrcmpi(szArchiveName, siCObject->szArchiveName) == 0)
00822     {
00823       siCNode = siCObject;
00824       break;
00825     }
00826 
00827     ++dwIndex;
00828     siCObject = SiCNodeGetObject(dwIndex, TRUE, AC_ALL);
00829   }
00830 
00831   return(siCNode);
00832 }
00833 
00834 int DownloadFiles(char *szInputIniFile,
00835                   char *szDownloadDir,
00836                   char *szProxyServer,
00837                   char *szProxyPort,
00838                   char *szProxyUser,
00839                   char *szProxyPasswd,
00840                   BOOL bShowRetryMsg,
00841                   BOOL bIgnoreAllNetworkErrors,
00842                   char *szFailedFile,
00843                   DWORD dwFailedFileSize)
00844 {
00845   char      szBuf[MAX_BUF];
00846   char      szCurrentFile[MAX_BUF];
00847   char      szSection[MAX_INI_SK];
00848   char      szKey[MAX_INI_SK];
00849   char      szSavedCwd[MAX_BUF_MEDIUM];
00850   int       iCounter;
00851   int       rv;
00852   int       iFileDownloadRetries;
00853   int       iIgnoreFileNetworkError;
00854   int       iLocalTimeOutCounter;
00855   DWORD     dwTotalEstDownloadSize;
00856   char      szPartiallyDownloadedFilename[MAX_BUF];
00857   BOOL      bDownloadInitiated;
00858   char      szTempURL[MAX_BUF];
00859   char      szWorkingURLPathOnly[MAX_BUF];
00860   siC       *siCCurrentFileObj = NULL;
00861 
00862   ZeroMemory(szTempURL, sizeof(szTempURL));
00863   ZeroMemory(szWorkingURLPathOnly, sizeof(szWorkingURLPathOnly));
00864   if(szInputIniFile == NULL)
00865     return(WIZ_ERROR_UNDEFINED);
00866 
00867   if(szFailedFile)
00868     ZeroMemory(szFailedFile, dwFailedFileSize);
00869 
00870   InitTickInfo();
00871   GetCurrentDirectory(sizeof(szSavedCwd), szSavedCwd);
00872   SetCurrentDirectory(szDownloadDir);
00873 
00874   rv                        = WIZ_OK;
00875   dwTotalEstDownloadSize    = 0;
00876   giTotalArchivesToDownload = 0;
00877   glLastBytesSoFar          = 0;
00878   glAbsoluteBytesSoFar      = 0;
00879   glBytesResumedFrom        = 0;
00880   gdwTickStart              = 0; /* Initialize the counter used to
00881                                   * calculate download rate */
00882   gbStartTickCounter        = FALSE; /* used to determine when to start
00883                                       * the tick counter used to calculate
00884                                       * the download rate */
00885   gbUrlChanged              = TRUE;
00886   gbDlgDownloadMinimized    = FALSE;
00887   gbDlgDownloadJustMinimized = FALSE;
00888   gdwDownloadDialogStatus   = CS_NONE;
00889   gbShowDownloadRetryMsg    = bShowRetryMsg;
00890   gszConfigIniFile          = szInputIniFile;
00891   bDownloadInitiated        = FALSE;
00892 
00893   GetTotalArchivesToDownload(&giTotalArchivesToDownload,
00894                              &dwTotalEstDownloadSize);
00895   glTotalKb                 = dwTotalEstDownloadSize;
00896   GetSetupCurrentDownloadFile(szPartiallyDownloadedFilename,
00897                               sizeof(szPartiallyDownloadedFilename));
00898 
00899   InitDownloadDlg();
00900 
00901   for(giIndex = 0; giIndex < giTotalArchivesToDownload; giIndex++)
00902   {
00903     /* set (or reset) the counter to 0 in order to read the
00904      * next files's 0'th url from the .idi file */
00905     iCounter     = 0;
00906     gbUrlChanged = TRUE; /* Update the download dialog with new URL */
00907     wsprintf(szSection, "File%d", giIndex);
00908     wsprintf(szKey,     "url%d",  iCounter);
00909     GetPrivateProfileString(szSection,
00910                             szKey,
00911                             "",
00912                             szTempURL,
00913                             sizeof(szTempURL),
00914                             gszConfigIniFile);
00915 
00916     if(*szTempURL == '\0')
00917       continue;
00918 
00919     if(!bDownloadInitiated)
00920     {
00921       ParsePath(szTempURL,
00922                 szWorkingURLPathOnly,
00923                 sizeof(szWorkingURLPathOnly),
00924                 TRUE, //use '/' as the path delimiter
00925                 PP_PATH_ONLY);
00926     }
00927 
00928     GetPrivateProfileString(szSection,
00929                             "desc",
00930                             "",
00931                             gszCurrentDownloadFileDescription,
00932                             sizeof(gszCurrentDownloadFileDescription),
00933                             gszConfigIniFile);
00934     iIgnoreFileNetworkError = GetPrivateProfileInt(szSection,
00935                             "Ignore File Network Error",
00936                             0,
00937                             gszConfigIniFile);
00938 
00939     /* save the file name to be downloaded */
00940     ParsePath(szTempURL,
00941               szCurrentFile,
00942               sizeof(szCurrentFile),
00943               TRUE, //use '/' as the path delimiter
00944               PP_FILENAME_ONLY);
00945 
00946     RemoveSlash(szWorkingURLPathOnly);
00947     wsprintf(gszUrl, "%s/%s", szWorkingURLPathOnly, szCurrentFile);
00948 
00949     /* retrieve the file's data structure */
00950     siCCurrentFileObj = GetObjectFromArchiveName(szCurrentFile);
00951 
00952     if((*szPartiallyDownloadedFilename != 0) &&
00953        (lstrcmpi(szPartiallyDownloadedFilename, szCurrentFile) == 0))
00954     {
00955       struct stat statBuf;
00956 
00957       if(stat(szPartiallyDownloadedFilename, &statBuf) != -1)
00958       {
00959         glAbsoluteBytesSoFar += statBuf.st_size;
00960         glBytesResumedFrom    = statBuf.st_size;
00961       }
00962     }
00963 
00964     lstrcpy(gszTo, szDownloadDir);
00965     AppendBackSlash(gszTo, sizeof(gszTo));
00966     lstrcat(gszTo, szCurrentFile);
00967 
00968     if(gbDlgDownloadMinimized)
00969       SetMinimizedDownloadTitle((int)GetPercentSoFar());
00970     else
00971     {
00972       SetStatusUrl();
00973       SetRestoredDownloadTitle();
00974     }
00975 
00976     SetSetupCurrentDownloadFile(szCurrentFile);
00977     iFileDownloadRetries = 0;
00978     iLocalTimeOutCounter = 0;
00979     do
00980     {
00981       ProcessWindowsMessages();
00982       /* Download starts here */
00983       if((szProxyServer != NULL) && (szProxyPort != NULL) &&
00984          (*szProxyServer != '\0') && (*szProxyPort != '\0'))
00985         /* If proxy info is provided, use HTTP proxy */
00986         rv = DownloadViaProxy(gszUrl,
00987                               szProxyServer,
00988                               szProxyPort,
00989                               szProxyUser,
00990                               szProxyPasswd);
00991       else
00992       {
00993         /* is this an HTTP URL? */
00994         if(strncmp(gszUrl, kHTTP, lstrlen(kHTTP)) == 0)
00995           rv = DownloadViaHTTP(gszUrl);
00996         /* or is this an FTP URL? */
00997         else if(strncmp(gszUrl, kFTP, lstrlen(kFTP)) == 0)
00998           rv = DownloadViaFTP(gszUrl);
00999       }
01000 
01001       bDownloadInitiated = TRUE;
01002       if((rv == nsFTPConn::E_USER_CANCEL) ||
01003          (gdwDownloadDialogStatus == CS_PAUSE))
01004       {
01005         if(gdwDownloadDialogStatus == CS_PAUSE)
01006         {
01007           CloseSocket(szProxyServer, szProxyPort);
01008 
01009           /* rv needs to be set to something
01010            * other than E_USER_CANCEL or E_OK */
01011           rv = nsFTPConn::E_CMD_UNEXPECTED;
01012 
01013           PauseTheDownload(rv, &iFileDownloadRetries);
01014           bDownloadInitiated = FALSE; /* restart the download using
01015                                        * new socket connection */
01016         }
01017         else
01018         {
01019           /* user canceled; break out of the do loop */
01020           break;
01021         }
01022       }
01023       else if((rv != nsFTPConn::OK) &&
01024               (rv != nsFTPConn::E_CMD_FAIL) &&
01025               (rv != nsSocket::E_BIND) &&
01026               (rv != nsHTTPConn::E_HTTP_RESPONSE) &&
01027               (gdwDownloadDialogStatus != CS_CANCEL))
01028       {
01029         /* We timed out.  No response from the server, or 
01030          * we somehow lost connection. */
01031 
01032         char szTitle[MAX_BUF_SMALL];
01033         char szMsgDownloadPaused[MAX_BUF];
01034 
01035         /* Incrememt the time out counter on E_TIMEOUT */
01036         if(rv == nsSocket::E_TIMEOUT)
01037         {
01038           ++siCCurrentFileObj->iNetTimeOuts;
01039           ++iLocalTimeOutCounter;
01040         }
01041 
01042         CloseSocket(szProxyServer, szProxyPort);
01043 
01044         /* If the number of timeouts is %3 == 0, then let's pause
01045          * the download process.  Otherwise, just close the
01046          * connection and open a new one to see if the download
01047          * can be restarted automatically. */
01048         if((rv != nsSocket::E_TIMEOUT) ||
01049            (rv == nsSocket::E_TIMEOUT) && ((iLocalTimeOutCounter % kModTimeOutValue) == 0))
01050         {
01051           /* Start the pause tick counter here because we don't know how
01052            * long before the user will dismiss the MessageBox() */
01053           if(!gtiPaused.bTickStarted)
01054           {
01055             gtiPaused.dwTickBegin          = GetTickCount();
01056             gtiPaused.bTickStarted         = TRUE;
01057             gtiPaused.bTickDownloadResumed = FALSE;
01058           }
01059 
01060           /* The connection unexepectedly dropped for some reason, so inform
01061            * the user that the download will be Paused, and then update the
01062            * Download dialog to show the Paused state. */
01063           GetConfigIniProfileString("Messages", "MB_WARNING_STR", "",
01064                                 szTitle, sizeof(szTitle));
01065           GetConfigIniProfileString("Strings", "Message Download Paused", "",
01066                                 szMsgDownloadPaused, sizeof(szMsgDownloadPaused));
01067           MessageBox(dlgInfo.hWndDlg,
01068                      szMsgDownloadPaused,
01069                      szTitle,
01070                      MB_ICONEXCLAMATION);
01071 
01072           /* Let's make sure we're in a paused state */
01073           gdwDownloadDialogStatus = CS_PAUSE;
01074           PauseTheDownload(rv, &iFileDownloadRetries);
01075         }
01076         else
01077           /* Let's make sure we're _not_ in a paused state */
01078           gdwDownloadDialogStatus = CS_NONE;
01079       }
01080 
01081       /* We don't count time outs as normal failures.  We're
01082        * keeping track of time outs differently. */
01083       if(rv != nsSocket::E_TIMEOUT)
01084         ++iFileDownloadRetries;
01085 
01086       if((iFileDownloadRetries > MAX_FILE_DOWNLOAD_RETRIES) &&
01087          (rv != nsFTPConn::E_USER_CANCEL) &&
01088          (gdwDownloadDialogStatus != CS_CANCEL))
01089       {
01090         /* since the download retries maxed out, increment the counter
01091          * to read the next url for the current file */
01092         ++iCounter;
01093         wsprintf(szKey, "url%d",  iCounter);
01094         GetPrivateProfileString(szSection,
01095                                 szKey,
01096                                 "",
01097                                 szTempURL,
01098                                 sizeof(szTempURL),
01099                                 gszConfigIniFile);
01100         if(*szTempURL != '\0')
01101         {
01102           /* Found more urls to download from for the current file.
01103            * Update the dialog to show the new url and reset the
01104            * file download retries to 0 since it's a new url. */
01105           gbUrlChanged = TRUE;
01106           iFileDownloadRetries = 0;
01107           bDownloadInitiated = FALSE; // restart the download using new socket connection
01108           CloseSocket(szProxyServer, szProxyPort);
01109           ParsePath(szTempURL,
01110                     szWorkingURLPathOnly,
01111                     sizeof(szWorkingURLPathOnly),
01112                     TRUE, //use '/' as the path delimiter
01113                     PP_PATH_ONLY);
01114           RemoveSlash(szWorkingURLPathOnly);
01115           wsprintf(gszUrl, "%s/%s", szWorkingURLPathOnly, szCurrentFile);
01116           SetStatusUrl();
01117         }
01118       }
01119     } while((rv != nsFTPConn::E_USER_CANCEL) &&
01120             (rv != nsFTPConn::OK) &&
01121             (gdwDownloadDialogStatus != CS_CANCEL) &&
01122             (iFileDownloadRetries <= MAX_FILE_DOWNLOAD_RETRIES));
01123 
01124     /* Save the number of retries for each file */
01125     siCCurrentFileObj->iNetRetries = iFileDownloadRetries < 1 ? 0:iFileDownloadRetries - 1;
01126 
01127     if((rv == nsFTPConn::E_USER_CANCEL) ||
01128        (gdwDownloadDialogStatus == CS_CANCEL))
01129     {
01130       /* make sure rv is E_USER_CANCEL when gdwDownloadDialogStatus
01131        * is CS_CANCEL */
01132       rv = nsFTPConn::E_USER_CANCEL;
01133 
01134       if(szFailedFile && ((DWORD)lstrlen(szCurrentFile) <= dwFailedFileSize))
01135         lstrcpy(szFailedFile, gszCurrentDownloadFileDescription);
01136 
01137       /* break out of for() loop */
01138       break;
01139     }
01140 
01141     if((rv != nsFTPConn::OK) &&
01142        (iFileDownloadRetries > MAX_FILE_DOWNLOAD_RETRIES) &&
01143        !bIgnoreAllNetworkErrors &&
01144        !iIgnoreFileNetworkError)
01145     {
01146       /* too many retries from failed downloads */
01147       char szMsg[MAX_BUF];
01148 
01149       if(szFailedFile && ((DWORD)lstrlen(szCurrentFile) <= dwFailedFileSize))
01150         lstrcpy(szFailedFile, gszCurrentDownloadFileDescription);
01151 
01152       GetConfigIniProfileString("Strings", "Error Too Many Network Errors", "",
01153                             szMsg, sizeof(szMsg));
01154       if(*szMsg != '\0')
01155       {
01156         wsprintf(szBuf, szMsg, szCurrentFile);
01157         PrintError(szBuf, ERROR_CODE_HIDE);
01158       }
01159 
01160       iFileDownloadRetries = 0; // reset the file download retries counter since
01161                                 // we'll be restarting the download again.
01162       bDownloadInitiated = FALSE; // restart the download using new socket connection
01163       CloseSocket(szProxyServer, szProxyPort);
01164       --giIndex; // Decrement the file index counter because we'll be trying to
01165                  // download the same file again.  We don't want to go to the next
01166                  // file just yet.
01167 
01168       /* Let's make sure we're in a paused state. */
01169       /* The pause state will be unset by DownloadDlgProc(). */
01170       gdwDownloadDialogStatus = CS_PAUSE;
01171       PauseTheDownload(rv, &iFileDownloadRetries);
01172     }
01173     else if(bIgnoreAllNetworkErrors || iIgnoreFileNetworkError)
01174       rv = nsFTPConn::OK;
01175 
01176     UnsetSetupCurrentDownloadFile();
01177   }
01178 
01179   CloseSocket(szProxyServer, szProxyPort);
01180   DeInitDownloadDlg();
01181   SetCurrentDirectory(szSavedCwd);
01182   return(rv);
01183 }
01184 
01185 int ProgressCB(int aBytesSoFar, int aTotalFinalSize)
01186 {
01187   long   lBytesDiffSoFar;
01188   double dPercentSoFar;
01189   int    iRv = nsFTPConn::OK;
01190 
01191   if(sgProduct.mode != SILENT)
01192   {
01193     SetStatusUrl();
01194 
01195     if(glTotalKb == 0)
01196       glTotalKb = aTotalFinalSize;
01197 
01198     /* Calculate the difference between the last set of bytes read against
01199      * the current set of bytes read.  If the value is negative, that means
01200      * that it started a new file, so reset lBytesDiffSoFar to aBytesSoFar */
01201     lBytesDiffSoFar = ((aBytesSoFar - glLastBytesSoFar) < 1) ? aBytesSoFar : (aBytesSoFar - glLastBytesSoFar);
01202 
01203     /* Save the current bytes read as the last set of bytes read */
01204     glLastBytesSoFar = aBytesSoFar;
01205     glAbsoluteBytesSoFar += lBytesDiffSoFar;
01206 
01207     dPercentSoFar = GetPercentSoFar();
01208     if(gbDlgDownloadMinimized)
01209       SetMinimizedDownloadTitle((int)dPercentSoFar);
01210 
01211     UpdateGaugeFileProgressBar(dPercentSoFar);
01212     SetStatusStatus();
01213 
01214     if((gdwDownloadDialogStatus == CS_CANCEL) ||
01215        (gdwDownloadDialogStatus == CS_PAUSE))
01216       iRv = nsFTPConn::E_USER_CANCEL;
01217   }
01218 
01219   ProcessWindowsMessages();
01220   return(iRv);
01221 }
01222 
01223 // Window proc for dialog
01224 LRESULT CALLBACK
01225 DownloadDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
01226 {
01227   switch (msg)
01228   {
01229     case WM_INITDIALOG:
01230       GetConfigIniProfileString("Strings", "Status File Info", "",
01231                             gszFileInfo, sizeof(gszFileInfo));
01232       if(gbShowDownloadRetryMsg)
01233         SetDlgItemText(hWndDlg, IDC_MESSAGE0, diDownload.szMessageRetry0);
01234       else
01235         SetDlgItemText(hWndDlg, IDC_MESSAGE0, diDownload.szMessageDownload0);
01236 
01237       EnableWindow(GetDlgItem(hWndDlg, IDRESUME), FALSE);
01238       SetDlgItemText(hWndDlg, IDC_STATIC1, sgInstallGui.szStatus);
01239       SetDlgItemText(hWndDlg, IDC_STATIC2, sgInstallGui.szFile);
01240       SetDlgItemText(hWndDlg, IDC_STATIC4, sgInstallGui.szTo);
01241       SetDlgItemText(hWndDlg, IDC_STATIC3, sgInstallGui.szUrl);
01242       SetDlgItemText(hWndDlg, IDCANCEL, sgInstallGui.szCancel_);
01243       SetDlgItemText(hWndDlg, IDPAUSE, sgInstallGui.szPause_);
01244       SetDlgItemText(hWndDlg, IDRESUME, sgInstallGui.szResume_);
01245       SendDlgItemMessage (hWndDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01246       SendDlgItemMessage (hWndDlg, IDC_STATIC2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01247       SendDlgItemMessage (hWndDlg, IDC_STATIC3, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01248       SendDlgItemMessage (hWndDlg, IDCANCEL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01249       SendDlgItemMessage (hWndDlg, IDPAUSE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01250       SendDlgItemMessage (hWndDlg, IDRESUME, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01251       SendDlgItemMessage (hWndDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01252       SendDlgItemMessage (hWndDlg, IDC_STATUS_STATUS, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01253       SendDlgItemMessage (hWndDlg, IDC_STATUS_FILE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01254       SendDlgItemMessage (hWndDlg, IDC_STATUS_URL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01255       SendDlgItemMessage (hWndDlg, IDC_STATUS_TO, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
01256       return FALSE;
01257 
01258     case WM_SIZE:
01259       switch(wParam)
01260       {
01261         case SIZE_MINIMIZED:
01262           SetMinimizedDownloadTitle((int)GetPercentSoFar());
01263           gbDlgDownloadMinimized = TRUE;
01264           gbDlgDownloadJustMinimized = TRUE;
01265           break;
01266 
01267         case SIZE_RESTORED:
01268           SetStatusUrl();
01269           SetRestoredDownloadTitle();
01270           gbDlgDownloadMinimized = FALSE;
01271           break;
01272       }
01273       return(FALSE);
01274 
01275     case WM_COMMAND:
01276       switch(LOWORD(wParam))
01277       {
01278         case IDCANCEL:
01279           if(ShouldExitSetup(hWndDlg))
01280             gdwDownloadDialogStatus = CS_CANCEL;
01281           break;
01282 
01283         case IDPAUSE:
01284           if(!gtiPaused.bTickStarted)
01285           {
01286             gtiPaused.dwTickBegin          = GetTickCount();
01287             gtiPaused.bTickStarted         = TRUE;
01288             gtiPaused.bTickDownloadResumed = FALSE;
01289           }
01290 
01291           EnableWindow(GetDlgItem(hWndDlg, IDPAUSE),  FALSE);
01292           EnableWindow(GetDlgItem(hWndDlg, IDRESUME), TRUE);
01293           gdwDownloadDialogStatus = CS_PAUSE;
01294           break;
01295 
01296         case IDRESUME:
01297           gtiPaused.dwTickEnd = GetTickCount();
01298           gtiPaused.dwTickDif = GetTickDif(gtiPaused.dwTickEnd,
01299                                            gtiPaused.dwTickBegin);
01300           gtiPaused.bTickDownloadResumed = TRUE;
01301 
01302           EnableWindow(GetDlgItem(hWndDlg, IDRESUME), FALSE);
01303           EnableWindow(GetDlgItem(hWndDlg, IDPAUSE),  TRUE);
01304           gdwDownloadDialogStatus = CS_NONE;
01305           break;
01306 
01307         default:
01308           break;
01309       }
01310       return(TRUE);
01311   }
01312 
01313   return(FALSE);  // didn't handle the message
01314 }
01315 
01316 // This routine will update the File Gauge progress bar to the specified percentage
01317 // (value between 0 and 100)
01318 static void
01319 UpdateGaugeFileProgressBar(double value)
01320 {
01321        int            nBars;
01322   static long lModLastValue = 0;
01323 
01324   if(sgProduct.mode != SILENT)
01325   {
01326     if(!CheckInterval(&lModLastValue, UPDATE_INTERVAL_PROGRESS_BAR))
01327       return;
01328 
01329     // Figure out how many bars should be displayed
01330     nBars = (int)(dlgInfo.nMaxFileBars * value / 100);
01331 
01332     // Only paint if we need to display more bars
01333     if((nBars > dlgInfo.nFileBars) || (dlgInfo.nFileBars == 0))
01334     {
01335       HWND    hWndGauge = GetDlgItem(dlgInfo.hWndDlg, IDC_PROGRESS_FILE);
01336       RECT    rect;
01337 
01338       // Update the gauge state before painting
01339       dlgInfo.nFileBars = nBars;
01340 
01341       // Only invalidate the part that needs updating
01342       GetClientRect(hWndGauge, &rect);
01343       InvalidateRect(hWndGauge, &rect, FALSE);
01344     
01345       // Update the whole extracting dialog. We do this because we don't
01346       // have a message loop to process WM_PAINT messages in case the
01347       // extracting dialog was exposed
01348       UpdateWindow(dlgInfo.hWndDlg);
01349     }
01350   }
01351 }
01352 
01353 // Draws a recessed border around the gauge
01354 static void
01355 DrawGaugeBorder(HWND hWnd)
01356 {
01357        HDC           hDC = GetWindowDC(hWnd);
01358        RECT   rect;
01359        int           cx, cy;
01360        HPEN   hShadowPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
01361        HGDIOBJ       hOldPen;
01362 
01363        GetWindowRect(hWnd, &rect);
01364        cx = rect.right - rect.left;
01365        cy = rect.bottom - rect.top;
01366 
01367        // Draw a dark gray line segment
01368        hOldPen = SelectObject(hDC, (HGDIOBJ)hShadowPen);
01369        MoveToEx(hDC, 0, cy - 1, NULL);
01370        LineTo(hDC, 0, 0);
01371        LineTo(hDC, cx - 1, 0);
01372 
01373        // Draw a white line segment
01374        SelectObject(hDC, GetStockObject(WHITE_PEN));
01375        MoveToEx(hDC, 0, cy - 1, NULL);
01376        LineTo(hDC, cx - 1, cy - 1);
01377        LineTo(hDC, cx - 1, 0);
01378 
01379        SelectObject(hDC, hOldPen);
01380        DeleteObject(hShadowPen);
01381        ReleaseDC(hWnd, hDC);
01382 }
01383 
01384 // Draws the progress bar
01385 static void
01386 DrawProgressBar(HWND hWnd, int nBars)
01387 {
01388   int         i;
01389        PAINTSTRUCT   ps;
01390        HDC         hDC;
01391        RECT        rect;
01392        HBRUSH      hBrush;
01393 
01394   hDC = BeginPaint(hWnd, &ps);
01395        GetClientRect(hWnd, &rect);
01396   if(nBars <= 0)
01397   {
01398     /* clear the bars */
01399     hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
01400     FillRect(hDC, &rect, hBrush);
01401   }
01402   else
01403   {
01404        // Draw the bars
01405     hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
01406          rect.left     = rect.top = BAR_LIBXPNET_MARGIN;
01407          rect.bottom  -= BAR_LIBXPNET_MARGIN;
01408          rect.right    = rect.left + BAR_LIBXPNET_WIDTH;
01409 
01410          for(i = 0; i < nBars; i++)
01411     {
01412                 RECT dest;
01413 
01414                 if(IntersectRect(&dest, &ps.rcPaint, &rect))
01415                        FillRect(hDC, &rect, hBrush);
01416 
01417       OffsetRect(&rect, BAR_LIBXPNET_WIDTH + BAR_LIBXPNET_SPACING, 0);
01418          }
01419   }
01420 
01421        DeleteObject(hBrush);
01422        EndPaint(hWnd, &ps);
01423 }
01424 
01425 // Adjusts the width of the gauge based on the maximum number of bars
01426 static void
01427 SizeToFitGauge(HWND hWnd, int nMaxBars)
01428 {
01429        RECT   rect;
01430        int           cx;
01431 
01432        // Get the window size in pixels
01433        GetWindowRect(hWnd, &rect);
01434 
01435        // Size the width to fit
01436        cx = 2 * GetSystemMetrics(SM_CXBORDER) + 2 * BAR_LIBXPNET_MARGIN +
01437               nMaxBars * BAR_LIBXPNET_WIDTH + (nMaxBars - 1) * BAR_LIBXPNET_SPACING;
01438 
01439        SetWindowPos(hWnd, NULL, -1, -1, cx, rect.bottom - rect.top,
01440               SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
01441 }
01442 
01443 // Window proc for Download gauge
01444 BOOL CALLBACK
01445 GaugeDownloadWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
01446 {
01447        DWORD  dwStyle;
01448        RECT   rect;
01449 
01450        switch(msg)
01451   {
01452               case WM_NCCREATE:
01453                      dwStyle = GetWindowLong(hWnd, GWL_STYLE);
01454                      SetWindowLong(hWnd, GWL_STYLE, dwStyle | WS_BORDER);
01455                      return(TRUE);
01456 
01457               case WM_CREATE:
01458                      // Figure out the maximum number of bars that can be displayed
01459                      GetClientRect(hWnd, &rect);
01460                      dlgInfo.nFileBars = 0;
01461                      dlgInfo.nMaxFileBars = (rect.right - rect.left - 2 * BAR_LIBXPNET_MARGIN + BAR_LIBXPNET_SPACING) / (BAR_LIBXPNET_WIDTH + BAR_LIBXPNET_SPACING);
01462 
01463                      // Size the gauge to exactly fit the maximum number of bars
01464                      SizeToFitGauge(hWnd, dlgInfo.nMaxFileBars);
01465                      return(FALSE);
01466 
01467               case WM_NCPAINT:
01468                      DrawGaugeBorder(hWnd);
01469                      return(FALSE);
01470 
01471               case WM_PAINT:
01472                      DrawProgressBar(hWnd, dlgInfo.nFileBars);
01473                      return(FALSE);
01474        }
01475 
01476        return(DefWindowProc(hWnd, msg, wParam, lParam));
01477 }
01478 
01479 void InitDownloadDlg(void)
01480 {
01481        WNDCLASS      wc;
01482 
01483   if(sgProduct.mode != SILENT)
01484   {
01485     memset(&wc, 0, sizeof(wc));
01486     wc.style          = CS_GLOBALCLASS;
01487     wc.hInstance      = hInst;
01488     wc.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
01489     wc.lpfnWndProc    = (WNDPROC)GaugeDownloadWndProc;
01490     wc.lpszClassName  = "GaugeFile";
01491     RegisterClass(&wc);
01492 
01493     // Display the dialog box
01494     dlgInfo.hWndDlg = CreateDialog(hSetupRscInst, MAKEINTRESOURCE(DLG_DOWNLOADING), hWndMain, (DLGPROC)DownloadDlgProc);
01495     UpdateWindow(dlgInfo.hWndDlg);
01496     UpdateGaugeFileProgressBar(0);
01497   }
01498 }
01499 
01500 void DeInitDownloadDlg()
01501 {
01502   if(sgProduct.mode != SILENT)
01503   {
01504     DestroyWindow(dlgInfo.hWndDlg);
01505     UnregisterClass("GaugeFile", hInst);
01506   }
01507 }