summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--network/wechat-universal/README25
-rw-r--r--network/wechat-universal/doinst.sh9
-rw-r--r--network/wechat-universal/resources/fake_dde-file-manager44
-rw-r--r--network/wechat-universal/resources/keyBlocker.cpp90
-rw-r--r--network/wechat-universal/resources/libuosdevicea.c42
-rw-r--r--network/wechat-universal/resources/wechat-universal.desktop23
-rw-r--r--network/wechat-universal/resources/wechat-universal.sh324
-rw-r--r--network/wechat-universal/slack-desc19
-rw-r--r--network/wechat-universal/wechat-universal.SlackBuild141
-rw-r--r--network/wechat-universal/wechat-universal.info10
10 files changed, 727 insertions, 0 deletions
diff --git a/network/wechat-universal/README b/network/wechat-universal/README
new file mode 100644
index 0000000000..4fc2aed195
--- /dev/null
+++ b/network/wechat-universal/README
@@ -0,0 +1,25 @@
+WeChat is a messaging program developed by Tencent.
+
+This build re-packages a binary deb file of an unofficial
+client, written by a company called Universal, producing a
+properitary Linux spin-off called Universal OS.
+
+Although the program itself is capable of running as a
+simple userspace program, due to privacy privacy concerns,
+and also due to pickiness of the program to its environment,
+this build installs a bubblewrap (bwrap) wrapper around it,
+which works asynchronously.
+
+That is, you need to start and terminate it with separate
+commands: /usr/bin/wechat-universal start & and
+/usr/bin/wechat-universal stop
+
+One more thing: the system tray icon is dysfunctional, so if
+you run the program, and then close the window, it will stay
+in the background, but there will be no way to restore the
+window. However, this build provides a work-around. If
+you run /usr/bin/wechat-universal start & once again after
+the program has already been started, it will raise the
+program window.
+
+Wechat "magical" screenshot tool is disabled.
diff --git a/network/wechat-universal/doinst.sh b/network/wechat-universal/doinst.sh
new file mode 100644
index 0000000000..65c7e2eeb9
--- /dev/null
+++ b/network/wechat-universal/doinst.sh
@@ -0,0 +1,9 @@
+if [ -x /usr/bin/update-desktop-database ]; then
+ /usr/bin/update-desktop-database -q usr/share/applications >/dev/null 2>&1
+fi
+
+if [ -e usr/share/icons/hicolor/icon-theme.cache ]; then
+ if [ -x /usr/bin/gtk-update-icon-cache ]; then
+ /usr/bin/gtk-update-icon-cache -f usr/share/icons/hicolor >/dev/null 2>&1
+ fi
+fi
diff --git a/network/wechat-universal/resources/fake_dde-file-manager b/network/wechat-universal/resources/fake_dde-file-manager
new file mode 100644
index 0000000000..7db5a6b68f
--- /dev/null
+++ b/network/wechat-universal/resources/fake_dde-file-manager
@@ -0,0 +1,44 @@
+#!/bin/bash
+# 7Ji: this is a heavy hack. WeChat, for whatever reason, calls dde-file-manager -> nautilus -> dolphin for
+# any file that it wants to open, instead of a sane dbus call, or xdg-open.
+# Basically, we pretend to be dde-file-manager and hijack the whole call chain in the first place, and
+# convert the not-so-smart dde-file-manager call to a sane dbus-call, or xdg-open if that fails.
+
+_show_item=''
+_item=''
+for _arg in "$@"; do
+ if [[ "${_arg}" == --show-item ]]; then
+ _show_item='y'
+ else
+ [[ -z "${_item}" ]] && _item="${_arg}"
+ fi
+done
+
+if [[ "${_show_item}" ]]; then
+ _path=$(readlink -f -- "${_item}") # Resolve this to absolute path that's same across host / guest
+ echo "Fake deepin file manager: dbus-send to open '${_path}' in file manager"
+ if [[ -d "${_path}" ]]; then
+ # WeChat pass both files and folders in the same way, if we use ShowItems for folders,
+ # it would open that folder's parent folder, which is not right.
+ _object=ShowFolders
+ _target=folders
+ else
+ _object=ShowItems
+ _target=items
+ fi
+ exec dbus-send --print-reply --dest=org.freedesktop.FileManager1 \
+ /org/freedesktop/FileManager1 \
+ org.freedesktop.FileManager1."${_object}" \
+ array:string:"file://${_path}" \
+ string:fake-dde-file-manager-show-"${_target}"
+ # We should not fall to here, but add a fallback anyway
+ echo "Fake deepin file manager: fallback: xdg-open to show '${_path}' in file manager"
+ exec xdg-open "${_path}"
+else
+ echo "Fake deepin file manager: xdg-open with args $@"
+ exec xdg-open "$@"
+fi
+# At this stage, it's either: dbus-send not found, or xdg-open not found, this should not happen
+# In whatever case, bail out
+echo "Fake deepin file manager: could not open any thing, original args: $@"
+exit 1 \ No newline at end of file
diff --git a/network/wechat-universal/resources/keyBlocker.cpp b/network/wechat-universal/resources/keyBlocker.cpp
new file mode 100644
index 0000000000..5030c5be4f
--- /dev/null
+++ b/network/wechat-universal/resources/keyBlocker.cpp
@@ -0,0 +1,90 @@
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <xcb/xcb.h>
+#include <unordered_set>
+
+struct pair_hash
+{
+public:
+ template <typename T, typename U>
+ auto operator()(const std::pair<T, U> &x) const
+ {
+ return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
+ }
+};
+
+static std::unordered_set<std::pair<int, unsigned int>, pair_hash> blocked_hotkeys;
+
+extern "C" int XGrabKey(
+ Display *display,
+ int keycode,
+ unsigned int modifiers,
+ Window grab_window,
+ Bool owner_events,
+ int pointer_mode,
+ int keyboard_mode)
+{
+
+ blocked_hotkeys.insert({keycode, modifiers});
+ printf("Hotkey registration blocked: keycode=%d modifiers=%d\n", keycode, modifiers);
+ return 0;
+}
+
+extern "C" int XUngrabKey(
+ Display *display,
+ int keycode,
+ unsigned int modifiers,
+ Window grab_window)
+{
+ blocked_hotkeys.erase({keycode, modifiers});
+ printf("Hotkey unregistration blocked: keycode=%d modifiers=%d\n", keycode, modifiers);
+ return 0;
+}
+
+static bool filter_xcb_event(xcb_connection_t *c, xcb_generic_event_t *event)
+{
+ if (event != nullptr)
+ {
+ if (event->response_type == XCB_KEY_PRESS)
+ {
+ auto key_press = reinterpret_cast<xcb_key_press_event_t *>(event);
+ if (blocked_hotkeys.find({key_press->detail, key_press->state}) != blocked_hotkeys.end())
+ {
+ return false;
+ }
+ }
+ else if (event->response_type == XCB_KEY_RELEASE)
+ {
+ auto key_release = reinterpret_cast<xcb_key_release_event_t *>(event);
+ if (blocked_hotkeys.find({key_release->detail, key_release->state}) != blocked_hotkeys.end())
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+extern "C" xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c)
+{
+ static auto origin = reinterpret_cast<decltype(&xcb_wait_for_event)>(dlsym(RTLD_NEXT, "xcb_wait_for_event"));
+ xcb_generic_event_t *event;
+ do
+ {
+ event = origin(c);
+ } while (!filter_xcb_event(c, event));
+ return event;
+}
+
+extern "C" xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c)
+{
+ static auto origin = reinterpret_cast<decltype(&xcb_poll_for_event)>(dlsym(RTLD_NEXT, "xcb_poll_for_event"));
+ xcb_generic_event_t *event;
+ do
+ {
+ event = origin(c);
+ } while (!filter_xcb_event(c, event));
+ return event;
+}
diff --git a/network/wechat-universal/resources/libuosdevicea.c b/network/wechat-universal/resources/libuosdevicea.c
new file mode 100644
index 0000000000..05fa6a7b65
--- /dev/null
+++ b/network/wechat-universal/resources/libuosdevicea.c
@@ -0,0 +1,42 @@
+/*
+ * licensestub - compat layer for libuosdevicea
+ * Copyright (C) 2024 Zephyr Lykos <self@mochaa.ws>
+ * Copyright (C) 2024 Guoxin "7Ji" Pu <pugokushin@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <string.h>
+
+#define declare_string_getter(suffix, constant) void uos_get_##suffix(char *const restrict out) { if (out) strcpy(out, constant); }
+
+declare_string_getter(mac, // MAC address with colon stripped
+ "000000000000")
+declare_string_getter(hddsninfo,
+ "SN")
+declare_string_getter(hwserial, // MD5 of hddsninfo
+ "92666505ce75444ee14be2ebc2f10a60")
+declare_string_getter(mb_sn, // hardcoded
+ "E50022008800015957007202c59a1a8-3981-2020-0810-204909000000")
+declare_string_getter(osver,
+ "UnionTech OS Desktop")
+declare_string_getter(licensetoken,
+ "djEsdjEsMSwyLDk5QUFFN0FBQVdRQjk5OFhKS0FIU1QyOTQsMTAsOTI2NjY1MDVjZTc1NDQ0ZWUxNGJlMmViYzJmMTBhNjAsQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE6ZjA3NjAwYzZkNmMyMDkyMDBkMzE5YzU2OThmNTc3MGRlYWY1NjAyZTY5MzUxZTczNjI2NjlhNzIyZTBkNTJiOTNhYzk0MmM3YTNkZTgxNjIxMmUwMDA1NTUwODg4N2NlMDQ4ODMyNTExY2JhNGFiMjdmYzlmZjMyYzFiNTYwNjMwZDI3ZDI2NmE5ZGIxZDQ0N2QxYjNlNTNlNTVlOTY1MmU5YTU4OGY0NWYzMTMwZDE0NDc4MTRhM2FmZjRlZGNmYmNkZjhjMmFiMDc5OWYwNGVmYmQ2NjdiNGYwYzEwNDhkYzExNjYwZWU1NTdlNTdmNzBlNjA1N2I0NThkMDgyOA==")
+
+int uos_is_active() {
+ return 0;
+}
diff --git a/network/wechat-universal/resources/wechat-universal.desktop b/network/wechat-universal/resources/wechat-universal.desktop
new file mode 100644
index 0000000000..74bb488ead
--- /dev/null
+++ b/network/wechat-universal/resources/wechat-universal.desktop
@@ -0,0 +1,23 @@
+[Desktop Entry]
+Comment=WeChat Universal
+Comment[zh_CN]=
+TryExec=/usr/lib/wechat-universal/wechat-universal.sh start
+Exec=/usr/lib/wechat-universal/wechat-universal.sh start %u
+Icon=wechat-universal
+Name=WeChat (Universal)
+Name[zh_CN]=微信 Universal
+Categories=Network;InstantMessaging;Chat;
+Terminal=false
+Type=Application
+Keywords=wechat;weixin;we;w;
+Keywords[zh_CN]=微;微信;wechat;weixin;we;
+StartupWMClass=wechat
+X-GNOME-SingleWindow=true
+X-SingleMainWindow=true
+Actions=quit;
+
+[Desktop Action quit]
+Name=Quit WeChat
+Name[zh_CN]=退出
+Exec=/usr/lib/wechat-universal/wechat-universal.sh stop
+Icon=application-exit
diff --git a/network/wechat-universal/resources/wechat-universal.sh b/network/wechat-universal/resources/wechat-universal.sh
new file mode 100644
index 0000000000..921e2d9332
--- /dev/null
+++ b/network/wechat-universal/resources/wechat-universal.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+#
+# wechat-universal.sh - wrapper for WeChat Universal
+# Copyright (C) 2024 Guoxin "7Ji" Pu <pugokushin@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+dbus_call() { # $1: dest, $2: object path, $3: method
+ local args=(dbus-send --session --dest="$1" --print-reply "${@:2}")
+ echo "D-Bus calling with: ${args[@]}" >&2
+ "${args[@]}"
+}
+
+# Based on: https://github.com/web1n/wechat-universal-flatpak/blob/91f5d0d246881077812881e800a22f5a02cea438/wechat.sh#L3
+notifier_get() {
+ local dbus_item
+ for dbus_item in $(
+ dbus_call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames |
+ sed -n 's/ string "\(org\.kde\.StatusNotifierItem.\+\)"/\1/p'
+ )
+ do
+ if dbus_call "${dbus_item}" \
+ /StatusNotifierItem \
+ org.freedesktop.DBus.Properties.Get \
+ string:org.kde.StatusNotifierItem \
+ string:Id |
+ grep -q 'string "wechat"'
+ then
+ echo "${dbus_item}"
+ return
+ fi
+ done
+}
+
+try_move_foreground() {
+ # Try to find existing WeChat window first and display it, before actually opening a new one
+ notifier_item=$(notifier_get)
+ if [[ "${notifier_item}" ]]; then
+ echo 'WeChat is already running, moving it to foreground'
+ # Based on: https://github.com/web1n/wechat-universal-flatpak/blob/91f5d0d246881077812881e800a22f5a02cea438/wechat.sh#L25
+ dbus_call "${notifier_item}" \
+ /StatusNotifierItem \
+ org.kde.StatusNotifierItem.Activate \
+ int32:0 \
+ int32:0
+ return $?
+ fi
+ return 1
+}
+
+try_start() {
+
+ # Data folder setup
+ # If user has declared a custom data dir, no need to query xdg for documents dir, but always resolve that to absolute path
+ if [[ "${WECHAT_DATA_DIR}" ]]; then
+ WECHAT_DATA_DIR=$(readlink -f -- "${WECHAT_DATA_DIR}")
+ else
+ XDG_DOCUMENTS_DIR="${XDG_DOCUMENTS_DIR:-$(xdg-user-dir DOCUMENTS)}"
+ if [[ -z "${XDG_DOCUMENTS_DIR}" ]]; then
+ echo 'Error: Failed to get XDG_DOCUMENTS_DIR, refuse to continue'
+ exit 1
+ fi
+ WECHAT_DATA_DIR="${XDG_DOCUMENTS_DIR}/WeChat_Data"
+ fi
+ echo "Using '${WECHAT_DATA_DIR}' as Wechat Data folder"
+ WECHAT_FILES_DIR="${WECHAT_DATA_DIR}/xwechat_files"
+ WECHAT_HOME_DIR="${WECHAT_DATA_DIR}/home"
+
+ # Runtime folder setup
+ XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$(xdg-user-dir RUNTIME)}"
+ if [[ -z "${XDG_RUNTIME_DIR}" ]]; then
+ echo 'Error: Failed to get XDG_RUNTIME_DIR, refuse to continue'
+ exit 1
+ fi
+ if [[ -z "${XAUTHORITY}" ]]; then
+ echo 'Warning: No XAUTHORITY set, runnning in no-X environment? Generating it'
+ export XAUTHORITY=$(mktemp "${XDG_RUNTIME_DIR}"/xauth_XXXXXX)
+ echo "Info: Generated XAUTHORITY at '${XAUTHORITY}'"
+ fi
+
+ # wechat-universal only supports xcb
+ export QT_QPA_PLATFORM=xcb \
+ QT_AUTO_SCREEN_SCALE_FACTOR=1 \
+ PATH="/sandbox:${PATH}"
+
+ if [[ -z "${IME_WORKAROUND}" || "${IME_WORKAROUND}" == 'auto' ]]; then
+ case "${XMODIFIERS}" in
+ *@im=fcitx*)
+ IME_WORKAROUND='fcitx'
+ ;;
+ *@im=ibus*)
+ IME_WORKAROUND='ibus'
+ ;;
+ esac
+ fi
+
+ case "${IME_WORKAROUND}" in
+ fcitx)
+ echo "IME workaround for fcitx applied"
+ export QT_IM_MODULE=fcitx \
+ GTK_IM_MODULE=fcitx
+ ;;
+ ibus)
+ echo "IME workaround for ibus applied"
+ export QT_IM_MODULE=ibus \
+ GTK_IM_MODULE=ibus \
+ IBUS_USE_PORTAL=1
+ ;;
+ esac
+
+ BWRAP_DEV_BINDS=()
+ for DEV_NODE in /dev/{nvidia{-uvm,ctl,*[0-9]},video*[0-9]}; do
+ [[ -e "${DEV_NODE}" ]] && BWRAP_DEV_BINDS+=(--dev-bind "${DEV_NODE}"{,})
+ done
+
+ # Custom exposed folders
+ # echo "Hint: Custom binds could either be declared in '~/.config/wechat-universal/binds.list', each line a path, absolute or relative to your HOME; or as argument \`--bind [custom bind]\`"
+ BWRAP_CUSTOM_BINDS=()
+ if [[ -f "${CUSTOM_BINDS_CONFIG}" ]]; then
+ mapfile -t CUSTOM_BINDS_PRESISTENT < "${CUSTOM_BINDS_CONFIG}"
+ fi
+ cd ~ # 7Ji: two chdir.3 should be cheaper than a lot of per-dir calculation
+ for CUSTOM_BIND in "${CUSTOM_BINDS_RUNTIME[@]}" "${CUSTOM_BINDS_PRESISTENT[@]}"; do
+ CUSTOM_BIND=$(readlink -f -- "${CUSTOM_BIND}")
+ echo "Custom bind: '${CUSTOM_BIND}'"
+ BWRAP_CUSTOM_BINDS+=(--bind "${CUSTOM_BIND}"{,})
+ done
+ cd - > /dev/null
+
+ DBUS_SESSION_BUS_PATH=''
+ if [[ "${DBUS_SESSION_BUS_ADDRESS}" ]]; then
+ DBUS_SESSION_BUS_PATH=$(echo "${DBUS_SESSION_BUS_ADDRESS}" | sed 's/^unix:\(.\+=.\+\)\?path=\(.\+\)\(,.\+=.\+\|$\)/\2/')
+ fi
+ if [[ -z "${DBUS_SESSION_BUS_PATH}" ]]; then
+ DBUS_SESSION_BUS_PATH="${XDG_RUNTIME_DIR}/bus"
+ echo "Failed to extract \$DBUS_SESSION_BUS_ADDRESS from \$DBUS_SESSION_BUS_ADDRESS (${DBUS_SESSION_BUS_ADDRESS}), using fallback ${DBUS_SESSION_BUS_PATH}"
+ fi
+
+ mkdir -p "${WECHAT_FILES_DIR}" "${WECHAT_HOME_DIR}"
+ ln -snf "${WECHAT_FILES_DIR}" "${WECHAT_HOME_DIR}/xwechat_files"
+
+ BWRAP_ARGS=(
+ # Drop privileges
+ --unshare-all
+ --share-net
+ --cap-drop ALL
+# --die-with-parent
+
+ # /
+ --ro-bind /bin{,}
+ --ro-bind /sbin{,}
+ --ro-bind /lib{,}
+ --ro-bind /lib64{,}
+ # /usr
+ --ro-bind /usr{,}
+
+ --bind /bin/true /usr/bin/lsblk
+
+ # /sandbox
+ --ro-bind /usr/lib64/flatpak-xdg-utils/xdg-open /sandbox/xdg-open
+ --ro-bind /usr/lib64/wechat-universal/bin/dde-file-manager /sandbox/dde-file-manager
+ --ro-bind /sbin/ip /sandbox/ip
+ # /dev
+ --dev /dev
+ --dev-bind /dev/dri{,}
+ --tmpfs /dev/shm
+
+ # /proc
+ --proc /proc
+
+ # /etc
+ --ro-bind /etc/machine-id{,}
+ --ro-bind /etc/passwd{,}
+ --ro-bind /etc/nsswitch.conf{,}
+ --ro-bind /etc/resolv.conf{,}
+ --ro-bind /etc/localtime{,}
+ --ro-bind-try /etc/fonts{,}
+
+ # /sys
+ --dir /sys/dev # hack for Intel / AMD graphics, mesa calling virtual nodes needs /sys/dev being 0755
+ --ro-bind /sys/dev/char{,}
+ --ro-bind /sys/devices{,}
+
+ # /tmp
+ --tmpfs /tmp
+
+ # /opt
+ --ro-bind /opt/wechat-universal{,}
+
+ # license fixups in various places
+ --ro-bind /usr/lib64/wechat-universal/license/ /usr/lib/license
+ --ro-bind /usr/lib64/wechat-universal/etc/lsb-release /etc/lsb-release
+
+ # /home
+ --bind "${WECHAT_HOME_DIR}" "${HOME}"
+ --bind "${WECHAT_FILES_DIR}"{,}
+ --bind-try "${HOME}/.pki"{,}
+ --ro-bind-try "${HOME}/.fontconfig"{,}
+ --ro-bind-try "${HOME}/.fonts"{,}
+ --ro-bind-try "${HOME}/.config/fontconfig"{,}
+ --ro-bind-try "${HOME}/.local/share/fonts"{,}
+ --ro-bind-try "${HOME}/.icons"{,}
+ --ro-bind-try "${HOME}/.local/share/icons"{,}
+
+ # /run
+ --dev-bind /run/dbus{,}
+ --ro-bind-try /run/systemd/userdb{,}
+ --ro-bind-try "${XAUTHORITY}"{,}
+# --ro-bind "${DBUS_SESSION_BUS_PATH}"{,}
+ --ro-bind "${XDG_RUNTIME_DIR}/pulse"{,}
+ --setenv DBUS_SESSION_BUS_PATH "${DBUS_SESSION_BUS_PATH}"
+ --setenv LD_PRELOAD "/usr/lib64/wechat-universal/keyBlocker.so:${LD_PRELOAD}"
+ )
+
+ exec bwrap "${BWRAP_ARGS[@]}" "${BWRAP_CUSTOM_BINDS[@]}" "${BWRAP_DEV_BINDS[@]}" /opt/wechat-universal/wechat "$@"
+ echo "Error: Failed to exec bwrap, rerun this script with 'bash -x $0' to show the full command history"
+ return 1
+}
+
+bwrap_start() {
+ IFS=':' read -r -a CUSTOM_BINDS_RUNTIME <<< "${CUSTOM_BINDS}"
+ if [[ -z "${CUSTOM_BINDS_CONFIG}" && ! -v CUSTOM_BINDS_CONFIG ]]; then
+ CUSTOM_BINDS_CONFIG=~/.config/wechat-universal/binds.list
+ fi
+ # Parsing arguments, for any option, argument > environment
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ '--data')
+ WECHAT_DATA_DIR="$2"
+ shift
+ ;;
+ '--bind')
+ CUSTOM_BINDS_RUNTIME+=("$2")
+ shift
+ ;;
+ '--binds-config')
+ CUSTOM_BINDS_CONFIG="$2"
+ shift
+ ;;
+ '--ime')
+ IME_WORKAROUND="$2"
+ shift
+ ;;
+ '--help')
+ if [[ "${LANG}" == zh_CN* ]]; then
+ echo "$0 (--data [微信数据文件夹]) (--bind [自定义绑定挂载] (--bind ...))) (--ime [输入法]) (--help)"
+ echo
+ printf ' --%s\t%s\n' \
+ 'data [微信数据文件夹]' '微信数据文件夹的路径,绝对路径,或相对于用户HOME的相对路径。 默认:~/文档/Wechat_Data;环境变量: WECHAT_DATA_DIR' \
+ 'bind [自定义绑定挂载]' '自定义的绑定挂载,可被声明多次,绝对路径,或相对于用户HOME的相对路径。环境变量: CUSTOM_BINDS (用冒号:分隔,与PATH相似)' \
+ 'binds-config [文件]' '以每行一个的方式列明应被绑定挂载的路径的纯文本配置文件,每行定义与--bind一致。默认:~/.config/wechat-universal/binds.list;环境变量:CUSTOM_BINDS_CONFIG' \
+ 'ime [输入法名称或特殊值]' '应用输入法对应环境变量修改,可支持:fcitx (不论是否为5), ibus,特殊值:none不应用,auto自动判断。默认: auto;环境变量: IME_WORKAROUND'\
+ 'help' ''
+ echo
+ echo "命令行参数比环境变量优先级更高,如果命令行参数与环境变量皆为空,则使用默认值"
+ else
+ echo "$0 (--data [wechat data]) (--bind [custom bind] (--bind ...))) (--ime [ime]) (--help)"
+ echo
+ printf ' --%s\t%s\n' \
+ 'data [wechat data]' 'Path to Wechat_Data folder, absolute or relative to user home, default: ~/Documents/Wechat_Data, as environment: WECHAT_DATA_DIR' \
+ 'bind [custom bind]' 'Custom bindings, could be specified multiple times, absolute or relative to user home, as environment: CUSTOM_BINDS (colon ":" seperated like PATH)' \
+ 'binds-config [file]' 'Path to text file that contains one --bind value per line, default: ~/.config/wechat-universal/binds.list, as environment: CUSTOM_BINDS_CONFIG'\
+ 'ime [input method]' 'Apply IME-specific workaround, support: fcitx (also for 5), ibus, default: auto, as environment: IME_WORKAROUND'\
+ 'help' ''
+ echo
+ echo "Arguments take priority over environment, if both argument and environment are empty, the default value would be used"
+ fi
+ return 0
+ ;;
+ esac
+ shift
+ done
+ if try_move_foreground; then
+ return 0
+ else
+ try_start "$@"
+ return $?
+ fi
+}
+
+bwrap_stop() {
+ # Try to find existing WeChat window first and display it, before actually opening a new one
+ notifier_item=$(notifier_get)
+ [[ -z "${notifier_item}" ]] && return
+ echo 'Stopping running WeChat instance'
+ # Based on: https://github.com/web1n/wechat-universal-flatpak/blob/91f5d0d246881077812881e800a22f5a02cea438/wechat.sh#L35
+ dbus_call "${notifier_item}" \
+ /MenuBar \
+ com.canonical.dbusmenu.Event \
+ int32:1 \
+ string:clicked \
+ variant:string:'Quit WeChat' \
+ uint32:0
+}
+
+command="$1"
+case "$command" in
+ 'stop')
+ shift
+ bwrap_stop "$@"
+ ;;
+ 'start')
+ shift
+ bwrap_start "$@"
+ ;;
+ *)
+ echo "Unknown command '${command}', allowed: start, stop"
+ exit 1
+ ;;
+esac
+exit $?
diff --git a/network/wechat-universal/slack-desc b/network/wechat-universal/slack-desc
new file mode 100644
index 0000000000..5328c01718
--- /dev/null
+++ b/network/wechat-universal/slack-desc
@@ -0,0 +1,19 @@
+# HOW TO EDIT THIS FILE:
+# The "handy ruler" below makes it easier to edit a package description.
+# Line up the first '|' above the ':' following the base package name, and
+# the '|' on the right side marks the last column you can put a character in.
+# You must make exactly 11 lines for the formatting to be correct. It's also
+# customary to leave one space after the ':' except on otherwise blank lines.
+
+ |-----handy-ruler------------------------------------------------------|
+wechat-universal: wechat-universal (unofficial wechat from the Universal OS Store)
+wechat-universal:
+wechat-universal: Universal is the name of a company which developer a Qt port of
+wechat-universal: WeChat.
+wechat-universal:
+wechat-universal: WeChat is a messaging program from Tencent.
+wechat-universal:
+wechat-universal:
+wechat-universal:
+wechat-universal:
+wechat-universal:
diff --git a/network/wechat-universal/wechat-universal.SlackBuild b/network/wechat-universal/wechat-universal.SlackBuild
new file mode 100644
index 0000000000..92780577da
--- /dev/null
+++ b/network/wechat-universal/wechat-universal.SlackBuild
@@ -0,0 +1,141 @@
+#!/bin/bash
+
+# Slackware build script for wechat-universal
+
+# Copyright 2024, Lockywolf
+# All rights reserved.
+#
+# Redistribution and use of this script, with or without modification, is
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of this script must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+cd $(dirname $0) ; CWD=$(pwd)
+
+PRGNAM=wechat-universal
+VERSION=${VERSION:-1.0.0.242}
+BUILD=${BUILD:-1}
+TAG=${TAG:-_SBo}
+PKGTYPE=${PKGTYPE:-tgz}
+
+content_disposition_prefix=9d7b342b1a654ce5a63981a46aa64d81
+
+if [ -z "$ARCH" ]; then
+ case "$( uname -m )" in
+ i?86) ARCH=i586 ;;
+ arm*) ARCH=arm ;;
+ *) ARCH=$( uname -m ) ;;
+ esac
+fi
+
+if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
+ echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
+ exit 0
+fi
+
+TMP=${TMP:-/tmp/SBo}
+PKG=$TMP/package-$PRGNAM
+OUTPUT=${OUTPUT:-/tmp}
+
+if [ "$ARCH" = "i586" ]; then
+ SLKCFLAGS="-O2 -march=i586 -mtune=i686"
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" = "i686" ]; then
+ SLKCFLAGS="-O2 -march=i686 -mtune=i686"
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" = "x86_64" ]; then
+ SLKCFLAGS="-O2 -fPIC"
+ LIBDIRSUFFIX="64"
+elif [ "$ARCH" = "aarch64" ]; then
+ SLKCFLAGS="-O2 -fPIC"
+ LIBDIRSUFFIX="64"
+else
+ SLKCFLAGS="-O2"
+ LIBDIRSUFFIX=""
+fi
+
+set -e
+
+rm -rf $PKG
+mkdir -p $TMP $PKG $OUTPUT
+cd $TMP
+rm -rf $PKG-build
+mkdir $PKG-build
+cd $PKG-build
+#cp $CWD/com.tencent.wechat_${VERSION}_amd64.deb ./package.deb || cp $CWD/$content_disposition_prefix.deb ./package.deb
+#cp $CWD/wechat-beta_${VERSION}_amd64.rpm ./
+#rpm2targz ./*rpm
+#tar xvf ./*.tar.gz
+rpm2cpio $CWD/wechat-beta_${VERSION}_amd64.rpm | cpio -id
+
+chown -R root:root .
+find -L . \
+ \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
+ -o -perm 511 \) -exec chmod 755 {} \; -o \
+ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
+ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} +
+mkdir -p $PKG
+
+
+#rm ./opt/apps/com.tencent.wechat/files/libuosdevicea.so
+mkdir -p $PKG/opt
+#mv ./opt/apps/com.tencent.wechat/files $PKG/opt/$PRGNAM
+mv ./opt/wechat-beta $PKG/opt/$PRGNAM
+
+install -DTm644 "$PKG"/opt/$PRGNAM/icons/wechat.png $PKG/"usr/share/icons/hicolor/256x256/apps/$PRGNAM.png"
+# for res in 16 32 48 64 128 256; do
+# install -Dm644 \
+# ./opt/apps/com.tencent.wechat/entries/icons/hicolor/${res}x${res}/apps/com.tencent.wechat.png \
+# $PKG/usr/share/icons/hicolor/${res}x${res}/apps/$PRGNAM.png
+# done
+#rm -rf ./opt/apps
+
+
+
+install -d -m 755 $PKG/usr/lib/license/
+install -d -m 755 $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/license/
+printf '\n' > $PKG/usr/lib/license/.do-not-delete
+gcc ${SLKCFLAGS} -fPIC -shared $CWD/resources/libuosdevicea.c -o $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/license/libuosdevicea.so
+strip --strip-unneeded $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/license/libuosdevicea.so
+g++ ${SLKCFLAGS} -fPIC -shared $CWD/resources/keyBlocker.cpp -o $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/keyBlocker.so
+strip --strip-unneeded $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/keyBlocker.so
+
+printf '%s\n' 'DISTRIB_ID=uos' |
+ install -Dm755 /dev/stdin $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/etc/lsb-release
+
+
+install -Dm755 $CWD/resources/wechat-universal.sh $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/
+
+install -Dm755 $CWD/resources/fake_dde-file-manager $PKG/usr/lib$LIBDIRSUFFIX/$PRGNAM/bin/dde-file-manager
+
+install -Dm644 $CWD/resources/$PRGNAM.desktop "$PKG"/usr/share/applications/$PRGNAM.desktop
+
+sed -i "s|/usr/lib|/usr/lib$LIBDIRSUFFIX|g" "$PKG"/usr/share/applications/$PRGNAM.desktop
+
+printf '%s\n' '#!/bin/bash' 'exec /usr/lib'$LIBDIRSUFFIX'/'"$PRGNAM"'/wechat-universal.sh "$@"' | install -DTm 755 /dev/stdin $PKG/usr/bin/$PRGNAM
+( mkdir -p $PKG/usr/bin
+ cd $PKG/usr/bin
+ ln -srf ../../bin/lsblk ./
+)
+
+mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
+cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
+
+mkdir -p $PKG/install
+cat $CWD/slack-desc > $PKG/install/slack-desc
+cat $CWD/doinst.sh > $PKG/install/doinst.sh
+
+cd $PKG
+/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE
diff --git a/network/wechat-universal/wechat-universal.info b/network/wechat-universal/wechat-universal.info
new file mode 100644
index 0000000000..b55305e594
--- /dev/null
+++ b/network/wechat-universal/wechat-universal.info
@@ -0,0 +1,10 @@
+PRGNAM="wechat-universal"
+VERSION="1.0.0.242"
+HOMEPAGE="https://bbs.deepin.org/post/269371"
+DOWNLOAD="UNSUPPORTED"
+MD5SUM=""
+DOWNLOAD_x86_64="https://mirrors.opencloudos.tech/opencloudos/9.2/extras/x86_64/os/Packages/wechat-beta_1.0.0.242_amd64.rpm"
+MD5SUM_x86_64="c1d88d9f8503113cba6f4f8e256153ef"
+REQUIRES="bubblewrap flatpak-xdg-utils"
+MAINTAINER="Lockywolf"
+EMAIL="for_sbo.wechat-qt_2024-10-21@lockywolf.net"