--- a/gpupdate/gpoa/gpt/shortcuts.py 2025-04-03 11:13:27.000000000 +0400 +++ b/gpupdate/gpoa/gpt/shortcuts.py 2025-09-18 15:22:48.960748629 +0400 @@ -23,10 +23,15 @@ from xdg.DesktopEntry import DesktopEntry import json -from util.windows import transform_windows_path +from util.windows import ( + transform_windows_path, + expand_windows_var +) from util.xml import get_xml_root from util.paths import get_desktop_files_directory from .dynamic_attributes import DynamicAttributes +import os +import shlex class TargetType(Enum): FILESYSTEM = 'FILESYSTEM' @@ -71,23 +76,56 @@ ''' shortcuts = list() + def looks_like_url(p): + if not p: + return False + lower = p.lower() + return lower.startswith('http://') or lower.startswith('https://') or lower.startswith('ftp://') or lower.startswith('file://') #or lower.startswith('smb://') + for link in get_xml_root(shortcuts_file): props = link.find('Properties') # Location of the link itself dest = props.get('shortcutPath') # Location where link should follow path = transform_windows_path(props.get('targetPath')) + path = expand_windows_var(path) + # Location icon + path_icon = transform_windows_path(props.get('iconPath')) + path_icon = expand_windows_var(path_icon) + if path_icon.startswith('//'): + path_icon = f'{shlex.quote("smb://" + path_icon.lstrip("/"))}' # Arguments to executable file arguments = props.get('arguments') # URL or FILESYSTEM target_type = get_ttype(props.get('targetType')) - sc = shortcut(dest, path, arguments, link.get('name'), props.get('action'), target_type) + # Decide Exec behavior: + # - If target is a URL (starts with sheme://) or target_type != FILESYSTEM -> yse xdg-open + # - If target is a filesystem path but not executable -> yse xdg-open + exec_cmd = path # default: run path directly + + if path: + # If URL-like -> use xdg-open + if path.startswith('//'): + exec_cmd = f'{shlex.quote("smb://" + path.lstrip("/"))}' + elif looks_like_url(path): + exec_cmd = f'xdg-open {shlex.quote(path)}' + else: + # For filesystemc targets: if not executable, use xdg-open + try: + # os.access needs a real filesystem path; ignore if it's not absolute/exists + if os.path.isabs(path) and os.path.exists(path): + if not os.access(path, os.X_OK): + exec_cmd = f'xdg-open {shlex.quote(path)}' + except Exception: + pass + + sc = shortcut(dest, exec_cmd, arguments, link.get('name'), props.get('action'), target_type) sc.set_changed(link.get('changed')) sc.set_clsid(link.get('clsid')) sc.set_guid(link.get('uid')) sc.set_usercontext(link.get('userContext', False)) - sc.set_icon(props.get('iconPath')) + sc.set_icon(path_icon) if props.get('comment'): sc.set_comment(props.get('comment'))