blob: 73052ad99bd5547103bf2593e20e4835b776914b [file] [log] [blame]
Linus Walleij10c58422006-06-02 08:51:53 +00001/**
2 * \file libmtp.c
3 * This file provides an interface "glue" to the underlying
4 * PTP implementation from libgphoto2. It uses some local
5 * code to convert from/to UTF-8 (stored in unicode.c/.h)
6 * and some small utility functions, mainly for debugging
7 * (stored in util.c/.h).
8 *
mopoke96143402006-10-30 04:37:26 +00009 * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
Linus Walleij10c58422006-06-02 08:51:53 +000010 * plain copied from the libhphoto2 codebase.
11 *
12 * The files libusb-glue.c/.h are just what they say: an
13 * interface to libusb for the actual, physical USB traffic.
14 */
Linus Walleijb9256fd2006-02-15 09:40:43 +000015#include <string.h>
Linus Walleijdcde6082006-02-17 16:16:34 +000016#include <sys/types.h>
Linus Walleij3ff2cf82006-02-20 15:03:26 +000017#include <sys/stat.h>
Linus Walleijdcde6082006-02-17 16:16:34 +000018#include <fcntl.h>
Linus Walleij2eb884b2006-08-04 19:17:36 +000019#include <sys/mman.h>
20
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000021#include "libmtp.h"
Linus Walleijb9256fd2006-02-15 09:40:43 +000022#include "unicode.h"
Linus Walleij394bbbe2006-02-22 16:10:53 +000023#include "ptp.h"
Linus Walleij15e344f2006-03-06 15:15:00 +000024#include "libusb-glue.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000025
Linus Walleij3fcfea52006-11-13 07:07:36 +000026/* Enable enhanced MTP commands */
27#define ENABLE_MTP_ENHANCED
28
Linus Walleijc86afbd2006-05-04 19:05:24 +000029/*
mopoke96143402006-10-30 04:37:26 +000030 * On MacOS (Darwin) and *BSD we're not using glibc, but libiconv.
31 * glibc knows that UCS-2 is to be in the local machine endianness,
32 * whereas libiconv does not. So we construct this macro to get
Linus Walleijf82dcea2006-09-11 11:23:47 +000033 * things right. Reportedly, glibc 2.1.3 has a bug so that UCS-2
mopoke96143402006-10-30 04:37:26 +000034 * is always bigendian though, we would need to work around that
Linus Walleijf82dcea2006-09-11 11:23:47 +000035 * too...
Linus Walleijd5d51c82006-09-11 06:57:50 +000036 */
37#ifndef __GLIBC__
Linus Walleijf82dcea2006-09-11 11:23:47 +000038#define UCS_2_INTERNAL "UCS-2-INTERNAL"
Linus Walleijd5d51c82006-09-11 06:57:50 +000039#else
Linus Walleijf82dcea2006-09-11 11:23:47 +000040#if (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 )
41#error "Too old glibc. This versions iconv() implementation cannot be trusted."
42#endif
43#define UCS_2_INTERNAL "UCS-2"
Linus Walleijd5d51c82006-09-11 06:57:50 +000044#endif
45
46/*
Linus Walleijc86afbd2006-05-04 19:05:24 +000047 * This is a mapping between libmtp internal MTP filetypes and
48 * the libgphoto2/PTP equivalent defines. We need this because
49 * otherwise the libmtp.h device has to be dependent on ptp.h
50 * to be installed too, and we don't want that.
51 */
raveloxd9a28642006-05-26 23:42:22 +000052typedef struct filemap_t LIBMTP_filemap_t;
raveloxd9a28642006-05-26 23:42:22 +000053struct filemap_t {
54 char *description; /**< Text description for the file type */
55 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
56 uint16_t ptp_id; /**< PTP ID for the filetype */
57 void *constructor; /**< Function to create the data structure for this file type */
58 void *destructor; /**< Function to destroy the data structure for this file type */
59 void *datafunc; /**< Function to fill in the data for this file type */
60 LIBMTP_filemap_t *next;
Linus Walleij16c51f02006-05-04 13:20:22 +000061};
Linus Walleijc86afbd2006-05-04 19:05:24 +000062
Linus Walleijf67bca92006-05-29 09:33:39 +000063// Global variables
Linus Walleij438bd7f2006-06-08 11:35:44 +000064// This holds the global filetype mapping table
Linus Walleijf67bca92006-05-29 09:33:39 +000065static LIBMTP_filemap_t *filemap = NULL;
66
67// Forward declarations of local functions
Linus Walleij438bd7f2006-06-08 11:35:44 +000068static void flush_handles(LIBMTP_mtpdevice_t *device);
Linus Walleijf67bca92006-05-29 09:33:39 +000069static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
70static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
mopoke96143402006-10-30 04:37:26 +000071static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
Linus Walleijcf223e62006-06-19 09:31:53 +000072 char **unicstring, uint16_t property);
Linus Walleij8ab54262006-06-21 07:12:28 +000073static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
74 LIBMTP_track_t *track);
Linus Walleij3fcfea52006-11-13 07:07:36 +000075static MTPPropList *New_MTP_Prop_Entry();
76static void Destroy_MTP_Prop_Entry(MTPPropList *prop);
raveloxd9a28642006-05-26 23:42:22 +000077
78static LIBMTP_filemap_t *new_filemap_entry()
79{
Linus Walleijf67bca92006-05-29 09:33:39 +000080 LIBMTP_filemap_t *filemap;
mopoke96143402006-10-30 04:37:26 +000081
Linus Walleijf67bca92006-05-29 09:33:39 +000082 filemap = (LIBMTP_filemap_t *)malloc(sizeof(LIBMTP_filemap_t));
mopoke96143402006-10-30 04:37:26 +000083
Linus Walleijf67bca92006-05-29 09:33:39 +000084 if( filemap != NULL ) {
85 filemap->description = NULL;
86 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
87 filemap->ptp_id = PTP_OFC_Undefined;
88 filemap->constructor = NULL;
89 filemap->destructor = NULL;
90 filemap->datafunc = NULL;
91 filemap->next = NULL;
92 }
mopoke96143402006-10-30 04:37:26 +000093
Linus Walleijf67bca92006-05-29 09:33:39 +000094 return filemap;
raveloxd9a28642006-05-26 23:42:22 +000095}
96
raveloxd9a28642006-05-26 23:42:22 +000097/**
98 * Register an MTP or PTP filetype for data retrieval
99 *
100 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +0000101 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000102 * @param ptp_id PTP filetype id
103 * @param constructor Pointer to function to create data structure for filetype
104 * @param destructor Pointer to function to destroy data structure for filetype
105 * @param datafunc Pointer to function to fill data structure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000106 * @return 0 for success any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000107*/
mopoke96143402006-10-30 04:37:26 +0000108int LIBMTP_Register_Filetype(char const * const description, LIBMTP_filetype_t const id,
109 uint16_t const ptp_id, void const * const constructor,
Linus Walleij438bd7f2006-06-08 11:35:44 +0000110 void const * const destructor, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000111{
112 LIBMTP_filemap_t *new = NULL, *current;
113
114 // Has this LIBMTP filetype been registered before ?
115 current = filemap;
116 while (current != NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000117 if(current->id == id) {
118 break;
119 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000120 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000121 }
mopoke96143402006-10-30 04:37:26 +0000122
raveloxd9a28642006-05-26 23:42:22 +0000123 // Create the entry
124 if(current == NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000125 new = new_filemap_entry();
Linus Walleijf0f3d482006-05-29 14:10:21 +0000126 if(new == NULL) {
127 return 1;
128 }
mopoke96143402006-10-30 04:37:26 +0000129
Linus Walleijf67bca92006-05-29 09:33:39 +0000130 new->id = id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000131 if(description != NULL) {
132 new->description = strdup(description);
133 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000134 new->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000135 new->constructor = (void*) constructor;
136 new->destructor = (void*) destructor;
137 new->datafunc = (void*) datafunc;
mopoke96143402006-10-30 04:37:26 +0000138
Linus Walleijf67bca92006-05-29 09:33:39 +0000139 // Add the entry to the list
140 if(filemap == NULL) {
141 filemap = new;
142 } else {
143 current = filemap;
144 while (current->next != NULL ) current=current->next;
145 current->next = new;
146 }
147 // Update the existing entry
raveloxd9a28642006-05-26 23:42:22 +0000148 } else {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000149 if (current->description != NULL) {
150 free(current->description);
151 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000152 current->description = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000153 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000154 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000155 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000156 current->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000157 current->constructor = (void*) constructor;
158 current->destructor = (void*) destructor;
159 current->datafunc = (void*) datafunc;
raveloxd9a28642006-05-26 23:42:22 +0000160 }
161
Linus Walleijf0f3d482006-05-29 14:10:21 +0000162 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000163}
164
165/**
166 * Set the description for a MTP filetype
167 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000168 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000169 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +0000170 * @return 0 on success, any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000171*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000172int LIBMTP_Set_Filetype_Description(LIBMTP_filetype_t const id, char const * const description)
raveloxd9a28642006-05-26 23:42:22 +0000173{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000174 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000175
Linus Walleijf0f3d482006-05-29 14:10:21 +0000176 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000177 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000178 }
mopoke96143402006-10-30 04:37:26 +0000179
Linus Walleijf67bca92006-05-29 09:33:39 +0000180 // Go through the filemap until an entry is found
181 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000182
Linus Walleijf0f3d482006-05-29 14:10:21 +0000183 while(current != NULL) {
184 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000185 break;
186 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000187 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000188 }
mopoke96143402006-10-30 04:37:26 +0000189
Linus Walleijf0f3d482006-05-29 14:10:21 +0000190 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000191 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000192 }
193
194 if (current->description != NULL) {
195 free(current->description);
196 current->description = NULL;
197 }
198 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000199 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000200 }
201 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000202}
203
204/**
205 * Set the constructor for a MTP filetype
206 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000207 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000208 * @param constructor Pointer to a constructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000209 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000210*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000211int LIBMTP_Set_Constructor(LIBMTP_filetype_t const id, void const * const constructor)
raveloxd9a28642006-05-26 23:42:22 +0000212{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000213 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000214
Linus Walleijf0f3d482006-05-29 14:10:21 +0000215 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000216 return -1;
mopoke96143402006-10-30 04:37:26 +0000217 }
218
Linus Walleijf67bca92006-05-29 09:33:39 +0000219 // Go through the filemap until an entry is found
220 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000221
Linus Walleijf0f3d482006-05-29 14:10:21 +0000222 while(current != NULL) {
223 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000224 break;
raveloxd9a28642006-05-26 23:42:22 +0000225 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000226 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000227 }
mopoke96143402006-10-30 04:37:26 +0000228
Linus Walleijf0f3d482006-05-29 14:10:21 +0000229 if (current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000230 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000231 }
mopoke96143402006-10-30 04:37:26 +0000232
Linus Walleij438bd7f2006-06-08 11:35:44 +0000233 current->constructor = (void*) constructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000234 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000235}
236
237/**
238 * Set the destructor for a MTP filetype
239 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000240 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000241 * @param destructor Pointer to a destructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000242 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000243*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000244int LIBMTP_Set_Destructor(LIBMTP_filetype_t const id, void const * const destructor)
raveloxd9a28642006-05-26 23:42:22 +0000245{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000246 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000247
Linus Walleijf0f3d482006-05-29 14:10:21 +0000248 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000249 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000250 }
mopoke96143402006-10-30 04:37:26 +0000251
Linus Walleijf67bca92006-05-29 09:33:39 +0000252 // Go through the filemap until an entry is found
253 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000254
Linus Walleijf0f3d482006-05-29 14:10:21 +0000255 while(current != NULL) {
256 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000257 break;
raveloxd9a28642006-05-26 23:42:22 +0000258 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000259 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000260 }
mopoke96143402006-10-30 04:37:26 +0000261
Linus Walleijf0f3d482006-05-29 14:10:21 +0000262 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000263 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000264 }
mopoke96143402006-10-30 04:37:26 +0000265
Linus Walleij438bd7f2006-06-08 11:35:44 +0000266 current->destructor = (void *) destructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000267 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000268}
269
270/**
271 * Set the datafunc for a MTP filetype
272 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000273 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000274 * @param datafunc Pointer to a data function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000275 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000276*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000277int LIBMTP_Set_Datafunc(LIBMTP_filetype_t const id, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000278{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000279 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000280
Linus Walleijf0f3d482006-05-29 14:10:21 +0000281 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000282 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000283 }
mopoke96143402006-10-30 04:37:26 +0000284
Linus Walleijf67bca92006-05-29 09:33:39 +0000285 // Go through the filemap until an entry is found
286 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000287
Linus Walleijf0f3d482006-05-29 14:10:21 +0000288 while(current != NULL) {
289 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000290 break;
raveloxd9a28642006-05-26 23:42:22 +0000291 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000292 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000293 }
mopoke96143402006-10-30 04:37:26 +0000294
Linus Walleijf0f3d482006-05-29 14:10:21 +0000295 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000296 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000297 }
mopoke96143402006-10-30 04:37:26 +0000298
Linus Walleij438bd7f2006-06-08 11:35:44 +0000299 current->datafunc = (void *) datafunc;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000300 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000301}
302
303static void init_filemap()
304{
Linus Walleijf67bca92006-05-29 09:33:39 +0000305 LIBMTP_Register_Filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000306 LIBMTP_Register_Filetype("ISO MPEG Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
Linus Walleijf67bca92006-05-29 09:33:39 +0000307 LIBMTP_Register_Filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
308 LIBMTP_Register_Filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
Linus Walleije46f12e2006-06-22 17:53:25 +0000309 LIBMTP_Register_Filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
Linus Walleijf67bca92006-05-29 09:33:39 +0000310 LIBMTP_Register_Filetype("Advanced Acoustic Coding", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
311 LIBMTP_Register_Filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000312 LIBMTP_Register_Filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV,NULL,NULL,NULL);
313 LIBMTP_Register_Filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI,NULL,NULL,NULL);
314 LIBMTP_Register_Filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG,NULL,NULL,NULL);
315 LIBMTP_Register_Filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF,NULL,NULL,NULL);
316 LIBMTP_Register_Filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT,NULL,NULL,NULL);
317 LIBMTP_Register_Filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo,NULL,NULL,NULL);
Linus Walleij83f57eb2006-05-31 19:57:56 +0000318 LIBMTP_Register_Filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG,NULL,NULL,NULL);
319 LIBMTP_Register_Filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF,NULL,NULL,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000320 LIBMTP_Register_Filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF,NULL,NULL,NULL);
321 LIBMTP_Register_Filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP,NULL,NULL,NULL);
322 LIBMTP_Register_Filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF,NULL,NULL,NULL);
323 LIBMTP_Register_Filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT,NULL,NULL,NULL);
324 LIBMTP_Register_Filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG,NULL,NULL,NULL);
325 LIBMTP_Register_Filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat,NULL,NULL,NULL);
326 LIBMTP_Register_Filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1,NULL,NULL,NULL);
327 LIBMTP_Register_Filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2,NULL,NULL,NULL);
328 LIBMTP_Register_Filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2,NULL,NULL,NULL);
329 LIBMTP_Register_Filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3,NULL,NULL,NULL);
330 LIBMTP_Register_Filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable,NULL,NULL,NULL);
331 LIBMTP_Register_Filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text,NULL,NULL,NULL);
332 LIBMTP_Register_Filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML,NULL,NULL,NULL);
333 LIBMTP_Register_Filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined, NULL, NULL, NULL);
raveloxd9a28642006-05-26 23:42:22 +0000334}
Linus Walleij16c51f02006-05-04 13:20:22 +0000335
Linus Walleij16c51f02006-05-04 13:20:22 +0000336/**
337 * Returns the PTP filetype that maps to a certain libmtp internal file type.
338 * @param intype the MTP library interface type
339 * @return the PTP (libgphoto2) interface type
340 */
341static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
342{
raveloxd9a28642006-05-26 23:42:22 +0000343 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000344
raveloxd9a28642006-05-26 23:42:22 +0000345 current = filemap;
346
347 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000348 if(current->id == intype) {
349 return current->ptp_id;
350 }
351 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000352 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000353 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000354 return PTP_OFC_Undefined;
355}
356
357
358/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000359 * Returns the PTP internal filetype that maps to a certain libmtp
360 * interface file type.
mopoke96143402006-10-30 04:37:26 +0000361 * @param intype the PTP (libgphoto2) interface type
Linus Walleij8ab54262006-06-21 07:12:28 +0000362 * @return the MTP library interface type
Linus Walleij16c51f02006-05-04 13:20:22 +0000363 */
364static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
365{
raveloxd9a28642006-05-26 23:42:22 +0000366 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000367
raveloxd9a28642006-05-26 23:42:22 +0000368 current = filemap;
369
370 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000371 if(current->ptp_id == intype) {
372 return current->id;
373 }
374 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000375 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000376 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000377 return LIBMTP_FILETYPE_UNKNOWN;
378}
379
380/**
raveloxd9a28642006-05-26 23:42:22 +0000381 * Returns the data function for the file type
382 * @param intype the PTP library interface
383 * @return pointer to the data function
384 */
385static void *get_datafunc(uint16_t intype)
386{
387 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000388
raveloxd9a28642006-05-26 23:42:22 +0000389 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000390
raveloxd9a28642006-05-26 23:42:22 +0000391 while (current != NULL) {
392 if(current->ptp_id == intype) {
393 return current->datafunc;
394 }
395 current = current->next;
396 }
397 return NULL;
398}
399
400
401/**
402 * Returns the constructor for that file type data
403 * @param intype the PTP library interface type
404 * @return pointer to the constructor
405 */
406static void *get_constructor(uint16_t intype)
407{
408 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000409
raveloxd9a28642006-05-26 23:42:22 +0000410 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000411
raveloxd9a28642006-05-26 23:42:22 +0000412 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000413 if(current->ptp_id == intype) {
414 return current->constructor;
415 }
416 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000417 }
418 return NULL;
419}
420
421/**
422 * Returns the destructor for that file type data
423 * @param intype the PTP library interface type
424 * @return pointer to the destructor
425 */
426static void *get_destructor(uint16_t intype)
427{
428 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000429
raveloxd9a28642006-05-26 23:42:22 +0000430 current = filemap;
431
432 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000433 if(current->ptp_id == intype) {
434 return current->destructor;
435 }
436 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000437 }
438 return NULL;
439}
440
441/**
Linus Walleij16c51f02006-05-04 13:20:22 +0000442 * This helper function returns a textual description for a libmtp
443 * file type to be used in dialog boxes etc.
Linus Walleijf0f3d482006-05-29 14:10:21 +0000444 * @param intype the libmtp internal filetype to get a description for.
Linus Walleij16c51f02006-05-04 13:20:22 +0000445 * @return a string representing the filetype, this must <b>NOT</b>
446 * be free():ed by the caller!
447 */
448char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
449{
raveloxd9a28642006-05-26 23:42:22 +0000450 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000451
raveloxd9a28642006-05-26 23:42:22 +0000452 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000453
raveloxd9a28642006-05-26 23:42:22 +0000454 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000455 if(current->id == intype) {
456 return current->description;
457 }
458 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000459 }
mopoke96143402006-10-30 04:37:26 +0000460
Linus Walleij16c51f02006-05-04 13:20:22 +0000461 return "Unknown filetype";
462}
Linus Walleijfa1374c2006-02-27 07:41:46 +0000463
Linus Walleij6946ac52006-03-21 06:51:22 +0000464/**
Linus Walleijf0f3d482006-05-29 14:10:21 +0000465 * Initialize the library. You are only supposed to call this
466 * one, before using the library for the first time in a program.
467 * Never re-initialize libmtp!
468 *
raveloxd9a28642006-05-26 23:42:22 +0000469 * The only thing this does at the moment is to initialise the
470 * filetype mapping table.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000471 */
472void LIBMTP_Init(void)
473{
raveloxd9a28642006-05-26 23:42:22 +0000474 init_filemap();
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000475 return;
476}
477
478/**
raveloxd9a28642006-05-26 23:42:22 +0000479 * Retrieves a string from an object
480 *
481 * @param device a pointer to an MTP device.
482 * @param object_id Object reference
483 * @param attribute_id PTP attribute ID
Linus Walleij438bd7f2006-06-08 11:35:44 +0000484 * @return valid string or NULL on failure. The returned string
485 * must bee <code>free()</code>:ed by the caller after
486 * use.
raveloxd9a28642006-05-26 23:42:22 +0000487 */
mopoke96143402006-10-30 04:37:26 +0000488char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000489 uint16_t const attribute_id)
raveloxd9a28642006-05-26 23:42:22 +0000490{
491 PTPPropertyValue propval;
492 char *retstring = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000493 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000494 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +0000495
Linus Walleij438bd7f2006-06-08 11:35:44 +0000496 if ( device == NULL || object_id == 0) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000497 return NULL;
498 }
mopoke96143402006-10-30 04:37:26 +0000499
Linus Walleija823a702006-08-27 21:27:46 +0000500 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
raveloxd9a28642006-05-26 23:42:22 +0000501 if (ret == PTP_RC_OK) {
Linus Walleija823a702006-08-27 21:27:46 +0000502 if (propval.str != NULL) {
503 retstring = (char *) strdup(propval.str);
504 free(propval.str);
raveloxd9a28642006-05-26 23:42:22 +0000505 }
506 }
mopoke96143402006-10-30 04:37:26 +0000507
raveloxd9a28642006-05-26 23:42:22 +0000508 return retstring;
509}
510
511/**
512 * Retrieves an unsigned 32-bit integer from an object attribute
513 *
514 * @param device a pointer to an MTP device.
515 * @param object_id Object reference
516 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000517 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000518 * @return the value
raveloxd9a28642006-05-26 23:42:22 +0000519 */
mopoke96143402006-10-30 04:37:26 +0000520uint32_t LIBMTP_Get_U32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000521 uint16_t const attribute_id, uint32_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000522{
523 PTPPropertyValue propval;
524 uint32_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000525 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000526 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +0000527
Linus Walleijf0f3d482006-05-29 14:10:21 +0000528 if ( device == NULL ) {
529 return value_default;
530 }
raveloxd9a28642006-05-26 23:42:22 +0000531
raveloxd9a28642006-05-26 23:42:22 +0000532 ret = ptp_mtp_getobjectpropvalue(params, object_id,
533 attribute_id,
534 &propval,
535 PTP_DTC_UINT32);
536 if (ret == PTP_RC_OK) {
537 retval = propval.u32;
538 }
539
540 return retval;
541}
542
543/**
544 * Retrieves an unsigned 16-bit integer from an object attribute
545 *
546 * @param device a pointer to an MTP device.
547 * @param object_id Object reference
548 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000549 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000550 * @return a value
raveloxd9a28642006-05-26 23:42:22 +0000551 */
mopoke96143402006-10-30 04:37:26 +0000552uint16_t LIBMTP_Get_U16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000553 uint16_t const attribute_id, uint16_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000554{
555 PTPPropertyValue propval;
556 uint16_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000557 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000558 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000559
Linus Walleijf0f3d482006-05-29 14:10:21 +0000560 if ( device == NULL ) {
561 return value_default;
562 }
raveloxd9a28642006-05-26 23:42:22 +0000563
raveloxd9a28642006-05-26 23:42:22 +0000564 ret = ptp_mtp_getobjectpropvalue(params, object_id,
565 attribute_id,
566 &propval,
567 PTP_DTC_UINT16);
568 if (ret == PTP_RC_OK) {
569 retval = propval.u16;
570 }
mopoke96143402006-10-30 04:37:26 +0000571
raveloxd9a28642006-05-26 23:42:22 +0000572 return retval;
573}
574
575/**
Linus Walleij99310d42006-11-01 08:29:39 +0000576 * Retrieves an unsigned 8-bit integer from an object attribute
577 *
578 * @param device a pointer to an MTP device.
579 * @param object_id Object reference
580 * @param attribute_id PTP attribute ID
581 * @param value_default Default value to return on failure
582 * @return a value
583 */
584uint8_t LIBMTP_Get_U8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
585 uint16_t const attribute_id, uint8_t const value_default)
586{
587 PTPPropertyValue propval;
588 uint8_t retval = value_default;
589 PTPParams *params = (PTPParams *) device->params;
590 uint16_t ret;
591
592 if ( device == NULL ) {
593 return value_default;
594 }
595
596 ret = ptp_mtp_getobjectpropvalue(params, object_id,
597 attribute_id,
598 &propval,
599 PTP_DTC_UINT8);
600 if (ret == PTP_RC_OK) {
601 retval = propval.u8;
602 }
603
604 return retval;
605}
606
607/**
raveloxd9a28642006-05-26 23:42:22 +0000608 * Sets an object attribute from a string
609 *
610 * @param device a pointer to an MTP device.
611 * @param object_id Object reference
612 * @param attribute_id PTP attribute ID
613 * @param string string value to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000614 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000615 */
mopoke96143402006-10-30 04:37:26 +0000616int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000617 uint16_t const attribute_id, char const * const string)
raveloxd9a28642006-05-26 23:42:22 +0000618{
619 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000620 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000621 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000622
Linus Walleijf0f3d482006-05-29 14:10:21 +0000623 if (device == NULL || string == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000624 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000625 }
raveloxd9a28642006-05-26 23:42:22 +0000626
Linus Walleija823a702006-08-27 21:27:46 +0000627 propval.str = (char *) string;
628 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000629 if (ret != PTP_RC_OK) {
Linus Walleijda9500d2006-08-30 13:17:06 +0000630 printf("LIBMTP_Set_Object_String(): could not set object string.\n");
631 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000632 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000633 }
mopoke96143402006-10-30 04:37:26 +0000634
Linus Walleijf0f3d482006-05-29 14:10:21 +0000635 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000636}
637
638/**
639 * Sets an object attribute from an unsigned 32-bit integer
640 *
641 * @param device a pointer to an MTP device.
642 * @param object_id Object reference
643 * @param attribute_id PTP attribute ID
644 * @param value 32-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000645 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000646 */
mopoke96143402006-10-30 04:37:26 +0000647int LIBMTP_Set_Object_U32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000648 uint16_t const attribute_id, uint32_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000649{
650 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000651 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000652 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000653
Linus Walleijf0f3d482006-05-29 14:10:21 +0000654 if (device == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000655 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000656 }
raveloxd9a28642006-05-26 23:42:22 +0000657
658 propval.u32 = value;
659 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000660 if (ret != PTP_RC_OK) {
Linus Walleija52c93e2006-09-13 04:40:48 +0000661 printf("LIBMTP_Set_Object_U32(): could not set unsigned 32bit integer property.\n");
662 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000663 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000664 }
mopoke96143402006-10-30 04:37:26 +0000665
Linus Walleijf0f3d482006-05-29 14:10:21 +0000666 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000667}
668
669/**
670 * Sets an object attribute from an unsigned 16-bit integer
671 *
672 * @param device a pointer to an MTP device.
673 * @param object_id Object reference
674 * @param attribute_id PTP attribute ID
675 * @param value 16-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000676 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000677 */
mopoke96143402006-10-30 04:37:26 +0000678int LIBMTP_Set_Object_U16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000679 uint16_t const attribute_id, uint16_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000680{
681 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000682 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000683 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000684
Linus Walleijf0f3d482006-05-29 14:10:21 +0000685 if (device == NULL) {
686 return 1;
687 }
raveloxd9a28642006-05-26 23:42:22 +0000688
689 propval.u16 = value;
690 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000691 if (ret != PTP_RC_OK) {
Linus Walleija52c93e2006-09-13 04:40:48 +0000692 printf("LIBMTP_Set_Object_U16(): could not set unsigned 16bit integer property.\n");
693 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000694 return 1;
695 }
raveloxd9a28642006-05-26 23:42:22 +0000696
Linus Walleijf0f3d482006-05-29 14:10:21 +0000697 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000698}
699
700/**
Linus Walleij99310d42006-11-01 08:29:39 +0000701 * Sets an object attribute from an unsigned 8-bit integer
702 *
703 * @param device a pointer to an MTP device.
704 * @param object_id Object reference
705 * @param attribute_id PTP attribute ID
706 * @param value 8-bit unsigned integer to set
707 * @return 0 on success, any other value means failure
708 */
709int LIBMTP_Set_Object_U8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
710 uint16_t const attribute_id, uint8_t const value)
711{
712 PTPPropertyValue propval;
713 PTPParams *params = (PTPParams *) device->params;
714 uint16_t ret;
715
716 if (device == NULL) {
717 return 1;
718 }
719
720 propval.u8 = value;
721 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
722 if (ret != PTP_RC_OK) {
723 printf("LIBMTP_Set_Object_U8(): could not set unsigned 8bit integer property.\n");
724 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
725 return 1;
726 }
727
728 return 0;
729}
730
731/**
raveloxd9a28642006-05-26 23:42:22 +0000732 * Gets an array of object ids associated with a specified object
733 *
734 * @param device a pointer to an MTP device.
735 * @param object_id Object reference
736 * @param items array of unsigned 32-bit integers
737 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000738 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000739 */
mopoke96143402006-10-30 04:37:26 +0000740int LIBMTP_Get_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleijf0f3d482006-05-29 14:10:21 +0000741 uint32_t **items, uint32_t *len)
raveloxd9a28642006-05-26 23:42:22 +0000742{
743 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000744 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000745
Linus Walleijf0f3d482006-05-29 14:10:21 +0000746 // A device must be attached
raveloxd9a28642006-05-26 23:42:22 +0000747 if (device == NULL ) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000748 *items = NULL;
749 *len = 0;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000750 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000751 }
mopoke96143402006-10-30 04:37:26 +0000752
Linus Walleijf67bca92006-05-29 09:33:39 +0000753 ret = ptp_mtp_getobjectreferences (params, object_id, items, len);
raveloxd9a28642006-05-26 23:42:22 +0000754 if (ret != PTP_RC_OK) {
755 ptp_perror(params, ret);
756 printf("LIBMTP_Get_Object_References: Could not get object references\n");
Linus Walleijf0f3d482006-05-29 14:10:21 +0000757 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000758 }
759
Linus Walleijf0f3d482006-05-29 14:10:21 +0000760 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000761}
762
763/**
764 * Sets an array of object ids associated with a specified object
765 *
766 * @param device a pointer to an MTP device.
767 * @param object_id Object reference
768 * @param items array of unsigned 32-bit integers
769 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000770 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000771 */
mopoke96143402006-10-30 04:37:26 +0000772int LIBMTP_Set_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij438bd7f2006-06-08 11:35:44 +0000773 uint32_t const * const items, uint32_t const len)
raveloxd9a28642006-05-26 23:42:22 +0000774{
775 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000776 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000777
778 if (device == NULL || items == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000779 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000780 }
mopoke96143402006-10-30 04:37:26 +0000781
Linus Walleij438bd7f2006-06-08 11:35:44 +0000782 ret = ptp_mtp_setobjectreferences (params, object_id, (uint32_t *) items, len);
raveloxd9a28642006-05-26 23:42:22 +0000783 if (ret != PTP_RC_OK) {
784 ptp_perror(params, ret);
785 printf("LIBMTP_Set_Object_References: Could not set object references\n");
Linus Walleija52c93e2006-09-13 04:40:48 +0000786 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000787 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000788 }
mopoke96143402006-10-30 04:37:26 +0000789
Linus Walleijf0f3d482006-05-29 14:10:21 +0000790 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000791}
792
raveloxd9a28642006-05-26 23:42:22 +0000793/**
Linus Walleij6fd2f082006-03-28 07:19:22 +0000794 * Get a list of the supported devices.
795 *
Linus Walleijc86afbd2006-05-04 19:05:24 +0000796 * The developers depend on users of this library to constantly
797 * add in to the list of supported devices. What we need is the
798 * device name, USB Vendor ID (VID) and USB Product ID (PID).
799 * put this into a bug ticket at the project homepage, please.
800 * The VID/PID is used to let e.g. udev lift the device to
801 * console userspace access when it's plugged in.
802 *
Linus Walleij6fd2f082006-03-28 07:19:22 +0000803 * @param devices a pointer to a pointer that will hold a device
804 * list after the call to this function, if it was
805 * successful.
806 * @param numdevs a pointer to an integer that will hold the number
807 * of devices in the device list if the call was successful.
808 * @return 0 if the list was successfull retrieved, any other
809 * value means failure.
810 */
811int LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs)
812{
813 // Just dispatch to libusb glue file...
814 return get_device_list(devices, numdevs);
815}
816
817/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000818 * Get the first connected MTP device. There is currently no API for
819 * retrieveing multiple devices.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000820 * @return a device pointer.
821 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000822LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000823{
824 uint8_t interface_number;
Linus Walleij56d3e182006-02-10 15:46:54 +0000825 PTPParams *params;
826 PTP_USB *ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000827 PTPStorageIDs storageIDs;
Linus Walleijee01b642006-09-13 12:01:22 +0000828 uint32_t storageID = 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000829 PTPDevicePropDesc dpd;
Linus Walleijd31e6192006-09-12 07:55:27 +0000830 uint8_t batteryLevelMax = 100; // Some default
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000831 uint16_t ret;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000832 uint32_t i;
Linus Walleijb9256fd2006-02-15 09:40:43 +0000833 LIBMTP_mtpdevice_t *tmpdevice;
Richard Low43fdb882006-09-06 16:19:05 +0000834 uint8_t remaining_directories;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000835
Linus Walleij56d3e182006-02-10 15:46:54 +0000836 // Allocate a parameter block
837 params = (PTPParams *) malloc(sizeof(PTPParams));
Linus Walleijd5d51c82006-09-11 06:57:50 +0000838 params->cd_locale_to_ucs2 = iconv_open(UCS_2_INTERNAL, "UTF-8");
839 params->cd_ucs2_to_locale = iconv_open("UTF-8", UCS_2_INTERNAL);
Linus Walleija823a702006-08-27 21:27:46 +0000840 if (params->cd_locale_to_ucs2 == (iconv_t) -1 || params->cd_ucs2_to_locale == (iconv_t) -1) {
Linus Walleijd5d51c82006-09-11 06:57:50 +0000841 printf("LIBMTP panic: could not open iconv() converters to/from UCS-2!\n");
Linus Walleija823a702006-08-27 21:27:46 +0000842 return NULL;
843 }
mopoke96143402006-10-30 04:37:26 +0000844
Linus Walleij56d3e182006-02-10 15:46:54 +0000845 ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB));
Linus Walleijd214b9b2006-08-26 22:08:37 +0000846 // Callbacks and stuff
847 ptp_usb->callback_active = 0;
848 ptp_usb->current_transfer_total = 0;
849 ptp_usb->current_transfer_complete = 0;
850 ptp_usb->current_transfer_callback = NULL;
mopoke96143402006-10-30 04:37:26 +0000851
Linus Walleijd214b9b2006-08-26 22:08:37 +0000852 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000853 ret = connect_first_device(params, ptp_usb, &interface_number);
mopoke96143402006-10-30 04:37:26 +0000854
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000855 switch (ret)
856 {
857 case PTP_CD_RC_CONNECTED:
858 printf("Connected to MTP device.\n");
859 break;
860 case PTP_CD_RC_NO_DEVICES:
861 printf("No MTP devices.\n");
862 return NULL;
863 case PTP_CD_RC_ERROR_CONNECTING:
864 printf("Connection error.\n");
865 return NULL;
866 }
867
868 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000869 if (ptp_getstorageids (params, &storageIDs) == PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000870 if (storageIDs.n > 0)
871 storageID = storageIDs.Storage[0];
872 free(storageIDs.Storage);
873 }
mopoke96143402006-10-30 04:37:26 +0000874
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000875 // Make sure there are no handlers
Linus Walleij56d3e182006-02-10 15:46:54 +0000876 params->handles.Handler = NULL;
Linus Walleijb02a0662006-04-25 08:05:09 +0000877
Linus Walleij8c45b292006-04-26 14:12:44 +0000878 // Just cache the device information for any later use.
879 if (ptp_getdeviceinfo(params, &params->deviceinfo) != PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000880 goto error_handler;
881 }
mopoke96143402006-10-30 04:37:26 +0000882
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000883 // Get battery maximum level
Linus Walleijd31e6192006-09-12 07:55:27 +0000884 if (ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
885 if (ptp_getdevicepropdesc(params, PTP_DPC_BatteryLevel, &dpd) != PTP_RC_OK) {
886 printf("LIBMTP_Get_First_Device(): Unable to retrieve battery max level.\n");
887 goto error_handler;
888 }
889 // if is NULL, just leave as default
890 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
891 batteryLevelMax = dpd.FORM.Range.MaximumValue.u8;
892 }
893 ptp_free_devicepropdesc(&dpd);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000894 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000895
896 // OK everything got this far, so it is time to create a device struct!
Linus Walleijb9256fd2006-02-15 09:40:43 +0000897 tmpdevice = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000898 tmpdevice->interface_number = interface_number;
Linus Walleij9b28da32006-03-16 13:47:58 +0000899 tmpdevice->params = (void *) params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000900 tmpdevice->usbinfo = (void *) ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000901 tmpdevice->storage_id = storageID;
902 tmpdevice->maximum_battery_level = batteryLevelMax;
903
Linus Walleij05ccbe72006-06-13 07:46:58 +0000904 // Set all default folders to 0 == root directory
905 tmpdevice->default_music_folder = 0;
906 tmpdevice->default_playlist_folder = 0;
907 tmpdevice->default_picture_folder = 0;
908 tmpdevice->default_video_folder = 0;
909 tmpdevice->default_organizer_folder = 0;
910 tmpdevice->default_zencast_folder = 0;
911
912 /*
913 * Then get the handles and try to locate the default folders.
914 * This has the desired side effect of cacheing all handles from
915 * the device which speeds up later operations.
916 */
917 flush_handles(tmpdevice);
Linus Walleij0558ac52006-09-07 06:55:03 +0000918 /*
919 * Remaining directories to get the handles to.
920 * We can stop when done this to save time
921 */
922 remaining_directories = 6;
Richard Low43fdb882006-09-06 16:19:05 +0000923 for (i = 0; i < params->handles.n && remaining_directories > 0; i++) {
Linus Walleij05ccbe72006-06-13 07:46:58 +0000924 PTPObjectInfo oi;
925 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
926 // Ignore non-folders
927 if ( oi.ObjectFormat != PTP_OFC_Association )
928 continue;
Linus Walleij97c7a342006-09-11 07:03:03 +0000929 if ( oi.Filename == NULL)
930 continue;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000931 if (!strcmp(oi.Filename, "Music")) {
932 tmpdevice->default_music_folder = params->handles.Handler[i];
Linus Walleij0558ac52006-09-07 06:55:03 +0000933 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000934 continue;
935 } else if (!strcmp(oi.Filename, "My Playlists")) {
936 tmpdevice->default_playlist_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000937 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000938 continue;
939 } else if (!strcmp(oi.Filename, "Pictures")) {
940 tmpdevice->default_picture_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000941 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000942 continue;
943 } else if (!strcmp(oi.Filename, "Video")) {
944 tmpdevice->default_video_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000945 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000946 continue;
947 } else if (!strcmp(oi.Filename, "My Organizer")) {
948 tmpdevice->default_organizer_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000949 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000950 continue;
951 } else if (!strcmp(oi.Filename, "ZENcast")) {
952 tmpdevice->default_zencast_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000953 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000954 continue;
955 }
956 } else {
957 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
958 }
959 }
960
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000961 return tmpdevice;
mopoke96143402006-10-30 04:37:26 +0000962
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000963 // Then close it again.
964 error_handler:
Linus Walleij56d3e182006-02-10 15:46:54 +0000965 close_device(ptp_usb, params, interface_number);
Linus Walleijb02a0662006-04-25 08:05:09 +0000966 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
967 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij56d3e182006-02-10 15:46:54 +0000968 if (params->handles.Handler != NULL) {
969 free(params->handles.Handler);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000970 }
971 return NULL;
972}
973
974/**
975 * This closes and releases an allocated MTP device.
Linus Walleijb9256fd2006-02-15 09:40:43 +0000976 * @param device a pointer to the MTP device to release.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000977 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000978void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000979{
Linus Walleij9b28da32006-03-16 13:47:58 +0000980 PTPParams *params = (PTPParams *) device->params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000981 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij9b28da32006-03-16 13:47:58 +0000982
Linus Walleij2d411db2006-03-22 12:13:09 +0000983 close_device(ptp_usb, params, device->interface_number);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000984 // Free the device info and any handler
Linus Walleijb02a0662006-04-25 08:05:09 +0000985 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
986 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij9b28da32006-03-16 13:47:58 +0000987 if (params->handles.Handler != NULL) {
988 free(params->handles.Handler);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000989 params->handles.Handler = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000990 }
Linus Walleij3ec86312006-08-21 13:25:24 +0000991 // Free iconv() converters...
Linus Walleija823a702006-08-27 21:27:46 +0000992 iconv_close(params->cd_locale_to_ucs2);
993 iconv_close(params->cd_ucs2_to_locale);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000994 free(device);
995}
Linus Walleijb9256fd2006-02-15 09:40:43 +0000996
997/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000998 * This function refresh the internal handle list whenever
999 * the items stored inside the device is altered. On operations
1000 * that do not add or remove objects, this is typically not
1001 * called.
1002 * @param device a pointer to the MTP device to flush handles for.
1003 */
1004static void flush_handles(LIBMTP_mtpdevice_t *device)
1005{
1006 PTPParams *params = (PTPParams *) device->params;
1007 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +00001008
Linus Walleij438bd7f2006-06-08 11:35:44 +00001009 if (params->handles.Handler != NULL) {
1010 free(params->handles.Handler);
1011 }
1012
1013 // Get all the handles if we haven't already done that
1014 ret = ptp_getobjecthandles(params,
mopoke96143402006-10-30 04:37:26 +00001015 PTP_GOH_ALL_STORAGE,
1016 PTP_GOH_ALL_FORMATS,
1017 PTP_GOH_ALL_ASSOCS,
Linus Walleij438bd7f2006-06-08 11:35:44 +00001018 &params->handles);
1019 if (ret != PTP_RC_OK) {
1020 printf("flush_handles(): LIBMTP panic: Could not get object handles...\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00001021 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +00001022 }
1023
1024 return;
1025}
1026
1027/**
Linus Walleij8c45b292006-04-26 14:12:44 +00001028 * This function dumps out a large chunk of textual information
1029 * provided from the PTP protocol and additionally some extra
1030 * MTP-specific information where applicable.
1031 * @param device a pointer to the MTP device to report info from.
1032 */
1033void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
1034{
1035 int i;
1036 PTPParams *params = (PTPParams *) device->params;
Linus Walleijc6210fb2006-05-08 11:11:41 +00001037 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
mopoke96143402006-10-30 04:37:26 +00001038
Linus Walleijc6210fb2006-05-08 11:11:41 +00001039 printf("USB low-level info:\n");
1040 dump_usbinfo(ptp_usb);
Linus Walleij8c45b292006-04-26 14:12:44 +00001041 /* Print out some verbose information */
1042 printf("Device info:\n");
1043 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
1044 printf(" Model: %s\n", params->deviceinfo.Model);
1045 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
1046 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
1047 printf(" Vendor extension ID: 0x%08x\n", params->deviceinfo.VendorExtensionID);
1048 printf(" Vendor extension description: %s\n", params->deviceinfo.VendorExtensionDesc);
1049 printf("Supported operations:\n");
1050 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
Linus Walleij4f40d112006-09-21 07:44:53 +00001051 char txt[256];
1052
1053 (void) ptp_render_opcode (params, params->deviceinfo.OperationsSupported[i], sizeof(txt), txt);
1054 printf(" %04x: %s\n", params->deviceinfo.OperationsSupported[i], txt);
Linus Walleij8c45b292006-04-26 14:12:44 +00001055 }
1056 printf("Events supported:\n");
1057 if (params->deviceinfo.EventsSupported_len == 0) {
1058 printf(" None.\n");
1059 } else {
1060 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
1061 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
1062 }
1063 }
1064 printf("Device Properties Supported:\n");
1065 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
Linus Walleij16c51f02006-05-04 13:20:22 +00001066 char const *propdesc = ptp_get_property_description(params, params->deviceinfo.DevicePropertiesSupported[i]);
mopoke96143402006-10-30 04:37:26 +00001067
Linus Walleij545c7792006-06-13 15:22:30 +00001068 if (propdesc != NULL) {
1069 printf(" 0x%04x: %s\n", params->deviceinfo.DevicePropertiesSupported[i], propdesc);
1070 } else {
1071 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
Linus Walleijcf223e62006-06-19 09:31:53 +00001072 printf(" 0x%04x: Unknown property\n", prop);
Linus Walleij545c7792006-06-13 15:22:30 +00001073 }
Linus Walleij8c45b292006-04-26 14:12:44 +00001074 }
Linus Walleij0af979a2006-06-19 11:49:10 +00001075
1076 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
1077 printf("Playable File (Object) Types and Object Properties Supported:\n");
1078 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
1079 char txt[256];
1080 uint16_t ret;
1081 uint16_t *props = NULL;
1082 uint32_t propcnt = 0;
1083 int j;
mopoke96143402006-10-30 04:37:26 +00001084
Linus Walleij0af979a2006-06-19 11:49:10 +00001085 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i], sizeof(txt), txt);
1086 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
mopoke96143402006-10-30 04:37:26 +00001087
Linus Walleij0af979a2006-06-19 11:49:10 +00001088 ret = ptp_mtp_getobjectpropssupported (params, params->deviceinfo.ImageFormats[i], &propcnt, &props);
1089 if (ret != PTP_RC_OK) {
1090 printf(" Error on query for object properties.\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00001091 printf(" Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij0af979a2006-06-19 11:49:10 +00001092 } else {
1093 for (j=0;j<propcnt;j++) {
1094 (void) ptp_render_mtp_propname(props[j],sizeof(txt),txt);
1095 printf(" %04x: %s\n", props[j], txt);
1096 }
1097 free(props);
1098 }
1099 }
1100 }
mopoke96143402006-10-30 04:37:26 +00001101
Linus Walleij545c7792006-06-13 15:22:30 +00001102 printf("Special directories:\n");
1103 printf(" Default music folder: 0x%08x\n", device->default_music_folder);
1104 printf(" Default playlist folder: 0x%08x\n", device->default_playlist_folder);
1105 printf(" Default picture folder: 0x%08x\n", device->default_picture_folder);
1106 printf(" Default video folder: 0x%08x\n", device->default_video_folder);
1107 printf(" Default organizer folder: 0x%08x\n", device->default_organizer_folder);
1108 printf(" Default zencast folder: 0x%08x\n", device->default_zencast_folder);
Linus Walleij8c45b292006-04-26 14:12:44 +00001109}
1110
1111/**
mopoke96143402006-10-30 04:37:26 +00001112 * This retrieves the model name (often equal to product name)
Linus Walleij80124062006-03-15 10:26:09 +00001113 * of an MTP device.
1114 * @param device a pointer to the device to get the model name for.
1115 * @return a newly allocated UTF-8 string representing the model name.
1116 * The string must be freed by the caller after use. If the call
1117 * was unsuccessful this will contain NULL.
1118 */
1119char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
1120{
1121 char *retmodel = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001122 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001123
Linus Walleij9b28da32006-03-16 13:47:58 +00001124 if (params->deviceinfo.Model != NULL) {
1125 retmodel = strdup(params->deviceinfo.Model);
Linus Walleij80124062006-03-15 10:26:09 +00001126 }
1127 return retmodel;
1128}
1129
1130/**
1131 * This retrieves the serial number of an MTP device.
1132 * @param device a pointer to the device to get the serial number for.
1133 * @return a newly allocated UTF-8 string representing the serial number.
1134 * The string must be freed by the caller after use. If the call
1135 * was unsuccessful this will contain NULL.
1136 */
1137char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
1138{
1139 char *retnumber = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001140 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001141
Linus Walleij9b28da32006-03-16 13:47:58 +00001142 if (params->deviceinfo.SerialNumber != NULL) {
1143 retnumber = strdup(params->deviceinfo.SerialNumber);
Linus Walleij80124062006-03-15 10:26:09 +00001144 }
1145 return retnumber;
1146}
1147
1148/**
mopoke96143402006-10-30 04:37:26 +00001149 * This retrieves the device version (hardware and firmware version) of an
Linus Walleij80124062006-03-15 10:26:09 +00001150 * MTP device.
1151 * @param device a pointer to the device to get the device version for.
1152 * @return a newly allocated UTF-8 string representing the device version.
1153 * The string must be freed by the caller after use. If the call
1154 * was unsuccessful this will contain NULL.
1155 */
1156char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
1157{
1158 char *retversion = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001159 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001160
Linus Walleij9b28da32006-03-16 13:47:58 +00001161 if (params->deviceinfo.DeviceVersion != NULL) {
1162 retversion = strdup(params->deviceinfo.DeviceVersion);
Linus Walleij80124062006-03-15 10:26:09 +00001163 }
1164 return retversion;
1165}
1166
1167
1168/**
Linus Walleijfae27482006-08-19 20:13:25 +00001169 * This retrieves the "friendly name" of an MTP device. Usually
1170 * this is simply the name of the owner or something like
Linus Walleij30658792006-08-19 22:18:55 +00001171 * "John Doe's Digital Audio Player". This property should be supported
Linus Walleijfae27482006-08-19 20:13:25 +00001172 * by all MTP devices.
1173 * @param device a pointer to the device to get the friendly name for.
mopoke96143402006-10-30 04:37:26 +00001174 * @return a newly allocated UTF-8 string representing the friendly name.
Linus Walleijb9256fd2006-02-15 09:40:43 +00001175 * The string must be freed by the caller after use.
Linus Walleij30658792006-08-19 22:18:55 +00001176 * @see LIBMTP_Set_Friendlyname()
Linus Walleijb9256fd2006-02-15 09:40:43 +00001177 */
Linus Walleij30658792006-08-19 22:18:55 +00001178char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001179{
Linus Walleijb02a0662006-04-25 08:05:09 +00001180 PTPPropertyValue propval;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001181 char *retstring = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001182 PTPParams *params = (PTPParams *) device->params;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001183
Linus Walleijcf223e62006-06-19 09:31:53 +00001184 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
1185 return NULL;
1186 }
1187
mopoke96143402006-10-30 04:37:26 +00001188 if (ptp_getdevicepropvalue(params,
1189 PTP_DPC_MTP_DeviceFriendlyName,
1190 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001191 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001192 return NULL;
1193 }
Linus Walleija823a702006-08-27 21:27:46 +00001194 if (propval.str != NULL) {
1195 retstring = strdup(propval.str);
1196 free(propval.str);
1197 }
Linus Walleijfae27482006-08-19 20:13:25 +00001198 return retstring;
1199}
1200
1201/**
Linus Walleij30658792006-08-19 22:18:55 +00001202 * Sets the "friendly name" of an MTP device.
1203 * @param device a pointer to the device to set the friendly name for.
1204 * @param friendlyname the new friendly name for the device.
1205 * @return 0 on success, any other value means failure.
1206 * @see LIBMTP_Get_Ownername()
1207 */
1208int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
1209 char const * const friendlyname)
1210{
1211 PTPPropertyValue propval;
1212 PTPParams *params = (PTPParams *) device->params;
1213
1214 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
1215 return -1;
1216 }
Linus Walleija823a702006-08-27 21:27:46 +00001217 propval.str = (char *) friendlyname;
Linus Walleij30658792006-08-19 22:18:55 +00001218 if (ptp_setdevicepropvalue(params,
mopoke96143402006-10-30 04:37:26 +00001219 PTP_DPC_MTP_DeviceFriendlyName,
1220 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001221 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleij30658792006-08-19 22:18:55 +00001222 return -1;
1223 }
Linus Walleij30658792006-08-19 22:18:55 +00001224 return 0;
1225}
1226
1227/**
Linus Walleijfae27482006-08-19 20:13:25 +00001228 * This retrieves the syncronization partner of an MTP device. This
1229 * property should be supported by all MTP devices.
1230 * @param device a pointer to the device to get the sync partner for.
1231 * @return a newly allocated UTF-8 string representing the synchronization
1232 * partner. The string must be freed by the caller after use.
Linus Walleij30658792006-08-19 22:18:55 +00001233 * @see LIBMTP_Set_Syncpartner()
Linus Walleijfae27482006-08-19 20:13:25 +00001234 */
1235char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
1236{
1237 PTPPropertyValue propval;
1238 char *retstring = NULL;
1239 PTPParams *params = (PTPParams *) device->params;
1240
1241 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
1242 return NULL;
1243 }
1244
mopoke96143402006-10-30 04:37:26 +00001245 if (ptp_getdevicepropvalue(params,
1246 PTP_DPC_MTP_SynchronizationPartner,
1247 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001248 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleijfae27482006-08-19 20:13:25 +00001249 return NULL;
1250 }
Linus Walleija823a702006-08-27 21:27:46 +00001251 if (propval.str != NULL) {
1252 retstring = strdup(propval.str);
1253 free(propval.str);
1254 }
Linus Walleijb9256fd2006-02-15 09:40:43 +00001255 return retstring;
1256}
1257
Linus Walleij30658792006-08-19 22:18:55 +00001258
1259/**
1260 * Sets the synchronization partner of an MTP device. Note that
1261 * we have no idea what the effect of setting this to "foobar"
1262 * may be. But the general idea seems to be to tell which program
1263 * shall synchronize with this device and tell others to leave
1264 * it alone.
1265 * @param device a pointer to the device to set the sync partner for.
1266 * @param syncpartner the new synchronization partner for the device.
1267 * @return 0 on success, any other value means failure.
1268 * @see LIBMTP_Get_Syncpartner()
1269 */
1270int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
1271 char const * const syncpartner)
1272{
1273 PTPPropertyValue propval;
1274 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001275
Linus Walleij30658792006-08-19 22:18:55 +00001276 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
1277 return -1;
1278 }
Linus Walleija823a702006-08-27 21:27:46 +00001279 propval.str = (char *) syncpartner;
Linus Walleij30658792006-08-19 22:18:55 +00001280 if (ptp_setdevicepropvalue(params,
mopoke96143402006-10-30 04:37:26 +00001281 PTP_DPC_MTP_SynchronizationPartner,
1282 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001283 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleij30658792006-08-19 22:18:55 +00001284 return -1;
1285 }
Linus Walleij30658792006-08-19 22:18:55 +00001286 return 0;
1287}
1288
Linus Walleij394bbbe2006-02-22 16:10:53 +00001289/**
Linus Walleijfa1374c2006-02-27 07:41:46 +00001290 * This function finds out how much storage space is currently used
1291 * and any additional storage information. Storage may be a hard disk
1292 * or flash memory or whatever.
1293 * @param device a pointer to the device to get the storage info for.
mopoke96143402006-10-30 04:37:26 +00001294 * @param total a pointer to a variable that will hold the
Linus Walleijfa1374c2006-02-27 07:41:46 +00001295 * total the total number of bytes available on this volume after
1296 * the call.
mopoke96143402006-10-30 04:37:26 +00001297 * @param free a pointer to a variable that will hold the number of
Linus Walleijfa1374c2006-02-27 07:41:46 +00001298 * free bytes available on this volume right now after the call.
mopoke96143402006-10-30 04:37:26 +00001299 * @param storage_description a description of the storage. This may
1300 * be NULL after the call even if it succeeded. If it is not NULL,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001301 * it must be freed by the callee after use.
1302 * @param volume_label a volume label or similar. This may be NULL after the
1303 * call even if it succeeded. If it is not NULL, it must be
1304 * freed by the callee after use.
1305 * @return 0 if the storage info was successfully retrieved, any other
1306 * value means failure.
1307 */
mopoke96143402006-10-30 04:37:26 +00001308int LIBMTP_Get_Storageinfo(LIBMTP_mtpdevice_t *device, uint64_t * const total,
1309 uint64_t * const free, char ** const storage_description,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001310 char ** const volume_label)
1311{
1312 PTPStorageInfo storageInfo;
Linus Walleij9b28da32006-03-16 13:47:58 +00001313 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001314
Linus Walleij9b28da32006-03-16 13:47:58 +00001315 if (ptp_getstorageinfo(params, device->storage_id, &storageInfo) != PTP_RC_OK) {
Linus Walleijfa1374c2006-02-27 07:41:46 +00001316 printf("LIBMTP_Get_Diskinfo(): failed to get disk info\n");
1317 *total = 0;
1318 *free = 0;
1319 *storage_description = NULL;
1320 *volume_label = NULL;
1321 return -1;
1322 }
1323 *total = storageInfo.MaxCapability;
1324 *free = storageInfo.FreeSpaceInBytes;
1325 *storage_description = storageInfo.StorageDescription;
1326 *volume_label = storageInfo.VolumeLabel;
1327
1328 return 0;
1329}
1330
1331
1332/**
1333 * This function retrieves the current battery level on the device.
1334 * @param device a pointer to the device to get the battery level for.
mopoke96143402006-10-30 04:37:26 +00001335 * @param maximum_level a pointer to a variable that will hold the
Linus Walleijfa1374c2006-02-27 07:41:46 +00001336 * maximum level of the battery if the call was successful.
mopoke96143402006-10-30 04:37:26 +00001337 * @param current_level a pointer to a variable that will hold the
Linus Walleijfa1374c2006-02-27 07:41:46 +00001338 * current level of the battery if the call was successful.
Linus Walleij545c7792006-06-13 15:22:30 +00001339 * A value of 0 means that the device is on external power.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001340 * @return 0 if the storage info was successfully retrieved, any other
Linus Walleij80439342006-09-12 10:42:26 +00001341 * means failure. A typical cause of failure is that
Linus Walleij545c7792006-06-13 15:22:30 +00001342 * the device does not support the battery level property.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001343 */
mopoke96143402006-10-30 04:37:26 +00001344int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
1345 uint8_t * const maximum_level,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001346 uint8_t * const current_level)
1347{
Linus Walleijb02a0662006-04-25 08:05:09 +00001348 PTPPropertyValue propval;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001349 uint16_t ret;
Linus Walleij9b28da32006-03-16 13:47:58 +00001350 PTPParams *params = (PTPParams *) device->params;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001351
Linus Walleij545c7792006-06-13 15:22:30 +00001352 *maximum_level = 0;
1353 *current_level = 0;
1354
1355 if (!ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
1356 return -1;
1357 }
mopoke96143402006-10-30 04:37:26 +00001358
Linus Walleijb02a0662006-04-25 08:05:09 +00001359 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel, &propval, PTP_DTC_UINT8);
1360 if (ret != PTP_RC_OK) {
Linus Walleijda9500d2006-08-30 13:17:06 +00001361 printf("LIBMTP_Get_Batterylevel(): could not get devcie property value.\n");
1362 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001363 return -1;
1364 }
mopoke96143402006-10-30 04:37:26 +00001365
Linus Walleijfa1374c2006-02-27 07:41:46 +00001366 *maximum_level = device->maximum_battery_level;
Linus Walleijb02a0662006-04-25 08:05:09 +00001367 *current_level = propval.u8;
mopoke96143402006-10-30 04:37:26 +00001368
Linus Walleijfa1374c2006-02-27 07:41:46 +00001369 return 0;
1370}
1371
Linus Walleij13374a42006-09-13 11:55:30 +00001372
1373/**
1374 * Formats device storage (if the device supports the operation).
1375 * WARNING: This WILL delete all data from the device. Make sure you've
1376 * got confirmation from the user BEFORE you call this function.
1377 *
1378 * @param device a pointer to the device to format.
1379 * @return 0 on success, any other value means failure.
1380 */
1381int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device)
1382{
1383 uint16_t ret;
1384 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001385
Linus Walleij13374a42006-09-13 11:55:30 +00001386 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
1387 printf("LIBMTP_Format_Storage(): device cannot format storage\n");
1388 return -1;
1389 }
1390 ret = ptp_formatstore(params, device->storage_id);
1391 if (ret != PTP_RC_OK) {
1392 printf("LIBMTP_Format_Storage(): failed to format storage\n");
1393 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
1394 return -1;
1395 }
1396 return 0;
1397}
1398
Linus Walleijfa1374c2006-02-27 07:41:46 +00001399/**
Linus Walleij545c7792006-06-13 15:22:30 +00001400 * Helper function to extract a unicode property off a device.
Linus Walleije46f12e2006-06-22 17:53:25 +00001401 * This is the standard way of retrieveing unicode device
1402 * properties as described by the PTP spec.
Linus Walleijcf223e62006-06-19 09:31:53 +00001403 * @param device a pointer to the device to get the property from.
mopoke96143402006-10-30 04:37:26 +00001404 * @param unicstring a pointer to a pointer that will hold the
Linus Walleijcf223e62006-06-19 09:31:53 +00001405 * property after this call is completed.
1406 * @param property the property to retrieve.
1407 * @return 0 on success, any other value means failure.
Linus Walleij545c7792006-06-13 15:22:30 +00001408 */
mopoke96143402006-10-30 04:37:26 +00001409static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
Linus Walleijcf223e62006-06-19 09:31:53 +00001410 char **unicstring, uint16_t property)
Linus Walleij545c7792006-06-13 15:22:30 +00001411{
1412 PTPPropertyValue propval;
1413 PTPParams *params = (PTPParams *) device->params;
Linus Walleij16571dc2006-08-17 20:27:46 +00001414 uint16_t *tmp;
Linus Walleij545c7792006-06-13 15:22:30 +00001415 int i;
1416
1417 if (!ptp_property_issupported(params, property)) {
1418 return -1;
1419 }
1420
Linus Walleijcf223e62006-06-19 09:31:53 +00001421 // Unicode strings are 16bit unsigned integer arrays.
mopoke96143402006-10-30 04:37:26 +00001422 if (ptp_getdevicepropvalue(params,
1423 property,
1424 &propval,
Linus Walleij545c7792006-06-13 15:22:30 +00001425 PTP_DTC_AUINT16) != PTP_RC_OK) {
1426 return -1;
1427 }
1428
1429 // Extract the actual array.
Linus Walleij16571dc2006-08-17 20:27:46 +00001430 // printf("Array of %d elements\n", propval.a.count);
1431 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
Linus Walleij545c7792006-06-13 15:22:30 +00001432 for (i = 0; i < propval.a.count; i++) {
Linus Walleij16571dc2006-08-17 20:27:46 +00001433 tmp[i] = propval.a.v[i].u16;
1434 // printf("%04x ", tmp[i]);
Linus Walleij545c7792006-06-13 15:22:30 +00001435 }
Linus Walleij16571dc2006-08-17 20:27:46 +00001436 tmp[propval.a.count] = 0x0000U;
Linus Walleij545c7792006-06-13 15:22:30 +00001437 free(propval.a.v);
1438
Linus Walleij3ec86312006-08-21 13:25:24 +00001439 *unicstring = utf16_to_utf8(device, tmp);
Linus Walleij16571dc2006-08-17 20:27:46 +00001440
Linus Walleij545c7792006-06-13 15:22:30 +00001441 free(tmp);
1442
1443 return 0;
1444}
1445
1446/**
1447 * This function returns the secure time as an XML document string from
1448 * the device.
1449 * @param device a pointer to the device to get the secure time for.
1450 * @param sectime the secure time string as an XML document or NULL if the call
1451 * failed or the secure time property is not supported. This string
1452 * must be <code>free()</code>:ed by the caller after use.
1453 * @return 0 on success, any other value means failure.
1454 */
Linus Walleij8ab54262006-06-21 07:12:28 +00001455int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
Linus Walleij545c7792006-06-13 15:22:30 +00001456{
1457 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
1458}
1459
1460/**
mopoke96143402006-10-30 04:37:26 +00001461 * This function returns the device (public key) certificate as an
Linus Walleij545c7792006-06-13 15:22:30 +00001462 * XML document string from the device.
1463 * @param device a pointer to the device to get the device certificate for.
1464 * @param devcert the device certificate as an XML string or NULL if the call
1465 * failed or the device certificate property is not supported. This
1466 * string must be <code>free()</code>:ed by the caller after use.
1467 * @return 0 on success, any other value means failure.
1468 */
Linus Walleij8ab54262006-06-21 07:12:28 +00001469int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
Linus Walleij545c7792006-06-13 15:22:30 +00001470{
1471 return get_device_unicode_property(device, devcert, PTP_DPC_MTP_DeviceCertificate);
1472}
1473
1474/**
Linus Walleij8ab54262006-06-21 07:12:28 +00001475 * This function retrieves a list of supported file types, i.e. the file
1476 * types that this device claims it supports, e.g. audio file types that
1477 * the device can play etc. This list is mitigated to
1478 * inlcude the file types that libmtp can handle, i.e. it will not list
1479 * filetypes that libmtp will handle internally like playlists and folders.
1480 * @param device a pointer to the device to get the filetype capabilities for.
1481 * @param filetypes a pointer to a pointer that will hold the list of
1482 * supported filetypes if the call was successful. This list must
1483 * be <code>free()</code>:ed by the caller after use.
1484 * @param length a pointer to a variable that will hold the length of the
1485 * list of supported filetypes if the call was successful.
1486 * @return 0 on success, any other value means failure.
1487 * @see LIBMTP_Get_Filetype_Description()
1488 */
mopoke96143402006-10-30 04:37:26 +00001489int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
Linus Walleij8ab54262006-06-21 07:12:28 +00001490 uint16_t * const length)
1491{
1492 PTPParams *params = (PTPParams *) device->params;
1493 uint16_t *localtypes;
1494 uint16_t localtypelen;
1495 uint32_t i;
mopoke96143402006-10-30 04:37:26 +00001496
Linus Walleij8ab54262006-06-21 07:12:28 +00001497 // This is more memory than needed if there are unknown types, but what the heck.
1498 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
1499 localtypelen = 0;
mopoke96143402006-10-30 04:37:26 +00001500
Linus Walleij8ab54262006-06-21 07:12:28 +00001501 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
1502 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
1503 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
1504 localtypes[localtypelen] = localtype;
1505 localtypelen++;
1506 }
1507 }
1508
1509 *filetypes = localtypes;
1510 *length = localtypelen;
1511
1512 return 0;
1513}
1514
1515
1516/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00001517 * This creates a new MTP object structure and allocates memory
raveloxd9a28642006-05-26 23:42:22 +00001518 * for it. Notice that if you add strings to this structure they
1519 * will be freed by the corresponding <code>LIBMTP_destroy_object_t</code>
mopoke96143402006-10-30 04:37:26 +00001520 * operation later, so be careful of using strdup() when assigning
raveloxd9a28642006-05-26 23:42:22 +00001521 * strings, e.g.:
1522 *
1523 * <pre>
1524 * LIBMTP_object_t *object = LIBMTP_new_object_t();
1525 * object->name = strdup(namestr);
1526 * ....
1527 * LIBMTP_destroy_object_t(file);
1528 * </pre>
1529 *
1530 * @return a pointer to the newly allocated structure.
1531 * @see LIBMTP_destroy_object_t()
1532 */
1533LIBMTP_object_t *LIBMTP_new_object_t(void)
1534{
1535 LIBMTP_object_t *new = (LIBMTP_object_t *) malloc(sizeof(LIBMTP_object_t));
1536 if (new == NULL) {
1537 return NULL;
1538 }
1539
1540 new->id = 0;
1541 new->parent = 0;
1542 new->type = LIBMTP_FILETYPE_UNKNOWN;
1543 new->size = 0;
1544 new->name = NULL;
1545 new->data = NULL;
1546 new->sibling = NULL;
1547 new->child = NULL;
1548
1549 return new;
1550}
Linus Walleijf0f3d482006-05-29 14:10:21 +00001551
raveloxd9a28642006-05-26 23:42:22 +00001552/**
Linus Walleijf6bc1782006-03-24 15:12:47 +00001553 * This creates a new file metadata structure and allocates memory
1554 * for it. Notice that if you add strings to this structure they
1555 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
mopoke96143402006-10-30 04:37:26 +00001556 * operation later, so be careful of using strdup() when assigning
Linus Walleijf6bc1782006-03-24 15:12:47 +00001557 * strings, e.g.:
1558 *
1559 * <pre>
1560 * LIBMTP_file_t *file = LIBMTP_new_file_t();
1561 * file->filename = strdup(namestr);
1562 * ....
1563 * LIBMTP_destroy_file_t(file);
1564 * </pre>
1565 *
1566 * @return a pointer to the newly allocated metadata structure.
1567 * @see LIBMTP_destroy_file_t()
1568 */
1569LIBMTP_file_t *LIBMTP_new_file_t(void)
1570{
1571 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
1572 if (new == NULL) {
1573 return NULL;
1574 }
1575 new->filename = NULL;
1576 new->filesize = 0;
1577 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
1578 new->next = NULL;
1579 return new;
1580}
1581
1582/**
1583 * This destroys a file metadata structure and deallocates the memory
mopoke96143402006-10-30 04:37:26 +00001584 * used by it, including any strings. Never use a file metadata
Linus Walleijf6bc1782006-03-24 15:12:47 +00001585 * structure again after calling this function on it.
1586 * @param file the file metadata to destroy.
1587 * @see LIBMTP_new_file_t()
1588 */
1589void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
1590{
1591 if (file == NULL) {
1592 return;
1593 }
1594 if (file->filename != NULL)
1595 free(file->filename);
1596 free(file);
1597 return;
1598}
1599
1600/**
1601 * This returns a long list of all files available
1602 * on the current MTP device. Typical usage:
1603 *
1604 * <pre>
1605 * LIBMTP_file_t *filelist;
1606 *
1607 * filelist = LIBMTP_Get_Filelisting(device);
1608 * while (filelist != NULL) {
1609 * LIBMTP_file_t *tmp;
1610 *
1611 * // Do something on each element in the list here...
1612 * tmp = filelist;
1613 * filelist = filelist->next;
1614 * LIBMTP_destroy_file_t(tmp);
1615 * }
1616 * </pre>
1617 *
1618 * @param device a pointer to the device to get the file listing for.
1619 * @return a list of files that can be followed using the <code>next</code>
1620 * field of the <code>LIBMTP_file_t</code> data structure.
1621 * Each of the metadata tags must be freed after use, and may
1622 * contain only partial metadata information, i.e. one or several
1623 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001624 * @see LIBMTP_Get_Filemetadata()
Linus Walleijf6bc1782006-03-24 15:12:47 +00001625 */
1626LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
1627{
1628 uint32_t i = 0;
1629 LIBMTP_file_t *retfiles = NULL;
1630 LIBMTP_file_t *curfile = NULL;
1631 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001632
mopoke96143402006-10-30 04:37:26 +00001633 // Get all the handles if we haven't already done that
Linus Walleijf6bc1782006-03-24 15:12:47 +00001634 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00001635 flush_handles(device);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001636 }
mopoke96143402006-10-30 04:37:26 +00001637
Linus Walleijf6bc1782006-03-24 15:12:47 +00001638 for (i = 0; i < params->handles.n; i++) {
1639
1640 LIBMTP_file_t *file;
1641 PTPObjectInfo oi;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001642
1643 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleij16c51f02006-05-04 13:20:22 +00001644
Linus Walleij91405592006-05-05 14:22:51 +00001645 if (oi.ObjectFormat == PTP_OFC_Association) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00001646 // MTP use thesis object format for folders which means
Linus Walleij16c51f02006-05-04 13:20:22 +00001647 // these "files" will turn up on a folder listing instead.
1648 continue;
1649 }
1650
Linus Walleijf6bc1782006-03-24 15:12:47 +00001651 // Allocate a new file type
1652 file = LIBMTP_new_file_t();
Linus Walleijb02a0662006-04-25 08:05:09 +00001653
Linus Walleijd208f9c2006-04-27 14:16:06 +00001654 file->parent_id = oi.ParentObject;
Linus Walleij16c51f02006-05-04 13:20:22 +00001655
1656 // Set the filetype
1657 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001658
1659 // Original file-specific properties
1660 file->filesize = oi.ObjectCompressedSize;
1661 if (oi.Filename != NULL) {
1662 file->filename = strdup(oi.Filename);
1663 }
1664
1665 // This is some sort of unique ID so we can keep track of the track.
1666 file->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00001667
Linus Walleijf6bc1782006-03-24 15:12:47 +00001668 // Add track to a list that will be returned afterwards.
1669 if (retfiles == NULL) {
1670 retfiles = file;
1671 curfile = file;
1672 } else {
1673 curfile->next = file;
1674 curfile = file;
1675 }
mopoke96143402006-10-30 04:37:26 +00001676
Linus Walleijf6bc1782006-03-24 15:12:47 +00001677 // Call listing callback
1678 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
1679
1680 } else {
1681 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
1682 }
1683
1684 } // Handle counting loop
1685 return retfiles;
1686}
1687
1688/**
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001689 * This function retrieves the metadata for a single file off
1690 * the device.
1691 *
1692 * Do not call this function repeatedly! The file handles are linearly
1693 * searched O(n) and the call may involve (slow) USB traffic, so use
1694 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
1695 * as an efficient data structure such as a hash list.
1696 *
1697 * @param device a pointer to the device to get the file metadata from.
1698 * @param fileid the object ID of the file that you want the metadata for.
1699 * @return a metadata entry on success or NULL on failure.
1700 * @see LIBMTP_Get_Filelisting()
1701 */
1702LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
1703{
1704 uint32_t i = 0;
1705 PTPParams *params = (PTPParams *) device->params;
1706
mopoke96143402006-10-30 04:37:26 +00001707 // Get all the handles if we haven't already done that
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001708 if (params->handles.Handler == NULL) {
1709 flush_handles(device);
1710 }
1711
1712 for (i = 0; i < params->handles.n; i++) {
1713 LIBMTP_file_t *file;
1714 PTPObjectInfo oi;
1715
1716 // Is this the file we're looking for?
1717 if (params->handles.Handler[i] != fileid) {
1718 continue;
1719 }
1720
1721 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
1722
1723 if (oi.ObjectFormat == PTP_OFC_Association) {
1724 // MTP use thesis object format for folders which means
1725 // these "files" will turn up on a folder listing instead.
1726 return NULL;
1727 }
1728
1729 // Allocate a new file type
1730 file = LIBMTP_new_file_t();
mopoke96143402006-10-30 04:37:26 +00001731
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001732 file->parent_id = oi.ParentObject;
mopoke96143402006-10-30 04:37:26 +00001733
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001734 // Set the filetype
1735 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00001736
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001737 // Original file-specific properties
1738 file->filesize = oi.ObjectCompressedSize;
1739 if (oi.Filename != NULL) {
1740 file->filename = strdup(oi.Filename);
1741 }
mopoke96143402006-10-30 04:37:26 +00001742
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001743 // This is some sort of unique ID so we can keep track of the track.
1744 file->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00001745
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001746 return file;
1747 } else {
1748 return NULL;
1749 }
1750
1751 }
1752 return NULL;
1753}
1754
1755/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00001756 * This creates a new track metadata structure and allocates memory
1757 * for it. Notice that if you add strings to this structure they
1758 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
mopoke96143402006-10-30 04:37:26 +00001759 * operation later, so be careful of using strdup() when assigning
Linus Walleij394bbbe2006-02-22 16:10:53 +00001760 * strings, e.g.:
1761 *
Linus Walleij17e39f72006-02-23 15:54:28 +00001762 * <pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001763 * LIBMTP_track_t *track = LIBMTP_new_track_t();
1764 * track->title = strdup(titlestr);
1765 * ....
1766 * LIBMTP_destroy_track_t(track);
Linus Walleij17e39f72006-02-23 15:54:28 +00001767 * </pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001768 *
1769 * @return a pointer to the newly allocated metadata structure.
1770 * @see LIBMTP_destroy_track_t()
1771 */
1772LIBMTP_track_t *LIBMTP_new_track_t(void)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001773{
1774 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
1775 if (new == NULL) {
1776 return NULL;
1777 }
1778 new->title = NULL;
1779 new->artist = NULL;
1780 new->album = NULL;
1781 new->genre = NULL;
1782 new->date = NULL;
1783 new->filename = NULL;
1784 new->duration = 0;
1785 new->tracknumber = 0;
1786 new->filesize = 0;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001787 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
Linus Walleijcf223e62006-06-19 09:31:53 +00001788 new->samplerate = 0;
1789 new->nochannels = 0;
1790 new->wavecodec = 0;
1791 new->bitrate = 0;
1792 new->bitratetype = 0;
1793 new->rating = 0;
1794 new->usecount = 0;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001795 new->next = NULL;
1796 return new;
1797}
1798
Linus Walleij394bbbe2006-02-22 16:10:53 +00001799/**
1800 * This destroys a track metadata structure and deallocates the memory
mopoke96143402006-10-30 04:37:26 +00001801 * used by it, including any strings. Never use a track metadata
Linus Walleij394bbbe2006-02-22 16:10:53 +00001802 * structure again after calling this function on it.
1803 * @param track the track metadata to destroy.
1804 * @see LIBMTP_new_track_t()
1805 */
Linus Walleijb9256fd2006-02-15 09:40:43 +00001806void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
1807{
1808 if (track == NULL) {
1809 return;
1810 }
1811 if (track->title != NULL)
1812 free(track->title);
1813 if (track->artist != NULL)
1814 free(track->artist);
1815 if (track->album != NULL)
1816 free(track->album);
1817 if (track->genre != NULL)
1818 free(track->genre);
1819 if (track->date != NULL)
1820 free(track->date);
1821 if (track->filename != NULL)
1822 free(track->filename);
1823 free(track);
1824 return;
1825}
1826
1827/**
Linus Walleij8ab54262006-06-21 07:12:28 +00001828 * This function retrieves the track metadata for a track
1829 * given by a unique ID.
1830 * @param device a pointer to the device to get the track metadata off.
1831 * @param trackid the unique ID of the track.
1832 * @param objectformat the object format of this track, so we know what it supports.
1833 * @param track a metadata set to fill in.
1834 */
1835static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
1836 LIBMTP_track_t *track)
1837{
Linus Walleij00cf0642006-07-26 20:40:59 +00001838 uint16_t ret;
1839 PTPParams *params = (PTPParams *) device->params;
1840 uint32_t i;
Linus Walleij00cf0642006-07-26 20:40:59 +00001841
Linus Walleij3fcfea52006-11-13 07:07:36 +00001842#if 0 // #ifdef ENABLE_MTP_ENHANCED
1843 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)) {
1844 MTPPropList *proplist = NULL;
1845 MTPPropList *prop;
1846 MTPPropList *tmpprop;
1847
1848 ret = ptp_mtp_getobjectproplist(params, track->item_id, &proplist);
1849 prop = proplist;
1850 while (prop != NULL) {
1851 switch (prop->property) {
Linus Walleij00cf0642006-07-26 20:40:59 +00001852 case PTP_OPC_Name:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001853 track->title = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001854 break;
1855 case PTP_OPC_Artist:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001856 track->artist = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001857 break;
1858 case PTP_OPC_Duration:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001859 track->duration = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001860 break;
1861 case PTP_OPC_Track:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001862 track->tracknumber = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001863 break;
1864 case PTP_OPC_Genre:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001865 track->genre = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001866 break;
1867 case PTP_OPC_AlbumName:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001868 track->album = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001869 break;
1870 case PTP_OPC_OriginalReleaseDate:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001871 track->date = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001872 break;
1873 // These are, well not so important.
1874 case PTP_OPC_SampleRate:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001875 track->samplerate = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001876 break;
1877 case PTP_OPC_NumberOfChannels:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001878 track->nochannels = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001879 break;
1880 case PTP_OPC_AudioWAVECodec:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001881 track->wavecodec = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001882 break;
1883 case PTP_OPC_AudioBitRate:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001884 track->bitrate = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001885 break;
1886 case PTP_OPC_BitRateType:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001887 track->bitratetype = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001888 break;
1889 case PTP_OPC_Rating:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001890 track->rating = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001891 break;
1892 case PTP_OPC_UseCount:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001893 track->usecount = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001894 break;
1895 }
Linus Walleij3fcfea52006-11-13 07:07:36 +00001896 tmpprop = prop;
1897 prop = prop->next;
1898 Destroy_MTP_Prop_Entry(tmpprop);
Linus Walleij00cf0642006-07-26 20:40:59 +00001899 }
Linus Walleij3fcfea52006-11-13 07:07:36 +00001900 } else {
1901#else
1902 {
1903#endif
1904 uint16_t *props = NULL;
1905 uint32_t propcnt = 0;
1906
1907 // First see which properties can be retrieved for this object format
1908 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
1909 if (ret != PTP_RC_OK) {
1910 // Just bail out for now, nothing is ever set.
1911 return;
1912 } else {
1913 for (i=0;i<propcnt;i++) {
1914 switch (props[i]) {
1915 case PTP_OPC_Name:
1916 track->title = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Name);
1917 break;
1918 case PTP_OPC_Artist:
1919 track->artist = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Artist);
1920 break;
1921 case PTP_OPC_Duration:
1922 track->duration = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_Duration, 0);
1923 break;
1924 case PTP_OPC_Track:
1925 track->tracknumber = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_Track, 0);
1926 break;
1927 case PTP_OPC_Genre:
1928 track->genre = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Genre);
1929 break;
1930 case PTP_OPC_AlbumName:
1931 track->album = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_AlbumName);
1932 break;
1933 case PTP_OPC_OriginalReleaseDate:
1934 track->date = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
1935 break;
1936 // These are, well not so important.
1937 case PTP_OPC_SampleRate:
1938 track->samplerate = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_SampleRate, 0);
1939 break;
1940 case PTP_OPC_NumberOfChannels:
1941 track->nochannels = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
1942 break;
1943 case PTP_OPC_AudioWAVECodec:
1944 track->wavecodec = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
1945 break;
1946 case PTP_OPC_AudioBitRate:
1947 track->bitrate = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
1948 break;
1949 case PTP_OPC_BitRateType:
1950 track->bitratetype = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_BitRateType, 0);
1951 break;
1952 case PTP_OPC_Rating:
1953 track->rating = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_Rating, 0);
1954 break;
1955 case PTP_OPC_UseCount:
1956 track->usecount = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_UseCount, 0);
1957 break;
1958 }
1959 }
1960 free(props);
1961 }
Linus Walleij00cf0642006-07-26 20:40:59 +00001962 }
Linus Walleij8ab54262006-06-21 07:12:28 +00001963}
1964
1965/**
Linus Walleij3fcfea52006-11-13 07:07:36 +00001966 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
1967 * NOT TO USE IT.
1968 * @see LIBMTP_Get_Tracklisting_With_Callback()
1969 */
1970LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
1971{
1972 printf("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
1973 printf("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
1974 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL);
1975}
1976
1977/**
Linus Walleijb9256fd2006-02-15 09:40:43 +00001978 * This returns a long list of all tracks available
Linus Walleija4982732006-02-24 15:46:02 +00001979 * on the current MTP device. Typical usage:
1980 *
1981 * <pre>
1982 * LIBMTP_track_t *tracklist;
1983 *
1984 * tracklist = LIBMTP_Get_Tracklisting(device);
1985 * while (tracklist != NULL) {
1986 * LIBMTP_track_t *tmp;
1987 *
1988 * // Do something on each element in the list here...
1989 * tmp = tracklist;
1990 * tracklist = tracklist->next;
1991 * LIBMTP_destroy_track_t(tmp);
1992 * }
1993 * </pre>
1994 *
Linus Walleijb9256fd2006-02-15 09:40:43 +00001995 * @param device a pointer to the device to get the track listing for.
Linus Walleij3fcfea52006-11-13 07:07:36 +00001996 * @param callback a function to be called during the tracklisting retrieveal
1997 * for displaying progress bars etc, or NULL if you don't want
1998 * any callbacks.
Linus Walleija4982732006-02-24 15:46:02 +00001999 * @return a list of tracks that can be followed using the <code>next</code>
2000 * field of the <code>LIBMTP_track_t</code> data structure.
2001 * Each of the metadata tags must be freed after use, and may
2002 * contain only partial metadata information, i.e. one or several
2003 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002004 * @see LIBMTP_Get_Trackmetadata()
Linus Walleijb9256fd2006-02-15 09:40:43 +00002005 */
Linus Walleij3fcfea52006-11-13 07:07:36 +00002006LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device, LIBMTP_progressfunc_t const callback)
Linus Walleijb9256fd2006-02-15 09:40:43 +00002007{
2008 uint32_t i = 0;
2009 LIBMTP_track_t *retracks = NULL;
2010 LIBMTP_track_t *curtrack = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00002011 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002012
mopoke96143402006-10-30 04:37:26 +00002013 // Get all the handles if we haven't already done that
Linus Walleij9b28da32006-03-16 13:47:58 +00002014 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002015 flush_handles(device);
Linus Walleijb9256fd2006-02-15 09:40:43 +00002016 }
mopoke96143402006-10-30 04:37:26 +00002017
Linus Walleij9b28da32006-03-16 13:47:58 +00002018 for (i = 0; i < params->handles.n; i++) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00002019 LIBMTP_track_t *track;
2020 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00002021
Linus Walleij9b28da32006-03-16 13:47:58 +00002022 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
mopoke96143402006-10-30 04:37:26 +00002023
Linus Walleijb9256fd2006-02-15 09:40:43 +00002024 // Ignore stuff we don't know how to handle...
Linus Walleij8ab54262006-06-21 07:12:28 +00002025 // TODO: get this list as an intersection of the sets
2026 // supported by the device and the from the device and
2027 // all known audio track files?
mopoke96143402006-10-30 04:37:26 +00002028 if ( oi.ObjectFormat != PTP_OFC_WAV &&
2029 oi.ObjectFormat != PTP_OFC_MP3 &&
Linus Walleij9c6ca022006-04-21 10:24:15 +00002030 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
mopoke96143402006-10-30 04:37:26 +00002031 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
Linus Walleij9c6ca022006-04-21 10:24:15 +00002032 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
2033 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
Linus Walleijafe61432006-05-05 13:51:34 +00002034 // printf("Not a music track (format: %d), skipping...\n",oi.ObjectFormat);
Linus Walleijb9256fd2006-02-15 09:40:43 +00002035 continue;
2036 }
mopoke96143402006-10-30 04:37:26 +00002037
Linus Walleijb9256fd2006-02-15 09:40:43 +00002038 // Allocate a new track type
2039 track = LIBMTP_new_track_t();
Linus Walleij8ab54262006-06-21 07:12:28 +00002040
2041 // This is some sort of unique ID so we can keep track of the track.
2042 track->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00002043
Linus Walleij16c51f02006-05-04 13:20:22 +00002044 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00002045
Linus Walleijb9256fd2006-02-15 09:40:43 +00002046 // Original file-specific properties
2047 track->filesize = oi.ObjectCompressedSize;
2048 if (oi.Filename != NULL) {
2049 track->filename = strdup(oi.Filename);
Linus Walleijb9256fd2006-02-15 09:40:43 +00002050 }
Linus Walleij8ab54262006-06-21 07:12:28 +00002051
2052 get_track_metadata(device, oi.ObjectFormat, track);
mopoke96143402006-10-30 04:37:26 +00002053
Linus Walleijb9256fd2006-02-15 09:40:43 +00002054 // Add track to a list that will be returned afterwards.
2055 if (retracks == NULL) {
2056 retracks = track;
2057 curtrack = track;
2058 } else {
2059 curtrack->next = track;
2060 curtrack = track;
2061 }
mopoke96143402006-10-30 04:37:26 +00002062
Linus Walleijb9256fd2006-02-15 09:40:43 +00002063 // Call listing callback
Linus Walleij9b28da32006-03-16 13:47:58 +00002064 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
Linus Walleijb9256fd2006-02-15 09:40:43 +00002065
2066 } else {
2067 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
2068 }
2069
2070 } // Handle counting loop
2071 return retracks;
2072}
Linus Walleijdcde6082006-02-17 16:16:34 +00002073
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002074/**
2075 * This function retrieves the metadata for a single track off
2076 * the device.
2077 *
2078 * Do not call this function repeatedly! The track handles are linearly
2079 * searched O(n) and the call may involve (slow) USB traffic, so use
2080 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
2081 * as an efficient data structure such as a hash list.
2082 *
2083 * @param device a pointer to the device to get the track metadata from.
2084 * @param trackid the object ID of the track that you want the metadata for.
2085 * @return a track metadata entry on success or NULL on failure.
2086 * @see LIBMTP_Get_Tracklisting()
2087 */
2088LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
2089{
2090 uint32_t i = 0;
2091 PTPParams *params = (PTPParams *) device->params;
2092
mopoke96143402006-10-30 04:37:26 +00002093 // Get all the handles if we haven't already done that
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002094 if (params->handles.Handler == NULL) {
2095 flush_handles(device);
2096 }
2097
2098 for (i = 0; i < params->handles.n; i++) {
2099 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00002100
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002101 // Skip if this is not the track we want.
2102 if (params->handles.Handler[i] != trackid) {
2103 continue;
2104 }
2105
2106 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
2107 LIBMTP_track_t *track;
mopoke96143402006-10-30 04:37:26 +00002108
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002109 // Ignore stuff we don't know how to handle...
mopoke96143402006-10-30 04:37:26 +00002110 if ( oi.ObjectFormat != PTP_OFC_WAV &&
2111 oi.ObjectFormat != PTP_OFC_MP3 &&
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002112 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
mopoke96143402006-10-30 04:37:26 +00002113 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002114 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
2115 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
2116 return NULL;
2117 }
mopoke96143402006-10-30 04:37:26 +00002118
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002119 // Allocate a new track type
2120 track = LIBMTP_new_track_t();
Linus Walleij8ab54262006-06-21 07:12:28 +00002121
2122 // This is some sort of unique ID so we can keep track of the track.
2123 track->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00002124
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002125 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00002126
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002127 // Original file-specific properties
2128 track->filesize = oi.ObjectCompressedSize;
2129 if (oi.Filename != NULL) {
2130 track->filename = strdup(oi.Filename);
2131 }
Linus Walleij8ab54262006-06-21 07:12:28 +00002132
2133 get_track_metadata(device, oi.ObjectFormat, track);
mopoke96143402006-10-30 04:37:26 +00002134
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002135 return track;
2136
2137 } else {
2138 return NULL;
2139 }
2140
2141 }
2142 return NULL;
2143}
2144
Linus Walleijf6bc1782006-03-24 15:12:47 +00002145
2146/**
2147 * This gets a file off the device to a local file identified
2148 * by a filename.
2149 * @param device a pointer to the device to get the track from.
2150 * @param id the file ID of the file to retrieve.
2151 * @param path a filename to use for the retrieved file.
2152 * @param callback a progress indicator function or NULL to ignore.
2153 * @param data a user-defined pointer that is passed along to
2154 * the <code>progress</code> function in order to
2155 * pass along some user defined data to the progress
2156 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002157 * @return 0 if the transfer was successful, any other value means
Linus Walleijf6bc1782006-03-24 15:12:47 +00002158 * failure.
2159 * @see LIBMTP_Get_File_To_File_Descriptor()
2160 */
mopoke96143402006-10-30 04:37:26 +00002161int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
Linus Walleijee73ef22006-08-27 19:56:00 +00002162 char const * const path, LIBMTP_progressfunc_t const callback,
Linus Walleijf6bc1782006-03-24 15:12:47 +00002163 void const * const data)
2164{
2165 int fd = -1;
2166 int ret;
2167
2168 // Sanity check
2169 if (path == NULL) {
2170 printf("LIBMTP_Get_File_To_File(): Bad arguments, path was NULL\n");
2171 return -1;
2172 }
2173
2174 // Open file
2175#ifdef __WIN32__
flavienbfd80eb2006-06-01 22:41:49 +00002176 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU|S_IRGRP)) == -1 ) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00002177#else
2178 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
2179#endif
2180 printf("LIBMTP_Get_File_To_File(): Could not create file \"%s\"\n", path);
2181 return -1;
2182 }
mopoke96143402006-10-30 04:37:26 +00002183
Linus Walleijf6bc1782006-03-24 15:12:47 +00002184 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
2185
2186 // Close file
2187 close(fd);
mopoke96143402006-10-30 04:37:26 +00002188
Linus Walleijf6bc1782006-03-24 15:12:47 +00002189 return ret;
2190}
2191
2192/**
2193 * This gets a file off the device to a file identified
2194 * by a file descriptor.
Linus Walleij0558ac52006-09-07 06:55:03 +00002195 *
mopoke96143402006-10-30 04:37:26 +00002196 * This function can potentially be used for streaming
2197 * files off the device for playback or broadcast for example,
Linus Walleij0558ac52006-09-07 06:55:03 +00002198 * by downloading the file into a stream sink e.g. a socket.
2199 *
Linus Walleijf6bc1782006-03-24 15:12:47 +00002200 * @param device a pointer to the device to get the file from.
2201 * @param id the file ID of the file to retrieve.
2202 * @param fd a local file descriptor to write the file to.
2203 * @param callback a progress indicator function or NULL to ignore.
2204 * @param data a user-defined pointer that is passed along to
2205 * the <code>progress</code> function in order to
2206 * pass along some user defined data to the progress
2207 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002208 * @return 0 if the transfer was successful, any other value means
Linus Walleijf6bc1782006-03-24 15:12:47 +00002209 * failure.
2210 * @see LIBMTP_Get_File_To_File()
2211 */
mopoke96143402006-10-30 04:37:26 +00002212int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
2213 uint32_t const id,
2214 int const fd,
Linus Walleijee73ef22006-08-27 19:56:00 +00002215 LIBMTP_progressfunc_t const callback,
Linus Walleijf6bc1782006-03-24 15:12:47 +00002216 void const * const data)
2217{
2218 PTPObjectInfo oi;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002219 uint16_t ret;
Linus Walleijf6bc1782006-03-24 15:12:47 +00002220 PTPParams *params = (PTPParams *) device->params;
Linus Walleijee73ef22006-08-27 19:56:00 +00002221 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleijf6bc1782006-03-24 15:12:47 +00002222
Linus Walleijf6bc1782006-03-24 15:12:47 +00002223 if (ptp_getobjectinfo(params, id, &oi) != PTP_RC_OK) {
2224 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get object info\n");
2225 return -1;
2226 }
2227 if (oi.ObjectFormat == PTP_OFC_Association) {
2228 printf("LIBMTP_Get_File_To_File_Descriptor(): Bad object format\n");
2229 return -1;
2230 }
Linus Walleijf6bc1782006-03-24 15:12:47 +00002231
Linus Walleijee73ef22006-08-27 19:56:00 +00002232 // Callbacks
2233 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002234 ptp_usb->current_transfer_total = oi.ObjectCompressedSize+
2235 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
Linus Walleijee73ef22006-08-27 19:56:00 +00002236 ptp_usb->current_transfer_complete = 0;
2237 ptp_usb->current_transfer_callback = callback;
2238 ptp_usb->current_transfer_callback_data = data;
mopoke96143402006-10-30 04:37:26 +00002239
Linus Walleij96c62432006-08-21 10:04:02 +00002240 // This now exist in upstream
2241 ret = ptp_getobject_tofd(params, id, fd);
Linus Walleijee73ef22006-08-27 19:56:00 +00002242
2243 ptp_usb->callback_active = 0;
2244 ptp_usb->current_transfer_callback = NULL;
2245 ptp_usb->current_transfer_callback_data = NULL;
mopoke96143402006-10-30 04:37:26 +00002246
Linus Walleijb02a0662006-04-25 08:05:09 +00002247 if (ret != PTP_RC_OK) {
2248 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device (%d)\n", ret);
Linus Walleijf6bc1782006-03-24 15:12:47 +00002249 return -1;
2250 }
mopoke96143402006-10-30 04:37:26 +00002251
Linus Walleijf6bc1782006-03-24 15:12:47 +00002252 return 0;
2253}
2254
Linus Walleijdcde6082006-02-17 16:16:34 +00002255/**
2256 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00002257 * by a filename. This is actually just a wrapper for the
2258 * \c LIBMTP_Get_Track_To_File() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00002259 * @param device a pointer to the device to get the track from.
2260 * @param id the track ID of the track to retrieve.
2261 * @param path a filename to use for the retrieved track.
2262 * @param callback a progress indicator function or NULL to ignore.
2263 * @param data a user-defined pointer that is passed along to
2264 * the <code>progress</code> function in order to
2265 * pass along some user defined data to the progress
2266 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002267 * @return 0 if the transfer was successful, any other value means
Linus Walleijdcde6082006-02-17 16:16:34 +00002268 * failure.
2269 * @see LIBMTP_Get_Track_To_File_Descriptor()
2270 */
mopoke96143402006-10-30 04:37:26 +00002271int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
Linus Walleijee73ef22006-08-27 19:56:00 +00002272 char const * const path, LIBMTP_progressfunc_t const callback,
Linus Walleij0cd85432006-02-20 14:37:50 +00002273 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00002274{
Linus Walleijf6bc1782006-03-24 15:12:47 +00002275 // This is just a wrapper
2276 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00002277}
2278
2279/**
2280 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00002281 * by a file descriptor. This is actually just a wrapper for
2282 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00002283 * @param device a pointer to the device to get the track from.
2284 * @param id the track ID of the track to retrieve.
2285 * @param fd a file descriptor to write the track to.
2286 * @param callback a progress indicator function or NULL to ignore.
2287 * @param data a user-defined pointer that is passed along to
2288 * the <code>progress</code> function in order to
2289 * pass along some user defined data to the progress
2290 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002291 * @return 0 if the transfer was successful, any other value means
Linus Walleijdcde6082006-02-17 16:16:34 +00002292 * failure.
2293 * @see LIBMTP_Get_Track_To_File()
2294 */
mopoke96143402006-10-30 04:37:26 +00002295int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
2296 uint32_t const id,
2297 int const fd,
Linus Walleijee73ef22006-08-27 19:56:00 +00002298 LIBMTP_progressfunc_t const callback,
Linus Walleij0cd85432006-02-20 14:37:50 +00002299 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00002300{
Linus Walleijf6bc1782006-03-24 15:12:47 +00002301 // This is just a wrapper
2302 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00002303}
Linus Walleij394bbbe2006-02-22 16:10:53 +00002304
2305/**
2306 * This function sends a track from a local file to an
2307 * MTP device. A filename and a set of metadata must be
2308 * given as input.
2309 * @param device a pointer to the device to send the track to.
2310 * @param path the filename of a local file which will be sent.
2311 * @param metadata a track metadata set to be written along with the file.
2312 * @param callback a progress indicator function or NULL to ignore.
2313 * @param data a user-defined pointer that is passed along to
2314 * the <code>progress</code> function in order to
2315 * pass along some user defined data to the progress
2316 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002317 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002318 * in. Since some devices are a bit picky about where files
2319 * are placed, a default folder will be chosen if libmtp
2320 * has detected one for the current filetype and this
2321 * parameter is set to 0. If this is 0 and no default folder
2322 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002323 * @return 0 if the transfer was successful, any other value means
Linus Walleij394bbbe2006-02-22 16:10:53 +00002324 * failure.
2325 * @see LIBMTP_Send_Track_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002326 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002327 */
mopoke96143402006-10-30 04:37:26 +00002328int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
Linus Walleij394bbbe2006-02-22 16:10:53 +00002329 char const * const path, LIBMTP_track_t * const metadata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002330 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002331 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002332{
2333 int fd;
2334 int ret;
2335
2336 // Sanity check
2337 if (path == NULL) {
2338 printf("LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL\n");
2339 return -1;
2340 }
2341
2342 // Open file
2343#ifdef __WIN32__
2344 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2345#else
2346 if ( (fd = open(path, O_RDONLY)) == -1) {
2347#endif
Linus Walleijd6a49972006-05-02 08:24:54 +00002348 printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002349 return -1;
2350 }
2351
Linus Walleijd6a49972006-05-02 08:24:54 +00002352 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data, parenthandle);
mopoke96143402006-10-30 04:37:26 +00002353
Linus Walleij394bbbe2006-02-22 16:10:53 +00002354 // Close file.
2355 close(fd);
2356
2357 return ret;
2358}
2359
Linus Walleijfa1374c2006-02-27 07:41:46 +00002360
Linus Walleij99310d42006-11-01 08:29:39 +00002361static MTPPropList *New_MTP_Prop_Entry()
2362{
2363 MTPPropList *prop;
2364 prop = (MTPPropList *) malloc(sizeof(MTPPropList));
2365 prop->property = PTP_OPC_StorageID; /* Should be "unknown" */
2366 prop->datatype = PTP_DTC_UNDEF;
2367 prop->next = NULL;
2368 return prop;
2369}
2370
2371static void Destroy_MTP_Prop_Entry(MTPPropList *prop)
2372{
2373 if (prop->datatype == PTP_DTC_STR) {
2374 free(prop->propval.str);
2375 }
2376 free(prop);
2377}
2378
Linus Walleijfa1374c2006-02-27 07:41:46 +00002379/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00002380 * This function sends a track from a file descriptor to an
2381 * MTP device. A filename and a set of metadata must be
2382 * given as input.
2383 * @param device a pointer to the device to send the track to.
2384 * @param fd the filedescriptor for a local file which will be sent.
2385 * @param metadata a track metadata set to be written along with the file.
2386 * After this call the field <code>item_id</code>
2387 * will contain the new track ID.
2388 * @param callback a progress indicator function or NULL to ignore.
2389 * @param data a user-defined pointer that is passed along to
2390 * the <code>progress</code> function in order to
2391 * pass along some user defined data to the progress
2392 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002393 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002394 * in. Since some devices are a bit picky about where files
2395 * are placed, a default folder will be chosen if libmtp
2396 * has detected one for the current filetype and this
2397 * parameter is set to 0. If this is 0 and no default folder
2398 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002399 * @return 0 if the transfer was successful, any other value means
Linus Walleij394bbbe2006-02-22 16:10:53 +00002400 * failure.
2401 * @see LIBMTP_Send_Track_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002402 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002403 */
mopoke96143402006-10-30 04:37:26 +00002404int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
Linus Walleij394bbbe2006-02-22 16:10:53 +00002405 int const fd, LIBMTP_track_t * const metadata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002406 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002407 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002408{
Linus Walleij394bbbe2006-02-22 16:10:53 +00002409 uint16_t ret;
2410 uint32_t store = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002411 int subcall_ret;
Linus Walleij9b28da32006-03-16 13:47:58 +00002412 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd6a49972006-05-02 08:24:54 +00002413 uint32_t localph = parenthandle;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002414 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij99310d42006-11-01 08:29:39 +00002415 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
Richard Low4c60f6e2006-11-07 20:36:42 +00002416 uint16_t *props = NULL;
2417 uint32_t propcnt = 0;
2418 uint32_t i = 0;
2419
Linus Walleij05ccbe72006-06-13 07:46:58 +00002420 if (localph == 0) {
2421 localph = device->default_music_folder;
2422 }
2423
Linus Walleij16c51f02006-05-04 13:20:22 +00002424 // Sanity check, is this really a track?
2425 if (metadata->filetype != LIBMTP_FILETYPE_WAV &&
2426 metadata->filetype != LIBMTP_FILETYPE_MP3 &&
2427 metadata->filetype != LIBMTP_FILETYPE_WMA &&
2428 metadata->filetype != LIBMTP_FILETYPE_OGG &&
2429 metadata->filetype != LIBMTP_FILETYPE_MP4 &&
2430 metadata->filetype != LIBMTP_FILETYPE_UNDEF_AUDIO) {
2431 printf("LIBMTP_Send_Track_From_File_Descriptor: I don't think this is actually a track, strange filetype...\n");
Linus Walleij99310d42006-11-01 08:29:39 +00002432 nonconsumable = 0x01U; /* Not suitable for consumption */
Linus Walleij394bbbe2006-02-22 16:10:53 +00002433 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002434
Linus Walleij99310d42006-11-01 08:29:39 +00002435 if (metadata->filetype == LIBMTP_FILETYPE_UNDEF_AUDIO) {
2436 nonconsumable = 0x01U; /* Not suitable for consumption */
2437 }
Linus Walleij37253292006-10-11 08:38:14 +00002438
Linus Walleij99310d42006-11-01 08:29:39 +00002439#ifdef ENABLE_MTP_ENHANCED
2440 if (ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
2441 /*
2442 * MTP enhanched does it this way (from a sniff):
2443 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
2444 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
2445 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
2446 * Length: 0x00000020
2447 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
2448 * Code: 0x9808
2449 * Transaction ID: 0x0000001B
2450 * Param1: 0x00010001 <- store
2451 * Param2: 0xffffffff <- parent handle (-1 ?)
2452 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
2453 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
2454 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
2455 *
2456 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
2457 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
2458 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
2459 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
2460 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
2461 * 00 4F DC 02 00 01 - dc4f = non consumable
2462 * Length: 0x00000046
2463 * Type: 0x0002 PTP_USB_CONTAINER_DATA
2464 * Code: 0x9808
2465 * Transaction ID: 0x0000001B
2466 * Metadata....
2467 * 0x00000003 <- Number of metadata items
2468 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
2469 * 0xdc07 <- metadata type: file name
2470 * 0xffff <- metadata type: string
2471 * 0x0d <- number of (uint16_t) characters
2472 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
2473 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
2474 * 0xdc03 <- metadata type: protection status
2475 * 0x0004 <- metadata type: uint16_t
2476 * 0x0000 <- not protected
2477 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
2478 * 0xdc4f <- non consumable
2479 * 0x0002 <- metadata type: uint8_t
2480 * 0x01 <- non-consumable (this device cannot display PDF)
2481 *
2482 * <- Read 0x18 bytes back
2483 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
2484 * 00 00 00 00 01 40 00 00
2485 * Length: 0x000000018
2486 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
2487 * Code: 0x2001 PTP_OK
2488 * Transaction ID: 0x0000001B
2489 * Param1: 0x00010001 <- store
2490 * Param2: 0x00000000 <- parent handle
2491 * Param3: 0x00004001 <- new file/object ID
2492 *
2493 * -> PTP_OC_SendObject (0x100d)
2494 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
2495 * -> ... all the bytes ...
2496 * <- Read 0x0c bytes back
2497 * 0C 00 00 00 03 00 01 20 1C 00 00 00
2498 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
2499 */
Richard Low4c60f6e2006-11-07 20:36:42 +00002500 MTPPropList *proplist = NULL;
2501 MTPPropList *prop = NULL;
2502 MTPPropList *previous = NULL;
Linus Walleij37253292006-10-11 08:38:14 +00002503
Linus Walleij99310d42006-11-01 08:29:39 +00002504 /* Send an object property list of that is supported */
2505 localph = 0xFFFFFFFFU; // Set to -1
2506 metadata->item_id = 0x00000000U;
Richard Low4c60f6e2006-11-07 20:36:42 +00002507
2508 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &props);
2509
2510 if (ret == PTP_RC_OK)
2511 {
2512 for (i=0;i<propcnt;i++) {
2513 switch (props[i]) {
2514 case PTP_OPC_ObjectFileName:
2515 prop = New_MTP_Prop_Entry();
2516 prop->property = PTP_OPC_ObjectFileName;
2517 prop->datatype = PTP_DTC_STR;
2518 prop->propval.str = strdup(metadata->filename);
mopoke96143402006-10-30 04:37:26 +00002519
Richard Low4c60f6e2006-11-07 20:36:42 +00002520 if (previous != NULL)
2521 previous->next = prop;
2522 else
2523 proplist = prop;
2524 previous = prop;
2525 prop->next = NULL;
2526 break;
2527 case PTP_OPC_ProtectionStatus:
2528 prop = New_MTP_Prop_Entry();
2529 prop->property = PTP_OPC_ProtectionStatus;
2530 prop->datatype = PTP_DTC_UINT16;
2531 prop->propval.u16 = 0x0000U; /* Not protected */
Linus Walleij99310d42006-11-01 08:29:39 +00002532
Richard Low4c60f6e2006-11-07 20:36:42 +00002533 if (previous != NULL)
2534 previous->next = prop;
2535 else
2536 proplist = prop;
2537 previous = prop;
2538 prop->next = NULL;
2539 break;
2540 case PTP_OPC_NonConsumable:
2541 prop = New_MTP_Prop_Entry();
2542 prop->property = PTP_OPC_NonConsumable;
2543 prop->datatype = PTP_DTC_UINT8;
2544 prop->propval.u8 = nonconsumable;
2545
2546 if (previous != NULL)
2547 previous->next = prop;
2548 else
2549 proplist = prop;
2550 previous = prop;
2551 prop->next = NULL;
2552 break;
2553 }
2554 }
Linus Walleij3fcfea52006-11-13 07:07:36 +00002555 free(props);
Richard Low4c60f6e2006-11-07 20:36:42 +00002556 }
2557
Richard Low4c60f6e2006-11-07 20:36:42 +00002558
Linus Walleij99310d42006-11-01 08:29:39 +00002559 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &metadata->item_id,
2560 map_libmtp_type_to_ptp_type(metadata->filetype),
2561 metadata->filesize, proplist);
2562
2563 /* Free property list */
2564 prop = proplist;
2565 while (prop != NULL) {
Linus Walleij3fcfea52006-11-13 07:07:36 +00002566 previous = prop;
Linus Walleij99310d42006-11-01 08:29:39 +00002567 prop = prop->next;
Linus Walleij3fcfea52006-11-13 07:07:36 +00002568 Destroy_MTP_Prop_Entry(previous);
Linus Walleij99310d42006-11-01 08:29:39 +00002569 }
2570
2571 if (ret != PTP_RC_OK) {
2572 ptp_perror(params, ret);
2573 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object property list.\n");
2574 if (ret == PTP_RC_AccessDenied) {
2575 printf("ACCESS DENIED.\n");
2576 } else {
2577 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2578 }
2579 return -1;
2580 }
2581 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
2582#else // !ENABLE_MTP_ENHANCED
2583 {
2584#endif // ENABLE_MTP_ENHANCED
2585 PTPObjectInfo new_track;
2586
2587 /* Else use the fallback compatibility mode */
2588 new_track.Filename = metadata->filename;
2589 new_track.ObjectCompressedSize = metadata->filesize;
2590 new_track.ObjectFormat = map_libmtp_type_to_ptp_type(metadata->filetype);
2591
2592 // Create the object
2593 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->item_id, &new_track);
2594 if (ret != PTP_RC_OK) {
2595 ptp_perror(params, ret);
2596 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object info.\n");
2597 if (ret == PTP_RC_AccessDenied) {
2598 printf("ACCESS DENIED.\n");
2599 } else {
2600 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2601 }
2602 return -1;
2603 }
Linus Walleij394bbbe2006-02-22 16:10:53 +00002604 }
2605
Linus Walleijee73ef22006-08-27 19:56:00 +00002606 // Callbacks
Linus Walleijd214b9b2006-08-26 22:08:37 +00002607 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002608 // The callback will deactivate itself after this amount of data has been sent
2609 // One BULK header for the request, one for the data phase. No parameters to the request.
2610 ptp_usb->current_transfer_total = metadata->filesize+PTP_USB_BULK_HDR_LEN*2;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002611 ptp_usb->current_transfer_complete = 0;
2612 ptp_usb->current_transfer_callback = callback;
2613 ptp_usb->current_transfer_callback_data = data;
mopoke96143402006-10-30 04:37:26 +00002614
Linus Walleije7f44be2006-08-25 19:32:29 +00002615 ret = ptp_sendobject_fromfd(params, fd, metadata->filesize);
mopoke96143402006-10-30 04:37:26 +00002616
Linus Walleijee73ef22006-08-27 19:56:00 +00002617 ptp_usb->callback_active = 0;
2618 ptp_usb->current_transfer_callback = NULL;
2619 ptp_usb->current_transfer_callback_data = NULL;
2620
Linus Walleije7f44be2006-08-25 19:32:29 +00002621 if (ret != PTP_RC_OK) {
2622 ptp_perror(params, ret);
2623 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object\n");
Linus Walleij394bbbe2006-02-22 16:10:53 +00002624 return -1;
2625 }
mopoke96143402006-10-30 04:37:26 +00002626
Linus Walleij17e39f72006-02-23 15:54:28 +00002627 // Set track metadata for the new fine track
2628 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
2629 if (subcall_ret != 0) {
2630 printf("LIBMTP_Send_Track_From_File_Descriptor: error setting metadata for new track\n");
Linus Walleij438bd7f2006-06-08 11:35:44 +00002631 (void) LIBMTP_Delete_Object(device, metadata->item_id);
Linus Walleij17e39f72006-02-23 15:54:28 +00002632 return -1;
2633 }
Linus Walleij99310d42006-11-01 08:29:39 +00002634 if (nonconsumable != 0x00U) {
2635 /* Flag it as non-consumable if it is */
2636 subcall_ret = LIBMTP_Set_Object_U8(device, metadata->item_id, PTP_OPC_NonConsumable, nonconsumable);
2637 if (subcall_ret != 0) {
2638 printf("LIBMTP_Update_Track_Metadata(): could not set non-consumable status.\n");
2639 return -1;
2640 }
2641 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002642
2643 // Added object so flush handles
2644 flush_handles(device);
mopoke96143402006-10-30 04:37:26 +00002645
Linus Walleij17e39f72006-02-23 15:54:28 +00002646 return 0;
2647}
2648
Linus Walleijd6a49972006-05-02 08:24:54 +00002649/**
mopoke96143402006-10-30 04:37:26 +00002650 * This function sends a local file to an MTP device.
Linus Walleijd6a49972006-05-02 08:24:54 +00002651 * A filename and a set of metadata must be
2652 * given as input.
2653 * @param device a pointer to the device to send the track to.
2654 * @param path the filename of a local file which will be sent.
2655 * @param filedata a file strtuct to pass in info about the file.
2656 * After this call the field <code>item_id</code>
2657 * will contain the new file ID.
2658 * @param callback a progress indicator function or NULL to ignore.
2659 * @param data a user-defined pointer that is passed along to
2660 * the <code>progress</code> function in order to
2661 * pass along some user defined data to the progress
2662 * updates. If not used, set this to NULL.
2663 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002664 * in. Since some devices are a bit picky about where files
2665 * are placed, a default folder will be chosen if libmtp
2666 * has detected one for the current filetype and this
2667 * parameter is set to 0. If this is 0 and no default folder
2668 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002669 * @return 0 if the transfer was successful, any other value means
Linus Walleijd6a49972006-05-02 08:24:54 +00002670 * failure.
2671 * @see LIBMTP_Send_File_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002672 * @see LIBMTP_Delete_Object()
Linus Walleijd6a49972006-05-02 08:24:54 +00002673 */
mopoke96143402006-10-30 04:37:26 +00002674int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
Linus Walleijd6a49972006-05-02 08:24:54 +00002675 char const * const path, LIBMTP_file_t * const filedata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002676 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002677 void const * const data, uint32_t const parenthandle)
2678{
2679 int fd;
2680 int ret;
2681
2682 // Sanity check
2683 if (path == NULL) {
2684 printf("LIBMTP_Send_File_From_File(): Bad arguments, path was NULL\n");
2685 return -1;
2686 }
2687
2688 // Open file
2689#ifdef __WIN32__
2690 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2691#else
2692 if ( (fd = open(path, O_RDONLY)) == -1) {
2693#endif
2694 printf("LIBMTP_Send_File_From_File(): Could not open source file \"%s\"\n", path);
2695 return -1;
2696 }
2697
2698 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data, parenthandle);
mopoke96143402006-10-30 04:37:26 +00002699
Linus Walleijd6a49972006-05-02 08:24:54 +00002700 // Close file.
2701 close(fd);
2702
2703 return ret;
2704}
2705
Linus Walleijd208f9c2006-04-27 14:16:06 +00002706/**
2707 * This function sends a generic file from a file descriptor to an
2708 * MTP device. A filename and a set of metadata must be
2709 * given as input.
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002710 *
2711 * This can potentially be used for sending in a stream of unknown
2712 * length. Set <code>filedata->filesize = (uint64_t) -1</code> to
2713 * make libmtp send some dummy length to the device and just
2714 * accept a stream up to some device-determined max length. There
2715 * is not guarantee this will work on all devices... Remember to
2716 * set correct metadata for the track with
2717 * <code>LIBMTP_Update_Track_Metadata()</code> afterwards if it's
2718 * a music file. (This doesn't seem to work very well right now.)
2719 *
Linus Walleijd208f9c2006-04-27 14:16:06 +00002720 * @param device a pointer to the device to send the file to.
2721 * @param fd the filedescriptor for a local file which will be sent.
Linus Walleijd6a49972006-05-02 08:24:54 +00002722 * @param filedata a file strtuct to pass in info about the file.
Linus Walleijd208f9c2006-04-27 14:16:06 +00002723 * After this call the field <code>item_id</code>
2724 * will contain the new track ID.
2725 * @param callback a progress indicator function or NULL to ignore.
2726 * @param data a user-defined pointer that is passed along to
2727 * the <code>progress</code> function in order to
2728 * pass along some user defined data to the progress
2729 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002730 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002731 * in. Since some devices are a bit picky about where files
2732 * are placed, a default folder will be chosen if libmtp
2733 * has detected one for the current filetype and this
2734 * parameter is set to 0. If this is 0 and no default folder
2735 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002736 * @return 0 if the transfer was successful, any other value means
Linus Walleijd208f9c2006-04-27 14:16:06 +00002737 * failure.
Linus Walleijd6a49972006-05-02 08:24:54 +00002738 * @see LIBMTP_Send_File_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002739 * @see LIBMTP_Delete_Object()
Linus Walleijd208f9c2006-04-27 14:16:06 +00002740 */
mopoke96143402006-10-30 04:37:26 +00002741int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
Linus Walleijd208f9c2006-04-27 14:16:06 +00002742 int const fd, LIBMTP_file_t * const filedata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002743 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002744 void const * const data, uint32_t const parenthandle)
Linus Walleijd208f9c2006-04-27 14:16:06 +00002745{
2746 uint16_t ret;
2747 uint32_t store = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +00002748 uint32_t localph = parenthandle;
Linus Walleijd208f9c2006-04-27 14:16:06 +00002749 PTPObjectInfo new_file;
2750 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002751 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij05ccbe72006-06-13 07:46:58 +00002752
Linus Walleijd208f9c2006-04-27 14:16:06 +00002753 new_file.Filename = filedata->filename;
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002754 if (filedata->filesize == (uint64_t) -1) {
2755 // This is a stream. Set a dummy length...
2756 new_file.ObjectCompressedSize = 1;
2757 } else {
2758 new_file.ObjectCompressedSize = filedata->filesize;
2759 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002760 new_file.ObjectFormat = map_libmtp_type_to_ptp_type(filedata->filetype);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002761
mopoke96143402006-10-30 04:37:26 +00002762 /*
Linus Walleij05ccbe72006-06-13 07:46:58 +00002763 * If no destination folder was given, look up a default
2764 * folder if possible. Perhaps there is some way of retrieveing
2765 * the default folder for different forms of content, what
2766 * do I know, we use a fixed list in lack of any better method.
2767 * Some devices obviously need to have their files in certain
mopoke96143402006-10-30 04:37:26 +00002768 * folders in order to find/display them at all (hello Creative),
Linus Walleij05ccbe72006-06-13 07:46:58 +00002769 * so we have to have a method for this.
2770 */
2771
2772 if (localph == 0) {
2773 uint16_t of = new_file.ObjectFormat;
2774 if (of == PTP_OFC_WAV ||
2775 of == PTP_OFC_MP3 ||
2776 of == PTP_OFC_MTP_WMA ||
2777 of == PTP_OFC_MTP_OGG ||
2778 of == PTP_OFC_MTP_MP4 ||
2779 of == PTP_OFC_MTP_UndefinedAudio) {
2780 localph = device->default_music_folder;
2781 } else if (of == PTP_OFC_MTP_WMV ||
2782 of == PTP_OFC_AVI ||
2783 of == PTP_OFC_MPEG ||
2784 of == PTP_OFC_ASF ||
2785 of == PTP_OFC_QT ||
2786 of == PTP_OFC_MTP_UndefinedVideo) {
2787 localph = device->default_video_folder;
2788 } else if (of == PTP_OFC_EXIF_JPEG ||
2789 of == PTP_OFC_JFIF ||
2790 of == PTP_OFC_TIFF ||
2791 of == PTP_OFC_BMP ||
2792 of == PTP_OFC_GIF ||
2793 of == PTP_OFC_PICT ||
2794 of == PTP_OFC_PNG ||
2795 of == PTP_OFC_MTP_WindowsImageFormat) {
2796 localph = device->default_picture_folder;
2797 } else if (of == PTP_OFC_MTP_vCalendar1 ||
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002798 of == PTP_OFC_MTP_vCalendar2 ||
2799 of == PTP_OFC_MTP_UndefinedContact ||
2800 of == PTP_OFC_MTP_vCard2 ||
2801 of == PTP_OFC_MTP_vCard3 ||
2802 of == PTP_OFC_MTP_UndefinedCalendarItem) {
Linus Walleij05ccbe72006-06-13 07:46:58 +00002803 localph = device->default_organizer_folder;
2804 }
2805 }
2806
Linus Walleijd208f9c2006-04-27 14:16:06 +00002807 // Create the object
Linus Walleijd6a49972006-05-02 08:24:54 +00002808 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002809 if (ret != PTP_RC_OK) {
2810 ptp_perror(params, ret);
2811 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object info\n");
Linus Walleij99310d42006-11-01 08:29:39 +00002812 if (ret == PTP_RC_AccessDenied) {
2813 printf("ACCESS DENIED.\n");
2814 } else {
2815 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2816 }
Linus Walleijd208f9c2006-04-27 14:16:06 +00002817 return -1;
2818 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002819
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002820 if (filedata->filesize != (uint64_t) -1) {
2821 // Callbacks
2822 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002823 // The callback will deactivate itself after this amount of data has been sent
2824 // One BULK header for the request, one for the data phase. No parameters to the request.
2825 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002826 ptp_usb->current_transfer_complete = 0;
2827 ptp_usb->current_transfer_callback = callback;
2828 ptp_usb->current_transfer_callback_data = data;
mopoke96143402006-10-30 04:37:26 +00002829
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002830 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
mopoke96143402006-10-30 04:37:26 +00002831
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002832 ptp_usb->callback_active = 0;
2833 ptp_usb->current_transfer_callback = NULL;
2834 ptp_usb->current_transfer_callback_data = NULL;
2835 } else {
2836 // This is a stream..
Linus Walleija9310fa2006-09-04 06:47:42 +00002837 ret = ptp_sendobject_fromfd(params, fd, 0xFFFFFFFFU-PTP_USB_BULK_HDR_LEN);
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002838 if (ret == PTP_ERROR_IO) {
2839 // That's expected. The stream ends, simply...
2840 ret = PTP_RC_OK;
2841 } else {
2842 printf("LIBMTP_Send_File_From_File_Descriptor: Error while sending stream.\n");
2843 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2844 }
2845 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002846
2847 if (ret != PTP_RC_OK) {
2848 ptp_perror(params, ret);
2849 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object\n");
2850 return -1;
2851 }
mopoke96143402006-10-30 04:37:26 +00002852
Linus Walleij438bd7f2006-06-08 11:35:44 +00002853 // Added object so flush handles.
2854 flush_handles(device);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002855 return 0;
2856}
2857
Linus Walleij17e39f72006-02-23 15:54:28 +00002858/**
2859 * This function updates the MTP object metadata on a single file
2860 * identified by an object ID.
mopoke96143402006-10-30 04:37:26 +00002861 * @param device a pointer to the device to update the track
Linus Walleij95698cd2006-02-24 10:40:40 +00002862 * metadata on.
Linus Walleij17e39f72006-02-23 15:54:28 +00002863 * @param metadata a track metadata set to be written to the file.
2864 * notice that the <code>track_id</code> field of the
2865 * metadata structure must be correct so that the
Linus Walleija4982732006-02-24 15:46:02 +00002866 * function can update the right file. If some properties
2867 * of this metadata are set to NULL (strings) or 0
2868 * (numerical values) they will be discarded and the
2869 * track will not be tagged with these blank values.
Linus Walleij17e39f72006-02-23 15:54:28 +00002870 * @return 0 on success, any other value means failure.
2871 */
mopoke96143402006-10-30 04:37:26 +00002872int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
Linus Walleij17e39f72006-02-23 15:54:28 +00002873 LIBMTP_track_t const * const metadata)
2874{
Linus Walleij17e39f72006-02-23 15:54:28 +00002875 uint16_t ret;
Linus Walleij00cf0642006-07-26 20:40:59 +00002876 PTPParams *params = (PTPParams *) device->params;
2877 uint32_t i;
2878 uint16_t *props = NULL;
2879 uint32_t propcnt = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002880
mopoke96143402006-10-30 04:37:26 +00002881 // First see which properties can be set on this file format and apply accordingly
Linus Walleij00cf0642006-07-26 20:40:59 +00002882 // i.e only try to update this metadata for object tags that exist on the current player.
2883 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &props);
2884 if (ret != PTP_RC_OK) {
2885 // Just bail out for now, nothing is ever set.
raveloxd9a28642006-05-26 23:42:22 +00002886 return -1;
Linus Walleij00cf0642006-07-26 20:40:59 +00002887 } else {
2888 for (i=0;i<propcnt;i++) {
2889 switch (props[i]) {
2890 case PTP_OPC_Name:
2891 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00002892 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Name, metadata->title);
Linus Walleij00cf0642006-07-26 20:40:59 +00002893 if (ret != 0) {
2894 printf("LIBMTP_Update_Track_Metadata(): could not set track title\n");
2895 return -1;
2896 }
2897 break;
2898 case PTP_OPC_AlbumName:
2899 // Update album
Linus Walleija823a702006-08-27 21:27:46 +00002900 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
Linus Walleij00cf0642006-07-26 20:40:59 +00002901 if (ret != 0) {
2902 printf("LIBMTP_Update_Track_Metadata(): could not set track album name\n");
2903 return -1;
2904 }
2905 break;
2906 case PTP_OPC_Artist:
2907 // Update artist
Linus Walleija823a702006-08-27 21:27:46 +00002908 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
Linus Walleij00cf0642006-07-26 20:40:59 +00002909 if (ret != 0) {
2910 printf("LIBMTP_Update_Track_Metadata(): could not set track artist name\n");
2911 return -1;
2912 }
2913 break;
2914 case PTP_OPC_Genre:
2915 // Update genre
Linus Walleija823a702006-08-27 21:27:46 +00002916 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
Linus Walleij00cf0642006-07-26 20:40:59 +00002917 if (ret != 0) {
2918 printf("LIBMTP_Update_Track_Metadata(): could not set track genre name\n");
2919 return -1;
2920 }
2921 break;
2922 case PTP_OPC_Duration:
2923 // Update duration
2924 if (metadata->duration != 0) {
2925 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_Duration, metadata->duration);
2926 if (ret != 0) {
2927 printf("LIBMTP_Update_Track_Metadata(): could not set track duration\n");
2928 return -1;
2929 }
2930 }
2931 break;
2932 case PTP_OPC_Track:
2933 // Update track number.
2934 if (metadata->tracknumber != 0) {
2935 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Track, metadata->tracknumber);
2936 if (ret != 0) {
2937 printf("LIBMTP_Update_Track_Metadata(): could not set track tracknumber\n");
2938 return -1;
2939 }
2940 }
2941 break;
2942 case PTP_OPC_OriginalReleaseDate:
2943 // Update creation datetime
Linus Walleija823a702006-08-27 21:27:46 +00002944 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
Linus Walleij00cf0642006-07-26 20:40:59 +00002945 if (ret != 0) {
2946 printf("LIBMTP_Update_Track_Metadata(): could not set track release date\n");
2947 return -1;
2948 }
2949 break;
2950 // These are, well not so important.
2951 case PTP_OPC_SampleRate:
2952 // Update sample rate
2953 if (metadata->samplerate != 0) {
2954 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_SampleRate, metadata->samplerate);
2955 if (ret != 0) {
2956 printf("LIBMTP_Update_Track_Metadata(): could not set samplerate\n");
2957 return -1;
2958 }
2959 }
2960 break;
2961 case PTP_OPC_NumberOfChannels:
2962 // Update number of channels
2963 if (metadata->nochannels != 0) {
2964 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_NumberOfChannels, metadata->nochannels);
2965 if (ret != 0) {
2966 printf("LIBMTP_Update_Track_Metadata(): could not set number of channels\n");
2967 return -1;
2968 }
2969 }
2970 break;
2971 case PTP_OPC_AudioWAVECodec:
2972 // Update WAVE codec
2973 if (metadata->wavecodec != 0) {
2974 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, metadata->wavecodec);
2975 if (ret != 0) {
2976 printf("LIBMTP_Update_Track_Metadata(): could not set WAVE codec\n");
2977 return -1;
2978 }
2979 }
2980 break;
2981 case PTP_OPC_AudioBitRate:
2982 // Update bitrate
2983 if (metadata->bitrate != 0) {
2984 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_AudioBitRate, metadata->bitrate);
2985 if (ret != 0) {
2986 printf("LIBMTP_Update_Track_Metadata(): could not set bitrate\n");
2987 return -1;
2988 }
2989 }
2990 break;
2991 case PTP_OPC_BitRateType:
2992 // Update bitrate type
2993 if (metadata->bitratetype != 0) {
2994 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_BitRateType, metadata->bitratetype);
2995 if (ret != 0) {
2996 printf("LIBMTP_Update_Track_Metadata(): could not set bitratetype\n");
2997 return -1;
2998 }
2999 }
3000 break;
3001 case PTP_OPC_Rating:
3002 // Update user rating
3003 // TODO: shall this be set for rating 0?
3004 if (metadata->rating != 0) {
3005 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Rating, metadata->rating);
3006 if (ret != 0) {
3007 printf("LIBMTP_Update_Track_Metadata(): could not set user rating\n");
3008 return -1;
3009 }
3010 }
3011 break;
3012 case PTP_OPC_UseCount:
3013 // Update use count, set even to zero if desired.
3014 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_UseCount, metadata->usecount);
3015 if (ret != 0) {
3016 printf("LIBMTP_Update_Track_Metadata(): could not set use count\n");
3017 return -1;
3018 }
3019 break;
Linus Walleij17e39f72006-02-23 15:54:28 +00003020
Linus Walleij00cf0642006-07-26 20:40:59 +00003021 // NOTE: File size is not updated, this should not change anyway.
3022 // neither will we change the filename.
3023 }
Linus Walleija4982732006-02-24 15:46:02 +00003024 }
Linus Walleij00cf0642006-07-26 20:40:59 +00003025 return 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00003026 }
Linus Walleij394bbbe2006-02-22 16:10:53 +00003027}
Linus Walleij95698cd2006-02-24 10:40:40 +00003028
3029/**
Linus Walleij438bd7f2006-06-08 11:35:44 +00003030 * This function deletes a single file, track, playlist or
3031 * any other object off the MTP device,
Linus Walleij95698cd2006-02-24 10:40:40 +00003032 * identified by an object ID.
Linus Walleijf6bc1782006-03-24 15:12:47 +00003033 * @param device a pointer to the device to delete the file or track from.
Linus Walleij95698cd2006-02-24 10:40:40 +00003034 * @param item_id the item to delete.
3035 * @return 0 on success, any other value means failure.
3036 */
mopoke96143402006-10-30 04:37:26 +00003037int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
Linus Walleij438bd7f2006-06-08 11:35:44 +00003038 uint32_t object_id)
Linus Walleij95698cd2006-02-24 10:40:40 +00003039{
Linus Walleij438bd7f2006-06-08 11:35:44 +00003040 uint16_t ret;
3041 PTPParams *params = (PTPParams *) device->params;
3042
3043 ret = ptp_deleteobject(params, object_id, 0);
3044 if (ret != PTP_RC_OK) {
3045 ptp_perror(params, ret);
3046 printf("LIBMTP_Delete_Object(): could not delete object\n");
3047 return -1;
3048 }
3049 // Removed object so flush handles.
3050 flush_handles(device);
3051 return 0;
Linus Walleij95698cd2006-02-24 10:40:40 +00003052}
Linus Walleij9c6ca022006-04-21 10:24:15 +00003053
Linus Walleij9c6ca022006-04-21 10:24:15 +00003054/**
3055 * Helper function. This indicates if a track exists on the device
3056 * @param device a pointer to the device to get the track from.
3057 * @param id the track ID of the track to retrieve.
3058 * @return TRUE (1) if the track exists, FALSE (0) if not
3059 */
3060int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
3061 uint32_t const id)
3062{
3063 PTPObjectInfo oi;
3064 PTPParams *params = (PTPParams *) device->params;
3065
3066 if (ptp_getobjectinfo(params, id, &oi) == PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003067 return -1;
Linus Walleij9c6ca022006-04-21 10:24:15 +00003068 }
3069 return 0;
3070}
3071
3072/**
3073 * This creates a new folder structure and allocates memory
3074 * for it. Notice that if you add strings to this structure they
3075 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
3076 * operation later, so be careful of using strdup() when assigning
3077 * strings, e.g.:
3078 *
3079 * @return a pointer to the newly allocated folder structure.
3080 * @see LIBMTP_destroy_folder_t()
3081 */
3082LIBMTP_folder_t *LIBMTP_new_folder_t(void)
3083{
3084 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
3085 if (new == NULL) {
3086 return NULL;
3087 }
3088 new->folder_id = 0;
3089 new->parent_id = 0;
3090 new->name = NULL;
3091 new->sibling = NULL;
3092 new->child = NULL;
3093 return new;
3094}
3095
3096/**
raveloxd9a28642006-05-26 23:42:22 +00003097 *
3098 * This deletes the memory for an object structure
3099 * and makes use of the registered destructor for the object
3100 * type data.
3101 *
3102 * @param object object structure to destroy
3103 * @param recurse indicate if the call should recursively delete
3104 * the object. Specify 1 for recursion.
3105 * @see LIBMTP_new_object_t()
3106 */
3107void LIBMTP_destroy_object_t(LIBMTP_object_t *object, uint32_t recursive)
3108{
Linus Walleijf0f3d482006-05-29 14:10:21 +00003109 if(object == NULL) {
3110 return;
3111 }
mopoke96143402006-10-30 04:37:26 +00003112
Linus Walleijf0f3d482006-05-29 14:10:21 +00003113 //Destroy from the bottom up
3114 if(recursive==1) {
3115 LIBMTP_destroy_object_t(object->child, recursive);
3116 object->child = NULL;
3117 LIBMTP_destroy_object_t(object->sibling, recursive);
3118 object->sibling = NULL;
3119 }
raveloxd9a28642006-05-26 23:42:22 +00003120
Linus Walleijf0f3d482006-05-29 14:10:21 +00003121 if(object->name != NULL) free(object->name);
mopoke96143402006-10-30 04:37:26 +00003122
Linus Walleijf0f3d482006-05-29 14:10:21 +00003123 //Use the data type destructor
3124 if(object->data != NULL) {
3125 void (*destructor)(void *);
mopoke96143402006-10-30 04:37:26 +00003126
Linus Walleijf0f3d482006-05-29 14:10:21 +00003127 destructor = get_destructor(object->type);
mopoke96143402006-10-30 04:37:26 +00003128
Linus Walleijf0f3d482006-05-29 14:10:21 +00003129 if(destructor != NULL) {
3130 (*destructor)(object->data);
3131 }
3132 object->data = NULL;
3133 }
mopoke96143402006-10-30 04:37:26 +00003134
Linus Walleijf0f3d482006-05-29 14:10:21 +00003135 free(object);
raveloxd9a28642006-05-26 23:42:22 +00003136}
3137
3138/**
Linus Walleij9c6ca022006-04-21 10:24:15 +00003139 * This recursively deletes the memory for a folder structure
3140 *
3141 * @param folder folder structure to destroy
3142 * @see LIBMTP_new_folder_t()
3143 */
3144void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
3145{
3146
3147 if(folder == NULL) {
3148 return;
3149 }
3150
3151 //Destroy from the bottom up
3152 if(folder->child != NULL) {
3153 LIBMTP_destroy_folder_t(folder->child);
3154 }
3155
3156 if(folder->sibling != NULL) {
3157 LIBMTP_destroy_folder_t(folder->sibling);
3158 }
3159
3160 if(folder->name != NULL) {
3161 free(folder->name);
3162 }
3163
3164 free(folder);
3165}
3166
3167/**
3168 * Helper function. Returns a folder structure for a
3169 * specified id.
3170 *
3171 * @param folderlist list of folders to search
3172 * @id id of folder to look for
3173 * @return a folder or NULL if not found
3174 */
3175LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
3176{
3177 LIBMTP_folder_t *ret = NULL;
mopoke96143402006-10-30 04:37:26 +00003178
Linus Walleij9c6ca022006-04-21 10:24:15 +00003179 if(folderlist == NULL) {
3180 return NULL;
3181 }
mopoke96143402006-10-30 04:37:26 +00003182
Linus Walleij9c6ca022006-04-21 10:24:15 +00003183 if(folderlist->folder_id == id) {
3184 return folderlist;
3185 }
mopoke96143402006-10-30 04:37:26 +00003186
Linus Walleij9c6ca022006-04-21 10:24:15 +00003187 if(folderlist->sibling) {
3188 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
3189 }
mopoke96143402006-10-30 04:37:26 +00003190
Linus Walleij9c6ca022006-04-21 10:24:15 +00003191 if(folderlist->child && ret == NULL) {
3192 ret = LIBMTP_Find_Folder(folderlist->child, id);
3193 }
mopoke96143402006-10-30 04:37:26 +00003194
Linus Walleij9c6ca022006-04-21 10:24:15 +00003195 return ret;
3196}
3197
3198/**
3199 * This returns a list of all folders available
3200 * on the current MTP device.
3201 *
3202 * @param device a pointer to the device to get the track listing for.
3203 * @return a list of folders
3204 */
3205LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
3206{
3207 uint32_t i = 0;
3208 LIBMTP_folder_t *retfolders = NULL;
3209 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003210
mopoke96143402006-10-30 04:37:26 +00003211 // Get all the handles if we haven't already done that
Linus Walleij9c6ca022006-04-21 10:24:15 +00003212 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003213 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00003214 }
mopoke96143402006-10-30 04:37:26 +00003215
Linus Walleij9c6ca022006-04-21 10:24:15 +00003216 for (i = 0; i < params->handles.n; i++) {
3217 LIBMTP_folder_t *folder;
3218 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00003219
Linus Walleij9c6ca022006-04-21 10:24:15 +00003220 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
3221 if (oi.ObjectFormat != PTP_OFC_Association) {
3222 continue;
3223 }
3224 folder = LIBMTP_new_folder_t();
3225 folder->folder_id = params->handles.Handler[i];
3226 folder->parent_id = oi.ParentObject;
Richard Low64fa3992006-11-06 21:24:11 +00003227 if (oi.Filename != NULL)
3228 folder->name = (char *)strdup(oi.Filename);
3229 else
3230 folder->name = NULL;
Richard Low4c60f6e2006-11-07 20:36:42 +00003231
Linus Walleij9c6ca022006-04-21 10:24:15 +00003232 // Work out where to put this new item
3233 if(retfolders == NULL) {
3234 retfolders = folder;
3235 continue;
3236 } else {
3237 LIBMTP_folder_t *parent_folder;
3238 LIBMTP_folder_t *current_folder;
mopoke96143402006-10-30 04:37:26 +00003239
Linus Walleij9c6ca022006-04-21 10:24:15 +00003240 parent_folder = LIBMTP_Find_Folder(retfolders, folder->parent_id);
mopoke96143402006-10-30 04:37:26 +00003241
Linus Walleij9c6ca022006-04-21 10:24:15 +00003242 if(parent_folder == NULL) {
3243 current_folder = retfolders;
3244 } else {
3245 if(parent_folder->child == NULL) {
3246 parent_folder->child = folder;
3247 continue;
3248 } else {
3249 current_folder = parent_folder->child;
3250 }
3251 }
mopoke96143402006-10-30 04:37:26 +00003252
Linus Walleij9c6ca022006-04-21 10:24:15 +00003253 while(current_folder->sibling != NULL) {
3254 current_folder=current_folder->sibling;
3255 }
mopoke96143402006-10-30 04:37:26 +00003256
Linus Walleij9c6ca022006-04-21 10:24:15 +00003257 current_folder->sibling = folder;
3258 }
3259 }
3260 }
3261 return retfolders;
3262}
3263
3264/**
Linus Walleijc86afbd2006-05-04 19:05:24 +00003265 * This create a folder on the current MTP device. The PTP name
3266 * for a folder is "association". The PTP/MTP devices does not
3267 * have an internal "folder" concept really, it contains a flat
3268 * list of all files and some file are "associations" that other
3269 * files and folders may refer to as its "parent".
Linus Walleij9c6ca022006-04-21 10:24:15 +00003270 *
Linus Walleijc86afbd2006-05-04 19:05:24 +00003271 * @param device a pointer to the device to create the folder on.
3272 * @param name the name of the new folder.
3273 * @param parent_id id of parent folder to add the new folder to,
3274 * or 0 to put it in the root directory.
3275 * @return id to new folder or 0 if an error occured
Linus Walleij9c6ca022006-04-21 10:24:15 +00003276 */
3277uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name, uint32_t parent_id)
3278{
3279 PTPParams *params = (PTPParams *) device->params;
3280 uint32_t parenthandle = 0;
3281 uint32_t store = 0;
3282 PTPObjectInfo new_folder;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003283 uint16_t ret;
Linus Walleij9c6ca022006-04-21 10:24:15 +00003284 uint32_t new_id = 0;
3285
3286 memset(&new_folder, 0, sizeof(new_folder));
3287 new_folder.Filename = name;
3288 new_folder.ObjectCompressedSize = 1;
3289 new_folder.ObjectFormat = PTP_OFC_Association;
3290 new_folder.ParentObject = parent_id;
3291
3292 parenthandle = parent_id;
3293 // Create the object
3294 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
3295 if (ret != PTP_RC_OK) {
3296 ptp_perror(params, ret);
3297 printf("LIBMTP_Create_Folder: Could not send object info\n");
Linus Walleij99310d42006-11-01 08:29:39 +00003298 if (ret == PTP_RC_AccessDenied) {
3299 printf("ACCESS DENIED.\n");
3300 } else {
3301 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
3302 }
Linus Walleijc86afbd2006-05-04 19:05:24 +00003303 return 0;
Linus Walleij9c6ca022006-04-21 10:24:15 +00003304 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003305 // Created new object so flush handles
3306 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00003307 return new_id;
3308}
raveloxd9a28642006-05-26 23:42:22 +00003309
3310
3311/**
3312 * Helper function. Returns a folder structure for a
3313 * specified id.
3314 *
3315 * @param objectlist list of objects to search
3316 * @id id of object to look for
3317 * @return a object or NULL if not found
3318 */
3319LIBMTP_object_t *LIBMTP_Find_Object(LIBMTP_object_t *objectlist, uint32_t id)
3320{
3321 LIBMTP_object_t *ret = NULL;
3322
3323 if(objectlist == NULL) {
3324 return NULL;
3325 }
3326
3327 if(objectlist->id == id) {
3328 return objectlist;
3329 }
3330
3331 if(objectlist->sibling) {
3332 ret = LIBMTP_Find_Object(objectlist->sibling, id);
3333 }
3334
3335 if(objectlist->child && ret == NULL) {
3336 ret = LIBMTP_Find_Object(objectlist->child, id);
3337 }
3338
3339 return ret;
3340}
3341
3342/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00003343 * This returns a list of objects on the current MTP device,
3344 * selected by a filter based on PTP object ID:s.
raveloxd9a28642006-05-26 23:42:22 +00003345 *
Linus Walleijf0f3d482006-05-29 14:10:21 +00003346 * @param device a pointer to the device to get the object listing for.
raveloxd9a28642006-05-26 23:42:22 +00003347 * @param filter array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00003348 * to include in the list
3349 * @param filter_len length of filter array in 32-bit words
raveloxd9a28642006-05-26 23:42:22 +00003350 * @param exclusions array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00003351 * to exclude from the list
raveloxd9a28642006-05-26 23:42:22 +00003352 * @param exclusion_len length of exclusion array
3353 * @return a list of objects
3354 * @see LIBMTP_destroy_object_t()
3355 */
mopoke96143402006-10-30 04:37:26 +00003356LIBMTP_object_t *LIBMTP_Make_List(LIBMTP_mtpdevice_t *device, uint32_t *filter,
Linus Walleijf0f3d482006-05-29 14:10:21 +00003357 uint32_t filter_len, uint32_t *exclusions, uint32_t exclusion_len)
raveloxd9a28642006-05-26 23:42:22 +00003358{
3359 uint32_t i = 0;
3360 LIBMTP_object_t *objectlist = NULL;
3361 PTPParams *params = (PTPParams *) device->params;
raveloxd9a28642006-05-26 23:42:22 +00003362 uint32_t max_exclusions = 0;
3363 uint32_t max_filter = 0;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003364
mopoke96143402006-10-30 04:37:26 +00003365 // Get all the handles if we haven't already done that
raveloxd9a28642006-05-26 23:42:22 +00003366 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003367 flush_handles(device);
raveloxd9a28642006-05-26 23:42:22 +00003368 }
mopoke96143402006-10-30 04:37:26 +00003369
raveloxd9a28642006-05-26 23:42:22 +00003370 if(filter != NULL) max_filter = filter_len;
3371 if(exclusions != NULL) max_exclusions = exclusion_len;
mopoke96143402006-10-30 04:37:26 +00003372
raveloxd9a28642006-05-26 23:42:22 +00003373 for (i = 0; i < params->handles.n; i++) {
3374 LIBMTP_object_t *object;
3375 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00003376
raveloxd9a28642006-05-26 23:42:22 +00003377 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00003378 uint32_t x = 0;
3379 uint32_t exclude = 0, filter_allow = 0;
3380 void (*datafunc)(LIBMTP_mtpdevice_t *, uint32_t, void *);
3381 void *(*constructor)(void);
mopoke96143402006-10-30 04:37:26 +00003382
raveloxd9a28642006-05-26 23:42:22 +00003383 // Is the ObjectFormat in the list of exclusions ?
Linus Walleijf0f3d482006-05-29 14:10:21 +00003384 for(x = 0; x < max_exclusions; x++) {
3385 if (oi.ObjectFormat == exclusions[x]) {
3386 exclude = 1;
3387 break;
3388 }
raveloxd9a28642006-05-26 23:42:22 +00003389 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003390 if(exclude == 1) {
3391 continue;
3392 }
mopoke96143402006-10-30 04:37:26 +00003393
Linus Walleijf0f3d482006-05-29 14:10:21 +00003394 // Is the ObjectFormat in the filter ?
3395 for(x = 0; x < max_filter; x++) {
3396 if (oi.ObjectFormat == filter[x]) {
3397 filter_allow = 1;
3398 break;
3399 }
3400 }
3401 if(filter_allow == 0) {
3402 continue;
3403 }
mopoke96143402006-10-30 04:37:26 +00003404
raveloxd9a28642006-05-26 23:42:22 +00003405 object = LIBMTP_new_object_t();
3406 object->id = params->handles.Handler[i];
3407 object->parent = oi.ParentObject;
3408 object->name = (char *)strdup(oi.Filename);
3409 object->size = oi.ObjectCompressedSize;
Linus Walleijf0f3d482006-05-29 14:10:21 +00003410 object->type = oi.ObjectFormat;
mopoke96143402006-10-30 04:37:26 +00003411
Linus Walleijf0f3d482006-05-29 14:10:21 +00003412 // Get the function pointers for the constructor and datafunc
3413 constructor = get_constructor(oi.ObjectFormat);
3414 datafunc = get_datafunc(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00003415
Linus Walleijf0f3d482006-05-29 14:10:21 +00003416 if(constructor != NULL) {
3417 object->data = (*constructor)();
3418 if(datafunc != NULL) {
3419 (*datafunc)(device, object->id, object->data);
3420 }
3421 }
mopoke96143402006-10-30 04:37:26 +00003422
raveloxd9a28642006-05-26 23:42:22 +00003423 // Work out where to put this new item
3424 if(objectlist == NULL) {
3425 objectlist = object;
3426 continue;
3427 } else {
3428 LIBMTP_object_t *parent_object;
3429 LIBMTP_object_t *current_object;
mopoke96143402006-10-30 04:37:26 +00003430
raveloxd9a28642006-05-26 23:42:22 +00003431 parent_object = LIBMTP_Find_Object(objectlist, object->parent);
mopoke96143402006-10-30 04:37:26 +00003432
raveloxd9a28642006-05-26 23:42:22 +00003433 if(parent_object == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00003434 current_object = objectlist;
raveloxd9a28642006-05-26 23:42:22 +00003435 } else {
3436 if(parent_object->child == NULL) {
3437 parent_object->child = object;
3438 continue;
3439 } else {
3440 current_object = parent_object->child;
3441 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003442 }
mopoke96143402006-10-30 04:37:26 +00003443
raveloxd9a28642006-05-26 23:42:22 +00003444 while(current_object->sibling != NULL) {
3445 current_object=current_object->sibling;
3446 }
3447 current_object->sibling = object;
3448 }
3449 }
3450 }
mopoke96143402006-10-30 04:37:26 +00003451
raveloxd9a28642006-05-26 23:42:22 +00003452 return objectlist;
3453}
mopoke96143402006-10-30 04:37:26 +00003454
raveloxd9a28642006-05-26 23:42:22 +00003455/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00003456 * Debug function that dumps out some textual representation
3457 * of an object list.
raveloxd9a28642006-05-26 23:42:22 +00003458 *
3459 * @param list object list returned from LIBMTP_Make_List
3460 *
3461 * @see LIBMTP_Make_List()
3462 */
3463void LIBMTP_Dump_List(LIBMTP_object_t *list)
3464{
Linus Walleijf0f3d482006-05-29 14:10:21 +00003465 if(list == NULL) return;
mopoke96143402006-10-30 04:37:26 +00003466
Linus Walleijf0f3d482006-05-29 14:10:21 +00003467 printf("Id : %u\n", list->id);
3468 printf("Parent: %u\n", list->parent);
3469 printf("Size : %u\n", list->size);
3470 printf("Name : %s\n", (list->name ? list->name : ""));
3471 printf("Type : 0x%04x\n", list->type);
3472 printf("--\n");
mopoke96143402006-10-30 04:37:26 +00003473
Linus Walleijf0f3d482006-05-29 14:10:21 +00003474 LIBMTP_Dump_List(list->child);
3475 LIBMTP_Dump_List(list->sibling);
raveloxd9a28642006-05-26 23:42:22 +00003476}
Linus Walleij438bd7f2006-06-08 11:35:44 +00003477
3478/**
3479 * This creates a new playlist metadata structure and allocates memory
3480 * for it. Notice that if you add strings to this structure they
3481 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
mopoke96143402006-10-30 04:37:26 +00003482 * operation later, so be careful of using strdup() when assigning
Linus Walleij438bd7f2006-06-08 11:35:44 +00003483 * strings, e.g.:
3484 *
3485 * <pre>
3486 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
3487 * pl->name = strdup(str);
3488 * ....
3489 * LIBMTP_destroy_playlist_t(pl);
3490 * </pre>
3491 *
3492 * @return a pointer to the newly allocated metadata structure.
3493 * @see LIBMTP_destroy_playlist_t()
3494 */
3495LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
3496{
3497 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
3498 if (new == NULL) {
3499 return NULL;
3500 }
3501 new->playlist_id = 0;
3502 new->name = NULL;
3503 new->tracks = NULL;
3504 new->no_tracks = 0;
3505 new->next = NULL;
3506 return new;
3507}
3508
3509/**
3510 * This destroys a playlist metadata structure and deallocates the memory
mopoke96143402006-10-30 04:37:26 +00003511 * used by it, including any strings. Never use a track metadata
Linus Walleij438bd7f2006-06-08 11:35:44 +00003512 * structure again after calling this function on it.
3513 * @param playlist the playlist metadata to destroy.
3514 * @see LIBMTP_new_playlist_t()
3515 */
3516void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
3517{
3518 if (playlist == NULL) {
3519 return;
3520 }
3521 if (playlist->name != NULL)
3522 free(playlist->name);
3523 if (playlist->tracks != NULL)
3524 free(playlist->tracks);
3525 free(playlist);
3526 return;
3527}
3528
3529/**
3530 * This function returns a list of the playlists available on the
3531 * device. Typical usage:
3532 *
3533 * <pre>
3534 * </pre>
3535 *
3536 * @param device a pointer to the device to get the playlist listing from.
3537 * @return a playlist list on success, else NULL. If there are no playlists
3538 * on the device, NULL will be returned as well.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003539 * @see LIBMTP_Get_Playlist()
Linus Walleij438bd7f2006-06-08 11:35:44 +00003540 */
3541LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
3542{
3543 PTPParams *params = (PTPParams *) device->params;
3544 LIBMTP_playlist_t *retlists = NULL;
3545 LIBMTP_playlist_t *curlist = NULL;
3546 uint32_t i;
3547
3548 // Get all the handles if we haven't already done that
3549 if (params->handles.Handler == NULL) {
3550 flush_handles(device);
3551 }
3552
3553 for (i = 0; i < params->handles.n; i++) {
3554 LIBMTP_playlist_t *pl;
3555 PTPObjectInfo oi;
3556 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +00003557
Linus Walleij438bd7f2006-06-08 11:35:44 +00003558 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3559 if ( ret == PTP_RC_OK) {
mopoke96143402006-10-30 04:37:26 +00003560
Linus Walleij438bd7f2006-06-08 11:35:44 +00003561 // Ignore stuff that isn't playlists
3562 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
3563 continue;
3564 }
mopoke96143402006-10-30 04:37:26 +00003565
Linus Walleij438bd7f2006-06-08 11:35:44 +00003566 // Allocate a new playlist type
3567 pl = LIBMTP_new_playlist_t();
mopoke96143402006-10-30 04:37:26 +00003568
Linus Walleij438bd7f2006-06-08 11:35:44 +00003569 // Ignoring the io.Filename field.
Linus Walleija823a702006-08-27 21:27:46 +00003570 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
mopoke96143402006-10-30 04:37:26 +00003571
Linus Walleij438bd7f2006-06-08 11:35:44 +00003572 // This is some sort of unique playlist ID so we can keep track of it
3573 pl->playlist_id = params->handles.Handler[i];
3574
3575 // Then get the track listing for this playlist
3576 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
3577 if (ret != PTP_RC_OK) {
3578 printf("LIBMTP_Get_Playlist: Could not get object references\n");
3579 pl->tracks = NULL;
3580 pl->no_tracks = 0;
3581 }
mopoke96143402006-10-30 04:37:26 +00003582
Linus Walleij438bd7f2006-06-08 11:35:44 +00003583 // Add playlist to a list that will be returned afterwards.
3584 if (retlists == NULL) {
3585 retlists = pl;
3586 curlist = pl;
3587 } else {
3588 curlist->next = pl;
3589 curlist = pl;
3590 }
mopoke96143402006-10-30 04:37:26 +00003591
Linus Walleij438bd7f2006-06-08 11:35:44 +00003592 // Call callback here if we decide to add that possibility...
3593
3594 } else {
3595 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
3596 }
mopoke96143402006-10-30 04:37:26 +00003597 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003598 return retlists;
3599}
3600
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003601
3602/**
3603 * This function retrieves an individual playlist from the device.
3604 * @param device a pointer to the device to get the playlist from.
3605 * @param plid the unique ID of the playlist to retrieve.
3606 * @return a valid playlist metadata post or NULL on failure.
3607 * @see LIBMTP_Get_Playlist_List()
3608 */
3609LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
3610{
3611 PTPParams *params = (PTPParams *) device->params;
3612 uint32_t i;
3613
3614 // Get all the handles if we haven't already done that
3615 if (params->handles.Handler == NULL) {
3616 flush_handles(device);
3617 }
3618
3619 for (i = 0; i < params->handles.n; i++) {
3620 LIBMTP_playlist_t *pl;
3621 PTPObjectInfo oi;
3622 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +00003623
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003624 if (params->handles.Handler[i] != plid) {
3625 continue;
3626 }
3627
3628 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3629 if ( ret == PTP_RC_OK) {
mopoke96143402006-10-30 04:37:26 +00003630
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003631 // Ignore stuff that isn't playlists
3632 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
3633 return NULL;
3634 }
mopoke96143402006-10-30 04:37:26 +00003635
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003636 // Allocate a new playlist type
3637 pl = LIBMTP_new_playlist_t();
mopoke96143402006-10-30 04:37:26 +00003638
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003639 // Ignoring the io.Filename field.
Linus Walleija823a702006-08-27 21:27:46 +00003640 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
mopoke96143402006-10-30 04:37:26 +00003641
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003642 // This is some sort of unique playlist ID so we can keep track of it
3643 pl->playlist_id = params->handles.Handler[i];
3644
3645 // Then get the track listing for this playlist
3646 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
3647 if (ret != PTP_RC_OK) {
3648 printf("LIBMTP_Get_Playlist: Could not get object references\n");
3649 pl->tracks = NULL;
3650 pl->no_tracks = 0;
3651 }
mopoke96143402006-10-30 04:37:26 +00003652
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003653 return pl;
3654 } else {
3655 return NULL;
3656 }
mopoke96143402006-10-30 04:37:26 +00003657 }
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003658 return NULL;
3659}
3660
Linus Walleij438bd7f2006-06-08 11:35:44 +00003661/**
3662 * This routine creates a new playlist based on the metadata
3663 * supplied. If the <code>tracks</code> field of the metadata
3664 * contains a track listing, these tracks will be added to the
3665 * playlist.
3666 * @param device a pointer to the device to create the new playlist on.
3667 * @param metadata the metadata for the new playlist. If the function
3668 * exits with success, the <code>playlist_id</code> field of this
3669 * struct will contain the new playlist ID of the playlist.
3670 * @param parenthandle the parent (e.g. folder) to store this playlist
3671 * in. Pass in 0 to put the playlist in the root directory.
3672 * @return 0 on success, any other value means failure.
3673 * @see LIBMTP_Update_Playlist()
3674 * @see LIBMTP_Delete_Object()
3675 */
mopoke96143402006-10-30 04:37:26 +00003676int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
Linus Walleij438bd7f2006-06-08 11:35:44 +00003677 LIBMTP_playlist_t * const metadata,
3678 uint32_t const parenthandle)
3679{
3680 uint16_t ret;
3681 uint32_t store = 0;
3682 PTPObjectInfo new_pl;
3683 PTPParams *params = (PTPParams *) device->params;
3684 uint32_t localph = parenthandle;
3685 char fname[256];
Linus Walleijd14e84f2006-06-16 14:50:59 +00003686 uint8_t data[2];
Linus Walleij438bd7f2006-06-08 11:35:44 +00003687
Linus Walleij05ccbe72006-06-13 07:46:58 +00003688 // Use a default folder if none given
3689 if (localph == 0) {
3690 localph = device->default_playlist_folder;
3691 }
3692
Linus Walleij438bd7f2006-06-08 11:35:44 +00003693 // .zpl is the "abstract audio/video playlist "file" suffix
3694 new_pl.Filename = NULL;
3695 if (strlen(metadata->name) > 4) {
3696 char *suff = &metadata->name[strlen(metadata->name)-4];
3697 if (!strcmp(suff, ".zpl")) {
3698 // Home free.
3699 new_pl.Filename = metadata->name;
3700 }
3701 }
3702 // If it didn't end with ".zpl" then add that here.
3703 if (new_pl.Filename == NULL) {
3704 strncpy(fname, metadata->name, sizeof(fname)-5);
3705 strcat(fname, ".zpl");
3706 fname[sizeof(fname)-1] = '\0';
3707 new_pl.Filename = fname;
3708 }
3709
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003710 // Playlists created on device have size (uint32_t) -1 = 0xFFFFFFFFU, but setting:
3711 // new_pl.ObjectCompressedSize = 0; <- DOES NOT WORK! (return PTP_RC_GeneralError)
3712 // new_pl.ObjectCompressedSize = (uint32_t) -1; <- DOES NOT WORK! (return PTP_RC_MTP_Object_Too_Large)
Linus Walleijd14e84f2006-06-16 14:50:59 +00003713 new_pl.ObjectCompressedSize = 1;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003714 new_pl.ObjectFormat = PTP_OFC_MTP_AbstractAudioVideoPlaylist;
mopoke96143402006-10-30 04:37:26 +00003715
Linus Walleij438bd7f2006-06-08 11:35:44 +00003716 // Create the object
3717 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
3718 if (ret != PTP_RC_OK) {
3719 ptp_perror(params, ret);
3720 printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
Linus Walleij99310d42006-11-01 08:29:39 +00003721 if (ret == PTP_RC_AccessDenied) {
3722 printf("ACCESS DENIED.\n");
3723 } else {
3724 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
3725 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003726 return -1;
3727 }
mopoke96143402006-10-30 04:37:26 +00003728
Linus Walleij438bd7f2006-06-08 11:35:44 +00003729 /*
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003730 * We have to send this one blank data byte.
3731 * If we don't, the handle will not be created and thus there is no playlist.
Linus Walleij438bd7f2006-06-08 11:35:44 +00003732 */
Linus Walleijd14e84f2006-06-16 14:50:59 +00003733 data[0] = '\0';
3734 data[1] = '\0';
3735 ret = ptp_sendobject(params, data, 1);
3736 if (ret != PTP_RC_OK) {
3737 ptp_perror(params, ret);
3738 printf("LIBMTP_New_Playlist(): Could not send blank object data\n");
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003739 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003740 return -1;
3741 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003742
3743 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00003744 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003745 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003746 printf("LIBMTP_New_Playlist(): could not set playlist name\n");
3747 return -1;
3748 }
3749
3750 if (metadata->no_tracks > 0) {
3751 // Add tracks to the new playlist as object references.
3752 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3753 if (ret != PTP_RC_OK) {
3754 printf("LIBMTP_New_Playlist(): could not add tracks as object references\n");
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003755 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +00003756 return -1;
3757 }
3758 }
mopoke96143402006-10-30 04:37:26 +00003759
Linus Walleij438bd7f2006-06-08 11:35:44 +00003760 // Created new item, so flush handles
3761 flush_handles(device);
3762
3763 return 0;
3764}
3765
3766/**
3767 * This routine updates a playlist based on the metadata
3768 * supplied. If the <code>tracks</code> field of the metadata
3769 * contains a track listing, these tracks will be added to the
3770 * playlist in place of those already present, i.e. the
3771 * previous track listing will be deleted.
3772 * @param device a pointer to the device to create the new playlist on.
3773 * @param metadata the metadata for the playlist to be updated.
mopoke96143402006-10-30 04:37:26 +00003774 * notice that the field <code>playlist_id</code>
Linus Walleij438bd7f2006-06-08 11:35:44 +00003775 * must contain the apropriate playlist ID.
3776 * @return 0 on success, any other value means failure.
3777 * @see LIBMTP_Create_New_Playlist()
3778 * @see LIBMTP_Delete_Object()
3779 */
mopoke96143402006-10-30 04:37:26 +00003780int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
Linus Walleijf5306352006-06-08 12:00:23 +00003781 LIBMTP_playlist_t const * const metadata)
Linus Walleij438bd7f2006-06-08 11:35:44 +00003782{
3783 uint16_t ret;
Linus Walleijf5306352006-06-08 12:00:23 +00003784 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003785
3786 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00003787 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003788 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003789 printf("LIBMTP_Update_Playlist(): could not set playlist name\n");
3790 return -1;
3791 }
3792
3793 if (metadata->no_tracks > 0) {
3794 // Add tracks to the new playlist as object references.
3795 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3796 if (ret != PTP_RC_OK) {
3797 printf("LIBMTP_Update_Playlist(): could not add tracks as object references\n");
3798 return -1;
3799 }
3800 }
3801 return 0;
3802}
Linus Walleijaa4b0752006-07-26 22:21:04 +00003803
Linus Walleij0c33ec02006-10-27 10:15:40 +00003804/**
3805 * This creates a new album metadata structure and allocates memory
3806 * for it. Notice that if you add strings to this structure they
3807 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
3808 * operation later, so be careful of using strdup() when assigning
3809 * strings.
3810 *
3811 * @return a pointer to the newly allocated metadata structure.
3812 * @see LIBMTP_destroy_album_t()
3813 */
3814LIBMTP_album_t *LIBMTP_new_album_t(void)
3815{
3816 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
3817 if (new == NULL) {
3818 return NULL;
3819 }
3820 new->album_id = 0;
3821 new->name = NULL;
3822 new->tracks = NULL;
3823 new->no_tracks = 0;
3824 new->next = NULL;
3825 return new;
3826}
3827
3828/**
3829 * This recursively deletes the memory for an album structure
3830 *
3831 * @param album structure to destroy
3832 * @see LIBMTP_new_album_t()
3833 */
3834void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
3835{
3836 if (album == NULL) {
3837 return;
3838 }
3839 if (album->name != NULL)
3840 free(album->name);
3841 if (album->tracks != NULL)
3842 free(album->tracks);
3843 free(album);
3844 return;
3845}
3846
3847/**
3848 * This function returns a list of the albums available on the
3849 * device.
3850 *
3851 * @param device a pointer to the device to get the album listing from.
3852 * @return an album list on success, else NULL. If there are no albums
3853 * on the device, NULL will be returned as well.
3854 * @see LIBMTP_Get_Album()
3855 */
3856LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
3857{
3858 PTPParams *params = (PTPParams *) device->params;
3859 LIBMTP_album_t *retalbums = NULL;
3860 LIBMTP_album_t *curalbum = NULL;
3861 uint32_t i;
3862
3863 // Get all the handles if we haven't already done that
3864 if (params->handles.Handler == NULL) {
3865 flush_handles(device);
3866 }
3867
3868 for (i = 0; i < params->handles.n; i++) {
3869 LIBMTP_album_t *alb;
3870 PTPObjectInfo oi;
3871 uint16_t ret;
3872
3873 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3874 if ( ret == PTP_RC_OK) {
3875
3876 // Ignore stuff that isn't an album
3877 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
3878 continue;
3879 }
3880
3881 // Allocate a new album type
3882 alb = LIBMTP_new_album_t();
3883 alb->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
3884 alb->album_id = params->handles.Handler[i];
3885
3886 // Then get the track listing for this album
3887 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
3888 if (ret != PTP_RC_OK) {
3889 printf("LIBMTP_Get_Album: Could not get object references\n");
3890 alb->tracks = NULL;
3891 alb->no_tracks = 0;
3892 }
3893
3894 // Add album to a list that will be returned afterwards.
3895 if (retalbums == NULL) {
3896 retalbums = alb;
3897 curalbum = alb;
3898 } else {
3899 curalbum->next = alb;
3900 curalbum = alb;
3901 }
3902
3903 } else {
3904 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
3905 }
3906 }
3907 return retalbums;
3908}
3909
3910/**
3911 * This function retrieves an individual album from the device.
3912 * @param device a pointer to the device to get the album from.
3913 * @param albid the unique ID of the album to retrieve.
3914 * @return a valid album metadata or NULL on failure.
3915 * @see LIBMTP_Get_Album_List()
3916 */
3917LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
3918{
3919 PTPParams *params = (PTPParams *) device->params;
3920 uint32_t i;
3921
3922 // Get all the handles if we haven't already done that
3923 if (params->handles.Handler == NULL) {
3924 flush_handles(device);
3925 }
3926
3927 for (i = 0; i < params->handles.n; i++) {
3928 LIBMTP_album_t *alb;
3929 PTPObjectInfo oi;
3930 uint16_t ret;
3931
3932 if (params->handles.Handler[i] != albid) {
3933 continue;
3934 }
3935
3936 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3937 if ( ret == PTP_RC_OK) {
3938
3939 // Ignore stuff that isn't an album
3940 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
3941 return NULL;
3942 }
3943
3944 // Allocate a new album type
3945 alb = LIBMTP_new_album_t();
3946 alb->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
3947 alb->album_id = params->handles.Handler[i];
3948 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
3949 if (ret != PTP_RC_OK) {
3950 printf("LIBMTP_Get_Album: Could not get object references\n");
3951 alb->tracks = NULL;
3952 alb->no_tracks = 0;
3953 }
3954
3955 return alb;
3956 } else {
3957 return NULL;
3958 }
3959 }
3960 return NULL;
3961}
3962
3963/**
3964 * This routine creates a new album based on the metadata
3965 * supplied. If the <code>tracks</code> field of the metadata
3966 * contains a track listing, these tracks will be added to the
3967 * album.
3968 * @param device a pointer to the device to create the new album on.
3969 * @param metadata the metadata for the new album. If the function
3970 * exits with success, the <code>album_id</code> field of this
3971 * struct will contain the new ID of the album.
3972 * @param parenthandle the parent (e.g. folder) to store this album
3973 * in. Pass in 0 to put the album in the default music directory.
3974 * @return 0 on success, any other value means failure.
3975 * @see LIBMTP_Update_Album()
3976 * @see LIBMTP_Delete_Object()
3977 */
3978int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
3979 LIBMTP_album_t * const metadata,
3980 uint32_t const parenthandle)
3981{
3982 uint16_t ret;
3983 uint32_t store = 0;
3984 PTPObjectInfo new_alb;
3985 PTPParams *params = (PTPParams *) device->params;
3986 uint32_t localph = parenthandle;
3987 char fname[256];
3988 uint8_t data[1];
3989
Linus Walleij622a22a2006-10-30 09:21:45 +00003990 // Check if we can create an object of type PTP_OFC_MTP_AbstractAudioAlbum
mopoke96143402006-10-30 04:37:26 +00003991 int i;
3992 int supported = 0;
3993 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
Linus Walleij622a22a2006-10-30 09:21:45 +00003994 if (params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_AbstractAudioAlbum) {
mopoke96143402006-10-30 04:37:26 +00003995 supported = 1;
Linus Walleij622a22a2006-10-30 09:21:45 +00003996 break;
3997 }
mopoke96143402006-10-30 04:37:26 +00003998 }
3999 if (!supported) {
4000 printf("LIBMTP_Create_New_Album(): Player does not support the AbstractAudioAlbum type\n");
4001 return -1;
4002 }
4003
Linus Walleij0c33ec02006-10-27 10:15:40 +00004004 // Use a default folder if none given
4005 if (localph == 0) {
4006 localph = device->default_music_folder;
4007 }
4008
4009 new_alb.Filename = NULL;
4010 if (strlen(metadata->name) > 4) {
4011 char *suff = &metadata->name[strlen(metadata->name)-4];
4012 if (!strcmp(suff, ".alb")) {
4013 new_alb.Filename = metadata->name;
4014 }
4015 }
4016 // If it didn't end with ".alb" then add that here.
4017 if (new_alb.Filename == NULL) {
4018 strncpy(fname, metadata->name, sizeof(fname)-5);
4019 strcat(fname, ".alb");
4020 fname[sizeof(fname)-1] = '\0';
4021 new_alb.Filename = fname;
4022 }
4023
4024 new_alb.ObjectCompressedSize = 1;
4025 new_alb.ObjectFormat = PTP_OFC_MTP_AbstractAudioAlbum;
4026
4027 // Create the object
4028 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->album_id, &new_alb);
4029 if (ret != PTP_RC_OK) {
4030 ptp_perror(params, ret);
4031 printf("LIBMTP_New_Album(): Could not send object info (the album itself)\n");
4032 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4033 return -1;
4034 }
4035 data[0] = '\0';
4036 ret = ptp_sendobject(params, data, 1);
4037 if (ret != PTP_RC_OK) {
4038 ptp_perror(params, ret);
4039 printf("LIBMTP_New_Album(): Could not send blank object data\n");
4040 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4041 return -1;
4042 }
4043
4044 // Update title
4045 ret = LIBMTP_Set_Object_String(device, metadata->album_id, PTP_OPC_Name, metadata->name);
4046 if (ret != 0) {
4047 printf("LIBMTP_New_Album(): could not set album name\n");
4048 return -1;
4049 }
4050
4051 if (metadata->no_tracks > 0) {
4052 // Add tracks to the new album as object references.
4053 ret = ptp_mtp_setobjectreferences (params, metadata->album_id, metadata->tracks, metadata->no_tracks);
4054 if (ret != PTP_RC_OK) {
4055 printf("LIBMTP_New_Album(): could not add tracks as object references\n");
4056 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4057 return -1;
4058 }
4059 }
4060
4061 // Created new item, so flush handles
4062 flush_handles(device);
4063
4064 return 0;
4065}
4066
4067/**
4068 * This routine sends cover art for an album object. This uses the
4069 * RepresentativeSampleData property of the album, if the device
4070 * supports it. The data should be of a format acceptable to the
4071 * player (for iRiver and Creative, this seems to be JPEG) and
4072 * must not be too large. (for a Creative, max seems to be about 20KB.)
4073 * TODO: there must be a way to find the max size for an ObjectPropertyValue.
4074 * @param device a pointer to the device which the album is on.
4075 * @param id unique id of the album object.
4076 * @param imagedata pointer to an array of uint8_t containing the image data.
4077 * @param imagesize number of bytes in the image.
4078 * @return 0 on success, any other value means failure.
4079 * @see LIBMTP_Create_New_Album()
4080 */
4081int LIBMTP_Send_Album_Art(LIBMTP_mtpdevice_t *device,
4082 uint32_t const id,
4083 uint8_t * const imagedata,
4084 uint32_t const imagesize)
4085{
4086 uint16_t ret;
4087 PTPParams *params = (PTPParams *) device->params;
4088 PTPPropertyValue propval;
4089
4090 int i;
4091 propval.a.count = imagesize;
4092 propval.a.v = malloc(sizeof(PTPPropertyValue) * imagesize);
4093 for (i = 0; i < imagesize; i++) {
4094 propval.a.v[i].u8 = imagedata[i];
4095 }
4096
4097 // check that we can send album art
4098 uint16_t *props = NULL;
4099 uint32_t propcnt = 0;
4100 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
4101 if (ret != PTP_RC_OK) {
4102 printf("LIBMTP_Send_Album_Art(): could not get object properties\n");
4103 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4104 return -1;
4105 }
4106 int supported = 0;
4107 for (i = 0; i < propcnt; i++) {
4108 if (props[i] == PTP_OPC_RepresentativeSampleData)
4109 supported = 1;
4110 }
4111 if (!supported) {
4112 printf("LIBMTP_Send_Album_Art(): device doesn't support RepresentativeSampleData\n");
4113 return -1;
4114 }
4115
4116 // go ahead and send the data
4117 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
4118 &propval,PTP_DTC_AUINT8);
4119 if (ret != PTP_RC_OK) {
4120 printf("LIBMTP_Send_Album_Art(): could not send album art\n");
4121 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4122 return -1;
4123 }
4124 return 0;
4125}
4126
4127/**
4128 * This routine updates an album based on the metadata
4129 * supplied. If the <code>tracks</code> field of the metadata
4130 * contains a track listing, these tracks will be added to the
4131 * album in place of those already present, i.e. the
4132 * previous track listing will be deleted.
4133 * @param device a pointer to the device to create the new album on.
4134 * @param metadata the metadata for the album to be updated.
4135 * notice that the field <code>album_id</code>
4136 * must contain the apropriate album ID.
4137 * @return 0 on success, any other value means failure.
4138 * @see LIBMTP_Create_New_Album()
4139 * @see LIBMTP_Delete_Object()
4140 */
4141int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
4142 LIBMTP_album_t const * const metadata)
4143{
4144 uint16_t ret;
4145 PTPParams *params = (PTPParams *) device->params;
4146
4147 // Update title
4148 ret = LIBMTP_Set_Object_String(device, metadata->album_id, PTP_OPC_Name, metadata->name);
4149 if (ret != 0) {
4150 printf("LIBMTP_Update_Album(): could not set album name\n");
4151 return -1;
4152 }
4153
4154 if (metadata->no_tracks > 0) {
4155 // Add tracks to the new album as object references.
4156 ret = ptp_mtp_setobjectreferences (params, metadata->album_id, metadata->tracks, metadata->no_tracks);
4157 if (ret != PTP_RC_OK) {
4158 printf("LIBMTP_Update_Album(): could not add tracks as object references\n");
4159 return -1;
4160 }
4161 }
4162 return 0;
4163}
Linus Walleijaa4b0752006-07-26 22:21:04 +00004164
4165/**
4166 * Dummy function needed to interface to upstream
4167 * ptp.c/ptp.h files.
4168 */
4169void ptp_nikon_getptpipguid (unsigned char* guid) {
4170 return;
4171}