Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package tail-tray for openSUSE:Factory 
checked in at 2025-05-07 19:22:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tail-tray (Old)
 and      /work/SRC/openSUSE:Factory/.tail-tray.new.30101 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tail-tray"

Wed May  7 19:22:22 2025 rev:16 rq:1275319 version:0.2.22

Changes:
--------
--- /work/SRC/openSUSE:Factory/tail-tray/tail-tray.changes      2025-04-29 
16:42:03.318411053 +0200
+++ /work/SRC/openSUSE:Factory/.tail-tray.new.30101/tail-tray.changes   
2025-05-07 19:22:31.894411313 +0200
@@ -1,0 +2,28 @@
+Wed May 07 15:43:17 UTC 2025 - Johannes Kastl 
<opensuse_buildserv...@ojkastl.de>
+
+- Update to version 0.2.22:
+  * What's new in this release
+    This release has some new Notification handling if you are
+    building and running it for KDE Plasma 6 or later, using this
+    feature will give you fancy notification integrations into your
+    Plasma Desktop.
+    It also comes with the regular flow of bug fixes, most notable
+    are fixes around potential segfaults, that hopefully should be
+    fully resolved now
+  * Commits
+    - [Issue #36] - Use KNotification framework for notifications
+      (#73) (Marcus Grenängen) #73
+    - Test to build on kdeneon/plasma:user (Marcus Grenängen)
+    - Revert "Test to build on kdeneon/plasma:user" (Marcus
+      Grenängen)
+    - gh runner (Marcus Grenängen)
+    - Revert "gh runner" (Marcus Grenängen)
+    - KNOTIFICATIONS_ENABLED=OFF to have it still build for ubuntu
+      24.04 and Debian stable (Marcus Grenängen)
+    - Fix for potential segfault due to double free + code
+      readability fix/cleanup (Marcus Grenängen)
+    - Ignore .cache dir (Marcus Grenängen)
+    - Fix segfault for Issue #75 (Marcus Grenängen)
+    - Bump version to 0.2.22 (Marcus Grenängen)
+
+-------------------------------------------------------------------
@@ -5 +33 @@
-  * What's new in this release 🎉
+  * What's new in this release

Old:
----
  tail-tray-0.2.21.obscpio

New:
----
  tail-tray-0.2.22.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ tail-tray.spec ++++++
--- /var/tmp/diff_new_pack.v354Ro/_old  2025-05-07 19:22:32.422433362 +0200
+++ /var/tmp/diff_new_pack.v354Ro/_new  2025-05-07 19:22:32.422433362 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           tail-tray
-Version:        0.2.21
+Version:        0.2.22
 Release:        0
 Summary:        Tailscale tray menu and UI for the KDE Plasma Desktop
 License:        GPL-3.0-only

++++++ _service ++++++
--- /var/tmp/diff_new_pack.v354Ro/_old  2025-05-07 19:22:32.458434866 +0200
+++ /var/tmp/diff_new_pack.v354Ro/_new  2025-05-07 19:22:32.462435033 +0200
@@ -2,8 +2,8 @@
   <service name="obs_scm" mode="manual">
     <param name="url">https://github.com/SneWs/tail-tray</param>
     <param name="scm">git</param>
-    <param name="revision">refs/tags/v0.2.21</param>
-    <param name="match-tag">v0.2.21</param>
+    <param name="revision">refs/tags/v0.2.22</param>
+    <param name="match-tag">v0.2.22</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.v354Ro/_old  2025-05-07 19:22:32.490436203 +0200
+++ /var/tmp/diff_new_pack.v354Ro/_new  2025-05-07 19:22:32.494436370 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://github.com/SneWs/tail-tray</param>
-              <param 
name="changesrevision">5bf5ad3aab9f6940dab6ec35e7bb5c366ffab9b5</param></service></servicedata>
+              <param 
name="changesrevision">124e20bae18e886553d44a2bd85ee60f8e8f0502</param></service></servicedata>
 (No newline at EOF)
 

++++++ tail-tray-0.2.21.obscpio -> tail-tray-0.2.22.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tail-tray-0.2.21/.github/workflows/cmake-multi-platform.yml 
new/tail-tray-0.2.22/.github/workflows/cmake-multi-platform.yml
--- old/tail-tray-0.2.21/.github/workflows/cmake-multi-platform.yml     
2025-04-25 23:50:35.000000000 +0200
+++ new/tail-tray-0.2.22/.github/workflows/cmake-multi-platform.yml     
2025-05-07 15:30:19.000000000 +0200
@@ -47,6 +47,7 @@
         echo "Running Linux build"
           cmake -B ${{ steps.strings.outputs.build-output-dir }} \
             -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
+            -DKNOTIFICATIONS_ENABLED=OFF \
             -S ${{ github.workspace }} \
             -G "Unix Makefiles" # Use Unix Makefiles for Ubuntu
       shell: bash  # This makes sure we use Bash on both platforms.
@@ -56,7 +57,7 @@
       run: |
         echo "Running Windows build"
         echo "Build output directory: ${{ 
steps.strings.outputs.build-output-dir }}" 
-        cmake -B ${{ steps.strings.outputs.build-output-dir }} 
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S ${{ github.workspace }} -G 
"Visual Studio 17 2022"
+        cmake -B ${{ steps.strings.outputs.build-output-dir }} 
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DKNOTIFICATIONS_ENABLED=OFF -S ${{ 
github.workspace }} -G "Visual Studio 17 2022"
       shell: pwsh
 
     - name: Build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tail-tray-0.2.21/.github/workflows/tagged-releases.yml 
new/tail-tray-0.2.22/.github/workflows/tagged-releases.yml
--- old/tail-tray-0.2.21/.github/workflows/tagged-releases.yml  2025-04-25 
23:50:35.000000000 +0200
+++ new/tail-tray-0.2.22/.github/workflows/tagged-releases.yml  2025-05-07 
15:30:19.000000000 +0200
@@ -56,6 +56,7 @@
         -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
         -DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
         -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
+        -DKNOTIFICATIONS_ENABLED=OFF
         -S ${{ github.workspace }}
 
     - name: Build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/.gitignore 
new/tail-tray-0.2.22/.gitignore
--- old/tail-tray-0.2.21/.gitignore     2025-04-25 23:50:35.000000000 +0200
+++ new/tail-tray-0.2.22/.gitignore     2025-05-07 15:30:19.000000000 +0200
@@ -14,6 +14,7 @@
 build/
 cmake-build-debug/
 cmake-build-release/
+.cache/
 
 packaging/
 .flatpak-builder/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/.vscode/launch.json 
new/tail-tray-0.2.22/.vscode/launch.json
--- old/tail-tray-0.2.21/.vscode/launch.json    2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/.vscode/launch.json    2025-05-07 15:30:19.000000000 
+0200
@@ -5,7 +5,7 @@
     "version": "0.2.0",
     "configurations": [
         {
-            "name": "(Windows) Launch",
+            "name": "(Debug) Launch",
             "type": "cppdbg",
             "request": "launch",
             "args": [],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/CMakeLists.txt 
new/tail-tray-0.2.22/CMakeLists.txt
--- old/tail-tray-0.2.21/CMakeLists.txt 2025-04-25 23:50:35.000000000 +0200
+++ new/tail-tray-0.2.22/CMakeLists.txt 2025-05-07 15:30:19.000000000 +0200
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.21)
 
-project(tail-tray VERSION 0.2.21 LANGUAGES CXX)
+project(tail-tray VERSION 0.2.22 LANGUAGES CXX)
 
 set(CMAKE_AUTOUIC ON)
 set(CMAKE_AUTOMOC ON)
@@ -31,56 +31,74 @@
 find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Network LinguistTools)
 find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network 
LinguistTools)
 
+# Use KNotifications
+option(KNOTIFICATIONS_ENABLED "Enable KNotifications" OFF)
+if (KNOTIFICATIONS_ENABLED)
+    message("KNotifications has been enabled! This requires Plasma 6")
+
+    find_package(ECM REQUIRED NO_MODULE)
+    set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
+    include(KDEInstallDirs)
+    include(KDECMakeSettings)
+
+    add_definitions(-DKNOTIFICATIONS_ENABLED)
+    find_package(KF6Notifications)
+else ()
+    message("KNotifications has not been enabled!")
+endif (KNOTIFICATIONS_ENABLED)
+
 set(PROJECT_SOURCES
-        src/main.cpp
-        src/MainWindow.cpp
-        src/MainWindow.h
-        src/MainWindow.ui
-        resources.qrc
-        src/models/TailAccountInfo.h
-        src/models/TailDeviceInfo.h
-        src/models/TailUser.h
-        src/models/TailNetInfo.h
-        src/models/TailDriveInfo.h
-        src/models/TailStatus.h
-        src/models/TailState.h
-        src/models/TailDnsStatus.h
-        src/models/CurrentTailPrefs.h
-        src/models/JsonHelpers.h
-        src/models/Models.h
-        src/models/IpnEvents.h 
-        src/TrayMenuManager.cpp
-        src/TrayMenuManager.h
-        src/TailSettings.cpp
-        src/TailSettings.h
-        src/AccountsTabUiManager.cpp
-        src/AccountsTabUiManager.h
-        src/SysCommand.cpp
-        src/SysCommand.h
-        src/KnownValues.h
-        src/TailFileReceiver.cpp
-        src/TailFileReceiver.h
-        src/TailRunner.h
-        src/TailRunner.cpp
-        src/TailDriveUiManager.h
-        src/TailDriveUiManager.cpp
-        src/ManageDriveWindow.h
-        src/ManageDriveWindow.cpp
-        src/ManageDriveWindow.ui
-        src/NetworkStateMonitor.cpp
-        src/NetworkStateMonitor.h
-        src/AdvertiseRoutesDlg.h
-        src/AdvertiseRoutesDlg.cpp
-        src/AdvertiseRoutesDlg.ui
-        src/DnsSettingsDlg.h
-        src/DnsSettingsDlg.cpp
-        src/DnsSettingsDlg.ui
-        src/IpnWatcher.cpp
-        src/IpnWatcher.h
-        src/SingleApplicationImpl.h
-        src/PleaseWaitDlg.h
-        src/PleaseWaitDlg.cpp
-        src/PleaseWaitDlg.ui
+    src/main.cpp
+    src/MainWindow.cpp
+    src/MainWindow.h
+    src/MainWindow.ui
+    resources.qrc
+    src/models/TailAccountInfo.h
+    src/models/TailDeviceInfo.h
+    src/models/TailUser.h
+    src/models/TailNetInfo.h
+    src/models/TailDriveInfo.h
+    src/models/TailStatus.h
+    src/models/TailState.h
+    src/models/TailDnsStatus.h
+    src/models/CurrentTailPrefs.h
+    src/models/JsonHelpers.h
+    src/models/Models.h
+    src/models/IpnEvents.h 
+    src/TrayMenuManager.cpp
+    src/TrayMenuManager.h
+    src/TailSettings.cpp
+    src/TailSettings.h
+    src/AccountsTabUiManager.cpp
+    src/AccountsTabUiManager.h
+    src/SysCommand.cpp
+    src/SysCommand.h
+    src/KnownValues.h
+    src/TailFileReceiver.cpp
+    src/TailFileReceiver.h
+    src/TailRunner.h
+    src/TailRunner.cpp
+    src/TailDriveUiManager.h
+    src/TailDriveUiManager.cpp
+    src/ManageDriveWindow.h
+    src/ManageDriveWindow.cpp
+    src/ManageDriveWindow.ui
+    src/NetworkStateMonitor.cpp
+    src/NetworkStateMonitor.h
+    src/AdvertiseRoutesDlg.h
+    src/AdvertiseRoutesDlg.cpp
+    src/AdvertiseRoutesDlg.ui
+    src/DnsSettingsDlg.h
+    src/DnsSettingsDlg.cpp
+    src/DnsSettingsDlg.ui
+    src/IpnWatcher.cpp
+    src/IpnWatcher.h
+    src/SingleApplicationImpl.h
+    src/PleaseWaitDlg.h
+    src/PleaseWaitDlg.cpp
+    src/PleaseWaitDlg.ui
+    src/NotificationsManager.h
+    src/NotificationsManager.cpp
 )
 
 if (APPLE)
@@ -128,7 +146,18 @@
 )
 qt_standard_project_setup(I18N_TRANSLATED_LANGUAGES en_US sv_SE de_DE fr_FR)
 
-target_link_libraries(tail-tray PRIVATE Qt${QT_VERSION_MAJOR}::Widgets 
Qt${QT_VERSION_MAJOR}::Network)
+target_link_libraries(
+    tail-tray PRIVATE 
+    Qt${QT_VERSION_MAJOR}::Widgets 
+    Qt${QT_VERSION_MAJOR}::Network 
+)
+
+if (KNOTIFICATIONS_ENABLED)
+    target_link_libraries(
+        tail-tray PRIVATE 
+        KF6::Notifications
+    )
+endif (KNOTIFICATIONS_ENABLED)
 
 configure_file(src/Paths.h.in ${CMAKE_SOURCE_DIR}/src/Paths.h @ONLY)
 
@@ -152,6 +181,10 @@
         DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications
     )
 
+if (KNOTIFICATIONS_ENABLED)
+    install(FILES "tail-tray.notifyrc" DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
+endif (KNOTIFICATIONS_ENABLED)
+
     install(FILES "${CMAKE_BINARY_DIR}/tail_tray_en_US.qm"
             "${CMAKE_BINARY_DIR}/tail_tray_sv_SE.qm"
             "${CMAKE_BINARY_DIR}/tail_tray_fr_FR.qm"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/debian/changelog 
new/tail-tray-0.2.22/debian/changelog
--- old/tail-tray-0.2.21/debian/changelog       2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/debian/changelog       2025-05-07 15:30:19.000000000 
+0200
@@ -1,4 +1,4 @@
-tail-tray (0.2.21) UNRELEASED; urgency=medium
+tail-tray (0.2.22) UNRELEASED; urgency=medium
 
   * New upstream release.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/docs/build-from-src.md 
new/tail-tray-0.2.22/docs/build-from-src.md
--- old/tail-tray-0.2.21/docs/build-from-src.md 2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/docs/build-from-src.md 2025-05-07 15:30:19.000000000 
+0200
@@ -3,17 +3,17 @@
    * Git, QT 6, cmake and a c++ compiler, for example:
       * On Ubuntu and Ubuntu based distros
          ```bash
-         sudo apt install git qt6-tools-dev qt6-tools-dev-tools g++ clang 
cmake davfs2
+         sudo apt install git qt6-tools-dev qt6-tools-dev-tools g++ clang 
cmake davfs2 extra-cmake-modules
          ```
      * On Fedora
         ```bash
-        sudo dnf install -y git g++ clang cmake qt6-qtbase-devel 
qt6-qttools-devel qt6-qtbase-private-devel davfs2
+        sudo dnf install -y git g++ clang cmake qt6-qtbase-devel 
qt6-qttools-devel qt6-qtbase-private-devel davfs2 extra-cmake-modules
         ```
       * On Arch Linux
         * You can use the AUR package from here 
https://aur.archlinux.org/packages/tail-tray-git provided by @HeavenVolkoff
         * or, build it from source yourself:
          ```bash
-         sudo pacman -S git clang cmake qt6-base qt6-tools
+         sudo pacman -S git clang cmake qt6-base qt6-tools extra-cmake-modules
          ```
         ```bash 
         # For davfs2 we need to use the AUR
@@ -25,8 +25,10 @@
       * If you are running Gnome and not using Ubuntu, make sure to install 
AppIndicator so you can see your tray icons. See 
https://extensions.gnome.org/extension/615/appindicator-support/
 2. Clone the repo
 3. cd into the repo `cd tail-tray`
-4. Run `cmake -B "./build" -DCMAKE_BUILD_TYPE="Release"`
-   * If you want to disable DAVFS: `cmake -B "./build" -DDAVFS_ENABLED=OFF 
-DCMAKE_BUILD_TYPE="Release"`
+   * NOTE: There are several options that can be toggled ON/OFF dep on needs 
and wants.
+   * For exampel: `KNOTIFICATIONS_ENABLED` to use rich notifications, this 
requires KDE Plasma 6 and later with KNotification support
+4. Run `cmake -B "./build" -DKNOTIFICATIONS_ENABLED=ON 
-DCMAKE_BUILD_TYPE="Release"`
+   * If you want to disable DAVFS: `cmake -B "./build" -DDAVFS_ENABLED=OFF 
-DKNOTIFICATIONS_ENABLED=ON -DCMAKE_BUILD_TYPE="Release"`
 5. Run `cmake --build "./build" --config Release`
 6. Run `cd build`
 7. Run `sudo make install`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/MainWindow.cpp 
new/tail-tray-0.2.22/src/MainWindow.cpp
--- old/tail-tray-0.2.21/src/MainWindow.cpp     2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/src/MainWindow.cpp     2025-05-07 15:30:19.000000000 
+0200
@@ -1,6 +1,5 @@
 #include <QDir>
 #include <QFile>
-#include <QDialog>
 
 #include "MainWindow.h"
 #include "Paths.h"
@@ -24,20 +23,18 @@
     , pTrayManager(nullptr)
     , pCurrentExecution(nullptr)
     , pLoginInProgressDlg(nullptr)
-    , pTailStatus()
     , pFileReceiver(nullptr)
-    , eCurrentState(TailState::NoAccount)
     , pNetworkStateMonitor(std::make_unique<NetworkStateMonitor>(this))
     , pIpnWatcher(std::make_unique<IpnWatcher>(this))
-    , pDnsStatus()
-#if defined(DAVFS_ENABLED)
-    , pTailDriveUiManager()
-#endif
+    , eCurrentState(TailState::NoAccount)
     , settings(this)
 {
     ui->setupUi(this);
 
     pCurrentExecution = std::make_unique<TailRunner>(settings, this);
+    accountsTabUi = std::make_unique<AccountsTabUiManager>(ui.get(), 
pCurrentExecution.get(), this);
+    pTrayManager = std::make_unique<TrayMenuManager>(settings, 
pCurrentExecution.get(), this);
+    pNotificationsManager = 
std::make_unique<NotificationsManager>(pTrayManager.get(), this);
 
     // Remove the tail drive tab by default
     ui->tabWidget->removeTab(2);
@@ -79,8 +76,7 @@
     connect(ui->btnAdvertiseRoutes, &QPushButton::clicked, this, 
&MainWindow::showAdvertiseRoutesDialog);
     connect(ui->btnTailscaleDnsSettings, &QPushButton::clicked, this, 
&MainWindow::showDnsSettingsDialog);
 
-    accountsTabUi = std::make_unique<AccountsTabUiManager>(ui.get(), 
pCurrentExecution.get(), this);
-    pTrayManager = std::make_unique<TrayMenuManager>(settings, 
pCurrentExecution.get(), this);
+    connect(pTrayManager.get(), &TrayMenuManager::ipAddressCopiedToClipboard, 
this, &MainWindow::ipAddressCopiedToClipboard);
 
     changeToState(TailState::NotLoggedIn);
 
@@ -365,6 +361,11 @@
     pCurrentExecution->bootstrap();
 }
 
+void MainWindow::ipAddressCopiedToClipboard(const QString& ipAddress, const 
QString& hostname) {
+        pNotificationsManager->showNotification(tr("IP address copied"),
+            "IP Address " + ipAddress + " for " + hostname + " have been 
copied to clipboard!");
+}
+
 #if defined(DAVFS_ENABLED)
 void MainWindow::drivesListed(const QList<TailDriveInfo>& drives, bool error, 
const QString& errorMsg) {
     if (error) {
@@ -395,7 +396,7 @@
 
 void MainWindow::fileSentToDevice(bool success, const QString& errorMsg, void* 
userData) const {
     if (!success) {
-        pTrayManager->trayIcon()->showMessage(tr("Failed to send file"), 
errorMsg, QSystemTrayIcon::MessageIcon::Critical, 5000);
+        pNotificationsManager->showErrorNotification(tr("Failed to send 
file"), errorMsg);
     }
 
     if (userData == nullptr) {
@@ -403,9 +404,10 @@
     }
 
     auto userDataStr = static_cast<QString*>(userData);
-    pTrayManager->trayIcon()->showMessage(tr("File sent"), *userDataStr, 
QSystemTrayIcon::MessageIcon::Information, 5000);
+    QFileInfo fileInfo(*userDataStr);
+    pNotificationsManager->showFileNotification(tr("File sent"),
+        tr("The file %1 has been sent!").arg(*userDataStr), fileInfo);
 
-    // We need to delete this here
     delete userDataStr;
 }
 
@@ -419,17 +421,15 @@
 
     connect(pFileReceiver.get(), &TailFileReceiver::errorListening,
         this, [this](const QString& errorMsg) {
-            pTrayManager->trayIcon()->showMessage(tr("Error"), errorMsg,
-                QSystemTrayIcon::MessageIcon::Critical, 5000);
+            pNotificationsManager->showErrorNotification(tr("Error"), 
errorMsg);
         });
 }
 
 void MainWindow::onTailnetFileReceived(QString filePath) const {
     const QFileInfo file(filePath);
-    const QString msg("File " + file.fileName() + " was received and saved in 
" + file.absolutePath());
-
-    pTrayManager->trayIcon()->showMessage(tr("File received"), msg,
-        QSystemTrayIcon::MessageIcon::Information, 8000);
+    pNotificationsManager->showFileNotification(tr("File received"),
+        tr("File %1 has been saved in 
%2").arg(file.fileName()).arg(file.absolutePath()),
+            file);
 }
 
 void MainWindow::onShowTailFileSaveLocationPicker() {
@@ -565,7 +565,7 @@
         }
     }
 
-    pTrayManager->trayIcon()->showMessage(title, message, 
QSystemTrayIcon::MessageIcon::Warning, 5000);
+    pNotificationsManager->showWarningNotification(title, message);
 }
 
 void MainWindow::showErrorMessage(const QString& title, const QString& 
message, bool timeLimited) {
@@ -583,7 +583,7 @@
         }
     }
 
-    pTrayManager->trayIcon()->showMessage(title, message, 
QSystemTrayIcon::MessageIcon::Critical, 5000);
+    pNotificationsManager->showErrorNotification(title, message);
 }
 
 bool MainWindow::isTailDriveFileAlreadySetup() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/MainWindow.h 
new/tail-tray-0.2.22/src/MainWindow.h
--- old/tail-tray-0.2.21/src/MainWindow.h       2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/src/MainWindow.h       2025-05-07 15:30:19.000000000 
+0200
@@ -17,6 +17,7 @@
 #include "IpnWatcher.h"
 #include "models/TailStatus.h"
 #include "PleaseWaitDlg.h"
+#include "NotificationsManager.h"
 
 #if defined(DAVFS_ENABLED)
 #include "TailDriveUiManager.h"
@@ -56,6 +57,7 @@
 #if defined(DAVFS_ENABLED)
     std::unique_ptr<TailDriveUiManager> pTailDriveUiManager;
 #endif
+    std::unique_ptr<NotificationsManager> pNotificationsManager;
 
     TailState eCurrentState;
     TailSettings settings;
@@ -73,6 +75,7 @@
     void loginFlowStarting(const QString& loginUrl);
     void loginFlowCompleted(bool success = true);
     void onIpnEvent(const IpnEventData& eventData);
+    void ipAddressCopiedToClipboard(const QString& ipAddress, const QString& 
hostname);
 
 #if defined(DAVFS_ENABLED)
     void drivesListed(const QList<TailDriveInfo>& drives, bool error, const 
QString& errorMsg);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/NotificationsManager.cpp 
new/tail-tray-0.2.22/src/NotificationsManager.cpp
--- old/tail-tray-0.2.21/src/NotificationsManager.cpp   1970-01-01 
01:00:00.000000000 +0100
+++ new/tail-tray-0.2.22/src/NotificationsManager.cpp   2025-05-07 
15:30:19.000000000 +0200
@@ -0,0 +1,98 @@
+#include "NotificationsManager.h"
+
+#include <QDesktopServices>
+
+NotificationsManager::NotificationsManager(TrayMenuManager const* pTrayMgr, 
QObject* parent)
+    : QObject(parent)
+    , m_pTrayMgr(pTrayMgr)
+{ }
+
+NotificationsManager::~NotificationsManager() = default;
+
+void NotificationsManager::showNotification(const QString& title, const 
QString& message, const QString& iconName) {
+#if defined(KNOTIFICATIONS_ENABLED)
+    auto* notification = new KNotification("BasicNotification", 
KNotification::NotificationFlag::CloseOnTimeout, this);
+    notification->setTitle(title);
+    notification->setText(message);
+
+    notification->setUrgency(KNotification::Urgency::DefaultUrgency);
+    if (!iconName.isEmpty()) {
+        notification->setIconName(iconName);
+    }
+    else {
+        notification->setIconName("notification-active");
+    }
+
+    notification->sendEvent();
+#else
+    m_pTrayMgr->trayIcon()->showMessage(title, message,
+        QSystemTrayIcon::MessageIcon::Information, 5000);
+#endif
+}
+
+void NotificationsManager::showFileNotification(const QString& title, const 
QString& message, const QFileInfo& fileInfo,
+    const QString& iconName) {
+
+#if defined(KNOTIFICATIONS_ENABLED)
+    auto* notification = new KNotification("FileTransfer", 
KNotification::NotificationFlag::CloseOnTimeout, this);
+    notification->setTitle(title);
+    notification->setText(message);
+
+    // Setting the file URI will trigger the hamburger menu where one can 
select to open the file etc
+    QUrl fileUrl("file://" + fileInfo.absoluteFilePath());
+    notification->setUrls(QList{fileUrl});
+
+    notification->setUrgency(KNotification::Urgency::DefaultUrgency);
+    if (!iconName.isEmpty()) {
+        notification->setIconName(iconName);
+    }
+    else {
+        notification->setIconName("edit-image");
+    }
+
+    notification->sendEvent();
+#else
+    m_pTrayMgr->trayIcon()->showMessage(title, message,
+        QSystemTrayIcon::MessageIcon::Information, 5000);
+#endif
+}
+
+void NotificationsManager::showWarningNotification(const QString& title, const 
QString& message, const QString& iconName) {
+#if defined(KNOTIFICATIONS_ENABLED)
+    auto* notification = new KNotification("BasicNotification", 
KNotification::NotificationFlag::CloseOnTimeout, this);
+    notification->setTitle(title);
+    notification->setText(message);
+
+    notification->setUrgency(KNotification::Urgency::DefaultUrgency);
+    if (!iconName.isEmpty()) {
+        notification->setIconName(iconName);
+    }
+    else {
+        notification->setIconName("dialog-warning");
+    }
+
+    notification->sendEvent();
+#else
+    m_pTrayMgr->trayIcon()->showMessage(title, message, 
QSystemTrayIcon::Warning, 5000);
+#endif
+}
+
+void NotificationsManager::showErrorNotification(const QString& title, const 
QString& message, const QString& iconName) {
+#if defined(KNOTIFICATIONS_ENABLED)
+    auto* notification = new KNotification("BasicNotification", 
KNotification::NotificationFlag::CloseOnTimeout, this);
+    notification->setTitle(title);
+    notification->setText(message);
+
+    notification->setUrgency(KNotification::Urgency::DefaultUrgency);
+    if (!iconName.isEmpty()) {
+        notification->setIconName(iconName);
+    }
+    else {
+        notification->setIconName("dialog-error");
+    }
+
+    notification->sendEvent();
+#else
+    m_pTrayMgr->trayIcon()->showMessage(title, message, 
QSystemTrayIcon::Critical, 5000);
+#endif
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/NotificationsManager.h 
new/tail-tray-0.2.22/src/NotificationsManager.h
--- old/tail-tray-0.2.21/src/NotificationsManager.h     1970-01-01 
01:00:00.000000000 +0100
+++ new/tail-tray-0.2.22/src/NotificationsManager.h     2025-05-07 
15:30:19.000000000 +0200
@@ -0,0 +1,30 @@
+#ifndef NOTIFICATIONS_MANAGER
+#define NOTIFICATIONS_MANAGER
+
+#include <QFileInfo>
+
+#if defined(KNOTIFICATIONS_ENABLED)
+#include <KNotification>
+#endif
+
+#include "TrayMenuManager.h"
+
+class NotificationsManager : public QObject
+{
+    Q_OBJECT
+public:
+    explicit NotificationsManager(TrayMenuManager const* pTrayMgr, QObject* 
parent = nullptr);
+    ~NotificationsManager() override;
+
+    void showNotification(const QString &title, const QString& message, const 
QString& iconName = QString());
+    void showFileNotification(const QString& title, const QString& message, 
const QFileInfo& fileInfo,
+        const QString& iconName = QString());
+
+    void showWarningNotification(const QString& title, const QString& message, 
const QString& iconName = QString("dialog-warning"));
+    void showErrorNotification(const QString& title, const QString& message, 
const QString& iconName = QString("dialog-error"));
+
+private:
+    TrayMenuManager const* m_pTrayMgr;
+};
+
+#endif // NOTIFICATIONS_MANAGER
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/TailRunner.cpp 
new/tail-tray-0.2.22/src/TailRunner.cpp
--- old/tail-tray-0.2.21/src/TailRunner.cpp     2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/src/TailRunner.cpp     2025-05-07 15:30:19.000000000 
+0200
@@ -39,37 +39,24 @@
         return "Unknown (Not mapped) command (" + 
QString::number(static_cast<int>(cmd)) + ")";
     }
 
+    static BufferedProcessWrapper* pActiveLoginFlow = nullptr;
 }
 
 TailRunner::TailRunner(const TailSettings& s, QObject* parent)
     : QObject(parent)
     , settings(s)
-    , processes()
     , currentPrefs()
 {
 }
 
 TailRunner::~TailRunner()
 {
-    runCompletedCleanup();
 }
 
 void TailRunner::shutdown() {
     // Kill off any pending process calls, this is needed in cases such as:
     // - When the user is in a pending login state, then the process is 
waiting for user to complete web auth flows
-    
-    for (const auto& proc : processes) {
-        auto* p = proc->process();
-        if (!p)
-            continue;
-
-        if (p->state() == QProcess::Running) {
-            p->terminate();
-            p->close();
-        }
-    }
-
-    runCompletedCleanup();
+    cancelLoginFlow();
 }
 
 void TailRunner::checkIfInstalled() {
@@ -199,11 +186,11 @@
 }
 
 void TailRunner::cancelLoginFlow() {
-    for (const auto& proc : processes) {
-        if (proc->command() == Command::Login) {
-            proc->cancel();
-        }
+    if (pActiveLoginFlow == nullptr) {
+        return;
     }
+
+    pActiveLoginFlow->cancel();
 }
 
 void TailRunner::start(const bool usePkExec) {
@@ -262,11 +249,16 @@
 }
 
 void TailRunner::runCommand(const Command cmdType, const QString& cmd, const 
QStringList& args, const bool jsonResult, const bool usePkExec, void* userData) 
{
-    if (hasPendingCommandOfType(cmdType))
+    auto isLoginCmd = cmdType == Command::Login;
+    if (isLoginCmd && pActiveLoginFlow != nullptr) {
+        // Already in a login flow...
         return;
+    }
 
-    auto wrapper = new BufferedProcessWrapper(cmdType, cmdType == 
Command::Login, this);
-    processes.emplace_back(wrapper);
+    auto wrapper = new BufferedProcessWrapper(cmdType, isLoginCmd, this);
+    if (isLoginCmd) {
+        pActiveLoginFlow = wrapper;
+    }
 
     connect(wrapper, &BufferedProcessWrapper::processErrorOccurred,
         this, &TailRunner::onProcessErrorOccurred);
@@ -283,7 +275,7 @@
     wrapper->start(cmd, args, jsonResult, usePkExec, userData);
 }
 
-void TailRunner::onProcessCanReadStdOut(const BufferedProcessWrapper* wrapper) 
{
+void TailRunner::onProcessCanReadStdOut(BufferedProcessWrapper* wrapper) {
     const auto data = wrapper->process()->readAllStandardOutput();
 
     // Parse the status object
@@ -372,7 +364,7 @@
     }
 }
 
-void TailRunner::onProcessCanReadStandardError(const BufferedProcessWrapper* 
wrapper) {
+void TailRunner::onProcessCanReadStandardError(BufferedProcessWrapper* 
wrapper) {
     const auto commandInfo = wrapper->command();
 
     // NOTE! For whatever reason, the login command output is not captured by 
the readyReadStandardOutput signal
@@ -433,7 +425,7 @@
     }
 }
 
-void TailRunner::onProcessErrorOccurred(const BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error) {
+void TailRunner::onProcessErrorOccurred(BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error) {
     const auto commandInfo = wrapper->command();
     qDebug() << "Command" << commandToString(commandInfo) << "failed to 
execute!";
     qDebug() << "Command error" << error;
@@ -441,14 +433,21 @@
     if (commandInfo == Command::CheckIfInstalled) {
         emit tailscaleIsInstalled(false);
     }
-
-    runCompletedCleanup();
 }
 
-void TailRunner::onProcessFinished(const BufferedProcessWrapper* process, int 
exitCode, const QProcess::ExitStatus exitStatus) {
-    //qDebug() << "Process exit code " << exitCode << " - " << exitStatus;
+void TailRunner::onProcessFinished(BufferedProcessWrapper* process, int 
exitCode, const QProcess::ExitStatus exitStatus) {
+    qDebug() << "Process exit code " << exitCode << " - " << exitStatus;
+
+    //runCompletedCleanup();
+    process->deleteLater();
 
     const auto commandInfo = process->command();
+
+    // Reset login flow tracking ptr
+    if (commandInfo == Command::Login) {
+        pActiveLoginFlow = nullptr;
+    }
+
     if (exitCode != 0) {
         if (commandInfo == Command::Connect || commandInfo == 
Command::Disconnect) {
             // If we failed to connect or disconnect we probably need to 
invoke pkexec
@@ -505,8 +504,6 @@
             emit fileSent(true, QString{}, process->userData());
         }
     }
-
-    runCompletedCleanup();
 }
 
 void TailRunner::parseStatusResponse(const QJsonObject& obj) {
@@ -517,31 +514,6 @@
     currentPrefs = CurrentTailPrefs::parse(obj);
 }
 
-bool TailRunner::hasPendingCommandOfType(const Command cmdType) const {
-    for (const auto* process : processes) {
-        if (process->command() == cmdType && process->isRunning())
-            return true;
-    }
-
-    return false;
-}
-
-void TailRunner::runCompletedCleanup() {
-    for (auto it = processes.begin(); it != processes.end();) {
-        if (!(*it)->isRunning()) {
-            const auto cmd = commandToString((*it)->command());
-            qDebug() << "Cleaning up process " << cmd;
-
-            delete (*it);
-            it = processes.erase(it);
-            qDebug() << "Processes active: " << processes.size();
-        }
-        else {
-            ++it;
-        }
-    }
-}
-
 
 
////////////////////////////////////////////////////////////////////////////////////////////////////
 // ProcessWrapper impl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/TailRunner.h 
new/tail-tray-0.2.22/src/TailRunner.h
--- old/tail-tray-0.2.21/src/TailRunner.h       2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/src/TailRunner.h       2025-05-07 15:30:19.000000000 
+0200
@@ -39,6 +39,7 @@
     Q_OBJECT
 public:
     explicit BufferedProcessWrapper(Command cmd, bool emitOnActualSignals = 
false, QObject* parent = nullptr);
+    ~BufferedProcessWrapper() = default;
 
     /// Start the process with the given command and arguments
     void start(const QString& cmd, QStringList args, bool jsonResult, bool 
usePkExec, void* userData);
@@ -46,7 +47,7 @@
     [[nodiscard]] QProcess* process() const { return proc.get();}
     [[nodiscard]] Command command() const { return eCommand; }
     [[nodiscard]] void* userData() const { return pUserData; }
-    [[nodiscard]] bool isRunning() const { return proc != nullptr && 
proc->state() != QProcess::NotRunning; }
+    [[nodiscard]] bool isRunning() const { return proc != nullptr && 
proc->state() == QProcess::Running; }
     void cancel(bool raiseEvents = true) {
         if (proc != nullptr) {
             proc->terminate();
@@ -58,7 +59,7 @@
     }
 
 signals:
-    void processErrorOccurred(const BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error);
+    void processErrorOccurred(BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error);
     void processCanReadStdOut(BufferedProcessWrapper* process);
     void processCanReadStandardError(BufferedProcessWrapper* process);
     void processFinished(BufferedProcessWrapper* process, int exitCode, 
QProcess::ExitStatus exitStatus);
@@ -120,7 +121,6 @@
 private:
     const TailSettings& settings;
     CurrentTailPrefs currentPrefs;
-    std::vector<BufferedProcessWrapper*> processes;
 
 signals:
     void tailscaleIsInstalled(bool installed);
@@ -140,14 +140,11 @@
     void parseStatusResponse(const QJsonObject& obj);
     void parseSettingsResponse(const QJsonObject& obj);
 
-    [[nodiscard]] bool hasPendingCommandOfType(Command cmdType) const;
-    void runCompletedCleanup();
-
 private slots:
-    void onProcessErrorOccurred(const BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error);
-    void onProcessCanReadStdOut(const BufferedProcessWrapper* wrapper);
-    void onProcessCanReadStandardError(const BufferedProcessWrapper* wrapper);
-    void onProcessFinished(const BufferedProcessWrapper* wrapper, int 
exitCode, QProcess::ExitStatus exitStatus);
+    void onProcessErrorOccurred(BufferedProcessWrapper* wrapper, 
QProcess::ProcessError error);
+    void onProcessCanReadStdOut(BufferedProcessWrapper* wrapper);
+    void onProcessCanReadStandardError(BufferedProcessWrapper* wrapper);
+    void onProcessFinished(BufferedProcessWrapper* wrapper, int exitCode, 
QProcess::ExitStatus exitStatus);
 };
 
 #endif // TAILRUNNER_H
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/TrayMenuManager.cpp 
new/tail-tray-0.2.22/src/TrayMenuManager.cpp
--- old/tail-tray-0.2.21/src/TrayMenuManager.cpp        2025-04-25 
23:50:35.000000000 +0200
+++ new/tail-tray-0.2.22/src/TrayMenuManager.cpp        2025-05-07 
15:30:19.000000000 +0200
@@ -73,7 +73,7 @@
     accounts = foundAccounts;
 }
 
-void TrayMenuManager::stateChangedTo(TailState newState, const TailStatus& 
pTailStatus) const {
+void TrayMenuManager::stateChangedTo(TailState newState, const TailStatus& 
pTailStatus) {
     cleanupDisposableActions();
     cleanupDisposableMenus();
 
@@ -143,7 +143,7 @@
     buildAccountsMenu();
 }
 
-void TrayMenuManager::buildConnectedMenu(const TailStatus& pTailStatus) const {
+void TrayMenuManager::buildConnectedMenu(const TailStatus& pTailStatus) {
     pTrayMenu->clear();
     pTrayMenu->addAction(pConnected.get());
     pTrayMenu->addAction(pDisconnect.get());
@@ -176,18 +176,13 @@
                 auto* deviceMenu = netDevs->addMenu(name + ipStr);
                 disposableMenus.push_back(deviceMenu);
                 action = deviceMenu->addAction(tr("Copy IP address"));
-                connect(action, &QAction::triggered, this, [this, dev, name, 
ipStr](bool) {
+                connect(action, &QAction::triggered, this, [this, dev, 
name](bool) {
                     QClipboard* clipboard = QApplication::clipboard();
                     const auto& str = dev.tailscaleIPs.first();
                     qDebug() << str;
                     clipboard->setText(str, QClipboard::Clipboard);
-                    if (clipboard->supportsSelection()) {
-                        clipboard->setText(str, QClipboard::Selection);
-                    }
 
-                    pSysTray->showMessage(tr("IP address copied"),
-                        "IP Address " + ipStr + " for " + name + " have been 
copied to clipboard!",
-                        QSystemTrayIcon::Information, 5000);
+                    emit ipAddressCopiedToClipboard(str, name);
                 });
 
                 disposableConnectedMenuActions.push_back(
@@ -212,7 +207,7 @@
 
                     // The user data will be cleaned up when the signal is 
triggered back to us
                     pTailRunner->sendFile(name, file,
-                        new QString("File " + file + " sent to " + name));
+                        new QString(file));
                 });
             }
             disposableConnectedMenuActions.push_back(action);
@@ -432,9 +427,6 @@
     });
 
     connect(pConnect.get(), &QAction::triggered, this, [this](bool) {
-        pSysTray->showMessage(tr("Please wait"), tr("Connecting to your 
Tailscale network"),
-            QSystemTrayIcon::MessageIcon::Information, 3000);
-
         pTailRunner->start();
     });
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/TrayMenuManager.h 
new/tail-tray-0.2.22/src/TrayMenuManager.h
--- old/tail-tray-0.2.21/src/TrayMenuManager.h  2025-04-25 23:50:35.000000000 
+0200
+++ new/tail-tray-0.2.22/src/TrayMenuManager.h  2025-05-07 15:30:19.000000000 
+0200
@@ -19,10 +19,13 @@
     explicit TrayMenuManager(TailSettings& s, TailRunner* runner, QObject* 
parent = nullptr);
 
     void onAccountsListed(const QList<TailAccountInfo>& foundAccounts);
-    void stateChangedTo(TailState newState, const TailStatus& pTailStatus) 
const;
+    void stateChangedTo(TailState newState, const TailStatus& pTailStatus);
 
     [[nodiscard]] QSystemTrayIcon* trayIcon() const { return pSysTray.get(); }
 
+signals:
+    void ipAddressCopiedToClipboard(const QString& ipAddress, const QString& 
hostname);
+
 private:
     QList<TailAccountInfo> accounts;
     TailSettings& settings;
@@ -46,7 +49,7 @@
 private:
     void buildNotLoggedInMenu() const;
     void buildNotConnectedMenu(const TailStatus& pTailStatus) const;
-    void buildConnectedMenu(const TailStatus& pTailStatus) const;
+    void buildConnectedMenu(const TailStatus& pTailStatus);
     void buildAccountsMenu() const;
 
     void setupWellKnownActions() const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/src/main.cpp 
new/tail-tray-0.2.22/src/main.cpp
--- old/tail-tray-0.2.21/src/main.cpp   2025-04-25 23:50:35.000000000 +0200
+++ new/tail-tray-0.2.22/src/main.cpp   2025-05-07 15:30:19.000000000 +0200
@@ -9,7 +9,7 @@
 int main(int argc, char** argv) {
     QCoreApplication::setOrganizationName("grenangen");
     QCoreApplication::setOrganizationDomain("grenangen.se");
-    QCoreApplication::setApplicationName("Tail Tray");
+    QCoreApplication::setApplicationName("tail-tray");
 
     SingleApplicationImpl a(argc, argv);
     if (!a.claimInstance()) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tail-tray-0.2.21/tail-tray.notifyrc 
new/tail-tray-0.2.22/tail-tray.notifyrc
--- old/tail-tray-0.2.21/tail-tray.notifyrc     1970-01-01 01:00:00.000000000 
+0100
+++ new/tail-tray-0.2.22/tail-tray.notifyrc     2025-05-07 15:30:19.000000000 
+0200
@@ -0,0 +1,17 @@
+[Global]
+    IconName=tailscale
+    Name=Tail Tray
+    Comment=A Tailscale Tray Application
+    DesktopEntry=Tail Tray
+
+[Event/BasicNotification]
+    Name=BasicNotification
+    Comment=Basic notifications without actions
+    Action=Sound|Popup
+    Urgency=Normal
+
+[Event/FileTransfer]
+    Name=FileTransfer
+    Comment=A file have been sent or received on this machine over 
Tailscale/Wireguard
+    Action=Sound|Popup
+    Urgency=Normal
\ No newline at end of file

++++++ tail-tray.obsinfo ++++++
--- /var/tmp/diff_new_pack.v354Ro/_old  2025-05-07 19:22:32.746446893 +0200
+++ /var/tmp/diff_new_pack.v354Ro/_new  2025-05-07 19:22:32.746446893 +0200
@@ -1,5 +1,5 @@
 name: tail-tray
-version: 0.2.21
-mtime: 1745617835
-commit: 5bf5ad3aab9f6940dab6ec35e7bb5c366ffab9b5
+version: 0.2.22
+mtime: 1746624619
+commit: 124e20bae18e886553d44a2bd85ee60f8e8f0502
 

Reply via email to