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 
DisposeWinsock(int aUNUSED)27 	static __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
Usage(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
DumpFirewallPrefsTemplate(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
InitConnectionInfo(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 = NULL;
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
CloseHost(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
SetStartupURL(const char * const urlgiven)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
OpenURL(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
PreInit(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
PostInit(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
Plug(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
PostShell(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
main(int argc,const char ** const argv)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 */
478