- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / rosapps / net / ncftp / ncftp / main.c
1 /* main.c
2 *
3 * Copyright (c) 1992-2001 by Mike Gleason.
4 * All rights reserved.
5 *
6 */
7
8 #include "syshdrs.h"
9 #include "ls.h"
10 #include "bookmark.h"
11 #include "shell.h"
12 #include "cmds.h"
13 #include "main.h"
14 #include "getopt.h"
15 #include "progress.h"
16 #include "pref.h"
17 #include "readln.h"
18 #include "trace.h"
19 #include "log.h"
20 #include "spool.h"
21 #include "util.h"
22
23 #if defined(WIN32) || defined(_WINDOWS)
24 WSADATA wsaData;
25 int wsaInit = 0;
26
27 __inline void DisposeWinsock(int aUNUSED) { if (wsaInit > 0) WSACleanup(); wsaInit--; }
28 #else
29 # define DisposeWinsock(a)
30 #endif
31
32 int gStartupUrlParameterGiven = 0;
33 int gIsTTY, gIsTTYr;
34 int gScreenColumns;
35
36 FTPLibraryInfo gLib;
37 FTPConnectionInfo gConn;
38 LineList gStartupURLCdList;
39 int gTransferTypeInitialized = 0;
40 int gTransferType;
41 int gURLMode = 0;
42 extern int gUnprocessedJobs;
43 char gLocalCWD[512], gPrevLocalCWD[512];
44
45 extern char *gOptArg;
46 extern int gOptInd;
47 extern char gRemoteCWD[512], gPrevRemoteCWD[512];
48 extern Bookmark gBm;
49 extern int gLoadedBm;
50 extern int gFirstTimeUser;
51 extern int gFirewallType;
52 extern char gAutoAscii[];
53 extern char gFirewallHost[64];
54 extern char gFirewallUser[32];
55 extern char gFirewallPass[32];
56 extern char gFirewallExceptionList[];
57 extern char gCopyright[], gVersion[];
58 extern unsigned int gFirewallPort;
59 extern int gConnTimeout, gXferTimeout, gCtrlTimeout;
60 extern int gDataPortMode, gRedialDelay;
61 extern int gDebug;
62 extern int gNumProgramRuns, gDoNotDisplayAds;
63 extern int gSOBufsize;
64 extern FTPProgressMeterProc gProgressMeter;
65
66 static void
67 Usage(void)
68 {
69 FILE *fp;
70 #ifdef UNAME
71 char s[80];
72 #endif
73
74 fp = stderr;
75 (void) fprintf(fp, "\nUsage: ncftp [flags] [<host> | <directory URL to browse>]\n");
76 (void) fprintf(fp, "\nFlags:\n\
77 -u XX Use username XX instead of anonymous.\n\
78 -p XX Use password XX with the username.\n\
79 -P XX Use port number XX instead of the default FTP service port (21).\n\
80 -j XX Use account XX with the username (rarely needed).\n\
81 -F Dump a sample $HOME/.ncftp/firewall prefs file to stdout and exit.\n");
82
83 (void) fprintf(fp, "\nProgram version: %s\nLibrary version: %s\n", gVersion + 5, gLibNcFTPVersion + 5);
84 #ifdef UNAME
85 AbbrevStr(s, UNAME, 60, 1);
86 (void) fprintf(fp, "System: %s\n", s);
87 #endif
88 (void) fprintf(fp, "\nThis is a freeware program by Mike Gleason (ncftp@ncftp.com).\n");
89 (void) fprintf(fp, "Use ncftpget and ncftpput for command-line FTP.\n\n");
90 exit(2);
91 } /* Usage */
92
93
94
95
96 static void
97 DumpFirewallPrefsTemplate(void)
98 {
99 WriteDefaultFirewallPrefs(stdout);
100 } /* DumpFirewallPrefsTemplate */
101
102
103
104
105 /* This resets our state information whenever we are ready to open a new
106 * host.
107 */
108 void
109 InitConnectionInfo(void)
110 {
111 int result;
112
113 result = FTPInitConnectionInfo(&gLib, &gConn, kDefaultFTPBufSize);
114 if (result < 0) {
115 (void) fprintf(stderr, "ncftp: init connection info error %d (%s).\n", result, FTPStrError(result));
116 exit(1);
117 }
118
119 gConn.debugLog = NULL;
120 gConn.errLog = stderr;
121 SetDebug(gDebug);
122 UseTrace();
123 (void) STRNCPY(gConn.user, "anonymous");
124 gConn.host[0] = '\0';
125 gConn.progress = gProgressMeter;
126 gTransferTypeInitialized = 0;
127 gTransferType = kTypeBinary;
128 gConn.leavePass = 1; /* Don't let the lib zap it. */
129 gConn.connTimeout = gConnTimeout;
130 gConn.xferTimeout = gXferTimeout;
131 gConn.ctrlTimeout = gCtrlTimeout;
132 gConn.dataPortMode = gDataPortMode;
133 gConn.maxDials = (-1); /* Dial forever, until they hit ^C. */
134 gUnprocessedJobs = 0;
135 gPrevRemoteCWD[0] = '\0';
136 gConn.dataSocketRBufSize = gConn.dataSocketSBufSize = gSOBufsize;
137 if (gRedialDelay >= 10)
138 gConn.redialDelay = gRedialDelay;
139 if ((gAutoAscii[0] == '\0') || (ISTREQ(gAutoAscii, "no")) || (ISTREQ(gAutoAscii, "off")) || (ISTREQ(gAutoAscii, "false"))) {
140 gConn.asciiFilenameExtensions = NULL;
141 } else {
142 gConn.asciiFilenameExtensions = gAutoAscii;
143 }
144 } /* InitConnectionInfo */
145
146
147
148
149 /* This lets us do things with our state information just before the
150 * host is closed.
151 */
152 void
153 CloseHost(void)
154 {
155 if (gConn.connected != 0) {
156 if (gConn.loggedIn != 0) {
157 SaveUnsavedBookmark();
158 }
159 RunBatchIfNeeded(&gConn);
160 }
161 gConn.ctrlTimeout = 3;
162 (void) FTPCloseHost(&gConn);
163 } /* CloseHost */
164
165
166
167
168 /* If the user specified a URL on the command-line, this initializes
169 * our state information based upon it.
170 */
171 static void
172 SetStartupURL(const char *const urlgiven)
173 {
174 int rc;
175 char url[256];
176 char urlfile[128];
177
178 gLoadedBm = 0;
179 (void) STRNCPY(url, urlgiven);
180
181 rc = DecodeDirectoryURL(&gConn, url, &gStartupURLCdList, urlfile, sizeof(urlfile));
182 if (rc == kMalformedURL) {
183 (void) fprintf(stderr, "Malformed URL: %s\n", url);
184 exit(1);
185 } else if (rc == kNotURL) {
186 /* This is what should happen most of the time. */
187 (void) STRNCPY(gConn.host, urlgiven);
188 gURLMode = 2;
189 if (GetBookmark(gConn.host, &gBm) >= 0) {
190 gLoadedBm = 1;
191 (void) STRNCPY(gConn.host, gBm.name);
192 (void) STRNCPY(gConn.user, gBm.user);
193 (void) STRNCPY(gConn.pass, gBm.pass);
194 (void) STRNCPY(gConn.acct, gBm.acct);
195 gConn.hasSIZE = gBm.hasSIZE;
196 gConn.hasMDTM = gBm.hasMDTM;
197 gConn.hasPASV = gBm.hasPASV;
198 gConn.hasUTIME = gBm.hasUTIME;
199 gConn.port = gBm.port;
200 } else {
201 SetBookmarkDefaults(&gBm);
202 }
203
204 if (MayUseFirewall(gConn.host, gFirewallType, gFirewallExceptionList) != 0) {
205 gConn.firewallType = gFirewallType;
206 (void) STRNCPY(gConn.firewallHost, gFirewallHost);
207 (void) STRNCPY(gConn.firewallUser, gFirewallUser);
208 (void) STRNCPY(gConn.firewallPass, gFirewallPass);
209 gConn.firewallPort = gFirewallPort;
210 }
211 } else {
212 /* URL okay */
213 if (urlfile[0] != '\0') {
214 /* It was obviously not a directory */
215 (void) fprintf(stderr, "Use ncftpget or ncftpput to handle file URLs.\n");
216 exit(1);
217 }
218 gURLMode = 1;
219 if (MayUseFirewall(gConn.host, gFirewallType, gFirewallExceptionList) != 0) {
220 gConn.firewallType = gFirewallType;
221 (void) STRNCPY(gConn.firewallHost, gFirewallHost);
222 (void) STRNCPY(gConn.firewallUser, gFirewallUser);
223 (void) STRNCPY(gConn.firewallPass, gFirewallPass);
224 gConn.firewallPort = gFirewallPort;
225 }
226 }
227 } /* SetStartupURL */
228
229
230
231
232 static void
233 OpenURL(void)
234 {
235 LinePtr lp;
236 int result;
237
238 if (gURLMode == 1) {
239 SetBookmarkDefaults(&gBm);
240 if (DoOpen() >= 0) {
241 for (lp = gStartupURLCdList.first; lp != NULL; lp = lp->next) {
242 result = FTPChdir(&gConn, lp->line);
243 if (result != kNoErr) {
244 FTPPerror(&gConn, result, kErrCWDFailed, "Could not chdir to", lp->line);
245 break;
246 }
247 }
248 result = FTPGetCWD(&gConn, gRemoteCWD, sizeof(gRemoteCWD));
249 if (result != kNoErr) {
250 FTPPerror(&gConn, result, kErrPWDFailed, NULL, NULL);
251 } else {
252 (void) printf("Current remote directory is %s.\n", gRemoteCWD);
253 }
254 }
255 } else if (gURLMode == 2) {
256 (void) DoOpen();
257 }
258 } /* OpenURL */
259
260
261
262
263 /* These things are done first, before we even parse the command-line
264 * options.
265 */
266 static void
267 PreInit(void)
268 {
269 int result;
270
271 #if defined(WIN32) || defined(_WINDOWS)
272 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
273 fprintf(stderr, "could not initialize winsock\n");
274 exit(1);
275 }
276 wsaInit++;
277 #endif
278
279 #ifdef HAVE_SETLOCALE
280 setlocale(LC_ALL, "");
281 #endif
282 #if defined(WIN32) || defined(_WINDOWS)
283 gIsTTY = 1;
284 gIsTTYr = 1;
285 #else
286 gIsTTY = ((isatty(2) != 0) && (getppid() > 1)) ? 1 : 0;
287 gIsTTYr = ((isatty(0) != 0) && (getppid() > 1)) ? 1 : 0;
288 #endif
289 #ifdef SIGPOLL
290 (void) NcSignal(SIGPOLL, (FTPSigProc) SIG_IGN);
291 #endif
292 InitUserInfo();
293 result = FTPInitLibrary(&gLib);
294 if (result < 0) {
295 (void) fprintf(stderr, "ncftp: init library error %d (%s).\n", result, FTPStrError(result));
296 exit(1);
297 }
298 #if defined(WIN32) || defined(_WINDOWS)
299 srand((unsigned int) (GetTickCount() & 0x7FFF));
300 #else
301 srand((unsigned int) getpid());
302 #endif
303 InitLineList(&gStartupURLCdList);
304 CheckForNewV3User();
305 InitLog();
306 InitPrefs();
307 LoadFirewallPrefs(0);
308 LoadPrefs();
309 InitConnectionInfo();
310 InitCommandList();
311 InitLs();
312 TruncBatchLog();
313 GetoptReset();
314 GetScreenColumns();
315 } /* PreInit */
316
317
318
319
320
321 /* These things are done at startup, but after we parse the command-line
322 * options.
323 */
324 static void
325 PostInit(void)
326 {
327 PostInitPrefs();
328 OpenTrace();
329 InitTermcap();
330 InitReadline();
331 (void) FTPGetLocalCWD(gLocalCWD, sizeof(gLocalCWD));
332 gPrevLocalCWD[0] = '\0';
333 PrintStartupBanner();
334 if (gNumProgramRuns <= 1)
335 (void) printf("\n%s\n", gCopyright + 5);
336
337 Trace(0, "Fw: %s Type: %d User: %s Pass: %s Port: %u\n",
338 gFirewallHost,
339 gFirewallType,
340 gFirewallUser,
341 (gFirewallPass[0] == '\0') ? "(none)" : "********",
342 gFirewallPort
343 );
344 Trace(0, "FwExceptions: %s\n", gFirewallExceptionList);
345 if (strchr(gLib.ourHostName, '.') == NULL) {
346 Trace(0, "NOTE: Your domain name could not be detected.\n");
347 if (gConn.firewallType != kFirewallNotInUse) {
348 Trace(0, " Make sure you manually add your domain name to firewall-exception-list.\n");
349 }
350 }
351 } /* PostInit */
352
353
354
355
356 /* Try to get the user to evaluate my commercial offerings. */
357 static void
358 Plug(void)
359 {
360 #if defined(WIN32) || defined(_WINDOWS)
361 /* NcFTPd hasn't been ported to Windows. */
362 #else
363 if ((gDoNotDisplayAds == 0) && ((gNumProgramRuns % 7) == 2)) {
364 (void) printf("\n\n\n\tThank you for using NcFTP Client.\n\tAsk your system administrator to try NcFTPd Server!\n\thttp://www.ncftpd.com\n\n\n\n");
365 }
366 #endif
367 } /* Plug */
368
369
370
371
372 /* These things are just before the program exits. */
373 static void
374 PostShell(void)
375 {
376 SetXtermTitle("RESTORE");
377 CloseHost();
378 DisposeReadline();
379 CloseTrace();
380 SavePrefs();
381 EndLog();
382 Plug();
383 DisposeWinsock(0);
384 } /* PostShell */
385
386
387
388
389 int
390 main(int argc, const char **const argv)
391 {
392 int c;
393 int n;
394
395 PreInit();
396 while ((c = Getopt(argc, argv, "P:u:p:J:rd:g:FVLD")) > 0) switch(c) {
397 case 'P':
398 case 'u':
399 case 'p':
400 case 'J':
401 gStartupUrlParameterGiven = 1;
402 break;
403 case 'r':
404 case 'g':
405 case 'd':
406 case 'V':
407 case 'L':
408 case 'D':
409 case 'F':
410 break;
411 default:
412 Usage();
413 }
414
415 if (gOptInd < argc) {
416 LoadFirewallPrefs(0);
417 SetStartupURL(argv[gOptInd]);
418 } else if (gStartupUrlParameterGiven != 0) {
419 /* One of the flags they specified
420 * requires a URL or hostname to
421 * open.
422 */
423 Usage();
424 }
425
426 GetoptReset();
427 /* Allow command-line parameters to override
428 * bookmark settings.
429 */
430
431 while ((c = Getopt(argc, argv, "P:u:p:j:J:rd:g:FVLD")) > 0) switch(c) {
432 case 'P':
433 gConn.port = atoi(gOptArg);
434 break;
435 case 'u':
436 (void) STRNCPY(gConn.user, gOptArg);
437 break;
438 case 'p':
439 (void) STRNCPY(gConn.pass, gOptArg); /* Don't recommend doing this! */
440 break;
441 case 'J':
442 case 'j':
443 (void) STRNCPY(gConn.acct, gOptArg);
444 break;
445 case 'r':
446 /* redial is always on */
447 break;
448 case 'g':
449 gConn.maxDials = atoi(gOptArg);
450 break;
451 case 'd':
452 n = atoi(gOptArg);
453 if (n >= 10)
454 gConn.redialDelay = n;
455 break;
456 case 'F':
457 DumpFirewallPrefsTemplate();
458 exit(0);
459 /*NOTREACHED*/
460 break;
461 case 'V':
462 /*FALLTHROUGH*/
463 case 'L':
464 /*FALLTHROUGH*/
465 case 'D':
466 /* silently ignore these legacy options */
467 break;
468 default:
469 Usage();
470 }
471
472 PostInit();
473 OpenURL();
474 CommandShell();
475 PostShell();
476 exit(0);
477 } /* main */