2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "License"); you may not use this file
4
* except in compliance with the License. You may obtain a copy of
5
* the License at http://www.mozilla.org/MPL/
7
* Software distributed under the License is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the License for the specific language governing
10
* rights and limitations under the License.
12
* The Original Code is Mozilla Navigator.
14
* The Initial Developer of the Original Code is Netscape Communications
15
* Corp. Portions created by Netscape Communications Corp. are
16
* Copyright (C) 1998, 1999, 2000, 2001 Netscape Communications Corp. All
20
* Sean Su <ssu@netscape.com>
31
#endif /* __cplusplus */
36
#include "xpnetHook.h"
40
#endif /* __cplusplus */
42
#include "nsFTPConn.h"
43
#include "nsHTTPConn.h"
46
#define UPDATE_INTERVAL_STATUS 1
47
#define UPDATE_INTERVAL_PROGRESS_BAR 1
50
#define CS_NONE 0x00000000
51
#define CS_CANCEL 0x00000001
52
#define CS_PAUSE 0x00000002
53
#define CS_RESUME 0x00000003
55
const int kProxySrvrLen = 1024;
56
const char kHTTP[8] = "http://";
57
const char kFTP[7] = "ftp://";
58
const char kLoclFile[7] = "zzzFTP";
59
const int kModTimeOutValue = 3;
61
static nsHTTPConn *connHTTP = NULL;
62
static nsFTPConn *connFTP = NULL;
63
static long glLastBytesSoFar;
64
static long glAbsoluteBytesSoFar;
65
static long glBytesResumedFrom;
66
static long glTotalKb;
67
char gszStrCopyingFile[MAX_BUF_MEDIUM];
68
char gszCurrentDownloadPath[MAX_BUF];
69
char gszCurrentDownloadFilename[MAX_BUF_TINY];
70
char gszCurrentDownloadFileDescription[MAX_BUF_TINY];
73
char gszFileInfo[MAX_BUF];
74
char *gszConfigIniFile;
75
BOOL gbDlgDownloadMinimized;
76
BOOL gbDlgDownloadJustMinimized;
78
BOOL gbShowDownloadRetryMsg;
79
DWORD gdwDownloadDialogStatus;
81
int giTotalArchivesToDownload;
83
BOOL gbStartTickCounter;
85
double GetPercentSoFar(void);
87
static void UpdateGaugeFileProgressBar(double value);
88
int ProgressCB(int aBytesSoFar, int aTotalFinalSize);
89
void InitDownloadDlg(void);
90
void DeInitDownloadDlg();
92
/* local prototypes */
93
siC *GetObjectFromArchiveName(char *szArchiveName);
95
struct DownloadFileInfo
98
char szFile[MAX_BUF_TINY];
101
struct ExtractFilesDlgInfo
104
int nMaxFileBars; // maximum number of bars that can be displayed
105
int nMaxArchiveBars; // maximum number of bars that can be displayed
106
int nFileBars; // current number of bars to display
107
int nArchiveBars; // current number of bars to display
116
BOOL bTickDownloadResumed;
119
BOOL CheckInterval(long *lModLastValue, int iInterval)
122
long lModCurrentValue;
126
lModCurrentValue = time(NULL);
127
if(lModCurrentValue != *lModLastValue)
132
lModCurrentValue = time(NULL) % iInterval;
133
if((lModCurrentValue == 0) && (*lModLastValue != 0))
137
*lModLastValue = lModCurrentValue;
141
char *GetTimeLeft(DWORD dwTimeLeft,
143
DWORD dwTimeStringBufSize)
148
ZeroMemory(&stTime, sizeof(stTime));
149
dwTimeLeftPP = dwTimeLeft + 1;
150
stTime.wHour = (unsigned)(dwTimeLeftPP / 60 / 60);
151
stTime.wMinute = (unsigned)((dwTimeLeftPP / 60) % 60);
152
stTime.wSecond = (unsigned)(dwTimeLeftPP % 60);
154
ZeroMemory(szTimeString, dwTimeStringBufSize);
155
/* format time string using user's local time format information */
156
GetTimeFormat(LOCALE_USER_DEFAULT,
157
TIME_NOTIMEMARKER|TIME_FORCE24HOURFORMAT,
161
dwTimeStringBufSize);
163
return(szTimeString);
166
DWORD AddToTick(DWORD dwTick, DWORD dwTickMoreToAdd)
168
DWORD dwTickLeftTillWrap = 0;
170
/* Since GetTickCount() is the number of milliseconds since the system
171
* has been on and the return value is a DWORD, this value will wrap
172
* every 49.71 days or 0xFFFFFFFF milliseconds. */
173
dwTickLeftTillWrap = 0xFFFFFFFF - dwTick;
174
if(dwTickMoreToAdd > dwTickLeftTillWrap)
175
dwTick = dwTickMoreToAdd - dwTickLeftTillWrap;
177
dwTick = dwTick + dwTickMoreToAdd;
182
DWORD GetTickDif(DWORD dwTickEnd, DWORD dwTickStart)
186
/* Since GetTickCount() is the number of milliseconds since the system
187
* has been on and the return value is a DWORD, this value will wrap
188
* every 49.71 days or 0xFFFFFFFF milliseconds.
190
* Assumption: dwTickEnd has not wrapped _and_ passed dwTickStart */
191
if(dwTickEnd < dwTickStart)
192
dwTickDif = 0xFFFFFFFF - dwTickStart + dwTickEnd;
194
dwTickDif = dwTickEnd - dwTickStart;
199
void InitTickInfo(void)
201
gtiPaused.dwTickBegin = 0;
202
gtiPaused.dwTickEnd = 0;
203
gtiPaused.dwTickDif = 0;
204
gtiPaused.bTickStarted = FALSE;
205
gtiPaused.bTickDownloadResumed = FALSE;
208
DWORD RoundDouble(double dValue)
210
if(0.5 <= (dValue - (DWORD)dValue))
211
return((DWORD)dValue + 1);
213
return((DWORD)dValue);
216
void SetStatusStatus(void)
218
char szStatusStatusLine[MAX_BUF_MEDIUM];
219
char szCurrentStatusInfo[MAX_BUF_MEDIUM];
220
char szPercentString[MAX_BUF_MEDIUM];
221
char szPercentageCompleted[MAX_BUF_MEDIUM];
222
static long lModLastValue = 0;
224
static double dRateCounter;
229
char szTimeLeft[MAX_BUF_TINY];
231
/* If the user just clicked on the Resume button, then the time lapsed
232
* between gdwTickStart and when the Resume button was clicked needs to
233
* be subtracted taken into account when calculating dwTickDif. So
234
* "this" lapsed time needs to be added to gdwTickStart. */
235
if(gtiPaused.bTickDownloadResumed)
237
gdwTickStart = AddToTick(gdwTickStart, gtiPaused.dwTickDif);
241
/* GetTickCount() returns time in milliseconds. This is more accurate,
242
* which will allow us to get at a 2 decimal precision value for the
244
dwTickNow = GetTickCount();
245
if((gdwTickStart == 0) && gbStartTickCounter)
246
dwTickNow = gdwTickStart = GetTickCount();
248
dwTickDif = GetTickDif(dwTickNow, gdwTickStart);
250
/* Only update the UI every UPDATE_INTERVAL_STATUS interval,
251
* which is currently set to 1 sec. */
252
if(!CheckInterval(&lModLastValue, UPDATE_INTERVAL_STATUS))
255
if(glAbsoluteBytesSoFar == 0)
258
dRateCounter = dwTickDif / 1000;
260
if(dRateCounter == 0.0)
263
dRate = (glAbsoluteBytesSoFar - glBytesResumedFrom) / dRateCounter / 1024;
265
dwKBytesSoFar = glAbsoluteBytesSoFar / 1024;
267
/* Use a rate that is rounded to the nearest integer. If dRate used directly,
268
* the "Time Left" will jump around quite a bit due to the rate usually
269
* varying up and down by quite a bit. The rounded rate give a "more linear"
270
* count down of the "Time Left". */
271
dwRoundedRate = RoundDouble(dRate);
272
if(dwRoundedRate > 0)
273
GetTimeLeft((glTotalKb - dwKBytesSoFar) / dwRoundedRate,
277
lstrcpy(szTimeLeft, "00:00:00");
279
if(!gbShowDownloadRetryMsg)
281
GetPrivateProfileString("Strings",
285
sizeof(szStatusStatusLine),
287
if(*szStatusStatusLine != '\0')
288
sprintf(szCurrentStatusInfo,
295
sprintf(szCurrentStatusInfo,
296
"%s at %.2fKB/sec (%uKB of %uKB downloaded)",
304
GetPrivateProfileString("Strings",
308
sizeof(szStatusStatusLine),
310
if(*szStatusStatusLine != '\0')
311
sprintf(szCurrentStatusInfo,
318
sprintf(szCurrentStatusInfo,
319
"%s at %.2KB/sec (%uKB of %uKB downloaded)",
326
GetPrivateProfileString("Strings",
327
"Status Percentage Completed",
329
szPercentageCompleted,
330
sizeof(szPercentageCompleted),
332
wsprintf(szPercentString, szPercentageCompleted, (int)GetPercentSoFar());
334
/* Set the download dialog title */
335
SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_STATUS, szCurrentStatusInfo);
336
SetDlgItemText(dlgInfo.hWndDlg, IDC_PERCENTAGE, szPercentString);
339
void SetStatusFile(void)
341
char szString[MAX_BUF];
343
/* Set the download dialog status*/
344
wsprintf(szString, gszFileInfo, gszCurrentDownloadFileDescription);
345
SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_FILE, szString);
349
void SetStatusUrl(void)
351
/* display the current url being processed */
354
char szUrlPathBuf[MAX_BUF];
355
char szToPathBuf[MAX_BUF];
356
HWND hStatusUrl = NULL;
357
HWND hStatusTo = NULL;
359
hStatusUrl = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS_URL);
361
TruncateString(hStatusUrl, gszUrl, szUrlPathBuf, sizeof(szUrlPathBuf));
363
lstrcpy(szUrlPathBuf, gszUrl);
365
hStatusTo = GetDlgItem(dlgInfo.hWndDlg, IDC_STATUS_TO);
367
TruncateString(hStatusTo, gszTo, szToPathBuf, sizeof(szToPathBuf));
369
lstrcpy(szToPathBuf, gszTo);
371
SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_URL, szUrlPathBuf);
372
SetDlgItemText(dlgInfo.hWndDlg, IDC_STATUS_TO, szToPathBuf);
374
gbUrlChanged = FALSE;
378
double GetPercentSoFar(void)
380
return((double)(((double)(glAbsoluteBytesSoFar / 1024) / (double)glTotalKb) * (double)100));
383
void SetMinimizedDownloadTitle(DWORD dwPercentSoFar)
385
static DWORD dwLastPercentSoFar = 0;
386
char szDownloadTitle[MAX_BUF_MEDIUM];
387
char gszCurrentDownloadInfo[MAX_BUF_MEDIUM];
389
GetPrivateProfileString("Strings", "Dialog Download Title Minimized", "", szDownloadTitle, sizeof(szDownloadTitle), szFileIniConfig);
391
if(*szDownloadTitle != '\0')
392
wsprintf(gszCurrentDownloadInfo, szDownloadTitle, dwPercentSoFar, gszCurrentDownloadFilename);
394
wsprintf(gszCurrentDownloadInfo, "%d%% for all files", dwPercentSoFar);
396
/* check and save the current percent so far to minimize flickering */
397
if((dwLastPercentSoFar != dwPercentSoFar) || gbDlgDownloadJustMinimized)
399
/* When the dialog is has just been minimized, the title is not set
400
* until the percentage changes, which when downloading via modem,
401
* could take several seconds. This variable allows us to tell when
402
* the dialog had *just* been minimized regardless if the percentage
403
* had changed or not. */
404
gbDlgDownloadJustMinimized = FALSE;
406
/* Set the download dialog title */
407
SetWindowText(dlgInfo.hWndDlg, gszCurrentDownloadInfo);
408
dwLastPercentSoFar = dwPercentSoFar;
412
void SetRestoredDownloadTitle(void)
414
/* Set the download dialog title */
415
SetWindowText(dlgInfo.hWndDlg, diDownload.szTitle);
418
void GetTotalArchivesToDownload(int *iTotalArchivesToDownload, DWORD *dwTotalEstDownloadSize)
422
char szSection[MAX_INI_SK];
423
char szDownloadSize[MAX_ITOA];
425
*dwTotalEstDownloadSize = 0;
427
wsprintf(szSection, "File%d", iIndex);
428
GetPrivateProfileString(szSection,
434
while(*szUrl != '\0')
436
GetPrivateProfileString(szSection, "size", "", szDownloadSize, sizeof(szDownloadSize), gszConfigIniFile);
437
if((lstrlen(szDownloadSize) < 32) && (*szDownloadSize != '\0'))
438
/* size will be in kb. 31 bits (int minus the signed bit) of precision should sufice */
439
*dwTotalEstDownloadSize += atoi(szDownloadSize);
442
wsprintf(szSection, "File%d", iIndex);
443
GetPrivateProfileString(szSection,
450
*iTotalArchivesToDownload = iIndex;
454
* Name: ProcessWndMsgCB
458
* Description: Callback function invoked by socket code and by FTP and HTTP layers
459
* to give the UI a chance to breath while we are in a look processing
460
* incoming data, or looping in select()
462
* Author: syd@netscape.com 5/11/2001
469
int iRv = nsFTPConn::OK;
471
ProcessWindowsMessages();
472
if((gdwDownloadDialogStatus == CS_CANCEL) ||
473
(gdwDownloadDialogStatus == CS_PAUSE))
474
iRv = nsFTPConn::E_USER_CANCEL;
479
/* Function used only to send the message stream error */
480
int WGet(char *szUrl,
488
char proxyURL[MAX_BUF];
489
nsHTTPConn *conn = NULL;
491
if((szProxyServer != NULL) && (szProxyPort != NULL) &&
492
(*szProxyServer != '\0') && (*szProxyPort != '\0'))
494
/* detected proxy information, let's use it */
495
memset(proxyURL, 0, sizeof(proxyURL));
496
wsprintf(proxyURL, "http://%s:%s", szProxyServer, szProxyPort);
498
conn = new nsHTTPConn(proxyURL);
500
return(WIZ_OUT_OF_MEMORY);
502
if((szProxyUser != NULL) && (*szProxyUser != '\0') &&
503
(szProxyPasswd != NULL) && (*szProxyPasswd != '\0'))
504
/* detected user and password info */
505
conn->SetProxyInfo(szUrl, szProxyUser, szProxyPasswd);
507
conn->SetProxyInfo(szUrl, NULL, NULL);
511
/* no proxy information supplied. set up normal http object */
512
conn = new nsHTTPConn(szUrl, ProcessWndMsgCB);
514
return(WIZ_OUT_OF_MEMORY);
520
rv = conn->Get(NULL, szFile);
530
int DownloadViaProxyOpen(char *szUrl, char *szProxyServer, char *szProxyPort, char *szProxyUser, char *szProxyPasswd)
533
char proxyURL[kProxySrvrLen];
535
if((!szUrl) || (*szUrl == '\0'))
536
return nsHTTPConn::E_PARAM;
539
memset(proxyURL, 0, kProxySrvrLen);
540
wsprintf(proxyURL, "http://%s:%s", szProxyServer, szProxyPort);
542
connHTTP = new nsHTTPConn(proxyURL, ProcessWndMsgCB);
545
char szBuf[MAX_BUF_TINY];
547
GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
548
PrintError(szBuf, ERROR_CODE_HIDE);
550
return(WIZ_OUT_OF_MEMORY);
553
if((szProxyUser != NULL) && (*szProxyUser != '\0') &&
554
(szProxyPasswd != NULL) && (*szProxyPasswd != '\0'))
555
connHTTP->SetProxyInfo(szUrl, szProxyUser, szProxyPasswd);
557
connHTTP->SetProxyInfo(szUrl, NULL, NULL);
559
rv = connHTTP->Open();
563
void DownloadViaProxyClose(void)
565
gbStartTickCounter = FALSE;
574
int DownloadViaProxy(char *szUrl, char *szProxyServer, char *szProxyPort, char *szProxyUser, char *szProxyPasswd)
580
if((!szUrl) || (*szUrl == '\0'))
581
return nsHTTPConn::E_PARAM;
585
rv = DownloadViaProxyOpen(szUrl,
591
if(rv != nsHTTPConn::OK)
593
DownloadViaProxyClose();
600
char szBuf[MAX_BUF_TINY];
602
GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
603
PrintError(szBuf, ERROR_CODE_HIDE);
605
return(WIZ_OUT_OF_MEMORY);
608
if(strrchr(szUrl, '/') != (szUrl + strlen(szUrl)))
609
file = strrchr(szUrl, '/') + 1; // set to leaf name
611
gbStartTickCounter = TRUE;
612
rv = connHTTP->Get(ProgressCB, file); // use leaf from URL
613
DownloadViaProxyClose();
617
int DownloadViaHTTPOpen(char *szUrl)
621
if((!szUrl) || (*szUrl == '\0'))
622
return nsHTTPConn::E_PARAM;
625
connHTTP = new nsHTTPConn(szUrl, ProcessWndMsgCB);
628
char szBuf[MAX_BUF_TINY];
630
GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), gszConfigIniFile);
631
PrintError(szBuf, ERROR_CODE_HIDE);
633
return(WIZ_OUT_OF_MEMORY);
636
rv = connHTTP->Open();
640
void DownloadViaHTTPClose(void)
642
gbStartTickCounter = FALSE;
651
int DownloadViaHTTP(char *szUrl)
656
if((!szUrl) || (*szUrl == '\0'))
657
return nsHTTPConn::E_PARAM;
661
rv = DownloadViaHTTPOpen(szUrl);
662
if(rv != nsHTTPConn::OK)
664
DownloadViaHTTPClose();
671
char szBuf[MAX_BUF_TINY];
673
GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), gszConfigIniFile);
674
PrintError(szBuf, ERROR_CODE_HIDE);
676
return(WIZ_OUT_OF_MEMORY);
680
if(strrchr(szUrl, '/') != (szUrl + strlen(szUrl)))
681
file = strrchr(szUrl, '/') + 1; // set to leaf name
683
gbStartTickCounter = TRUE;
684
rv = connHTTP->Get(ProgressCB, file);
685
DownloadViaHTTPClose();
689
int DownloadViaFTPOpen(char *szUrl)
691
char *host = 0, *path = 0, *file = (char*) kLoclFile;
695
if((!szUrl) || (*szUrl == '\0'))
696
return nsFTPConn::E_PARAM;
698
rv = nsHTTPConn::ParseURL(kFTP, szUrl, &host, &port, &path);
700
connFTP = new nsFTPConn(host, ProcessWndMsgCB);
703
char szBuf[MAX_BUF_TINY];
705
GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
706
PrintError(szBuf, ERROR_CODE_HIDE);
708
return(WIZ_OUT_OF_MEMORY);
711
rv = connFTP->Open();
720
void DownloadViaFTPClose(void)
722
gbStartTickCounter = FALSE;
731
int DownloadViaFTP(char *szUrl)
733
char *host = 0, *path = 0, *file = (char*) kLoclFile;
737
if((!szUrl) || (*szUrl == '\0'))
738
return nsFTPConn::E_PARAM;
742
rv = DownloadViaFTPOpen(szUrl);
743
if(rv != nsFTPConn::OK)
745
DownloadViaFTPClose();
752
char szBuf[MAX_BUF_TINY];
754
GetPrivateProfileString("Strings", "Error Out Of Memory", "", szBuf, sizeof(szBuf), szFileIniConfig);
755
PrintError(szBuf, ERROR_CODE_HIDE);
757
return(WIZ_OUT_OF_MEMORY);
760
rv = nsHTTPConn::ParseURL(kFTP, szUrl, &host, &port, &path);
762
if(strrchr(path, '/') != (path + strlen(path)))
763
file = strrchr(path, '/') + 1; // set to leaf name
765
gbStartTickCounter = TRUE;
766
rv = connFTP->Get(path, file, nsFTPConn::BINARY, TRUE, ProgressCB);
776
void PauseTheDownload(int rv, int *iFileDownloadRetries)
778
if(rv != nsFTPConn::E_USER_CANCEL)
780
SendMessage(dlgInfo.hWndDlg, WM_COMMAND, IDPAUSE, 0);
781
--*iFileDownloadRetries;
784
while(gdwDownloadDialogStatus == CS_PAUSE)
787
ProcessWindowsMessages();
791
void CloseSocket(char *szProxyServer, char *szProxyPort)
793
/* Close the socket connection from the first attempt. */
794
if((szProxyServer != NULL) && (szProxyPort != NULL) &&
795
(*szProxyServer != '\0') && (*szProxyPort != '\0'))
796
DownloadViaProxyClose();
799
/* is this an HTTP URL? */
800
if(strncmp(gszUrl, kHTTP, lstrlen(kHTTP)) == 0)
801
DownloadViaHTTPClose();
802
/* or is this an FTP URL? */
803
else if(strncmp(gszUrl, kFTP, lstrlen(kFTP)) == 0)
804
DownloadViaFTPClose();
808
siC *GetObjectFromArchiveName(char *szArchiveName)
811
siC *siCObject = NULL;
815
siCObject = SiCNodeGetObject(dwIndex, TRUE, AC_ALL);
818
if(lstrcmpi(szArchiveName, siCObject->szArchiveName) == 0)
825
siCObject = SiCNodeGetObject(dwIndex, TRUE, AC_ALL);
831
int DownloadFiles(char *szInputIniFile,
838
BOOL bIgnoreAllNetworkErrors,
840
DWORD dwFailedFileSize)
843
char szCurrentFile[MAX_BUF];
844
char szSection[MAX_INI_SK];
845
char szKey[MAX_INI_SK];
846
char szSavedCwd[MAX_BUF_MEDIUM];
849
int iFileDownloadRetries;
850
int iIgnoreFileNetworkError;
851
int iLocalTimeOutCounter;
852
DWORD dwTotalEstDownloadSize;
853
char szPartiallyDownloadedFilename[MAX_BUF];
854
BOOL bDownloadInitiated;
855
char szTempURL[MAX_BUF];
856
char szWorkingURLPathOnly[MAX_BUF];
857
siC *siCCurrentFileObj = NULL;
859
ZeroMemory(szTempURL, sizeof(szTempURL));
860
ZeroMemory(szWorkingURLPathOnly, sizeof(szWorkingURLPathOnly));
861
if(szInputIniFile == NULL)
862
return(WIZ_ERROR_UNDEFINED);
865
ZeroMemory(szFailedFile, dwFailedFileSize);
868
GetCurrentDirectory(sizeof(szSavedCwd), szSavedCwd);
869
SetCurrentDirectory(szDownloadDir);
872
dwTotalEstDownloadSize = 0;
873
giTotalArchivesToDownload = 0;
874
glLastBytesSoFar = 0;
875
glAbsoluteBytesSoFar = 0;
876
glBytesResumedFrom = 0;
877
gdwTickStart = 0; /* Initialize the counter used to
878
* calculate download rate */
879
gbStartTickCounter = FALSE; /* used to determine when to start
880
* the tick counter used to calculate
881
* the download rate */
883
gbDlgDownloadMinimized = FALSE;
884
gbDlgDownloadJustMinimized = FALSE;
885
gdwDownloadDialogStatus = CS_NONE;
886
gbShowDownloadRetryMsg = bShowRetryMsg;
887
gszConfigIniFile = szInputIniFile;
888
bDownloadInitiated = FALSE;
890
GetTotalArchivesToDownload(&giTotalArchivesToDownload,
891
&dwTotalEstDownloadSize);
892
glTotalKb = dwTotalEstDownloadSize;
893
GetSetupCurrentDownloadFile(szPartiallyDownloadedFilename,
894
sizeof(szPartiallyDownloadedFilename));
898
for(giIndex = 0; giIndex < giTotalArchivesToDownload; giIndex++)
900
/* set (or reset) the counter to 0 in order to read the
901
* next files's 0'th url from the .idi file */
903
gbUrlChanged = TRUE; /* Update the download dialog with new URL */
904
wsprintf(szSection, "File%d", giIndex);
905
wsprintf(szKey, "url%d", iCounter);
906
GetPrivateProfileString(szSection,
913
if(*szTempURL == '\0')
916
if(!bDownloadInitiated)
919
szWorkingURLPathOnly,
920
sizeof(szWorkingURLPathOnly),
921
TRUE, //use '/' as the path delimiter
925
GetPrivateProfileString(szSection,
928
gszCurrentDownloadFileDescription,
929
sizeof(gszCurrentDownloadFileDescription),
931
iIgnoreFileNetworkError = GetPrivateProfileInt(szSection,
932
"Ignore File Network Error",
936
/* save the file name to be downloaded */
939
sizeof(szCurrentFile),
940
TRUE, //use '/' as the path delimiter
943
RemoveSlash(szWorkingURLPathOnly);
944
wsprintf(gszUrl, "%s/%s", szWorkingURLPathOnly, szCurrentFile);
946
/* retrieve the file's data structure */
947
siCCurrentFileObj = GetObjectFromArchiveName(szCurrentFile);
949
if((*szPartiallyDownloadedFilename != 0) &&
950
(lstrcmpi(szPartiallyDownloadedFilename, szCurrentFile) == 0))
954
if(stat(szPartiallyDownloadedFilename, &statBuf) != -1)
956
glAbsoluteBytesSoFar += statBuf.st_size;
957
glBytesResumedFrom = statBuf.st_size;
961
lstrcpy(gszTo, szDownloadDir);
962
AppendBackSlash(gszTo, sizeof(gszTo));
963
lstrcat(gszTo, szCurrentFile);
965
if(gbDlgDownloadMinimized)
966
SetMinimizedDownloadTitle((int)GetPercentSoFar());
970
SetRestoredDownloadTitle();
973
SetSetupCurrentDownloadFile(szCurrentFile);
974
iFileDownloadRetries = 0;
975
iLocalTimeOutCounter = 0;
978
ProcessWindowsMessages();
979
/* Download starts here */
980
if((szProxyServer != NULL) && (szProxyPort != NULL) &&
981
(*szProxyServer != '\0') && (*szProxyPort != '\0'))
982
/* If proxy info is provided, use HTTP proxy */
983
rv = DownloadViaProxy(gszUrl,
990
/* is this an HTTP URL? */
991
if(strncmp(gszUrl, kHTTP, lstrlen(kHTTP)) == 0)
992
rv = DownloadViaHTTP(gszUrl);
993
/* or is this an FTP URL? */
994
else if(strncmp(gszUrl, kFTP, lstrlen(kFTP)) == 0)
995
rv = DownloadViaFTP(gszUrl);
998
bDownloadInitiated = TRUE;
999
if((rv == nsFTPConn::E_USER_CANCEL) ||
1000
(gdwDownloadDialogStatus == CS_PAUSE))
1002
if(gdwDownloadDialogStatus == CS_PAUSE)
1004
CloseSocket(szProxyServer, szProxyPort);
1006
/* rv needs to be set to something
1007
* other than E_USER_CANCEL or E_OK */
1008
rv = nsFTPConn::E_CMD_UNEXPECTED;
1010
PauseTheDownload(rv, &iFileDownloadRetries);
1011
bDownloadInitiated = FALSE; /* restart the download using
1012
* new socket connection */
1016
/* user canceled; break out of the do loop */
1020
else if((rv != nsFTPConn::OK) &&
1021
(rv != nsFTPConn::E_CMD_FAIL) &&
1022
(rv != nsSocket::E_BIND) &&
1023
(rv != nsHTTPConn::E_HTTP_RESPONSE) &&
1024
(gdwDownloadDialogStatus != CS_CANCEL))
1026
/* We timed out. No response from the server, or
1027
* we somehow lost connection. */
1029
char szTitle[MAX_BUF_SMALL];
1030
char szMsgDownloadPaused[MAX_BUF];
1032
/* Incrememt the time out counter on E_TIMEOUT */
1033
if(rv == nsSocket::E_TIMEOUT)
1035
++siCCurrentFileObj->iNetTimeOuts;
1036
++iLocalTimeOutCounter;
1039
CloseSocket(szProxyServer, szProxyPort);
1041
/* If the number of timeouts is %3 == 0, then let's pause
1042
* the download process. Otherwise, just close the
1043
* connection and open a new one to see if the download
1044
* can be restarted automatically. */
1045
if((rv != nsSocket::E_TIMEOUT) ||
1046
(rv == nsSocket::E_TIMEOUT) && ((iLocalTimeOutCounter % kModTimeOutValue) == 0))
1048
/* Start the pause tick counter here because we don't know how
1049
* long before the user will dismiss the MessageBox() */
1050
if(!gtiPaused.bTickStarted)
1052
gtiPaused.dwTickBegin = GetTickCount();
1053
gtiPaused.bTickStarted = TRUE;
1054
gtiPaused.bTickDownloadResumed = FALSE;
1057
/* The connection unexepectedly dropped for some reason, so inform
1058
* the user that the download will be Paused, and then update the
1059
* Download dialog to show the Paused state. */
1060
GetPrivateProfileString("Messages",
1066
GetPrivateProfileString("Strings",
1067
"Message Download Paused",
1069
szMsgDownloadPaused,
1070
sizeof(szMsgDownloadPaused),
1072
MessageBox(dlgInfo.hWndDlg,
1073
szMsgDownloadPaused,
1075
MB_ICONEXCLAMATION);
1077
/* Let's make sure we're in a paused state */
1078
gdwDownloadDialogStatus = CS_PAUSE;
1079
PauseTheDownload(rv, &iFileDownloadRetries);
1082
/* Let's make sure we're _not_ in a paused state */
1083
gdwDownloadDialogStatus = CS_NONE;
1086
/* We don't count time outs as normal failures. We're
1087
* keeping track of time outs differently. */
1088
if(rv != nsSocket::E_TIMEOUT)
1089
++iFileDownloadRetries;
1091
if((iFileDownloadRetries > MAX_FILE_DOWNLOAD_RETRIES) &&
1092
(rv != nsFTPConn::E_USER_CANCEL) &&
1093
(gdwDownloadDialogStatus != CS_CANCEL))
1095
/* since the download retries maxed out, increment the counter
1096
* to read the next url for the current file */
1098
wsprintf(szKey, "url%d", iCounter);
1099
GetPrivateProfileString(szSection,
1105
if(*szTempURL != '\0')
1107
/* Found more urls to download from for the current file.
1108
* Update the dialog to show the new url and reset the
1109
* file download retries to 0 since it's a new url. */
1110
gbUrlChanged = TRUE;
1111
iFileDownloadRetries = 0;
1112
bDownloadInitiated = FALSE; // restart the download using new socket connection
1113
CloseSocket(szProxyServer, szProxyPort);
1114
ParsePath(szTempURL,
1115
szWorkingURLPathOnly,
1116
sizeof(szWorkingURLPathOnly),
1117
TRUE, //use '/' as the path delimiter
1119
RemoveSlash(szWorkingURLPathOnly);
1120
wsprintf(gszUrl, "%s/%s", szWorkingURLPathOnly, szCurrentFile);
1124
} while((rv != nsFTPConn::E_USER_CANCEL) &&
1125
(rv != nsFTPConn::OK) &&
1126
(gdwDownloadDialogStatus != CS_CANCEL) &&
1127
(iFileDownloadRetries <= MAX_FILE_DOWNLOAD_RETRIES));
1129
/* Save the number of retries for each file */
1130
siCCurrentFileObj->iNetRetries = iFileDownloadRetries < 1 ? 0:iFileDownloadRetries - 1;
1132
if((rv == nsFTPConn::E_USER_CANCEL) ||
1133
(gdwDownloadDialogStatus == CS_CANCEL))
1135
/* make sure rv is E_USER_CANCEL when gdwDownloadDialogStatus
1137
rv = nsFTPConn::E_USER_CANCEL;
1139
if(szFailedFile && ((DWORD)lstrlen(szCurrentFile) <= dwFailedFileSize))
1140
lstrcpy(szFailedFile, gszCurrentDownloadFileDescription);
1142
/* break out of for() loop */
1146
if((rv != nsFTPConn::OK) &&
1147
(iFileDownloadRetries > MAX_FILE_DOWNLOAD_RETRIES) &&
1148
!bIgnoreAllNetworkErrors &&
1149
!iIgnoreFileNetworkError)
1151
/* too many retries from failed downloads */
1152
char szMsg[MAX_BUF];
1154
if(szFailedFile && ((DWORD)lstrlen(szCurrentFile) <= dwFailedFileSize))
1155
lstrcpy(szFailedFile, gszCurrentDownloadFileDescription);
1157
GetPrivateProfileString("Strings",
1158
"Error Too Many Network Errors",
1165
wsprintf(szBuf, szMsg, szCurrentFile);
1166
PrintError(szBuf, ERROR_CODE_HIDE);
1169
iFileDownloadRetries = 0; // reset the file download retries counter since
1170
// we'll be restarting the download again.
1171
bDownloadInitiated = FALSE; // restart the download using new socket connection
1172
CloseSocket(szProxyServer, szProxyPort);
1173
--giIndex; // Decrement the file index counter because we'll be trying to
1174
// download the same file again. We don't want to go to the next
1177
/* Let's make sure we're in a paused state. */
1178
/* The pause state will be unset by DownloadDlgProc(). */
1179
gdwDownloadDialogStatus = CS_PAUSE;
1180
PauseTheDownload(rv, &iFileDownloadRetries);
1182
else if(bIgnoreAllNetworkErrors || iIgnoreFileNetworkError)
1185
UnsetSetupCurrentDownloadFile();
1188
CloseSocket(szProxyServer, szProxyPort);
1189
DeInitDownloadDlg();
1190
SetCurrentDirectory(szSavedCwd);
1194
int ProgressCB(int aBytesSoFar, int aTotalFinalSize)
1196
long lBytesDiffSoFar;
1197
double dPercentSoFar;
1198
int iRv = nsFTPConn::OK;
1200
if(sgProduct.mode != SILENT)
1205
glTotalKb = aTotalFinalSize;
1207
/* Calculate the difference between the last set of bytes read against
1208
* the current set of bytes read. If the value is negative, that means
1209
* that it started a new file, so reset lBytesDiffSoFar to aBytesSoFar */
1210
lBytesDiffSoFar = ((aBytesSoFar - glLastBytesSoFar) < 1) ? aBytesSoFar : (aBytesSoFar - glLastBytesSoFar);
1212
/* Save the current bytes read as the last set of bytes read */
1213
glLastBytesSoFar = aBytesSoFar;
1214
glAbsoluteBytesSoFar += lBytesDiffSoFar;
1216
dPercentSoFar = GetPercentSoFar();
1217
if(gbDlgDownloadMinimized)
1218
SetMinimizedDownloadTitle((int)dPercentSoFar);
1220
UpdateGaugeFileProgressBar(dPercentSoFar);
1223
if((gdwDownloadDialogStatus == CS_CANCEL) ||
1224
(gdwDownloadDialogStatus == CS_PAUSE))
1225
iRv = nsFTPConn::E_USER_CANCEL;
1228
ProcessWindowsMessages();
1232
// Window proc for dialog
1234
DownloadDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1239
GetPrivateProfileString("Strings",
1243
sizeof(gszFileInfo),
1245
if(gbShowDownloadRetryMsg)
1246
SetDlgItemText(hWndDlg, IDC_MESSAGE0, diDownload.szMessageRetry0);
1248
SetDlgItemText(hWndDlg, IDC_MESSAGE0, diDownload.szMessageDownload0);
1250
EnableWindow(GetDlgItem(hWndDlg, IDRESUME), FALSE);
1251
SetDlgItemText(hWndDlg, IDC_STATIC1, sgInstallGui.szStatus);
1252
SetDlgItemText(hWndDlg, IDC_STATIC2, sgInstallGui.szFile);
1253
SetDlgItemText(hWndDlg, IDC_STATIC4, sgInstallGui.szTo);
1254
SetDlgItemText(hWndDlg, IDC_STATIC3, sgInstallGui.szUrl);
1255
SetDlgItemText(hWndDlg, IDCANCEL, sgInstallGui.szCancel_);
1256
SetDlgItemText(hWndDlg, IDPAUSE, sgInstallGui.szPause_);
1257
SetDlgItemText(hWndDlg, IDRESUME, sgInstallGui.szResume_);
1258
SendDlgItemMessage (hWndDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1259
SendDlgItemMessage (hWndDlg, IDC_STATIC2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1260
SendDlgItemMessage (hWndDlg, IDC_STATIC3, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1261
SendDlgItemMessage (hWndDlg, IDCANCEL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1262
SendDlgItemMessage (hWndDlg, IDPAUSE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1263
SendDlgItemMessage (hWndDlg, IDRESUME, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1264
SendDlgItemMessage (hWndDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1265
SendDlgItemMessage (hWndDlg, IDC_STATUS_STATUS, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1266
SendDlgItemMessage (hWndDlg, IDC_STATUS_FILE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1267
SendDlgItemMessage (hWndDlg, IDC_STATUS_URL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1268
SendDlgItemMessage (hWndDlg, IDC_STATUS_TO, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L);
1274
case SIZE_MINIMIZED:
1275
SetMinimizedDownloadTitle((int)GetPercentSoFar());
1276
gbDlgDownloadMinimized = TRUE;
1277
gbDlgDownloadJustMinimized = TRUE;
1282
SetRestoredDownloadTitle();
1283
gbDlgDownloadMinimized = FALSE;
1289
switch(LOWORD(wParam))
1292
if(ShouldExitSetup(hWndDlg))
1293
gdwDownloadDialogStatus = CS_CANCEL;
1297
if(!gtiPaused.bTickStarted)
1299
gtiPaused.dwTickBegin = GetTickCount();
1300
gtiPaused.bTickStarted = TRUE;
1301
gtiPaused.bTickDownloadResumed = FALSE;
1304
EnableWindow(GetDlgItem(hWndDlg, IDPAUSE), FALSE);
1305
EnableWindow(GetDlgItem(hWndDlg, IDRESUME), TRUE);
1306
gdwDownloadDialogStatus = CS_PAUSE;
1310
gtiPaused.dwTickEnd = GetTickCount();
1311
gtiPaused.dwTickDif = GetTickDif(gtiPaused.dwTickEnd,
1312
gtiPaused.dwTickBegin);
1313
gtiPaused.bTickDownloadResumed = TRUE;
1315
EnableWindow(GetDlgItem(hWndDlg, IDRESUME), FALSE);
1316
EnableWindow(GetDlgItem(hWndDlg, IDPAUSE), TRUE);
1317
gdwDownloadDialogStatus = CS_NONE;
1326
return(FALSE); // didn't handle the message
1329
// This routine will update the File Gauge progress bar to the specified percentage
1330
// (value between 0 and 100)
1332
UpdateGaugeFileProgressBar(double value)
1335
static long lModLastValue = 0;
1337
if(sgProduct.mode != SILENT)
1339
if(!CheckInterval(&lModLastValue, UPDATE_INTERVAL_PROGRESS_BAR))
1342
// Figure out how many bars should be displayed
1343
nBars = (int)(dlgInfo.nMaxFileBars * value / 100);
1345
// Only paint if we need to display more bars
1346
if((nBars > dlgInfo.nFileBars) || (dlgInfo.nFileBars == 0))
1348
HWND hWndGauge = GetDlgItem(dlgInfo.hWndDlg, IDC_PROGRESS_FILE);
1351
// Update the gauge state before painting
1352
dlgInfo.nFileBars = nBars;
1354
// Only invalidate the part that needs updating
1355
GetClientRect(hWndGauge, &rect);
1356
InvalidateRect(hWndGauge, &rect, FALSE);
1358
// Update the whole extracting dialog. We do this because we don't
1359
// have a message loop to process WM_PAINT messages in case the
1360
// extracting dialog was exposed
1361
UpdateWindow(dlgInfo.hWndDlg);
1366
// Draws a recessed border around the gauge
1368
DrawGaugeBorder(HWND hWnd)
1370
HDC hDC = GetWindowDC(hWnd);
1373
HPEN hShadowPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
1376
GetWindowRect(hWnd, &rect);
1377
cx = rect.right - rect.left;
1378
cy = rect.bottom - rect.top;
1380
// Draw a dark gray line segment
1381
hOldPen = SelectObject(hDC, (HGDIOBJ)hShadowPen);
1382
MoveToEx(hDC, 0, cy - 1, NULL);
1384
LineTo(hDC, cx - 1, 0);
1386
// Draw a white line segment
1387
SelectObject(hDC, GetStockObject(WHITE_PEN));
1388
MoveToEx(hDC, 0, cy - 1, NULL);
1389
LineTo(hDC, cx - 1, cy - 1);
1390
LineTo(hDC, cx - 1, 0);
1392
SelectObject(hDC, hOldPen);
1393
DeleteObject(hShadowPen);
1394
ReleaseDC(hWnd, hDC);
1397
// Draws the blue progress bar
1399
DrawProgressBar(HWND hWnd, int nBars)
1407
hDC = BeginPaint(hWnd, &ps);
1408
GetClientRect(hWnd, &rect);
1411
/* clear the bars */
1412
hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1413
FillRect(hDC, &rect, hBrush);
1418
hBrush = CreateSolidBrush(RGB(0, 0, 128));
1419
rect.left = rect.top = BAR_LIBXPNET_MARGIN;
1420
rect.bottom -= BAR_LIBXPNET_MARGIN;
1421
rect.right = rect.left + BAR_LIBXPNET_WIDTH;
1423
for(i = 0; i < nBars; i++)
1427
if(IntersectRect(&dest, &ps.rcPaint, &rect))
1428
FillRect(hDC, &rect, hBrush);
1430
OffsetRect(&rect, BAR_LIBXPNET_WIDTH + BAR_LIBXPNET_SPACING, 0);
1434
DeleteObject(hBrush);
1435
EndPaint(hWnd, &ps);
1438
// Adjusts the width of the gauge based on the maximum number of bars
1440
SizeToFitGauge(HWND hWnd, int nMaxBars)
1445
// Get the window size in pixels
1446
GetWindowRect(hWnd, &rect);
1448
// Size the width to fit
1449
cx = 2 * GetSystemMetrics(SM_CXBORDER) + 2 * BAR_LIBXPNET_MARGIN +
1450
nMaxBars * BAR_LIBXPNET_WIDTH + (nMaxBars - 1) * BAR_LIBXPNET_SPACING;
1452
SetWindowPos(hWnd, NULL, -1, -1, cx, rect.bottom - rect.top,
1453
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1456
// Window proc for Download gauge
1458
GaugeDownloadWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1466
dwStyle = GetWindowLong(hWnd, GWL_STYLE);
1467
SetWindowLong(hWnd, GWL_STYLE, dwStyle | WS_BORDER);
1471
// Figure out the maximum number of bars that can be displayed
1472
GetClientRect(hWnd, &rect);
1473
dlgInfo.nFileBars = 0;
1474
dlgInfo.nMaxFileBars = (rect.right - rect.left - 2 * BAR_LIBXPNET_MARGIN + BAR_LIBXPNET_SPACING) / (BAR_LIBXPNET_WIDTH + BAR_LIBXPNET_SPACING);
1476
// Size the gauge to exactly fit the maximum number of bars
1477
SizeToFitGauge(hWnd, dlgInfo.nMaxFileBars);
1481
DrawGaugeBorder(hWnd);
1485
DrawProgressBar(hWnd, dlgInfo.nFileBars);
1489
return(DefWindowProc(hWnd, msg, wParam, lParam));
1492
void InitDownloadDlg(void)
1496
if(sgProduct.mode != SILENT)
1498
memset(&wc, 0, sizeof(wc));
1499
wc.style = CS_GLOBALCLASS;
1500
wc.hInstance = hInst;
1501
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1502
wc.lpfnWndProc = (WNDPROC)GaugeDownloadWndProc;
1503
wc.lpszClassName = "GaugeFile";
1506
// Display the dialog box
1507
dlgInfo.hWndDlg = CreateDialog(hSetupRscInst, MAKEINTRESOURCE(DLG_DOWNLOADING), hWndMain, (DLGPROC)DownloadDlgProc);
1508
UpdateWindow(dlgInfo.hWndDlg);
1509
UpdateGaugeFileProgressBar(0);
1513
void DeInitDownloadDlg()
1515
if(sgProduct.mode != SILENT)
1517
DestroyWindow(dlgInfo.hWndDlg);
1518
UnregisterClass("GaugeFile", hInst);