|
Lines 23-32
Link Here
|
| 23 |
from xdg.DesktopEntry import DesktopEntry |
23 |
from xdg.DesktopEntry import DesktopEntry |
| 24 |
import json |
24 |
import json |
| 25 |
|
25 |
|
| 26 |
from util.windows import transform_windows_path |
26 |
from util.windows import ( |
|
|
27 |
transform_windows_path, |
| 28 |
expand_windows_var |
| 29 |
) |
| 27 |
from util.xml import get_xml_root |
30 |
from util.xml import get_xml_root |
| 28 |
from util.paths import get_desktop_files_directory |
31 |
from util.paths import get_desktop_files_directory |
| 29 |
from .dynamic_attributes import DynamicAttributes |
32 |
from .dynamic_attributes import DynamicAttributes |
|
|
33 |
import os |
| 34 |
import shlex |
| 30 |
|
35 |
|
| 31 |
class TargetType(Enum): |
36 |
class TargetType(Enum): |
| 32 |
FILESYSTEM = 'FILESYSTEM' |
37 |
FILESYSTEM = 'FILESYSTEM' |
|
Lines 71-93
Link Here
|
| 71 |
''' |
76 |
''' |
| 72 |
shortcuts = list() |
77 |
shortcuts = list() |
| 73 |
|
78 |
|
|
|
79 |
def looks_like_url(p): |
| 80 |
if not p: |
| 81 |
return False |
| 82 |
lower = p.lower() |
| 83 |
return lower.startswith('http://') or lower.startswith('https://') or lower.startswith('ftp://') or lower.startswith('file://') #or lower.startswith('smb://') |
| 84 |
|
| 74 |
for link in get_xml_root(shortcuts_file): |
85 |
for link in get_xml_root(shortcuts_file): |
| 75 |
props = link.find('Properties') |
86 |
props = link.find('Properties') |
| 76 |
# Location of the link itself |
87 |
# Location of the link itself |
| 77 |
dest = props.get('shortcutPath') |
88 |
dest = props.get('shortcutPath') |
| 78 |
# Location where link should follow |
89 |
# Location where link should follow |
| 79 |
path = transform_windows_path(props.get('targetPath')) |
90 |
path = transform_windows_path(props.get('targetPath')) |
|
|
91 |
path = expand_windows_var(path) |
| 92 |
# Location icon |
| 93 |
path_icon = transform_windows_path(props.get('iconPath')) |
| 94 |
path_icon = expand_windows_var(path_icon) |
| 95 |
if path_icon.startswith('//'): |
| 96 |
path_icon = f'{shlex.quote("smb://" + path_icon.lstrip("/"))}' |
| 80 |
# Arguments to executable file |
97 |
# Arguments to executable file |
| 81 |
arguments = props.get('arguments') |
98 |
arguments = props.get('arguments') |
| 82 |
# URL or FILESYSTEM |
99 |
# URL or FILESYSTEM |
| 83 |
target_type = get_ttype(props.get('targetType')) |
100 |
target_type = get_ttype(props.get('targetType')) |
| 84 |
|
101 |
|
| 85 |
sc = shortcut(dest, path, arguments, link.get('name'), props.get('action'), target_type) |
102 |
# Decide Exec behavior: |
|
|
103 |
# - If target is a URL (starts with sheme://) or target_type != FILESYSTEM -> yse xdg-open |
| 104 |
# - If target is a filesystem path but not executable -> yse xdg-open |
| 105 |
exec_cmd = path # default: run path directly |
| 106 |
|
| 107 |
if path: |
| 108 |
# If URL-like -> use xdg-open |
| 109 |
if path.startswith('//'): |
| 110 |
exec_cmd = f'{shlex.quote("smb://" + path.lstrip("/"))}' |
| 111 |
elif looks_like_url(path): |
| 112 |
exec_cmd = f'xdg-open {shlex.quote(path)}' |
| 113 |
else: |
| 114 |
# For filesystemc targets: if not executable, use xdg-open |
| 115 |
try: |
| 116 |
# os.access needs a real filesystem path; ignore if it's not absolute/exists |
| 117 |
if os.path.isabs(path) and os.path.exists(path): |
| 118 |
if not os.access(path, os.X_OK): |
| 119 |
exec_cmd = f'xdg-open {shlex.quote(path)}' |
| 120 |
except Exception: |
| 121 |
pass |
| 122 |
|
| 123 |
sc = shortcut(dest, exec_cmd, arguments, link.get('name'), props.get('action'), target_type) |
| 86 |
sc.set_changed(link.get('changed')) |
124 |
sc.set_changed(link.get('changed')) |
| 87 |
sc.set_clsid(link.get('clsid')) |
125 |
sc.set_clsid(link.get('clsid')) |
| 88 |
sc.set_guid(link.get('uid')) |
126 |
sc.set_guid(link.get('uid')) |
| 89 |
sc.set_usercontext(link.get('userContext', False)) |
127 |
sc.set_usercontext(link.get('userContext', False)) |
| 90 |
sc.set_icon(props.get('iconPath')) |
128 |
sc.set_icon(path_icon) |
| 91 |
if props.get('comment'): |
129 |
if props.get('comment'): |
| 92 |
sc.set_comment(props.get('comment')) |
130 |
sc.set_comment(props.get('comment')) |
| 93 |
|
131 |
|