Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package android-file-transfer-linux for 
openSUSE:Factory checked in at 2025-10-14 18:08:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/android-file-transfer-linux (Old)
 and      /work/SRC/openSUSE:Factory/.android-file-transfer-linux.new.18484 
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "android-file-transfer-linux"

Tue Oct 14 18:08:03 2025 rev:4 rq:1311166 version:4.5

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/android-file-transfer-linux/android-file-transfer-linux.changes
  2025-05-07 19:18:22.091963040 +0200
+++ 
/work/SRC/openSUSE:Factory/.android-file-transfer-linux.new.18484/android-file-transfer-linux.changes
       2025-10-14 18:09:51.714705638 +0200
@@ -1,0 +2,24 @@
+Mon Oct 13 14:36:00 UTC 2025 - llyyr <[email protected]>
+
+- Update to version 4.5:
+  * fix invalid close session parameters (graceful shutdown - fixes switch 
failure)
+  * fix qt5 compilation
+  * easier method to find zune codename
+  * support firmware upload/reboot device in UI
+  * add device property d235 - serial number (seems to match SN printed on 
Zune's back)
+  * add Zune recovery instructions
+  * add flash cli command
+  * send object info in separate bulk packets
+  * add device-reboot cli command
+  * add firmware version to device properties
+  * undefined firmware (called in publicly available "Inside MTP Responder" 
paper
+  * add EventCode enum values/ToString
+  * add mtp service extension codes
+  * send album cover in GUI
+  * use Supports(...) for attach cover context action
+  * add Library::AddCover, zune-import will upload cover automatically if 
supported
+  * pass empty initialiser as empty bytearray while removing album cover
+  * add Supported() helper for ObjectPropertyCodes
+  * add MetadataPicture, fill it with decoded PICTURE props
+
+-------------------------------------------------------------------

Old:
----
  android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1.tar.gz

New:
----
  android-file-transfer-linux-4.5.tar.gz

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

Other differences:
------------------
++++++ android-file-transfer-linux.spec ++++++
--- /var/tmp/diff_new_pack.Zap1Ah/_old  2025-10-14 18:09:52.254728636 +0200
+++ /var/tmp/diff_new_pack.Zap1Ah/_new  2025-10-14 18:09:52.254728636 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package android-file-transfer-linux
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 Name:           android-file-transfer-linux
 Summary:        Android file fransfer for Linux
-Version:        4.4.0~git.20250506T233238.058dbe1
+Version:        4.5
 Release:        0
 URL:            https://github.com/whoozle/android-file-transfer-linux
 Source0:        %{name}-%{version}.tar.gz

++++++ _service ++++++
--- /var/tmp/diff_new_pack.Zap1Ah/_old  2025-10-14 18:09:52.286729999 +0200
+++ /var/tmp/diff_new_pack.Zap1Ah/_new  2025-10-14 18:09:52.290730169 +0200
@@ -3,16 +3,18 @@
   <service name="obs_scm" mode="manual">
     <param name="scm">git</param>
     <param 
name="url">https://github.com/whoozle/android-file-transfer-linux</param>
-    <param name="revision">058dbe1b5405d8d46fdeec5573956762f0b9bded</param>
-    <param name="versionprefix">4.4.0~git</param>
-    <param name="versionformat">%ci.%h</param>
+    <param name="versionformat">@PARENT_TAG@</param>
+    <param name="versionrewrite-pattern">v(.*)</param>
+    <!-- <param name="revision">master</param> -->
+    <!-- <param name="versionprefix">4.5.0</param> -->
+    <!-- <param name="versionformat">%ci.%h</param> -->
     <param name="changesgenerate">enable</param>
   </service>
+  <service name="set_version" mode="manual"/>
   <service name="tar" mode="manual"/>
   <service name="recompress" mode="manual">
-    <param name="file">*.tar</param>
     <param name="compression">gz</param>
+    <param name="file">*.tar</param>
   </service>
-  <service name="set_version" mode="manual"/>
 </services>
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.Zap1Ah/_old  2025-10-14 18:09:52.310731022 +0200
+++ /var/tmp/diff_new_pack.Zap1Ah/_new  2025-10-14 18:09:52.318731362 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/whoozle/android-file-transfer-linux</param>
-              <param 
name="changesrevision">058dbe1b5405d8d46fdeec5573956762f0b9bded</param></service></servicedata>
+              <param 
name="changesrevision">d5c18820c2bae0656043ca127f4b05b756ea1479</param></service></servicedata>
 (No newline at EOF)
 

++++++ android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1.tar.gz -> 
android-file-transfer-linux-4.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/.github/workflows/actions.yml
 new/android-file-transfer-linux-4.5/.github/workflows/actions.yml
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/.github/workflows/actions.yml
     2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/.github/workflows/actions.yml   
2025-05-15 00:28:05.000000000 +0200
@@ -4,7 +4,7 @@
 
 jobs:
   Linux:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
     - name: Creating contiguous...
       uses: ncipollo/release-action@v1
@@ -30,7 +30,7 @@
     - name: Install Dependencies...
       run: |
         sudo apt-get update
-        sudo apt-get -y install qt5-default qttools5-dev qttools5-dev-tools 
libgtk2.0-dev libfuse-dev libmagic-dev libtag1-dev libssl-dev ninja-build cmake
+        sudo apt-get -y install qtbase5-dev qt5-qmake qttools5-dev 
qttools5-dev-tools libgtk2.0-dev libfuse3-dev libfuse2 libmagic-dev libtag1-dev 
libssl-dev ninja-build cmake
     - name: Checking out sources...
       uses: actions/checkout@v4
     - name: Configuring...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/CMakeLists.txt
 new/android-file-transfer-linux-4.5/CMakeLists.txt
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/CMakeLists.txt
    2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/CMakeLists.txt  2025-05-15 
00:28:05.000000000 +0200
@@ -124,6 +124,7 @@
        mtp/ptp/DataTypeCode.cpp
        mtp/ptp/Device.cpp
        mtp/ptp/DeviceProperty.cpp
+       mtp/ptp/EventCode.cpp
        mtp/ptp/Messages.cpp
        mtp/ptp/ObjectFormat.cpp
        mtp/ptp/ObjectProperty.cpp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/README.md 
new/android-file-transfer-linux-4.5/README.md
--- old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/README.md 
2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/README.md       2025-05-15 
00:28:05.000000000 +0200
@@ -1,7 +1,7 @@
 # Android File Transfer For Linux (FreeBSD and macOS, too!)
 
 
[![License](https://img.shields.io/:license-LGPLv2.1-blue.svg)](https://github.com/whoozle/android-file-transfer-linux/blob/master/LICENSE)
-[![Version](https://img.shields.io/:version-4.5-green.svg)](https://github.com/whoozle/android-file-transfer-linux)
+[![Version](https://img.shields.io/:version-4.6-green.svg)](https://github.com/whoozle/android-file-transfer-linux)
 [![Android File Transfer for Linux (and 
macOS!)](https://github.com/whoozle/android-file-transfer-linux/actions/workflows/actions.yml/badge.svg)](https://github.com/whoozle/android-file-transfer-linux/actions/workflows/actions.yml)
 
 Android File Transfer for Linux — a reliable 
[MTP](https://en.wikipedia.org/wiki/Media_Transfer_Protocol) client with 
minimalistic UI similar to [Android File 
Transfer](https://www.android.com/intl/en_us/filetransfer/).
@@ -168,6 +168,56 @@
 Remember, if you want album art to be displayed, it must be named 
'albumart.xxx' and placed *first* in the destination folder. Then copy other 
files.
 Also, note that FUSE could be 7-8 times slower than UI/CLI file transfer.
 
+### ZUNE firmware flashing/recovery
+
+1. Find Zune-Firmware-x86.msi on the internet
+2. Unpack it `7z x Zune-Firmware-x86.msi` in some directory, you should get 
the following files there:
+
+```
+DracoBaselineCab  FirmwareUpdateXml  KeelBaselineCab  PavoBaselineCab  
ScorpiusBaselineCab
+```
+3. Find the name of your update in FirmwareUpdateXml. If you're not sure, open 
[Zune Specifications](https://en.wikipedia.org/wiki/Zune#Specifications) 
wikipedia page, find your model in "Official Model Numbers" row, and match with 
"Codename".
+For instance Zune 4 model 1124 has codename "Scorpius".
+4. Unpack update for your device into some folder using cabextract: 
`cabextract XXXXBaselineCab`.
+
+Here's content of all cabs:
+```
+├── Draco
+│   ├── EBoot.bin
+│   ├── Games.cab
+│   ├── nk.bin
+│   └── recovery.bin
+├── Keel
+│   ├── EBoot.bin
+│   ├── Games.cab
+│   ├── nk.bin
+│   └── recovery.bin
+├── Pavo
+│   ├── EXT.bin
+│   ├── NK.bin
+│   ├── Recovery.bin
+│   └── ZBoot.bin
+└── Scorpius
+    ├── EBoot.bin
+    ├── Games.cab
+    ├── nk.bin
+    ├── recovery.bin
+    └── xldr.bin
+```
+
+5. Flash firmware files using cli tool. Generally you don't need to flash 
anything called `*boot*` or `*recovery*`.
+Original software starts with nk.bin, then EXT or Games.
+Here's an example of how I flash model 1395:
+```
+aft-mtp-cli -v -d 045e:063e # finds Zune HD 16Gb (model 1395)
+
+flash zune/Pavo/NK.bin
+flash zune/Pavo/EXT.bin
+device-reboot
+```
+6. Wait until your Zune restarts, it can take a minute or two.
+7. Voila, you don't need to fiddle with Zune software on windows anymore.
+
 ### Qt user interface
 
 1. Start application, choose destination folder and click any button on 
toolbar.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/android-file-transfer-linux.json
 new/android-file-transfer-linux-4.5/android-file-transfer-linux.json
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/android-file-transfer-linux.json
  2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/android-file-transfer-linux.json        
2025-05-15 00:28:05.000000000 +0200
@@ -13,7 +13,7 @@
       "config-opts": [ "-DCMAKE_BUILD_TYPE=Release" ],
       "sources": [{
         "type": "git",
-        "tag": "v4.5",
+        "tag": "v4.6",
         "url": "https://github.com/whoozle/android-file-transfer-linux.git";
       }]
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/cli/Session.cpp
 new/android-file-transfer-linux-4.5/cli/Session.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/cli/Session.cpp
   2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/cli/Session.cpp 2025-05-15 
00:28:05.000000000 +0200
@@ -125,6 +125,8 @@
                        make_function([this](const LocalPath &path, const Path 
&dst) -> void { Put(path, dst); }));
                AddCommand("put", "<file> uploads file",
                        make_function([this](const LocalPath &path) -> void { 
Put(path); }));
+               AddCommand("flash", "<file> sends file but set file format to 
UndefinedFirmware(0xb802).",
+                       make_function([this](const LocalPath &path) -> void { 
Flash(path); }));
 
                AddCommand("get", "<file> downloads file",
                        make_function([this](const Path &path) -> void { 
Get(path); }));
@@ -189,6 +191,10 @@
                                make_function([this](const LocalPath &path) -> 
void { ZuneImport(path); }));
                }
 
+               if 
(_session->GetDeviceInfo().Supports(mtp::OperationCode::RebootDevice)) {
+                       AddCommand("device-reboot", "reboots device (Microsoft 
specific?)", make_function([this]() -> void { RebootDevice(); }));
+               }
+
                AddCommand("test-property-list", "test GetObjectPropList on 
given object",
                        make_function([this](const Path &path) -> void { 
TestObjectPropertyList(path); }));
 
@@ -771,7 +777,7 @@
                }
        }
 
-       void Session::Put(mtp::ObjectId parentId, const LocalPath &src, const 
std::string &targetFilename)
+       void Session::Put(mtp::ObjectId parentId, const LocalPath &src, const 
std::string &targetFilename, mtp::ObjectFormat format)
        {
                using namespace mtp;
                struct stat st = Stat(src);
@@ -827,9 +833,12 @@
                        auto stream = std::make_shared<ObjectInputStream>(src);
                        stream->SetTotal(stream->GetSize());
 
+                       if (format == mtp::ObjectFormat::Any)
+                               format = ObjectFormatFromFilename(src);
+
                        msg::ObjectInfo oi;
                        oi.Filename = filename;
-                       oi.ObjectFormat = ObjectFormatFromFilename(src);
+                       oi.ObjectFormat = format;
                        oi.ObjectCompressedSize = stream->GetSize();
 
                        if (_showEvents)
@@ -1103,6 +1112,9 @@
                }
        }
 
+       void Session::RebootDevice()
+       { _session->RebootDevice(); }
+
        void Session::ZuneInit()
        {
                if (!_library)
@@ -1124,7 +1136,7 @@
                if (!meta)
                        throw std::runtime_error("no metadata");
 
-               print("metadata: ", meta->Artist, " / ", meta->Album, " (", 
meta->Year, ") / ", meta->Title);
+               print("metadata: ", meta->Artist, " / ", meta->Album, " (", 
meta->Year, ") / ", meta->Title, " picture description: ", 
meta->Picture.Description);
 
                auto artist = _library->GetArtist(meta->Artist);
                if (!artist)
@@ -1148,6 +1160,9 @@
                auto songId = _library->CreateTrack(artist, album, format, 
meta->Title, meta->Genre, meta->Track, filename, stream->GetSize());
                _session->SendObject(stream);
 
+               if (!meta->Picture.Data.empty())
+                       _library->AddCover(album, meta->Picture.Data);
+
                _library->AddTrack(album, songId);
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/cli/Session.h 
new/android-file-transfer-linux-4.5/cli/Session.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/cli/Session.h 
    2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/cli/Session.h   2025-05-15 
00:28:05.000000000 +0200
@@ -114,7 +114,7 @@
                { Get(dst, srcId, true); }
                void Cat(const Path &path);
                void Rename(const Path & path, const std::string & newName);
-               void Put(mtp::ObjectId parentId, const LocalPath &src, const 
std::string &targetFilename = std::string());
+               void Put(mtp::ObjectId parentId, const LocalPath &src, const 
std::string &targetFilename = std::string(), mtp::ObjectFormat format = 
mtp::ObjectFormat::Any);
                void Put(const LocalPath &src, const Path &dst);
                mtp::ObjectId MakeDirectory(mtp::ObjectId parentId, const 
std::string & name);
                void ListObjects(const std::string & format);
@@ -137,6 +137,9 @@
                void Put(const LocalPath &src)
                { Put(_cd, src); }
 
+               void Flash(const LocalPath &src)
+               { Put(_cd, src, {}, mtp::ObjectFormat::UndefinedFirmware); }
+
                void Get(const Path &src)
                { Get(Resolve(src)); }
 
@@ -174,6 +177,7 @@
 
                void ZuneInit();
                void ZuneImport(const LocalPath & path);
+               void RebootDevice();
 
                template <typename ...Args>
                void AddCommand(const std::string &name, const std::string 
&help, std::function<void(Args...)> && callback)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/fuse/fuse.cpp 
new/android-file-transfer-linux-4.5/fuse/fuse.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/fuse/fuse.cpp 
    2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/fuse/fuse.cpp   2025-05-15 
00:28:05.000000000 +0200
@@ -823,14 +823,14 @@
        void Init (void *userdata, struct fuse_conn_info *conn)
        {
                mtp::debug("Init: fuse proto version: ", conn->proto_major, 
".", conn->proto_minor,
-                       ", capability: 0x", mtp::hex(conn->capable_ext, 8),
+                       ", capability: 0x", mtp::hex(conn->capable, 8),
                        ", max readahead: ", conn->max_readahead, ", max write: 
", conn->max_write
                );
 
                //If synchronous reads are chosen, Fuse will wait for reads to 
complete before issuing any other requests.
                //mtp is completely synchronous. you cannot have two 
transaction in parallel, so you have to wait any operation to finish before 
starting another one
 
-               fuse_unset_feature_flag(conn, FUSE_CAP_ASYNC_READ);
+               conn->want &= ~FUSE_CAP_ASYNC_READ;
                try { g_wrapper->Init(userdata, conn); } catch (const 
std::exception &ex) { mtp::error("init failed:", ex.what()); }
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Library.cpp
 new/android-file-transfer-linux-4.5/mtp/metadata/Library.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Library.cpp
  2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/metadata/Library.cpp        
2025-05-15 00:28:05.000000000 +0200
@@ -52,7 +52,9 @@
                debug("device supports ObjectFormat::Artist: ", 
_artistSupported? "yes": "no");
                {
                        auto propsSupported = 
_session->GetObjectPropertiesSupported(ObjectFormat::AbstractAudioAlbum);
-                       _albumDateAuthoredSupported = 
std::find(propsSupported.ObjectPropertyCodes.begin(), 
propsSupported.ObjectPropertyCodes.end(), ObjectProperty::DateAuthored) != 
propsSupported.ObjectPropertyCodes.end();
+                       _albumDateAuthoredSupported = 
propsSupported.Supports(ObjectProperty::DateAuthored);
+                       _albumCoverSupported = 
propsSupported.Supports(ObjectProperty::RepresentativeSampleData);
+                       mtp::debug("abstract album supports date authored: ", 
_albumDateAuthoredSupported, ", cover: ", _albumCoverSupported);
                }
 
                _storage = storages.StorageIDs[0]; //picking up first storage.
@@ -405,6 +407,14 @@
                tracks.insert(std::make_pair(ti.Name, ti.Index));
        }
 
+       void Library::AddCover(AlbumPtr album, const mtp::ByteArray &data)
+       {
+               if (!album || !_albumCoverSupported)
+                       return;
+
+               mtp::debug("sending ", data.size(), " bytes of album cover...");
+               _session->SetObjectPropertyAsArray(album->Id, 
mtp::ObjectProperty::RepresentativeSampleData, data);
+       }
 
        bool Library::Supported(const mtp::SessionPtr & session)
        {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Library.h
 new/android-file-transfer-linux-4.5/mtp/metadata/Library.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Library.h
    2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/metadata/Library.h  2025-05-15 
00:28:05.000000000 +0200
@@ -3,6 +3,7 @@
 
 #include <mtp/ptp/ObjectId.h>
 #include <mtp/ptp/ObjectFormat.h>
+#include <mtp/ByteArray.h>
 #include <mtp/types.h>
 #include <functional>
 #include <memory>
@@ -68,6 +69,7 @@
                ObjectId _musicFolder;
                bool _artistSupported;
                bool _albumDateAuthoredSupported;
+               bool _albumCoverSupported;
 
                using ArtistMap = std::unordered_map<std::string, ArtistPtr>;
                ArtistMap _artists;
@@ -102,6 +104,7 @@
                bool HasTrack(const AlbumPtr & album, const std::string &name, 
int trackIndex);
                NewTrackInfo CreateTrack(const ArtistPtr & artist, const 
AlbumPtr & album, ObjectFormat type, std::string name, const std::string & 
genre, int trackIndex, const std::string &filename, size_t size);
                void AddTrack(AlbumPtr album, const NewTrackInfo &ti);
+               void AddCover(AlbumPtr album, const mtp::ByteArray &data);
        };
        DECLARE_PTR(Library);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Metadata.cpp
 new/android-file-transfer-linux-4.5/mtp/metadata/Metadata.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Metadata.cpp
 2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/metadata/Metadata.cpp       
2025-05-15 00:28:05.000000000 +0200
@@ -1,4 +1,5 @@
 #include <mtp/metadata/Metadata.h>
+#include <mtp/log.h>
 
 #ifdef HAVE_TAGLIB
 #      include <fileref.h>
@@ -34,6 +35,30 @@
                meta->Genre     = tag->genre().to8Bit(true);
                meta->Year              = tag->year();
                meta->Track             = tag->track();
+
+#if TAGLIB_MAJOR_VERSION >= 2
+               for(auto & props : tag->complexProperties("PICTURE"))
+               {
+                       auto &picture = meta->Picture;
+                       for(auto &kv : props)
+                       {
+                               auto &name = kv.first;
+                               auto &value = kv.second;
+                               if (name == "data") {
+                                       auto data = value.toByteVector();
+                                       picture.Data.assign(data.begin(), 
data.end());
+                               } else if (name == "pictureType") {
+                                       picture.Type = 
value.toString().to8Bit(true);
+                               } else if (name == "mimeType") {
+                                       picture.MimeType = 
value.toString().to8Bit(true);
+                               } else if (name == "description") {
+                                       picture.Description = 
value.toString().to8Bit(true);
+                               } else {
+                                       mtp::debug("unhandled PICTURE property 
", name.toCString(true));
+                               }
+                       }
+               }
+#endif
                return meta;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Metadata.h
 new/android-file-transfer-linux-4.5/mtp/metadata/Metadata.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/metadata/Metadata.h
   2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/metadata/Metadata.h 2025-05-15 
00:28:05.000000000 +0200
@@ -2,6 +2,7 @@
 #define AFTL_MTP_METADATA_METADATA_H
 
 #include <mtp/types.h>
+#include <mtp/ByteArray.h>
 #include <memory>
 #include <string>
 
@@ -10,6 +11,14 @@
        struct Metadata;
        DECLARE_PTR(Metadata);
 
+       struct MetadataPicture
+       {
+               std::string     Type;
+               std::string             MimeType;
+               std::string             Description;
+               mtp::ByteArray  Data;
+       };
+
        struct Metadata
        {
                std::string     Title;
@@ -18,6 +27,7 @@
                std::string     Genre;
                unsigned                Year;
                unsigned                Track;
+               MetadataPicture Picture;
 
                static MetadataPtr Read(const std::string & path);
        };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/DeviceProperty.values.h
 new/android-file-transfer-linux-4.5/mtp/ptp/DeviceProperty.values.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/DeviceProperty.values.h
   2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/DeviceProperty.values.h 
2025-05-15 00:28:05.000000000 +0200
@@ -31,17 +31,27 @@
 ENUM_VALUE(Artist, 0x501e)
 ENUM_VALUE(CopyrightInfo, 0x501f)
 
+ENUM_VALUE(SecureTime, 0xd101)
+ENUM_VALUE(DeviceCertificate, 0xd102)
+ENUM_VALUE(RevocationInfo, 0xd103)
+ENUM_VALUE(PlaysForSureID, 0xd131)
+
 ENUM_VALUE(DeviceEUI64, 0xd210)
+ENUM_VALUE(FirmwareVersion, 0xd233)
+ENUM_VALUE(SerialNumber, 0xd235)
+
+ENUM_VALUE(FunctionalID, 0xd301)
+ENUM_VALUE(ModelID, 0xd302)
+ENUM_VALUE(UseDeviceStage, 0xd303)
 
 ENUM_VALUE(SynchronizationPartner, 0xd401)
 ENUM_VALUE(DeviceFriendlyName, 0xd402)
 ENUM_VALUE(Volume, 0xd403)
 ENUM_VALUE(SupportedFormatsOrdered, 0xd404)
 ENUM_VALUE(DeviceIcon, 0xd405)
+ENUM_VALUE(SessionInitiatorVersionInfo, 0xd406)
+ENUM_VALUE(PerceivedDeviceType, 0xd407)
 ENUM_VALUE(PlaybackRate, 0xd410)
 ENUM_VALUE(PlaybackObject, 0xd411)
 ENUM_VALUE(PlaybackContainerIndex, 0xd412)
 ENUM_VALUE(PlaybackPosition, 0xd413)
-
-ENUM_VALUE(SessionInitiatorVersionInfo, 0xd406)
-ENUM_VALUE(PerceivedDeviceType, 0xd407)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/EventCode.cpp
 new/android-file-transfer-linux-4.5/mtp/ptp/EventCode.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/EventCode.cpp
     1970-01-01 01:00:00.000000000 +0100
+++ new/android-file-transfer-linux-4.5/mtp/ptp/EventCode.cpp   2025-05-15 
00:28:05.000000000 +0200
@@ -0,0 +1,15 @@
+#include <mtp/ptp/EventCode.h>
+#include <mtp/log.h>
+
+namespace mtp
+{
+       std::string ToString(EventCode code)
+       {
+               switch(code)
+               {
+#                      define ENUM_VALUE(NAME, VALUE) 
ENUM_VALUE_TO_STRING(EventCode, NAME, VALUE)
+#                      include <mtp/ptp/EventCode.values.h>
+                       ENUM_VALUE_TO_STRING_DEFAULT(OperationCode, code, 4);
+               }
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/EventCode.h
 new/android-file-transfer-linux-4.5/mtp/ptp/EventCode.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/EventCode.h
       2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/EventCode.h     2025-05-15 
00:28:05.000000000 +0200
@@ -1,3 +1,22 @@
+/*
+    This file is part of Android File Transfer For Linux.
+    Copyright (C) 2015-2025  Vladimir Menshakov
+
+    This library is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License,
+    or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation,
+    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
 #ifndef AFTL_MTP_PTP_EVENTCODE_H
 #define AFTL_MTP_PTP_EVENTCODE_H
 
@@ -7,26 +26,13 @@
 {
        enum struct EventCode : u16
        {
-               TransactionCancelled    = 0x4001,
-               ObjectAdded                             = 0x4002,
-               ObjectRemoved                   = 0x4003,
-               StoreAdded                              = 0x4004,
-               StoreRemoved                    = 0x4005,
-               DevicePropChanged               = 0x4006,
-               ObjectInfoChanged               = 0x4007,
-               DeviceInfoChanged               = 0x4008,
-               RequestObjectTransfer   = 0x4009,
-               StoreFull                               = 0x400a,
-               DeviceReset                             = 0x400b,
-               StorageInfoChanged              = 0x400c,
-               CaptureComplete                 = 0x400d,
-               UnreportedStatus                = 0x400e,
-
-               ObjectPropChanged               = 0xc801,
-               ObjectPropDescChanged   = 0xc802,
-               ObjectReferenceChanged  = 0xc803
+#define ENUM_VALUE(NAME, VALUE) ENUM_VALUE_DECL(NAME, VALUE)
+#              include <mtp/ptp/EventCode.values.h>
+#undef ENUM_VALUE
        };
        DECLARE_ENUM(EventCode, u16);
+
+       std::string ToString(EventCode code);
 }
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/EventCode.values.h
 new/android-file-transfer-linux-4.5/mtp/ptp/EventCode.values.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/EventCode.values.h
        1970-01-01 01:00:00.000000000 +0100
+++ new/android-file-transfer-linux-4.5/mtp/ptp/EventCode.values.h      
2025-05-15 00:28:05.000000000 +0200
@@ -0,0 +1,17 @@
+ENUM_VALUE(TransactionCancelled, 0x4001)
+ENUM_VALUE(ObjectAdded, 0x4002)
+ENUM_VALUE(ObjectRemoved, 0x4003)
+ENUM_VALUE(StoreAdded, 0x4004)
+ENUM_VALUE(StoreRemoved, 0x4005)
+ENUM_VALUE(DevicePropChanged, 0x4006)
+ENUM_VALUE(ObjectInfoChanged, 0x4007)
+ENUM_VALUE(DeviceInfoChanged, 0x4008)
+ENUM_VALUE(RequestObjectTransfer, 0x4009)
+ENUM_VALUE(StoreFull, 0x400a)
+ENUM_VALUE(DeviceReset, 0x400b)
+ENUM_VALUE(StorageInfoChanged, 0x400c)
+ENUM_VALUE(CaptureComplete, 0x400d)
+ENUM_VALUE(UnreportedStatus, 0x400e)
+ENUM_VALUE(ObjectPropChanged, 0xc801)
+ENUM_VALUE(ObjectPropDescChanged, 0xc802)
+ENUM_VALUE(ObjectReferenceChanged, 0xc803)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Messages.cpp
 new/android-file-transfer-linux-4.5/mtp/ptp/Messages.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Messages.cpp
      2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/Messages.cpp    2025-05-15 
00:28:05.000000000 +0200
@@ -61,4 +61,8 @@
                return ss.str();
        }
 
+       bool ObjectPropertiesSupported::Supports(ObjectProperty prop) const
+       { return std::find(ObjectPropertyCodes.begin(), 
ObjectPropertyCodes.end(), prop) != ObjectPropertyCodes.end(); }
+
+
 }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Messages.h
 new/android-file-transfer-linux-4.5/mtp/ptp/Messages.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Messages.h
        2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/Messages.h      2025-05-15 
00:28:05.000000000 +0200
@@ -219,6 +219,8 @@
        {
                std::vector<ObjectProperty>             ObjectPropertyCodes;
 
+               bool Supports(ObjectProperty prop) const;
+
                void Read(InputStream &stream)
                {
                        stream >> ObjectPropertyCodes;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/ObjectFormat.values.h
 new/android-file-transfer-linux-4.5/mtp/ptp/ObjectFormat.values.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/ObjectFormat.values.h
     2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/ObjectFormat.values.h   
2025-05-15 00:28:05.000000000 +0200
@@ -36,8 +36,7 @@
 ENUM_VALUE(M4a, 0xb215)
 ENUM_VALUE(Artist, 0xb218)
 
-ENUM_VALUE(UndefinedFirmware, 0xb800)
-ENUM_VALUE(UndefinedFirmwareAndroid, 0xb802)
+ENUM_VALUE(UndefinedFirmware, 0xb802)
 ENUM_VALUE(WindowsImageFormat, 0xb881)
 
 ENUM_VALUE(UndefinedAudio, 0xb900)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/OperationCode.values.h
 new/android-file-transfer-linux-4.5/mtp/ptp/OperationCode.values.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/OperationCode.values.h
    2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/OperationCode.values.h  
2025-05-15 00:28:05.000000000 +0200
@@ -49,6 +49,7 @@
 
 ENUM_VALUE(WMPMetadataRoundTrip, 0x9201)
 ENUM_VALUE(WmpGetAcquiredContent, 0x9202)
+ENUM_VALUE(RebootDevice, 0x9204)
 
 ENUM_VALUE(SendWMDRMPDAppRequest, 0x9212)
 ENUM_VALUE(GetWMDRMPDAppResponse, 0x9213)
@@ -56,6 +57,17 @@
 ENUM_VALUE(DisableTrustedFilesOperations, 0x9215)
 ENUM_VALUE(EndTrustedAppSession, 0x9216)
 
+ENUM_VALUE(GetServiceIDs, 0x9301)
+ENUM_VALUE(GetServiceInfo, 0x9302)
+ENUM_VALUE(GetServiceCapabilities, 0x9303)
+ENUM_VALUE(GetServicePropDesc, 0x9304)
+ENUM_VALUE(GetServicePropList, 0x9305)
+ENUM_VALUE(SetServicePropList, 0x9306)
+ENUM_VALUE(UpdateObjectPropList, 0x9307)
+ENUM_VALUE(DeleteObjectPropList, 0x9308)
+ENUM_VALUE(DeleteServicePropList, 0x9309)
+ENUM_VALUE(GetFormatCapabilities, 0x930a)
+
 ENUM_VALUE(SendTinyCLRData, 0x9401)
 ENUM_VALUE(GetTinyCLRData, 0x9402)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/ResponseType.values.h
 new/android-file-transfer-linux-4.5/mtp/ptp/ResponseType.values.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/ResponseType.values.h
     2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/ResponseType.values.h   
2025-05-15 00:28:05.000000000 +0200
@@ -30,6 +30,8 @@
 ENUM_VALUE(SessionAlreadyOpen, 0x201e)
 ENUM_VALUE(TransactionCancelled, 0x201f)
 ENUM_VALUE(SpecificationOfDestinationUnsupported, 0x2020)
+ENUM_VALUE(InvalidServiceID, 0xa301)
+ENUM_VALUE(InvalidServicePropCode, 0xa302)
 ENUM_VALUE(TinyCLRNotResponding, 0xa401)
 ENUM_VALUE(NoDataWaiting, 0xa402)
 ENUM_VALUE(InvalidObjectPropCode, 0xa801)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Session.cpp
 new/android-file-transfer-linux-4.5/mtp/ptp/Session.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Session.cpp
       2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/Session.cpp     2025-05-15 
00:28:05.000000000 +0200
@@ -105,7 +105,8 @@
        void Session::Close()
        {
                scoped_mutex_lock l(_mutex);
-               Send(OperationRequest(OperationCode::CloseSession, 0, 
_sessionId));
+               Transaction transaction(this);
+               Send(OperationRequest(OperationCode::CloseSession, 
transaction.Id));
                ByteArray data, response;
                ResponseType responseCode;
                _packeter.Read(0, data, responseCode, response, 
_defaultTimeout);
@@ -296,10 +297,25 @@
                Send(OperationRequest(OperationCode::SendObjectInfo, 
transaction.Id, storageId.Id, parentObject.Id));
                {
                        DataRequest req(OperationCode::SendObjectInfo, 
transaction.Id);
-                       OutputStream stream(req.Data);
-                       objectInfo.Write(stream);
-                       Container container(req);
-                       _packeter.Write(container.Data, _defaultTimeout);
+                       if (_separateBulkWrites)
+                       {
+                               ByteArray data;
+                               OutputStream os(data);
+                               objectInfo.Write(os);
+                               auto is = 
std::make_shared<ByteArrayObjectInputStream>(data);
+
+                               Container container(req, is);
+                               _packeter.Write(container.Data, 
_defaultTimeout);
+
+                               _packeter.Write(is, _defaultTimeout);
+                       }
+                       else
+                       {
+                               OutputStream stream(req.Data);
+                               objectInfo.Write(stream);
+                               Container container(req);
+                               _packeter.Write(container.Data, 
_defaultTimeout);
+                       }
                }
                ByteArray data, response;
                ResponseType responseCode;
@@ -319,7 +335,7 @@
                        Container container(req, inputStream);
                        if (_separateBulkWrites)
                        {
-                               
_packeter.Write(std::make_shared<ByteArrayObjectInputStream>(container.Data), 
timeout);
+                               _packeter.Write(container.Data, timeout);
                                _packeter.Write(inputStream, timeout);
                        } else
                                
_packeter.Write(std::make_shared<JoinedObjectInputStream>(std::make_shared<ByteArrayObjectInputStream>(container.Data),
 inputStream), timeout);
@@ -534,6 +550,9 @@
        void Session::EnableSecureFileOperations(u32 cmac[4])
        { RunTransaction(_defaultTimeout, 
OperationCode::EnableTrustedFilesOperations, cmac[0], cmac[1], cmac[2], 
cmac[3]); }
 
+       void Session::RebootDevice()
+       { RunTransaction(_defaultTimeout, OperationCode::RebootDevice); }
+
        Session::ObjectEditSession::ObjectEditSession(const SessionPtr & 
session, ObjectId objectId): _session(session), _objectId(objectId)
        { session->BeginEditObject(objectId); }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Session.h
 new/android-file-transfer-linux-4.5/mtp/ptp/Session.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/mtp/ptp/Session.h
 2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/mtp/ptp/Session.h       2025-05-15 
00:28:05.000000000 +0200
@@ -143,6 +143,7 @@
 
                //windows specific
                void EnableSecureFileOperations(u32 cmac1[4]);
+               void RebootDevice();
 
                static msg::DeviceInfo GetDeviceInfo(PipePacketer& packeter, 
u32 transactionId, int timeout = 0);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/commandqueue.cpp
 new/android-file-transfer-linux-4.5/qt/commandqueue.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/commandqueue.cpp
       2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/commandqueue.cpp     2025-05-15 
00:28:05.000000000 +0200
@@ -35,7 +35,7 @@
 { queue.finish(DirectoryId); }
 
 void UploadFile::execute(CommandQueue &queue)
-{ queue.uploadFile(Filename); }
+{ queue.uploadFile(Filename, Format); }
 
 void MakeDirectory::execute(CommandQueue &queue)
 { queue.createDirectory(Filename); }
@@ -99,7 +99,7 @@
        addProgress(fi.size());
 }
 
-void CommandQueue::uploadFile(const QString &filename)
+void CommandQueue::uploadFile(const QString &filename, mtp::ObjectFormat 
format)
 {
        if (_aborted)
                return;
@@ -107,7 +107,7 @@
        QFileInfo fi(filename);
        QString parentPath = fi.dir().path();
 
-       qDebug() << "uploading file " << filename << ", parent: " << parentPath;
+       qDebug() << "uploading file " << filename << ", parent: " << parentPath 
<< ", format: " << fromUtf8(mtp::ToString(format));
 
        if (_directories.empty())
        {
@@ -127,7 +127,7 @@
                if (_model->parentObjectId() != parent.value()) //needed for 
overwrite protection
                        _model->setParent(parent.value());
 
-               _model->uploadFile(parent.value(), filename);
+               _model->uploadFile(parent.value(), filename, {}, format);
        } catch(const std::exception &ex)
        { qDebug() << "uploading file " << filename << " failed: " << 
fromUtf8(ex.what()); }
 
@@ -208,6 +208,9 @@
                _albums.insert(std::make_pair(dir, album));
        }
 
+       if (!metadata->Picture.Data.empty())
+               _library->AddCover(album, metadata->Picture.Data);
+
        if (_library->HasTrack(album, metadata->Title, metadata->Track)) {
                qDebug() << "skipping" << filename << ", already uploaded";
                return;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/commandqueue.h
 new/android-file-transfer-linux-4.5/qt/commandqueue.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/commandqueue.h
 2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/commandqueue.h       2025-05-15 
00:28:05.000000000 +0200
@@ -66,7 +66,8 @@
 
 struct UploadFile : public FileCommand
 {
-       UploadFile(const QString &filename) : FileCommand(filename) { }
+       mtp::ObjectFormat Format;
+       UploadFile(const QString &filename, mtp::ObjectFormat format) : 
FileCommand(filename), Format(format) { }
        void execute(CommandQueue &queue);
 };
 
@@ -120,7 +121,7 @@
 
        void loadLibrary();
        void createDirectory(const QString &path);
-       void uploadFile(const QString &file);
+       void uploadFile(const QString &file, mtp::ObjectFormat format);
        void downloadFile(const QString &filename, mtp::ObjectId objectId);
        void importFile(const QString &file);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/fileuploader.cpp
 new/android-file-transfer-linux-4.5/qt/fileuploader.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/fileuploader.cpp
       2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/fileuploader.cpp     2025-05-15 
00:28:05.000000000 +0200
@@ -86,7 +86,7 @@
        emit finished();
 }
 
-void FileUploader::upload(QStringList files)
+void FileUploader::upload(QStringList files, mtp::ObjectFormat format)
 {
        _model->moveToThread(&_workerThread);
        _total = 0;
@@ -113,7 +113,7 @@
 
                                if (fi.isFile())
                                {
-                                       commands.push_back(new 
UploadFile(next));
+                                       commands.push_back(new UploadFile(next, 
format));
                                        _total += fi.size();
                                }
                                else if (fi.isDir())
@@ -125,7 +125,7 @@
                }
                else if (currentFileInfo.isFile())
                {
-                       commands.push_back(new UploadFile(currentFile));
+                       commands.push_back(new UploadFile(currentFile, format));
                        _total += currentFileInfo.size();
                }
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/fileuploader.h
 new/android-file-transfer-linux-4.5/qt/fileuploader.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/fileuploader.h
 2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/fileuploader.h       2025-05-15 
00:28:05.000000000 +0200
@@ -24,6 +24,7 @@
 #include <QThread>
 #include <QDateTime>
 #include <mtp/types.h>
+#include <mtp/ptp/ObjectFormat.h>
 #include <memory>
 
 class MtpObjectsModel;
@@ -62,7 +63,7 @@
        void tryCreateLibrary();
        mtp::LibraryPtr library() const;
 
-       void upload(QStringList files);
+       void upload(QStringList files, mtp::ObjectFormat format);
        void importMusic(const QString & path);
        void download(const QString &path, const QVector<mtp::ObjectId> & 
objectIds);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mainwindow.cpp
 new/android-file-transfer-linux-4.5/qt/mainwindow.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mainwindow.cpp
 2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/mainwindow.cpp       2025-05-15 
00:28:05.000000000 +0200
@@ -107,6 +107,8 @@
        connect(_ui->actionShowThumbnails, SIGNAL(triggered(bool)), 
SLOT(showThumbnails(bool)));
        connect(_ui->actionRemoveCover, SIGNAL(triggered(bool)), 
SLOT(removeCover()));
        connect(_ui->actionAttachCover, SIGNAL(triggered(bool)), 
SLOT(attachCover()));
+       connect(_ui->actionUploadFirmware, SIGNAL(triggered()), 
SLOT(uploadFirmware()));
+       connect(_ui->actionRebootDevice, SIGNAL(triggered()), 
SLOT(rebootDevice()));
 
        connect(_objectModel, SIGNAL(onFilesDropped(QStringList)), 
SLOT(onFilesDropped(QStringList)));
        connect(_objectModel, SIGNAL(existingFileOverwrite(QString)), 
SLOT(confirmOverwrite(QString)), Qt::BlockingQueuedConnection);
@@ -469,6 +471,9 @@
        _ui->actionGoDown->setEnabled(rows.size() == 1);
        _ui->actionBack->setEnabled(!_history.empty());
 
+       _ui->actionUploadFirmware->setEnabled(_session? 
_session->GetDeviceInfo().Supports(mtp::ObjectFormat::UndefinedFirmware): 
false);
+       _ui->actionRebootDevice->setEnabled(_session? 
_session->GetDeviceInfo().Supports(mtp::OperationCode::RebootDevice): false);
+
        QStringList statusList;
        for(const auto & h : _history)
                statusList.push_back(h.first);
@@ -558,12 +563,7 @@
 
                        visited.insert(format);
                        auto supportedProperties = 
_session->GetObjectPropertiesSupported(format);
-                       auto & properties = 
supportedProperties.ObjectPropertyCodes;
-                       auto it = std::find(properties.begin(), 
properties.end(), mtp::ObjectProperty::RepresentativeSampleData);
-                       if (it != properties.end()) {
-                               showRSMenu = true;
-                               break;
-                       }
+                       showRSMenu = 
supportedProperties.Supports(mtp::ObjectProperty::RepresentativeSampleData);
                } catch (const std::exception & ex) {
                        qWarning() << "checking representative sample failed";
                }
@@ -611,12 +611,12 @@
        saveGeometry("create-directory-dialog", d);
 }
 
-void MainWindow::uploadFiles(const QStringList &files)
+void MainWindow::uploadFiles(const QStringList &files, mtp::ObjectFormat 
format)
 {
        if (files.isEmpty())
                return;
 
-       qDebug() << "uploadFiles " << files;
+       qDebug() << "uploadFiles " << files << ", format: " << 
fromUtf8(mtp::ToString(format));
        _uploadAnswer = 0;
        _proxyModel->setSourceModel(NULL);
        ProgressDialog progressDialog(this);
@@ -628,7 +628,7 @@
        connect(_uploader, SIGNAL(uploadStarted(QString)), &progressDialog, 
SLOT(setFilename(QString)));
        connect(_uploader, SIGNAL(finished()), &progressDialog, SLOT(accept()));
        connect(&progressDialog, SIGNAL(abort()), _uploader, SLOT(abort()));
-       _uploader->upload(files);
+       _uploader->upload(files, format);
 
        progressDialog.exec();
 
@@ -987,15 +987,40 @@
        QItemSelectionModel *selection =_ui->listView->selectionModel();
        QModelIndexList rows = selection->selectedRows();
 
-       mtp::ByteArray value;
-
        for(QModelIndex row : rows)
        {
                row = mapIndex(row);
                auto id = _objectModel->objectIdAt(row.row());
                try
-               { _session->SetObjectPropertyAsArray(id, 
mtp::ObjectProperty::RepresentativeSampleData, value); }
+               { _session->SetObjectPropertyAsArray(id, 
mtp::ObjectProperty::RepresentativeSampleData, {}); }
                catch(const std::exception & ex)
                { qWarning() << "failed to remove cover:" << ex.what(); }
        }
 }
+
+void MainWindow::uploadFirmware()
+{
+       QFileDialog d(this);
+
+       QSettings settings;
+       {
+               QVariant ld = settings.value("the-latest-firmware-directory");
+               if (ld.isValid())
+                       d.setDirectory(ld.toString());
+       }
+
+       d.setAcceptMode(QFileDialog::AcceptOpen);
+       d.setFileMode(QFileDialog::ExistingFiles);
+       d.setOption(QFileDialog::ShowDirsOnly, false);
+       d.setOption(QFileDialog::ReadOnly, true);
+       restoreGeometry("upload-firmware", d);
+       if (!d.exec())
+               return;
+
+       saveGeometry("upload-firmware", d);
+       settings.setValue("the-latest-firmware-directory", 
d.directory().absolutePath());
+       uploadFiles(d.selectedFiles(), mtp::ObjectFormat::UndefinedFirmware);
+}
+
+void MainWindow::rebootDevice()
+{ _session->RebootDevice(); }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mainwindow.h
 new/android-file-transfer-linux-4.5/qt/mainwindow.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mainwindow.h
   2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/mainwindow.h 2025-05-15 
00:28:05.000000000 +0200
@@ -25,6 +25,7 @@
 #include <QVector>
 #include <QByteArray>
 #include <mtp/ptp/ObjectId.h>
+#include <mtp/ptp/ObjectFormat.h>
 #include <mtp/types.h>
 
 namespace Ui {
@@ -95,7 +96,7 @@
        void renameFile();
        void deleteFiles();
        void downloadFiles(const QVector<mtp::ObjectId> &objects);
-       void uploadFiles(const QStringList &files);
+       void uploadFiles(const QStringList &files, mtp::ObjectFormat format = 
mtp::ObjectFormat::Any);
        void onFilesDropped(const QStringList &files);
        void onStorageChanged(int idx);
        void validateClipboard();
@@ -104,6 +105,8 @@
        void showThumbnails(bool enable);
        void attachCover();
        void removeCover();
+       void uploadFirmware();
+       void rebootDevice();
 
 public slots:
        void downloadFiles(const QString & path, const QVector<mtp::ObjectId> 
&objects);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mainwindow.ui
 new/android-file-transfer-linux-4.5/qt/mainwindow.ui
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mainwindow.ui
  2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/mainwindow.ui        2025-05-15 
00:28:05.000000000 +0200
@@ -71,6 +71,9 @@
     <addaction name="separator"/>
     <addaction name="actionCreateDirectory"/>
     <addaction name="separator"/>
+    <addaction name="actionUploadFirmware"/>
+    <addaction name="actionRebootDevice"/>
+    <addaction name="separator"/>
     <addaction name="actionPaste"/>
     <addaction name="separator"/>
     <addaction name="actionExit"/>
@@ -119,7 +122,7 @@
   </action>
   <action name="actionCreateDirectory">
    <property name="text">
-    <string>&amp;CreateDirectory</string>
+    <string>&amp;CreateDirectory...</string>
    </property>
    <property name="shortcut">
     <string>Ctrl+N</string>
@@ -233,6 +236,16 @@
     <string>Import individual music files</string>
    </property>
   </action>
+  <action name="actionUploadFirmware">
+   <property name="text">
+    <string>Upload Firmware...</string>
+   </property>
+  </action>
+  <action name="actionRebootDevice">
+   <property name="text">
+    <string>Reboot Device</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources/>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mtpobjectsmodel.cpp
 new/android-file-transfer-linux-4.5/qt/mtpobjectsmodel.cpp
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mtpobjectsmodel.cpp
    2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/mtpobjectsmodel.cpp  2025-05-15 
00:28:05.000000000 +0200
@@ -256,10 +256,12 @@
        return noi.ObjectId;
 }
 
-bool MtpObjectsModel::uploadFile(mtp::ObjectId parentObjectId, const QString 
&filePath, QString filename)
+bool MtpObjectsModel::uploadFile(mtp::ObjectId parentObjectId, const QString 
&filePath, QString filename, mtp::ObjectFormat format)
 {
        QFileInfo fileInfo(filePath);
-       mtp::ObjectFormat objectFormat = 
mtp::ObjectFormatFromFilename(toUtf8(filePath));
+       mtp::ObjectFormat objectFormat = format == mtp::ObjectFormat::Any?
+               mtp::ObjectFormatFromFilename(toUtf8(filePath)):
+               format;
 
        if (filename.isEmpty())
                filename = fileInfo.fileName();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mtpobjectsmodel.h
 new/android-file-transfer-linux-4.5/qt/mtpobjectsmodel.h
--- 
old/android-file-transfer-linux-4.4.0~git.20250506T233238.058dbe1/qt/mtpobjectsmodel.h
      2025-05-07 00:32:38.000000000 +0200
+++ new/android-file-transfer-linux-4.5/qt/mtpobjectsmodel.h    2025-05-15 
00:28:05.000000000 +0200
@@ -101,9 +101,9 @@
        mtp::ObjectId createDirectory(const QString &name, mtp::AssociationType 
type = mtp::AssociationType::GenericFolder)
        { return createDirectory(_parentObjectId, name, type); }
 
-       bool uploadFile(mtp::ObjectId parentObjectId, const QString &filePath, 
QString filename = QString());
-       bool uploadFile(const QString &filePath, QString filename = QString())
-       { return uploadFile(_parentObjectId, filePath, filename); }
+       bool uploadFile(mtp::ObjectId parentObjectId, const QString &filePath, 
QString filename = QString(), mtp::ObjectFormat format = 
mtp::ObjectFormat::Any);
+       bool uploadFile(const QString &filePath, QString filename = QString(), 
mtp::ObjectFormat format = mtp::ObjectFormat::Any)
+       { return uploadFile(_parentObjectId, filePath, filename, format); }
        bool sendFile(const QString &filePath);
        bool downloadFile(const QString &filePath, mtp::ObjectId objectId);
        void rename(int idx, const QString &fileName);

Reply via email to