source: filezilla/trunk/fuentes/src/interface/file_utils.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 8.6 KB
Line 
1#include "filezilla.h"
2
3#include "file_utils.h"
4
5#include <wx/stdpaths.h>
6#ifdef __WXMSW__
7#include <wx/dynlib.h> // Used by GetDownloadDir
8#include <knownfolders.h>
9#else
10#include <wx/textfile.h>
11#include <wordexp.h>
12#endif //__WXMSW__
13
14wxString GetAsURL(const wxString& dir)
15{
16        // Cheap URL encode
17        wxString encoded;
18        const wxWX2MBbuf utf8 = dir.mb_str(wxConvUTF8);
19
20        if (!utf8)
21                return wxString();
22
23        const char* p = utf8;
24        while (*p)
25        {
26                // List of characters that don't need to be escaped taken
27                // from the BNF grammar in RFC 1738
28                // Again attention seeking Windows wants special treatment...
29                const unsigned char c = (unsigned char)*p++;
30                if ((c >= 'a' && c <= 'z') ||
31                        (c >= 'A' && c <= 'Z') ||
32                        (c >= '0' && c <= '9') ||
33                        c == '$' ||
34                        c == '_' ||
35                        c == '-' ||
36                        c == '.' ||
37                        c == '+' ||
38                        c == '!' ||
39                        c == '*' ||
40#ifndef __WXMSW__
41                        c == '\'' ||
42#endif
43                        c == '(' ||
44                        c == ')' ||
45                        c == ',' ||
46                        c == '?' ||
47                        c == ':' ||
48                        c == '@' ||
49                        c == '&' ||
50                        c == '=' ||
51                        c == '/')
52                {
53                        encoded += (wxChar)c;
54                }
55#ifdef __WXMSW__
56                else if (c == '\\')
57                        encoded += '/';
58#endif
59                else
60                        encoded += wxString::Format(_T("%%%x"), (unsigned int)c);
61        }
62#ifdef __WXMSW__
63        if (encoded.Left(2) == _T("//"))
64        {
65                // UNC path
66                encoded = encoded.Mid(2);
67        }
68        else
69                encoded = _T("/") + encoded;
70#endif
71        return _T("file://") + encoded;
72}
73
74bool OpenInFileManager(const wxString& dir)
75{
76        bool ret = false;
77#ifdef __WXMSW__
78        // Unfortunately under Windows, UTF-8 encoded file:// URLs don't work, so use native paths.
79        // Unfortunatelier, we cannot use this for UNC paths, have to use file:// here
80        // Unfortunateliest, we again have a problem with UTF-8 characters which we cannot fix...
81        if (dir.Left(2) != _T("\\\\") && dir != _T("/"))
82                ret = wxLaunchDefaultBrowser(dir);
83        else
84#endif
85        {
86                wxString url = GetAsURL(dir);
87                if (!url.empty())
88                        ret = wxLaunchDefaultBrowser(url);
89        }
90
91
92        if (!ret)
93                wxBell();
94
95        return ret;
96}
97
98wxString GetSystemOpenCommand(wxString file, bool &program_exists)
99{
100        wxFileName fn(file);
101
102        const wxString& ext = fn.GetExt();
103        if (ext.empty())
104                return wxString();
105
106#ifdef __WXGTK__
107        for (;;)
108#endif
109        {
110                wxFileType* pType = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
111                if (!pType)
112                        return wxString();
113
114                wxString cmd;
115                if (!pType->GetOpenCommand(&cmd, wxFileType::MessageParameters(file)))
116                {
117                        delete pType;
118                        return wxString();
119                }
120                delete pType;
121
122                if (cmd.empty())
123                        return wxString();
124
125                program_exists = false;
126
127                wxString editor;
128                bool is_dde = false;
129#ifdef __WXMSW__
130                if (cmd.Left(7) == _T("WX_DDE#"))
131                {
132                        // See wxWidget's wxExecute in src/msw/utilsexc.cpp
133                        // WX_DDE#<command>#DDE_SERVER#DDE_TOPIC#DDE_COMMAND
134                        editor = cmd.Mid(7);
135                        int pos = editor.Find('#');
136                        if (pos < 1)
137                                return cmd;
138                        editor = editor.Left(pos);
139                        is_dde = true;
140                }
141                else
142#endif
143                {
144                        editor = cmd;
145                }
146
147                wxString args;
148                if (!UnquoteCommand(editor, args, is_dde) || editor.empty())
149                        return cmd;
150
151                if (!PathExpand(editor))
152                        return cmd;
153
154                if (ProgramExists(editor))
155                        program_exists = true;
156
157#ifdef __WXGTK__
158                int pos = args.Find(file);
159                if (pos != -1 && file.Find(' ') != -1 && file[0] != '\'' && file[0] != '"')
160                {
161                        // Might need to quote filename, wxWidgets doesn't do it
162                        if ((!pos || (args[pos - 1] != '\'' && args[pos - 1] != '"')) &&
163                                (pos + file.Length() >= args.Length() || (args[pos + file.Length()] != '\'' && args[pos + file.Length()] != '"')))
164                        {
165                                // Filename in command arguments isn't quoted. Repeat with quoted filename
166                                file = _T("\"") + file + _T("\"");
167                                continue;
168                        }
169                }
170#endif
171                return cmd;
172        }
173
174        return wxString();
175}
176
177bool UnquoteCommand(wxString& command, wxString& arguments, bool is_dde)
178{
179        arguments = _T("");
180
181        if (command.empty())
182                return true;
183
184        wxChar inQuotes = 0;
185        wxString file;
186        for (unsigned int i = 0; i < command.Len(); i++)
187        {
188                const wxChar& c = command[i];
189                if (c == '"' || c == '\'')
190                {
191                        if (!inQuotes)
192                                inQuotes = c;
193                        else if (c != inQuotes)
194                                file += c;
195                        else if (command[i + 1] == c)
196                        {
197                                file += c;
198                                i++;
199                        }
200                        else
201                                inQuotes = false;
202                }
203                else if (command[i] == ' ' && !inQuotes)
204                {
205                        arguments = command.Mid(i + 1);
206                        arguments.Trim(false);
207                        break;
208                }
209                else if (is_dde && !inQuotes && (command[i] == ',' || command[i] == '#'))
210                {
211                        arguments = command.Mid(i + 1);
212                        arguments.Trim(false);
213                        break;
214                }
215                else
216                        file += command[i];
217        }
218        if (inQuotes)
219                return false;
220
221        command = file;
222
223        return true;
224}
225
226bool ProgramExists(const wxString& editor)
227{
228        if (wxFileName::FileExists(editor))
229                return true;
230
231#ifdef __WXMAC__
232        if (editor.Right(4) == _T(".app") && wxFileName::DirExists(editor))
233                return true;
234#endif
235
236        return false;
237}
238
239bool PathExpand(wxString& cmd)
240{
241#ifndef __WXMSW__
242        if (!cmd.empty() && cmd[0] == '/')
243                return true;
244#else
245        if (!cmd.empty() && cmd[0] == '\\')
246                // UNC or root of current working dir, whatever that is
247                return true;
248        if (cmd.Len() > 2 && cmd[1] == ':')
249                // Absolute path
250                return true;
251#endif
252
253        // Need to search for program in $PATH
254        wxString path;
255        if (!wxGetEnv(_T("PATH"), &path))
256                return false;
257
258        wxString full_cmd;
259        bool found = wxFindFileInPath(&full_cmd, path, cmd);
260#ifdef __WXMSW__
261        if (!found && cmd.Right(4).Lower() != _T(".exe"))
262        {
263                cmd += _T(".exe");
264                found = wxFindFileInPath(&full_cmd, path, cmd);
265        }
266#endif
267
268        if (!found)
269                return false;
270
271        cmd = full_cmd;
272        return true;
273}
274
275bool RenameFile(wxWindow* parent, wxString dir, wxString from, wxString to)
276{
277        if (dir.Right(1) != _T("\\") && dir.Right(1) != _T("/"))
278                dir += wxFileName::GetPathSeparator();
279
280#ifdef __WXMSW__
281        to = to.Left(255);
282
283        if ((to.Find('/') != -1) ||
284                (to.Find('\\') != -1) ||
285                (to.Find(':') != -1) ||
286                (to.Find('*') != -1) ||
287                (to.Find('?') != -1) ||
288                (to.Find('"') != -1) ||
289                (to.Find('<') != -1) ||
290                (to.Find('>') != -1) ||
291                (to.Find('|') != -1))
292        {
293                wxMessageBoxEx(_("Filenames may not contain any of the following characters: / \\ : * ? \" < > |"), _("Invalid filename"), wxICON_EXCLAMATION);
294                return false;
295        }
296
297        SHFILEOPSTRUCT op;
298        memset(&op, 0, sizeof(op));
299
300        from = dir + from + _T(" ");
301        from.SetChar(from.Length() - 1, '\0');
302        op.pFrom = from;
303        to = dir + to + _T(" ");
304        to.SetChar(to.Length()-1, '\0');
305        op.pTo = to;
306        op.hwnd = (HWND)parent->GetHandle();
307        op.wFunc = FO_RENAME;
308        op.fFlags = FOF_ALLOWUNDO;
309        return SHFileOperation(&op) == 0;
310#else
311        if ((to.Find('/') != -1) ||
312                (to.Find('*') != -1) ||
313                (to.Find('?') != -1) ||
314                (to.Find('<') != -1) ||
315                (to.Find('>') != -1) ||
316                (to.Find('|') != -1))
317        {
318                wxMessageBoxEx(_("Filenames may not contain any of the following characters: / * ? < > |"), _("Invalid filename"), wxICON_EXCLAMATION);
319                return false;
320        }
321
322        return wxRename(dir + from, dir + to) == 0;
323#endif
324}
325
326#ifdef __WXMSW__
327extern "C" typedef HRESULT (WINAPI *tSHGetKnownFolderPath)(const GUID& rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
328#else
329wxString ShellUnescape( wxString const& path )
330{
331        wxString ret;
332
333        const wxWX2MBbuf buf = path.mb_str();
334        if( buf && *buf ) {
335                wordexp_t p;
336                int res = wordexp( buf, &p, WRDE_NOCMD );
337                if( !res && p.we_wordc == 1 && p.we_wordv ) {
338                        ret = wxString(p.we_wordv[0], wxConvLocal);
339                }
340                wordfree(&p);
341        }
342        return ret;
343}
344#endif
345
346CLocalPath GetDownloadDir()
347{
348#ifdef __WXMSW__
349        // Unfortunately MinGW's import library lacks SHGetKnownFolderPath, even though it has it in its headers.
350        wxDynamicLibrary lib(_T("shell32.dll"));
351        if (lib.IsLoaded() && lib.HasSymbol(_T("SHGetKnownFolderPath"))) {
352                tSHGetKnownFolderPath pSHGetKnownFolderPath = (tSHGetKnownFolderPath)lib.GetSymbol(_T("SHGetKnownFolderPath"));
353
354                PWSTR path;
355                HRESULT result = pSHGetKnownFolderPath(FOLDERID_Downloads, 0, 0, &path);
356                if(result == S_OK) {
357                        wxString dir = path;
358                        CoTaskMemFree(path);
359                        return CLocalPath(dir);
360                }
361        }
362#elif !defined(__WXMAC__)
363        // Code copied from wx, but for downloads directory.
364        // Also, directory is now unescaped.
365        {
366                wxLogNull logNull;
367                wxString homeDir = wxFileName::GetHomeDir();
368                wxString configPath;
369                if (wxGetenv(wxT("XDG_CONFIG_HOME")))
370                        configPath = wxGetenv(wxT("XDG_CONFIG_HOME"));
371                else
372                        configPath = homeDir + wxT("/.config");
373                wxString dirsFile = configPath + wxT("/user-dirs.dirs");
374                if (wxFileExists(dirsFile)) {
375                        wxTextFile textFile;
376                        if (textFile.Open(dirsFile)) {
377                                size_t i;
378                                for (i = 0; i < textFile.GetLineCount(); i++) {
379                                        wxString line(textFile[i]);
380                                        int pos = line.Find(wxT("XDG_DOWNLOAD_DIR"));
381                                        if (pos != wxNOT_FOUND) {
382                                                wxString value = line.AfterFirst(wxT('='));
383                                                value = ShellUnescape(value);
384                                                if (!value.empty() && wxDirExists(value))
385                                                        return CLocalPath(value);
386                                                else
387                                                        break;
388                                        }
389                                }
390                        }
391                }
392        }
393#endif
394        return CLocalPath(wxStandardPaths::Get().GetDocumentsDir());
395}
Note: See TracBrowser for help on using the repository browser.