1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #ifdef _WIN32
8 #  if !defined( NOMINMAX )
9 #     define NOMINMAX
10 #  endif
11 #  include <winsock2.h>
12 #endif
13 
14 #include "drive-dlg.h"
15 #include "file-util.h"
16 #include "ncwin.h"
17 #include "globals.h"
18 #include "string-util.h"
19 #include "ltext.h"
20 #include "vfs-ftp.h"
21 #include "vfs-tmp.h"
22 #include "ftplogon.h"
23 #include "sftpdlg.h"
24 #include "smblogon.h"
25 
26 
27 #ifndef _WIN32
28 #  include "ux_util.h"
29 #else
30 #  include "w32util.h"
31 #endif
32 
33 
34 static int uiDriveDlg = GetUiID( "drive-dlg" );
35 
36 #ifdef _WIN32
37 
GetVolumeName(int i)38 std::string GetVolumeName( int i )
39 {
40 	char VolumeName[1024] = { 0 };
41 
42 	char RootPath[0x100];
43 	Lsnprintf( RootPath, sizeof( RootPath ), "%c:\\", i + 'A' );
44 	GetVolumeInformation( RootPath, VolumeName, sizeof( VolumeName ), nullptr, nullptr, nullptr, nullptr, 0 );
45 
46 	return std::string( VolumeName );
47 }
48 
GetDriveTypeString(unsigned int Type)49 std::string GetDriveTypeString( unsigned int Type )
50 {
51 	switch ( Type )
52 	{
53 		case DRIVE_REMOVABLE:
54 			return "removable";
55 
56 		case DRIVE_FIXED:
57 			return "fixed";
58 
59 		case DRIVE_REMOTE:
60 			return "remote";
61 
62 		case DRIVE_CDROM:
63 			return "CDROM";
64 
65 		case DRIVE_RAMDISK:
66 			return "RAM disk";
67 	}
68 
69 	return std::string();
70 }
71 
72 #endif // _WIN32
73 
74 
75 #ifdef __APPLE__
76 
77 #define VOLUMES_DIR	"/Volumes"
78 
GetVolumesOSX(ccollect<MntListNode> * MntList)79 void GetVolumesOSX( ccollect<MntListNode>* MntList )
80 {
81 	FSSys fs;
82 	FSList list;
83 	FSString path( VOLUMES_DIR );
84 	FSPath fspath( path );
85 	int err;
86 
87 	if ( fs.ReadDir( &list, fspath, &err, nullptr ) == 0 )
88 	{
89 		for ( FSNode* node = list.First(); node; node = node->next )
90 		{
91 			if ( node->IsDir() && !node->IsHidden() && !node->IsLnk() )
92 			{
93 				std::vector<char> Uri = carray_cat( VOLUMES_DIR, "/", node->name.GetUtf8() );
94 
95 				MntListNode n;
96 				n.path = Uri.data();
97 				MntList->append( n );
98 			}
99 		}
100 	}
101 	else
102 	{
103 		fprintf( stderr, "error:%s\n", fs.StrError( err ).GetUtf8() );
104 	}
105 }
106 
107 #endif // __APPLE__
108 
109 
110 /// returns 'true' if the dialog should be restarted
SelectDriveInternal(PanelWin * p,PanelWin * OtherPanel)111 bool SelectDriveInternal( PanelWin* p, PanelWin* OtherPanel )
112 {
113 #ifndef _WIN32
114 	ccollect<MntListNode> mntList;
115 
116 #ifdef __APPLE__
117 	GetVolumesOSX( &mntList );
118 #else
119 	UxMntList( &mntList );
120 #endif
121 
122 #endif // !_WIN32
123 
124 	clMenuData mData;
125 
126 	std::vector<unicode_t> OtherPanelPath = new_unicode_str( OtherPanel->UriOfDir().GetUnicode() );
127 
128 #ifdef _WIN32
129 	const size_t MaxLength = 20;
130 #else
131 	const size_t MaxLength = 50;
132 #endif
133 
134 	OtherPanelPath = TruncateToLength( OtherPanelPath, MaxLength, true );
135 
136 	mData.Add( OtherPanelPath.data(), nullptr, nullptr, ID_DEV_OTHER_PANEL );
137 	mData.AddSplitter();
138 
139 #ifdef _WIN32
140 	std::vector<unicode_t> homeUri = GetHomeUriWin();
141 
142 	if ( homeUri.data() )
143 	{
144 		mData.Add( _LT( "Home" ), nullptr, nullptr, ID_DEV_HOME );
145 	}
146 
147 	DWORD drv = GetLogicalDrives();
148 
149 	for ( int i = 0, mask = 1; i < 'z' - 'a' + 1; i++, mask <<= 1 )
150 	{
151 		if ( drv & mask )
152 		{
153 			char buf[0x100];
154 			Lsnprintf( buf, sizeof( buf ), "%c:", i + 'A' );
155 			UINT driveType = GetDriveType( buf );
156 
157 			bool ShouldReadVolumeName = ( driveType == DRIVE_FIXED || driveType == DRIVE_RAMDISK );
158 
159 			std::string DriveTypeStr = GetDriveTypeString( driveType );
160 			std::string VolumeName = ShouldReadVolumeName ? GetVolumeName( i ) : std::string();
161 
162 			mData.Add( buf, DriveTypeStr.c_str(), VolumeName.c_str(), ID_DEV_MS0 + i );
163 		}
164 	}
165 
166 	mData.AddSplitter();
167 	mData.Add( "1. NETWORK", nullptr, nullptr, ID_DEV_SMB );
168 	mData.Add( "2. FTP", nullptr, nullptr, ID_DEV_FTP );
169 #else
170 	mData.Add( "1. /", nullptr, nullptr,  ID_DEV_ROOT );
171 	mData.Add( _LT( "2. Home" ), nullptr, nullptr, ID_DEV_HOME );
172 	mData.Add( "3. FTP", nullptr, nullptr, ID_DEV_FTP );
173 
174 #ifdef LIBSMBCLIENT_EXIST
175 	mData.Add( "4. Smb network", nullptr, nullptr, ID_DEV_SMB );
176 	mData.Add( "5. Smb server", nullptr, nullptr, ID_DEV_SMB_SERVER );
177 #else
178 
179 #endif // LIBSMBCLIENT_EXIST
180 
181 #endif // _WIN32
182 
183 #if defined(LIBSSH_EXIST) || defined(LIBSSH2_EXIST)
184 	mData.Add( "6. SFTP", nullptr, nullptr, ID_DEV_SFTP );
185 #endif
186 	mData.Add( "7. temporary", nullptr, nullptr, ID_DEV_TMP );
187 
188 #ifndef _WIN32  //unix mounts
189 	//ID_MNT_UX0
190 	{
191 		if ( mntList.count() > 0 )
192 		{
193 			mData.AddSplitter();
194 		}
195 
196 		for ( int i = 0; i < 9 && i < mntList.count(); i++ )
197 		{
198 			std::string Uri = mntList[i].path;
199 
200 #ifdef __APPLE__
201 			// truncate /Volumes/ dir prefix
202 			Uri = Uri.substr( strlen( VOLUMES_DIR ) + 1, Uri.size() );
203 #endif
204 
205 			std::vector<unicode_t> un = sys_to_unicode_array( Uri.data() );
206 			static int maxNLen = 20;
207 			int nLen = unicode_strlen( un.data() );
208 
209 			if ( nLen > maxNLen )
210 			{
211 				int n2 = maxNLen / 2;
212 				un[n2] = 0;
213 				un[n2 - 1] = '.';
214 				un[n2 - 2] = '.';
215 				un[n2 - 3] = '.';
216 				un = carray_cat<unicode_t>( un.data(), un.data() + nLen - n2 );
217 			}
218 
219 			std::vector<unicode_t> ut = sys_to_unicode_array( mntList[i].type.data() );
220 
221 			static int maxTLen = 10;
222 
223 			if ( unicode_strlen( ut.data() ) > maxTLen )
224 			{
225 				ut[maxTLen] = 0;
226 				ut[maxTLen - 1] = '.';
227 				ut[maxTLen - 2] = '.';
228 				ut[maxTLen - 3] = '.';
229 			}
230 
231 			char buf[64];
232 			snprintf( buf, sizeof( buf ), "%c. ", i + 'A' );
233 
234 			mData.Add( carray_cat<unicode_t>( utf8_to_unicode( buf ).data(), un.data() ).data(), ut.data(), nullptr, ID_MNT_UX0 + i );
235 		}
236 	}
237 #endif
238 
239 	const int res = RunDldMenu( uiDriveDlg, p, "Drive", &mData );
240 	g_MainWin->SetCommandLineFocus();
241 
242 	if ( res == ID_RESTART_DIALOG )
243 	{
244 		// restart this dialog to reread the drives list (Ctrl+R)
245 		return true;
246 	}
247 
248 	if ( res == ID_DEV_OTHER_PANEL )
249 	{
250 		clPtr<FS> fs = OtherPanel->GetFSPtr();
251 		p->LoadPath( fs, OtherPanel->GetPath(), 0, 0, PanelWin::SET );
252 		return false;
253 	}
254 
255 #ifdef _WIN32
256 
257 	if ( res >= ID_DEV_MS0 && res < ID_DEV_MS0 + ( 'z' - 'a' + 1 ) )
258 	{
259 		int drive = res - ID_DEV_MS0;
260 		FSPath path( CS_UTF8, "/" );
261 		clPtr<FS> fs = p->GetFSPtr();
262 
263 		if ( !fs.IsNull() && fs->Type() == FS::SYSTEM && ( ( FSSys* )fs.Ptr() )->Drive() == drive )
264 		{
265 			path = p->GetPath();
266 		}
267 		else
268 		{
269 			fs = OtherPanel->GetFSPtr();
270 
271 			if ( !fs.IsNull() && fs->Type() == FS::SYSTEM && ( ( FSSys* )fs.Ptr() )->Drive() == drive )
272 			{
273 				path = OtherPanel->GetPath();
274 			}
275 			else
276 			{
277 				fs = 0;
278 			}
279 		}
280 
281 		if ( fs.IsNull() )
282 		{
283 			fs = new FSSys( drive );
284 		}
285 
286 		if ( !path.IsAbsolute() )
287 		{
288 			path.Set( CS_UTF8, "/" );
289 		}
290 
291 		p->LoadPath( fs, path, 0, 0, PanelWin::SET );
292 		return false;
293 	}
294 
295 #else
296 
297 	if ( res >= ID_MNT_UX0 && res < ID_MNT_UX0 + 100 )
298 	{
299 		const int n = res - ID_MNT_UX0;
300 
301 		if ( n < 0 || n >= mntList.count() )
302 		{
303 			return false;
304 		}
305 
306 		clPtr<FS> fs = new FSSys();
307 		FSPath path( sys_charset_id, mntList[n].path.data() );
308 		p->LoadPath( fs, path, 0, 0, PanelWin::SET );
309 		return false;
310 	}
311 
312 #endif
313 
314 	switch ( res )
315 	{
316 #ifndef _WIN32
317 
318 		case ID_DEV_ROOT:
319 		{
320 			FSPath path( CS_UTF8, "/" );
321 			p->LoadPath( new FSSys(), path, 0, 0, PanelWin::SET );
322 		}
323 		break;
324 #endif
325 
326 		case ID_DEV_HOME:
327 		{
328 			OpenHomeDir( p );
329 		}
330 		break;
331 
332 #ifdef _WIN32
333 
334 		case ID_DEV_SMB:
335 		{
336 			FSPath path( CS_UTF8, "/" );
337 			clPtr<FS> fs = new FSWin32Net( 0 );
338 
339 			if ( !fs.IsNull() )
340 			{
341 				p->LoadPath( fs, path, 0, 0, PanelWin::SET );
342 			}
343 		}
344 		break;
345 
346 #else
347 
348 #ifdef LIBSMBCLIENT_EXIST
349 
350 		case ID_DEV_SMB:
351 		{
352 			FSPath path( CS_UTF8, "/" );
353 			clPtr<FS> fs = new FSSmb() ;
354 
355 			if ( !fs.IsNull() )
356 			{
357 				p->LoadPath( fs, path, 0, 0, PanelWin::SET );
358 			}
359 		}
360 		break;
361 
362 		case ID_DEV_SMB_SERVER:
363 		{
364 			static FSSmbParam lastParams;
365 			FSSmbParam params = lastParams;
366 
367 			if ( !GetSmbLogon( g_MainWin, params, true ) )
368 			{
369 				return false;
370 			}
371 
372 			params.isSet = true;
373 			clPtr<FS> fs = new FSSmb( &params ) ;
374 			FSPath path( CS_UTF8, "/" );
375 
376 			if ( !fs.IsNull() )
377 			{
378 				lastParams = params;
379 				p->LoadPath( fs, path, 0, 0, PanelWin::SET );
380 			}
381 		}
382 		break;
383 
384 #endif
385 
386 #endif
387 
388 		case ID_DEV_FTP:
389 		{
390 			static FSFtpParam lastParams;
391 			FSFtpParam params = lastParams;
392 
393 			if ( !GetFtpLogon( g_MainWin, params ) )
394 			{
395 				return false;
396 			}
397 
398 			clPtr<FS> fs = new FSFtp( &params ) ;
399 
400 			FSPath path( CS_UTF8, "/" );
401 
402 			if ( !fs.IsNull() )
403 			{
404 				lastParams = params;
405 				p->LoadPath( fs, path, 0, 0, PanelWin::SET );
406 			}
407 		}
408 		break;
409 
410 #if defined(LIBSSH_EXIST) || defined(LIBSSH2_EXIST)
411 
412 		case ID_DEV_SFTP:
413 		{
414 			static FSSftpParam lastParams;
415 			FSSftpParam params = lastParams;
416 
417 			if ( !GetSftpLogon( g_MainWin, params ) )
418 			{
419 				return false;
420 			}
421 
422 			params.isSet = true;
423 			clPtr<FS> fs = new FSSftp( &params ) ;
424 			FSPath path( CS_UTF8, "/" );
425 
426 			if ( !fs.IsNull() )
427 			{
428 				lastParams = params;
429 				p->LoadPath( fs, path, 0, 0, PanelWin::SET );
430 			}
431 		}
432 		break;
433 #endif
434 
435 		case ID_DEV_TMP:
436 		{
437 			clPtr<FSTmp> fs = new FSTmp( OtherPanel->GetFS() );
438 			p->LoadPath( fs, FSTmp::rootPathName, 0, 0, PanelWin::PUSH );
439 		}
440 		break;
441 	};
442 
443 	return false;
444 }
445 
SelectDriveDlg(PanelWin * p,PanelWin * OtherPanel)446 void SelectDriveDlg( PanelWin* p, PanelWin* OtherPanel )
447 {
448 	bool RedoDialog = false;
449 
450 	do
451 	{
452 		RedoDialog = SelectDriveInternal( p, OtherPanel );
453 	}
454 	while ( RedoDialog );
455 }
456