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( ¶ms ) ;
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( ¶ms ) ;
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( ¶ms ) ;
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