UPD: Use our own quoting of parameters from libmime.

This commit is contained in:
cobines 2010-02-10 11:13:16 +00:00
commit fd280e0afe
5 changed files with 121 additions and 159 deletions

Binary file not shown.

View file

@ -67,144 +67,3 @@ VFSAppDesktop mime_get_desktop_entry( const char* file_name )
return app;
}
/*
* Parse Exec command line of app desktop file, and translate
* it into a real command which can be passed to g_spawn_command_line_async().
* file_list is a null-terminated file list containing full
* paths of the files passed to app.
* returned char* should be freed when no longer needed.
*/
char* translate_app_exec_to_command_line( const VFSAppDesktop* app,
GList* file_list )
{
char* file;
GList* l;
gchar *tmp;
const char * pexec;
GString* cmd = g_string_new("");
gboolean add_files = FALSE;
for( pexec = app->exec; *pexec; ++pexec )
{
if( *pexec == '%' )
{
++pexec;
switch( *pexec )
{
case 'U':
for( l = file_list; l; l = l->next )
{
tmp = g_filename_to_uri( (char*)l->data, NULL, NULL );
file = g_shell_quote( tmp );
g_free( tmp );
g_string_append( cmd, file );
g_string_append_c( cmd, ' ' );
g_free( file );
}
add_files = TRUE;
break;
case 'u':
if( file_list && file_list->data )
{
file = (char*)file_list->data;
tmp = g_filename_to_uri( file, NULL, NULL );
file = g_shell_quote( tmp );
g_free( tmp );
g_string_append( cmd, file );
g_free( file );
add_files = TRUE;
}
break;
case 'F':
case 'N':
for( l = file_list; l; l = l->next )
{
file = (char*)l->data;
tmp = g_shell_quote( file );
g_string_append( cmd, tmp );
g_string_append_c( cmd, ' ' );
g_free( tmp );
}
add_files = TRUE;
break;
case 'f':
case 'n':
if( file_list && file_list->data )
{
file = (char*)file_list->data;
tmp = g_shell_quote( file );
g_string_append( cmd, tmp );
g_free( tmp );
add_files = TRUE;
}
break;
case 'D':
for( l = file_list; l; l = l->next )
{
tmp = g_path_get_dirname( (char*)l->data );
file = g_shell_quote( tmp );
g_free( tmp );
g_string_append( cmd, file );
g_string_append_c( cmd, ' ' );
g_free( file );
}
add_files = TRUE;
break;
case 'd':
if( file_list && file_list->data )
{
tmp = g_path_get_dirname( (char*)file_list->data );
file = g_shell_quote( tmp );
g_free( tmp );
g_string_append( cmd, file );
g_free( tmp );
add_files = TRUE;
}
break;
case 'c':
g_string_append( cmd, app->disp_name );
break;
case 'i':
/* Add icon name */
if( app->icon_name )
{
g_string_append( cmd, "--icon " );
g_string_append( cmd, app->icon_name );
}
break;
case 'k':
/* Location of the desktop file */
break;
case 'v':
/* Device name */
break;
case '%':
g_string_append_c ( cmd, '%' );
break;
case '\0':
goto _finish;
break;
}
}
else /* not % escaped part */
{
g_string_append_c ( cmd, *pexec );
}
}
_finish:
if( ! add_files )
{
g_string_append_c ( cmd, ' ' );
for( l = file_list; l; l = l->next )
{
file = (char*)l->data;
tmp = g_shell_quote( file );
g_string_append( cmd, tmp );
g_string_append_c( cmd, ' ' );
g_free( tmp );
}
}
return g_string_free( cmd, FALSE );
}

Binary file not shown.

View file

@ -36,7 +36,7 @@ uses
type
PDesktopFileEntry = ^TDesktopFileEntry;
TDesktopFileEntry = record
FileName: String;
DesktopFilePath: String;
MimeType: String;
DisplayName: String;
Comment: String;
@ -56,7 +56,7 @@ function GetDesktopEntries(FileNames: TStringList): TList;
implementation
uses
uDCUtils, uIconTheme;
uDCUtils, uIconTheme, uClipboard;
type
PCDesktopFileEntry = ^TCDesktopFileEntry;
@ -78,17 +78,127 @@ function mime_type_get_by_filename(filename: PChar; stat: Pointer) : PChar; cdec
function mime_type_get_actions(mimeType: PChar): PPChar; cdecl; external libmime;
function mime_type_locate_desktop_file(DirectoryToCheck: PChar; DesktopFileId: PChar): PChar; cdecl; external libmime;
function mime_get_desktop_entry(DesktopFileName: PChar): TCDesktopFileEntry; cdecl; external libmime;
function translate_app_exec_to_command_line(const app: PCDesktopFileEntry; file_list: PGList): PChar; cdecl; external libmime;
function TranslateAppExecToCmdLine(const entry: PDesktopFileEntry;
const fileList: TStringList): String;
var
StartPos: Integer = 1;
CurPos: Integer = 1;
i: Integer;
filesAdded: Boolean = False;
begin
// The .desktop standard does not recommend using % parameters inside quotes
// in the Exec entry (the behaviour is undefined), so all those parameters
// can be quoted using any method.
Result := '';
while CurPos <= Length(entry^.ExecWithParams) do
begin
if entry^.ExecWithParams[CurPos] = '%' then
begin
Result := Result + Copy(entry^.ExecWithParams, StartPos, CurPos - StartPos);
Inc(CurPos);
if CurPos <= Length(entry^.ExecWithParams) then
case entry^.ExecWithParams[CurPos] of
'U':
begin
for i := 0 to fileList.Count - 1 do
begin
if i <> 0 then
Result := Result + ' ';
Result := Result + QuoteStr(URIEncode(fileList[i]));
end;
filesAdded := True;
end;
'u':
if fileList.Count > 0 then
begin
Result := Result + QuoteStr(URIEncode(fileList[0]));
filesAdded := True;
end;
'F':
begin
for i := 0 to fileList.Count - 1 do
begin
if i <> 0 then
Result := Result + ' ';
Result := Result + QuoteStr(fileList[i]);
end;
filesAdded := True;
end;
'f':
if fileList.Count > 0 then
begin
Result := Result + QuoteStr(fileList[0]);
filesAdded := True;
end;
'N': // deprecated
begin
for i := 0 to fileList.Count - 1 do
begin
if i <> 0 then
Result := Result + ' ';
Result := Result + QuoteStr(fileList[i]);
end;
filesAdded := True;
end;
'n': // deprecated
if fileList.Count > 0 then
begin
Result := Result + QuoteStr(fileList[0]);
filesAdded := True;
end;
'D': // deprecated
begin
for i := 0 to fileList.Count - 1 do
begin
if i <> 0 then
Result := Result + ' ';
Result := Result + QuoteStr(ExtractFilePath(fileList[i]));
end;
filesAdded := True;
end;
'd': // deprecated
if fileList.Count > 0 then
begin
Result := Result + QuoteStr(ExtractFilePath(fileList[0]));
filesAdded := True;
end;
'i':
if entry^.IconName <> '' then
Result := Result + '--icon ' + QuoteStr(entry^.IconName);
'c':
Result := Result + QuoteStr(entry^.DisplayName);
'k':
Result := Result + QuoteStr(entry^.DesktopFilePath);
'%':
Result := Result + '%';
end;
Inc(CurPos);
StartPos := CurPos;
end
else
Inc(CurPos);
end;
if (StartPos <> CurPos) then
Result := Result + Copy(entry^.ExecWithParams, StartPos, CurPos - StartPos);
if not filesAdded then
begin
for i := 0 to fileList.Count - 1 do
Result := Result + ' ' + QuoteStr(fileList[i]);
end;
end;
function GetDesktopEntries(FileNames: TStringList): TList;
var
mimeType: PChar;
actions: PPChar;
desktopFile: PChar;
i, j: Integer;
i: Integer;
app: TCDesktopFileEntry;
list: PGList = nil;
exec: PChar;
Entry: PDesktopFileEntry;
begin
if FileNames.Count = 0 then
@ -107,23 +217,21 @@ begin
i := 0;
while (actions[i] <> nil) and (actions[i] <> '') do
begin
for j := 0 to FileNames.Count - 1 do
begin
list := g_list_append(list, PChar(FileNames[j]));
end;
desktopFile := mime_type_locate_desktop_file(nil, actions[i]);
app := mime_get_desktop_entry(desktopFile);
exec := translate_app_exec_to_command_line(@app, list);
New(Entry);
Entry^.DesktopFilePath := StrPas(desktopFile);
Entry^.MimeType := StrPas(mimeType);
Entry^.DisplayName := StrPas(app.DisplayName);
Entry^.Comment := StrPas(app.Comment);
Entry^.Exec := StrPas(Exec);
Entry^.ExecWithParams := StrPas(app.Exec);
Entry^.IconName := StrPas(app.IconName);
Entry^.Terminal := app.Terminal;
Entry^.Hidden := app.Hidden;
// Set Exec as last because it uses other fields of Entry.
Entry^.Exec := TranslateAppExecToCmdLine(Entry, Filenames);
{
Some icon names in .desktop files are specified with an extension,
@ -135,14 +243,11 @@ begin
Result.Add(Entry);
g_free(exec);
g_free(desktopFile);
g_free(app.DisplayName);
g_free(app.Comment);
g_free(app.Exec);
g_free(app.IconName);
g_list_free(list);
list := nil;
i := i + 1;
end;

View file

@ -210,8 +210,6 @@ var
ExecCmd: String;
begin
ExecCmd := (Sender as TMenuItem).Hint;
// Special case for file names containing ' char
ExecCmd:= StringReplace(ExecCmd, '''\''''', '\''', [rfReplaceAll]);
ExecCmdFork(ExecCmd);
end;
{$ENDIF}