blob: aaf997831854574064179ed80a06db831b56fbd6 [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 *
9 * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
10 * 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 Walleijc86afbd2006-05-04 19:05:24 +000026/*
Linus Walleijf82dcea2006-09-11 11:23:47 +000027 * On MacOS (Darwin) and *BSD we're not using glibc, but libiconv.
28 * glibc knows that UCS-2 is to be in the local machine endianness,
29 * whereas libiconv does not. So we construct this macro to get
30 * things right. Reportedly, glibc 2.1.3 has a bug so that UCS-2
31 * is always bigendian though, we would need to work around that
32 * too...
Linus Walleijd5d51c82006-09-11 06:57:50 +000033 */
34#ifndef __GLIBC__
Linus Walleijf82dcea2006-09-11 11:23:47 +000035#define UCS_2_INTERNAL "UCS-2-INTERNAL"
Linus Walleijd5d51c82006-09-11 06:57:50 +000036#else
Linus Walleijf82dcea2006-09-11 11:23:47 +000037#if (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 )
38#error "Too old glibc. This versions iconv() implementation cannot be trusted."
39#endif
40#define UCS_2_INTERNAL "UCS-2"
Linus Walleijd5d51c82006-09-11 06:57:50 +000041#endif
42
43/*
Linus Walleijc86afbd2006-05-04 19:05:24 +000044 * This is a mapping between libmtp internal MTP filetypes and
45 * the libgphoto2/PTP equivalent defines. We need this because
46 * otherwise the libmtp.h device has to be dependent on ptp.h
47 * to be installed too, and we don't want that.
48 */
raveloxd9a28642006-05-26 23:42:22 +000049typedef struct filemap_t LIBMTP_filemap_t;
raveloxd9a28642006-05-26 23:42:22 +000050struct filemap_t {
51 char *description; /**< Text description for the file type */
52 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
53 uint16_t ptp_id; /**< PTP ID for the filetype */
54 void *constructor; /**< Function to create the data structure for this file type */
55 void *destructor; /**< Function to destroy the data structure for this file type */
56 void *datafunc; /**< Function to fill in the data for this file type */
57 LIBMTP_filemap_t *next;
Linus Walleij16c51f02006-05-04 13:20:22 +000058};
Linus Walleijc86afbd2006-05-04 19:05:24 +000059
Linus Walleijf67bca92006-05-29 09:33:39 +000060// Global variables
Linus Walleij438bd7f2006-06-08 11:35:44 +000061// This holds the global filetype mapping table
Linus Walleijf67bca92006-05-29 09:33:39 +000062static LIBMTP_filemap_t *filemap = NULL;
63
64// Forward declarations of local functions
Linus Walleij438bd7f2006-06-08 11:35:44 +000065static void flush_handles(LIBMTP_mtpdevice_t *device);
Linus Walleijf67bca92006-05-29 09:33:39 +000066static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
67static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
Linus Walleijcf223e62006-06-19 09:31:53 +000068static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
69 char **unicstring, uint16_t property);
Linus Walleij8ab54262006-06-21 07:12:28 +000070static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
71 LIBMTP_track_t *track);
raveloxd9a28642006-05-26 23:42:22 +000072
73static LIBMTP_filemap_t *new_filemap_entry()
74{
Linus Walleijf67bca92006-05-29 09:33:39 +000075 LIBMTP_filemap_t *filemap;
76
77 filemap = (LIBMTP_filemap_t *)malloc(sizeof(LIBMTP_filemap_t));
78
79 if( filemap != NULL ) {
80 filemap->description = NULL;
81 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
82 filemap->ptp_id = PTP_OFC_Undefined;
83 filemap->constructor = NULL;
84 filemap->destructor = NULL;
85 filemap->datafunc = NULL;
86 filemap->next = NULL;
87 }
88
89 return filemap;
raveloxd9a28642006-05-26 23:42:22 +000090}
91
raveloxd9a28642006-05-26 23:42:22 +000092/**
93 * Register an MTP or PTP filetype for data retrieval
94 *
95 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +000096 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +000097 * @param ptp_id PTP filetype id
98 * @param constructor Pointer to function to create data structure for filetype
99 * @param destructor Pointer to function to destroy data structure for filetype
100 * @param datafunc Pointer to function to fill data structure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000101 * @return 0 for success any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000102*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000103int LIBMTP_Register_Filetype(char const * const description, LIBMTP_filetype_t const id,
104 uint16_t const ptp_id, void const * const constructor,
105 void const * const destructor, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000106{
107 LIBMTP_filemap_t *new = NULL, *current;
108
109 // Has this LIBMTP filetype been registered before ?
110 current = filemap;
111 while (current != NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000112 if(current->id == id) {
113 break;
114 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000115 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000116 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000117
raveloxd9a28642006-05-26 23:42:22 +0000118 // Create the entry
119 if(current == NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000120 new = new_filemap_entry();
Linus Walleijf0f3d482006-05-29 14:10:21 +0000121 if(new == NULL) {
122 return 1;
123 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000124
125 new->id = id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000126 if(description != NULL) {
127 new->description = strdup(description);
128 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000129 new->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000130 new->constructor = (void*) constructor;
131 new->destructor = (void*) destructor;
132 new->datafunc = (void*) datafunc;
Linus Walleijf67bca92006-05-29 09:33:39 +0000133
134 // Add the entry to the list
135 if(filemap == NULL) {
136 filemap = new;
137 } else {
138 current = filemap;
139 while (current->next != NULL ) current=current->next;
140 current->next = new;
141 }
142 // Update the existing entry
raveloxd9a28642006-05-26 23:42:22 +0000143 } else {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000144 if (current->description != NULL) {
145 free(current->description);
146 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000147 current->description = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000148 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000149 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000150 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000151 current->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000152 current->constructor = (void*) constructor;
153 current->destructor = (void*) destructor;
154 current->datafunc = (void*) datafunc;
raveloxd9a28642006-05-26 23:42:22 +0000155 }
156
Linus Walleijf0f3d482006-05-29 14:10:21 +0000157 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000158}
159
160/**
161 * Set the description for a MTP filetype
162 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000163 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000164 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +0000165 * @return 0 on success, any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000166*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000167int LIBMTP_Set_Filetype_Description(LIBMTP_filetype_t const id, char const * const description)
raveloxd9a28642006-05-26 23:42:22 +0000168{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000169 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000170
Linus Walleijf0f3d482006-05-29 14:10:21 +0000171 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000172 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000173 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000174
175 // Go through the filemap until an entry is found
176 current = filemap;
177
Linus Walleijf0f3d482006-05-29 14:10:21 +0000178 while(current != NULL) {
179 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000180 break;
181 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000182 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000183 }
184
Linus Walleijf0f3d482006-05-29 14:10:21 +0000185 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000186 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000187 }
188
189 if (current->description != NULL) {
190 free(current->description);
191 current->description = NULL;
192 }
193 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000194 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000195 }
196 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000197}
198
199/**
200 * Set the constructor for a MTP filetype
201 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000202 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000203 * @param constructor Pointer to a constructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000204 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000205*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000206int LIBMTP_Set_Constructor(LIBMTP_filetype_t const id, void const * const constructor)
raveloxd9a28642006-05-26 23:42:22 +0000207{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000208 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000209
Linus Walleijf0f3d482006-05-29 14:10:21 +0000210 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000211 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000212 }
213
Linus Walleijf67bca92006-05-29 09:33:39 +0000214 // Go through the filemap until an entry is found
215 current = filemap;
216
Linus Walleijf0f3d482006-05-29 14:10:21 +0000217 while(current != NULL) {
218 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000219 break;
raveloxd9a28642006-05-26 23:42:22 +0000220 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000221 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000222 }
223
Linus Walleijf0f3d482006-05-29 14:10:21 +0000224 if (current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000225 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000226 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000227
Linus Walleij438bd7f2006-06-08 11:35:44 +0000228 current->constructor = (void*) constructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000229 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000230}
231
232/**
233 * Set the destructor for a MTP filetype
234 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000235 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000236 * @param destructor Pointer to a destructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000237 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000238*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000239int LIBMTP_Set_Destructor(LIBMTP_filetype_t const id, void const * const destructor)
raveloxd9a28642006-05-26 23:42:22 +0000240{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000241 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000242
Linus Walleijf0f3d482006-05-29 14:10:21 +0000243 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000244 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000245 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000246
247 // Go through the filemap until an entry is found
248 current = filemap;
249
Linus Walleijf0f3d482006-05-29 14:10:21 +0000250 while(current != NULL) {
251 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000252 break;
raveloxd9a28642006-05-26 23:42:22 +0000253 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000254 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000255 }
256
Linus Walleijf0f3d482006-05-29 14:10:21 +0000257 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000258 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000259 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000260
Linus Walleij438bd7f2006-06-08 11:35:44 +0000261 current->destructor = (void *) destructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000262 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000263}
264
265/**
266 * Set the datafunc for a MTP filetype
267 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000268 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000269 * @param datafunc Pointer to a data function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000270 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000271*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000272int LIBMTP_Set_Datafunc(LIBMTP_filetype_t const id, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000273{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000274 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000275
Linus Walleijf0f3d482006-05-29 14:10:21 +0000276 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000277 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000278 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000279
280 // Go through the filemap until an entry is found
281 current = filemap;
282
Linus Walleijf0f3d482006-05-29 14:10:21 +0000283 while(current != NULL) {
284 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000285 break;
raveloxd9a28642006-05-26 23:42:22 +0000286 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000287 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000288 }
289
Linus Walleijf0f3d482006-05-29 14:10:21 +0000290 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000291 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000292 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000293
Linus Walleij438bd7f2006-06-08 11:35:44 +0000294 current->datafunc = (void *) datafunc;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000295 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000296}
297
298static void init_filemap()
299{
Linus Walleijf67bca92006-05-29 09:33:39 +0000300 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 +0000301 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 +0000302 LIBMTP_Register_Filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
303 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 +0000304 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 +0000305 LIBMTP_Register_Filetype("Advanced Acoustic Coding", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
306 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 +0000307 LIBMTP_Register_Filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV,NULL,NULL,NULL);
308 LIBMTP_Register_Filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI,NULL,NULL,NULL);
309 LIBMTP_Register_Filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG,NULL,NULL,NULL);
310 LIBMTP_Register_Filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF,NULL,NULL,NULL);
311 LIBMTP_Register_Filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT,NULL,NULL,NULL);
312 LIBMTP_Register_Filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo,NULL,NULL,NULL);
Linus Walleij83f57eb2006-05-31 19:57:56 +0000313 LIBMTP_Register_Filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG,NULL,NULL,NULL);
314 LIBMTP_Register_Filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF,NULL,NULL,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000315 LIBMTP_Register_Filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF,NULL,NULL,NULL);
316 LIBMTP_Register_Filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP,NULL,NULL,NULL);
317 LIBMTP_Register_Filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF,NULL,NULL,NULL);
318 LIBMTP_Register_Filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT,NULL,NULL,NULL);
319 LIBMTP_Register_Filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG,NULL,NULL,NULL);
320 LIBMTP_Register_Filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat,NULL,NULL,NULL);
321 LIBMTP_Register_Filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1,NULL,NULL,NULL);
322 LIBMTP_Register_Filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2,NULL,NULL,NULL);
323 LIBMTP_Register_Filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2,NULL,NULL,NULL);
324 LIBMTP_Register_Filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3,NULL,NULL,NULL);
325 LIBMTP_Register_Filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable,NULL,NULL,NULL);
326 LIBMTP_Register_Filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text,NULL,NULL,NULL);
327 LIBMTP_Register_Filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML,NULL,NULL,NULL);
328 LIBMTP_Register_Filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined, NULL, NULL, NULL);
raveloxd9a28642006-05-26 23:42:22 +0000329}
Linus Walleij16c51f02006-05-04 13:20:22 +0000330
Linus Walleij16c51f02006-05-04 13:20:22 +0000331/**
332 * Returns the PTP filetype that maps to a certain libmtp internal file type.
333 * @param intype the MTP library interface type
334 * @return the PTP (libgphoto2) interface type
335 */
336static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
337{
raveloxd9a28642006-05-26 23:42:22 +0000338 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000339
raveloxd9a28642006-05-26 23:42:22 +0000340 current = filemap;
341
342 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000343 if(current->id == intype) {
344 return current->ptp_id;
345 }
346 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000347 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000348 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000349 return PTP_OFC_Undefined;
350}
351
352
353/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000354 * Returns the PTP internal filetype that maps to a certain libmtp
355 * interface file type.
Linus Walleij8ab54262006-06-21 07:12:28 +0000356 * @param intype the PTP (libgphoto2) interface type
357 * @return the MTP library interface type
Linus Walleij16c51f02006-05-04 13:20:22 +0000358 */
359static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
360{
raveloxd9a28642006-05-26 23:42:22 +0000361 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000362
raveloxd9a28642006-05-26 23:42:22 +0000363 current = filemap;
364
365 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000366 if(current->ptp_id == intype) {
367 return current->id;
368 }
369 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000370 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000371 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000372 return LIBMTP_FILETYPE_UNKNOWN;
373}
374
375/**
raveloxd9a28642006-05-26 23:42:22 +0000376 * Returns the data function for the file type
377 * @param intype the PTP library interface
378 * @return pointer to the data function
379 */
380static void *get_datafunc(uint16_t intype)
381{
382 LIBMTP_filemap_t *current;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000383
raveloxd9a28642006-05-26 23:42:22 +0000384 current = filemap;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000385
raveloxd9a28642006-05-26 23:42:22 +0000386 while (current != NULL) {
387 if(current->ptp_id == intype) {
388 return current->datafunc;
389 }
390 current = current->next;
391 }
392 return NULL;
393}
394
395
396/**
397 * Returns the constructor for that file type data
398 * @param intype the PTP library interface type
399 * @return pointer to the constructor
400 */
401static void *get_constructor(uint16_t intype)
402{
403 LIBMTP_filemap_t *current;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000404
raveloxd9a28642006-05-26 23:42:22 +0000405 current = filemap;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000406
raveloxd9a28642006-05-26 23:42:22 +0000407 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000408 if(current->ptp_id == intype) {
409 return current->constructor;
410 }
411 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000412 }
413 return NULL;
414}
415
416/**
417 * Returns the destructor for that file type data
418 * @param intype the PTP library interface type
419 * @return pointer to the destructor
420 */
421static void *get_destructor(uint16_t intype)
422{
423 LIBMTP_filemap_t *current;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000424
raveloxd9a28642006-05-26 23:42:22 +0000425 current = filemap;
426
427 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000428 if(current->ptp_id == intype) {
429 return current->destructor;
430 }
431 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000432 }
433 return NULL;
434}
435
436/**
Linus Walleij16c51f02006-05-04 13:20:22 +0000437 * This helper function returns a textual description for a libmtp
438 * file type to be used in dialog boxes etc.
Linus Walleijf0f3d482006-05-29 14:10:21 +0000439 * @param intype the libmtp internal filetype to get a description for.
Linus Walleij16c51f02006-05-04 13:20:22 +0000440 * @return a string representing the filetype, this must <b>NOT</b>
441 * be free():ed by the caller!
442 */
443char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
444{
raveloxd9a28642006-05-26 23:42:22 +0000445 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000446
raveloxd9a28642006-05-26 23:42:22 +0000447 current = filemap;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000448
raveloxd9a28642006-05-26 23:42:22 +0000449 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000450 if(current->id == intype) {
451 return current->description;
452 }
453 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000454 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000455
Linus Walleij16c51f02006-05-04 13:20:22 +0000456 return "Unknown filetype";
457}
Linus Walleijfa1374c2006-02-27 07:41:46 +0000458
Linus Walleij6946ac52006-03-21 06:51:22 +0000459/**
Linus Walleijf0f3d482006-05-29 14:10:21 +0000460 * Initialize the library. You are only supposed to call this
461 * one, before using the library for the first time in a program.
462 * Never re-initialize libmtp!
463 *
raveloxd9a28642006-05-26 23:42:22 +0000464 * The only thing this does at the moment is to initialise the
465 * filetype mapping table.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000466 */
467void LIBMTP_Init(void)
468{
raveloxd9a28642006-05-26 23:42:22 +0000469 init_filemap();
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000470 return;
471}
472
473/**
raveloxd9a28642006-05-26 23:42:22 +0000474 * Retrieves a string from an object
475 *
476 * @param device a pointer to an MTP device.
477 * @param object_id Object reference
478 * @param attribute_id PTP attribute ID
Linus Walleij438bd7f2006-06-08 11:35:44 +0000479 * @return valid string or NULL on failure. The returned string
480 * must bee <code>free()</code>:ed by the caller after
481 * use.
raveloxd9a28642006-05-26 23:42:22 +0000482 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000483char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleija823a702006-08-27 21:27:46 +0000484 uint32_t const attribute_id)
raveloxd9a28642006-05-26 23:42:22 +0000485{
486 PTPPropertyValue propval;
487 char *retstring = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000488 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000489 uint16_t ret;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000490
Linus Walleij438bd7f2006-06-08 11:35:44 +0000491 if ( device == NULL || object_id == 0) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000492 return NULL;
493 }
494
Linus Walleija823a702006-08-27 21:27:46 +0000495 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
raveloxd9a28642006-05-26 23:42:22 +0000496 if (ret == PTP_RC_OK) {
Linus Walleija823a702006-08-27 21:27:46 +0000497 if (propval.str != NULL) {
498 retstring = (char *) strdup(propval.str);
499 free(propval.str);
raveloxd9a28642006-05-26 23:42:22 +0000500 }
501 }
Linus Walleij438bd7f2006-06-08 11:35:44 +0000502
raveloxd9a28642006-05-26 23:42:22 +0000503 return retstring;
504}
505
506/**
507 * Retrieves an unsigned 32-bit integer from an object attribute
508 *
509 * @param device a pointer to an MTP device.
510 * @param object_id Object reference
511 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000512 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000513 * @return the value
raveloxd9a28642006-05-26 23:42:22 +0000514 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000515uint32_t LIBMTP_Get_U32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
516 uint32_t const attribute_id, uint32_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000517{
518 PTPPropertyValue propval;
519 uint32_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000520 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000521 uint16_t ret;
522
Linus Walleijf0f3d482006-05-29 14:10:21 +0000523 if ( device == NULL ) {
524 return value_default;
525 }
raveloxd9a28642006-05-26 23:42:22 +0000526
raveloxd9a28642006-05-26 23:42:22 +0000527 ret = ptp_mtp_getobjectpropvalue(params, object_id,
528 attribute_id,
529 &propval,
530 PTP_DTC_UINT32);
531 if (ret == PTP_RC_OK) {
532 retval = propval.u32;
533 }
534
535 return retval;
536}
537
538/**
539 * Retrieves an unsigned 16-bit integer from an object attribute
540 *
541 * @param device a pointer to an MTP device.
542 * @param object_id Object reference
543 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000544 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000545 * @return a value
raveloxd9a28642006-05-26 23:42:22 +0000546 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000547uint16_t LIBMTP_Get_U16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
548 uint32_t const attribute_id, uint16_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000549{
550 PTPPropertyValue propval;
551 uint16_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000552 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000553 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000554
Linus Walleijf0f3d482006-05-29 14:10:21 +0000555 if ( device == NULL ) {
556 return value_default;
557 }
raveloxd9a28642006-05-26 23:42:22 +0000558
raveloxd9a28642006-05-26 23:42:22 +0000559 ret = ptp_mtp_getobjectpropvalue(params, object_id,
560 attribute_id,
561 &propval,
562 PTP_DTC_UINT16);
563 if (ret == PTP_RC_OK) {
564 retval = propval.u16;
565 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000566
raveloxd9a28642006-05-26 23:42:22 +0000567 return retval;
568}
569
570/**
571 * Sets an object attribute from a string
572 *
573 * @param device a pointer to an MTP device.
574 * @param object_id Object reference
575 * @param attribute_id PTP attribute ID
576 * @param string string value to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000577 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000578 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000579int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleija823a702006-08-27 21:27:46 +0000580 uint32_t const attribute_id, char const * const string)
raveloxd9a28642006-05-26 23:42:22 +0000581{
582 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000583 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000584 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000585
Linus Walleijf0f3d482006-05-29 14:10:21 +0000586 if (device == NULL || string == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000587 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000588 }
raveloxd9a28642006-05-26 23:42:22 +0000589
Linus Walleija823a702006-08-27 21:27:46 +0000590 propval.str = (char *) string;
591 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000592 if (ret != PTP_RC_OK) {
Linus Walleijda9500d2006-08-30 13:17:06 +0000593 printf("LIBMTP_Set_Object_String(): could not set object string.\n");
594 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000595 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000596 }
Linus Walleij438bd7f2006-06-08 11:35:44 +0000597
Linus Walleijf0f3d482006-05-29 14:10:21 +0000598 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000599}
600
601/**
602 * Sets an object attribute from an unsigned 32-bit integer
603 *
604 * @param device a pointer to an MTP device.
605 * @param object_id Object reference
606 * @param attribute_id PTP attribute ID
607 * @param value 32-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000608 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000609 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000610int LIBMTP_Set_Object_U32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
611 uint32_t const attribute_id, uint32_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000612{
613 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000614 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000615 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000616
Linus Walleijf0f3d482006-05-29 14:10:21 +0000617 if (device == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000618 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000619 }
raveloxd9a28642006-05-26 23:42:22 +0000620
621 propval.u32 = value;
622 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000623 if (ret != PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000624 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000625 }
626
627 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000628}
629
630/**
631 * Sets an object attribute from an unsigned 16-bit integer
632 *
633 * @param device a pointer to an MTP device.
634 * @param object_id Object reference
635 * @param attribute_id PTP attribute ID
636 * @param value 16-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000637 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000638 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000639int LIBMTP_Set_Object_U16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
640 uint32_t const attribute_id, uint16_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000641{
642 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000643 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000644 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000645
Linus Walleijf0f3d482006-05-29 14:10:21 +0000646 if (device == NULL) {
647 return 1;
648 }
raveloxd9a28642006-05-26 23:42:22 +0000649
650 propval.u16 = value;
651 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000652 if (ret != PTP_RC_OK) {
653 return 1;
654 }
raveloxd9a28642006-05-26 23:42:22 +0000655
Linus Walleijf0f3d482006-05-29 14:10:21 +0000656 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000657}
658
659/**
660 * Gets an array of object ids associated with a specified object
661 *
662 * @param device a pointer to an MTP device.
663 * @param object_id Object reference
664 * @param items array of unsigned 32-bit integers
665 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000666 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000667 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000668int LIBMTP_Get_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleijf0f3d482006-05-29 14:10:21 +0000669 uint32_t **items, uint32_t *len)
raveloxd9a28642006-05-26 23:42:22 +0000670{
671 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000672 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000673
Linus Walleijf0f3d482006-05-29 14:10:21 +0000674 // A device must be attached
raveloxd9a28642006-05-26 23:42:22 +0000675 if (device == NULL ) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000676 *items = NULL;
677 *len = 0;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000678 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000679 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000680
681 ret = ptp_mtp_getobjectreferences (params, object_id, items, len);
raveloxd9a28642006-05-26 23:42:22 +0000682 if (ret != PTP_RC_OK) {
683 ptp_perror(params, ret);
684 printf("LIBMTP_Get_Object_References: Could not get object references\n");
Linus Walleijf0f3d482006-05-29 14:10:21 +0000685 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000686 }
687
Linus Walleijf0f3d482006-05-29 14:10:21 +0000688 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000689}
690
691/**
692 * Sets an array of object ids associated with a specified object
693 *
694 * @param device a pointer to an MTP device.
695 * @param object_id Object reference
696 * @param items array of unsigned 32-bit integers
697 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000698 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000699 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000700int LIBMTP_Set_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
701 uint32_t const * const items, uint32_t const len)
raveloxd9a28642006-05-26 23:42:22 +0000702{
703 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000704 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000705
706 if (device == NULL || items == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000707 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000708 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000709
Linus Walleij438bd7f2006-06-08 11:35:44 +0000710 ret = ptp_mtp_setobjectreferences (params, object_id, (uint32_t *) items, len);
raveloxd9a28642006-05-26 23:42:22 +0000711 if (ret != PTP_RC_OK) {
712 ptp_perror(params, ret);
713 printf("LIBMTP_Set_Object_References: Could not set object references\n");
Linus Walleijf0f3d482006-05-29 14:10:21 +0000714 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000715 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000716
Linus Walleijf0f3d482006-05-29 14:10:21 +0000717 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000718}
719
raveloxd9a28642006-05-26 23:42:22 +0000720/**
Linus Walleij6fd2f082006-03-28 07:19:22 +0000721 * Get a list of the supported devices.
722 *
Linus Walleijc86afbd2006-05-04 19:05:24 +0000723 * The developers depend on users of this library to constantly
724 * add in to the list of supported devices. What we need is the
725 * device name, USB Vendor ID (VID) and USB Product ID (PID).
726 * put this into a bug ticket at the project homepage, please.
727 * The VID/PID is used to let e.g. udev lift the device to
728 * console userspace access when it's plugged in.
729 *
Linus Walleij6fd2f082006-03-28 07:19:22 +0000730 * @param devices a pointer to a pointer that will hold a device
731 * list after the call to this function, if it was
732 * successful.
733 * @param numdevs a pointer to an integer that will hold the number
734 * of devices in the device list if the call was successful.
735 * @return 0 if the list was successfull retrieved, any other
736 * value means failure.
737 */
738int LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs)
739{
740 // Just dispatch to libusb glue file...
741 return get_device_list(devices, numdevs);
742}
743
744/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000745 * Get the first connected MTP device. There is currently no API for
746 * retrieveing multiple devices.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000747 * @return a device pointer.
748 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000749LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000750{
751 uint8_t interface_number;
Linus Walleij56d3e182006-02-10 15:46:54 +0000752 PTPParams *params;
753 PTP_USB *ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000754 PTPStorageIDs storageIDs;
755 unsigned storageID = 0;
756 PTPDevicePropDesc dpd;
Linus Walleijd31e6192006-09-12 07:55:27 +0000757 uint8_t batteryLevelMax = 100; // Some default
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000758 uint16_t ret;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000759 uint32_t i;
Linus Walleijb9256fd2006-02-15 09:40:43 +0000760 LIBMTP_mtpdevice_t *tmpdevice;
Richard Low43fdb882006-09-06 16:19:05 +0000761 uint8_t remaining_directories;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000762
Linus Walleij56d3e182006-02-10 15:46:54 +0000763 // Allocate a parameter block
764 params = (PTPParams *) malloc(sizeof(PTPParams));
Linus Walleijd5d51c82006-09-11 06:57:50 +0000765 params->cd_locale_to_ucs2 = iconv_open(UCS_2_INTERNAL, "UTF-8");
766 params->cd_ucs2_to_locale = iconv_open("UTF-8", UCS_2_INTERNAL);
Linus Walleija823a702006-08-27 21:27:46 +0000767 if (params->cd_locale_to_ucs2 == (iconv_t) -1 || params->cd_ucs2_to_locale == (iconv_t) -1) {
Linus Walleijd5d51c82006-09-11 06:57:50 +0000768 printf("LIBMTP panic: could not open iconv() converters to/from UCS-2!\n");
Linus Walleija823a702006-08-27 21:27:46 +0000769 return NULL;
770 }
771
Linus Walleij56d3e182006-02-10 15:46:54 +0000772 ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB));
Linus Walleijd214b9b2006-08-26 22:08:37 +0000773 // Callbacks and stuff
774 ptp_usb->callback_active = 0;
775 ptp_usb->current_transfer_total = 0;
776 ptp_usb->current_transfer_complete = 0;
777 ptp_usb->current_transfer_callback = NULL;
778
779 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000780 ret = connect_first_device(params, ptp_usb, &interface_number);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000781
782 switch (ret)
783 {
784 case PTP_CD_RC_CONNECTED:
785 printf("Connected to MTP device.\n");
786 break;
787 case PTP_CD_RC_NO_DEVICES:
788 printf("No MTP devices.\n");
789 return NULL;
790 case PTP_CD_RC_ERROR_CONNECTING:
791 printf("Connection error.\n");
792 return NULL;
793 }
794
795 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000796 if (ptp_getstorageids (params, &storageIDs) == PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000797 if (storageIDs.n > 0)
798 storageID = storageIDs.Storage[0];
799 free(storageIDs.Storage);
800 }
801
802 // Make sure there are no handlers
Linus Walleij56d3e182006-02-10 15:46:54 +0000803 params->handles.Handler = NULL;
Linus Walleijb02a0662006-04-25 08:05:09 +0000804
Linus Walleij8c45b292006-04-26 14:12:44 +0000805 // Just cache the device information for any later use.
806 if (ptp_getdeviceinfo(params, &params->deviceinfo) != PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000807 goto error_handler;
808 }
809
810 // Get battery maximum level
Linus Walleijd31e6192006-09-12 07:55:27 +0000811 if (ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
812 if (ptp_getdevicepropdesc(params, PTP_DPC_BatteryLevel, &dpd) != PTP_RC_OK) {
813 printf("LIBMTP_Get_First_Device(): Unable to retrieve battery max level.\n");
814 goto error_handler;
815 }
816 // if is NULL, just leave as default
817 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
818 batteryLevelMax = dpd.FORM.Range.MaximumValue.u8;
819 }
820 ptp_free_devicepropdesc(&dpd);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000821 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000822
823 // OK everything got this far, so it is time to create a device struct!
Linus Walleijb9256fd2006-02-15 09:40:43 +0000824 tmpdevice = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000825 tmpdevice->interface_number = interface_number;
Linus Walleij9b28da32006-03-16 13:47:58 +0000826 tmpdevice->params = (void *) params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000827 tmpdevice->usbinfo = (void *) ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000828 tmpdevice->storage_id = storageID;
829 tmpdevice->maximum_battery_level = batteryLevelMax;
830
Linus Walleij05ccbe72006-06-13 07:46:58 +0000831 // Set all default folders to 0 == root directory
832 tmpdevice->default_music_folder = 0;
833 tmpdevice->default_playlist_folder = 0;
834 tmpdevice->default_picture_folder = 0;
835 tmpdevice->default_video_folder = 0;
836 tmpdevice->default_organizer_folder = 0;
837 tmpdevice->default_zencast_folder = 0;
838
839 /*
840 * Then get the handles and try to locate the default folders.
841 * This has the desired side effect of cacheing all handles from
842 * the device which speeds up later operations.
843 */
844 flush_handles(tmpdevice);
Linus Walleij0558ac52006-09-07 06:55:03 +0000845 /*
846 * Remaining directories to get the handles to.
847 * We can stop when done this to save time
848 */
849 remaining_directories = 6;
Richard Low43fdb882006-09-06 16:19:05 +0000850 for (i = 0; i < params->handles.n && remaining_directories > 0; i++) {
Linus Walleij05ccbe72006-06-13 07:46:58 +0000851 PTPObjectInfo oi;
852 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
853 // Ignore non-folders
854 if ( oi.ObjectFormat != PTP_OFC_Association )
855 continue;
Linus Walleij97c7a342006-09-11 07:03:03 +0000856 if ( oi.Filename == NULL)
857 continue;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000858 if (!strcmp(oi.Filename, "Music")) {
859 tmpdevice->default_music_folder = params->handles.Handler[i];
Linus Walleij0558ac52006-09-07 06:55:03 +0000860 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000861 continue;
862 } else if (!strcmp(oi.Filename, "My Playlists")) {
863 tmpdevice->default_playlist_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000864 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000865 continue;
866 } else if (!strcmp(oi.Filename, "Pictures")) {
867 tmpdevice->default_picture_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000868 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000869 continue;
870 } else if (!strcmp(oi.Filename, "Video")) {
871 tmpdevice->default_video_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000872 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000873 continue;
874 } else if (!strcmp(oi.Filename, "My Organizer")) {
875 tmpdevice->default_organizer_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000876 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000877 continue;
878 } else if (!strcmp(oi.Filename, "ZENcast")) {
879 tmpdevice->default_zencast_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000880 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000881 continue;
882 }
883 } else {
884 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
885 }
886 }
887
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000888 return tmpdevice;
889
890 // Then close it again.
891 error_handler:
Linus Walleij56d3e182006-02-10 15:46:54 +0000892 close_device(ptp_usb, params, interface_number);
Linus Walleijb02a0662006-04-25 08:05:09 +0000893 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
894 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij56d3e182006-02-10 15:46:54 +0000895 if (params->handles.Handler != NULL) {
896 free(params->handles.Handler);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000897 }
898 return NULL;
899}
900
901/**
902 * This closes and releases an allocated MTP device.
Linus Walleijb9256fd2006-02-15 09:40:43 +0000903 * @param device a pointer to the MTP device to release.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000904 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000905void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000906{
Linus Walleij9b28da32006-03-16 13:47:58 +0000907 PTPParams *params = (PTPParams *) device->params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000908 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij9b28da32006-03-16 13:47:58 +0000909
Linus Walleij2d411db2006-03-22 12:13:09 +0000910 close_device(ptp_usb, params, device->interface_number);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000911 // Free the device info and any handler
Linus Walleijb02a0662006-04-25 08:05:09 +0000912 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
913 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij9b28da32006-03-16 13:47:58 +0000914 if (params->handles.Handler != NULL) {
915 free(params->handles.Handler);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000916 params->handles.Handler = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000917 }
Linus Walleij3ec86312006-08-21 13:25:24 +0000918 // Free iconv() converters...
Linus Walleija823a702006-08-27 21:27:46 +0000919 iconv_close(params->cd_locale_to_ucs2);
920 iconv_close(params->cd_ucs2_to_locale);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000921 free(device);
922}
Linus Walleijb9256fd2006-02-15 09:40:43 +0000923
924/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000925 * This function refresh the internal handle list whenever
926 * the items stored inside the device is altered. On operations
927 * that do not add or remove objects, this is typically not
928 * called.
929 * @param device a pointer to the MTP device to flush handles for.
930 */
931static void flush_handles(LIBMTP_mtpdevice_t *device)
932{
933 PTPParams *params = (PTPParams *) device->params;
934 uint16_t ret;
935
936 if (params->handles.Handler != NULL) {
937 free(params->handles.Handler);
938 }
939
940 // Get all the handles if we haven't already done that
941 ret = ptp_getobjecthandles(params,
942 PTP_GOH_ALL_STORAGE,
943 PTP_GOH_ALL_FORMATS,
944 PTP_GOH_ALL_ASSOCS,
945 &params->handles);
946 if (ret != PTP_RC_OK) {
947 printf("flush_handles(): LIBMTP panic: Could not get object handles...\n");
Linus Walleijda9500d2006-08-30 13:17:06 +0000948 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000949 }
950
951 return;
952}
953
954/**
Linus Walleij8c45b292006-04-26 14:12:44 +0000955 * This function dumps out a large chunk of textual information
956 * provided from the PTP protocol and additionally some extra
957 * MTP-specific information where applicable.
958 * @param device a pointer to the MTP device to report info from.
959 */
960void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
961{
962 int i;
963 PTPParams *params = (PTPParams *) device->params;
Linus Walleijc6210fb2006-05-08 11:11:41 +0000964 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
965
966 printf("USB low-level info:\n");
967 dump_usbinfo(ptp_usb);
Linus Walleij8c45b292006-04-26 14:12:44 +0000968 /* Print out some verbose information */
969 printf("Device info:\n");
970 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
971 printf(" Model: %s\n", params->deviceinfo.Model);
972 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
973 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
974 printf(" Vendor extension ID: 0x%08x\n", params->deviceinfo.VendorExtensionID);
975 printf(" Vendor extension description: %s\n", params->deviceinfo.VendorExtensionDesc);
976 printf("Supported operations:\n");
977 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
978 printf(" 0x%04x\n", params->deviceinfo.OperationsSupported[i]);
979 }
980 printf("Events supported:\n");
981 if (params->deviceinfo.EventsSupported_len == 0) {
982 printf(" None.\n");
983 } else {
984 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
985 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
986 }
987 }
988 printf("Device Properties Supported:\n");
989 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
Linus Walleij16c51f02006-05-04 13:20:22 +0000990 char const *propdesc = ptp_get_property_description(params, params->deviceinfo.DevicePropertiesSupported[i]);
Linus Walleij545c7792006-06-13 15:22:30 +0000991
992 if (propdesc != NULL) {
993 printf(" 0x%04x: %s\n", params->deviceinfo.DevicePropertiesSupported[i], propdesc);
994 } else {
995 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
Linus Walleijcf223e62006-06-19 09:31:53 +0000996 printf(" 0x%04x: Unknown property\n", prop);
Linus Walleij545c7792006-06-13 15:22:30 +0000997 }
Linus Walleij8c45b292006-04-26 14:12:44 +0000998 }
Linus Walleij0af979a2006-06-19 11:49:10 +0000999
1000 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
1001 printf("Playable File (Object) Types and Object Properties Supported:\n");
1002 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
1003 char txt[256];
1004 uint16_t ret;
1005 uint16_t *props = NULL;
1006 uint32_t propcnt = 0;
1007 int j;
1008
1009 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i], sizeof(txt), txt);
1010 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
1011
1012 ret = ptp_mtp_getobjectpropssupported (params, params->deviceinfo.ImageFormats[i], &propcnt, &props);
1013 if (ret != PTP_RC_OK) {
1014 printf(" Error on query for object properties.\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00001015 printf(" Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij0af979a2006-06-19 11:49:10 +00001016 } else {
1017 for (j=0;j<propcnt;j++) {
1018 (void) ptp_render_mtp_propname(props[j],sizeof(txt),txt);
1019 printf(" %04x: %s\n", props[j], txt);
1020 }
1021 free(props);
1022 }
1023 }
1024 }
Linus Walleij545c7792006-06-13 15:22:30 +00001025
1026 printf("Special directories:\n");
1027 printf(" Default music folder: 0x%08x\n", device->default_music_folder);
1028 printf(" Default playlist folder: 0x%08x\n", device->default_playlist_folder);
1029 printf(" Default picture folder: 0x%08x\n", device->default_picture_folder);
1030 printf(" Default video folder: 0x%08x\n", device->default_video_folder);
1031 printf(" Default organizer folder: 0x%08x\n", device->default_organizer_folder);
1032 printf(" Default zencast folder: 0x%08x\n", device->default_zencast_folder);
Linus Walleij8c45b292006-04-26 14:12:44 +00001033}
1034
1035/**
Linus Walleij80124062006-03-15 10:26:09 +00001036 * This retrieves the model name (often equal to product name)
1037 * of an MTP device.
1038 * @param device a pointer to the device to get the model name for.
1039 * @return a newly allocated UTF-8 string representing the model name.
1040 * The string must be freed by the caller after use. If the call
1041 * was unsuccessful this will contain NULL.
1042 */
1043char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
1044{
1045 char *retmodel = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001046 PTPParams *params = (PTPParams *) device->params;
Linus Walleij80124062006-03-15 10:26:09 +00001047
Linus Walleij9b28da32006-03-16 13:47:58 +00001048 if (params->deviceinfo.Model != NULL) {
1049 retmodel = strdup(params->deviceinfo.Model);
Linus Walleij80124062006-03-15 10:26:09 +00001050 }
1051 return retmodel;
1052}
1053
1054/**
1055 * This retrieves the serial number of an MTP device.
1056 * @param device a pointer to the device to get the serial number for.
1057 * @return a newly allocated UTF-8 string representing the serial number.
1058 * The string must be freed by the caller after use. If the call
1059 * was unsuccessful this will contain NULL.
1060 */
1061char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
1062{
1063 char *retnumber = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001064 PTPParams *params = (PTPParams *) device->params;
Linus Walleij80124062006-03-15 10:26:09 +00001065
Linus Walleij9b28da32006-03-16 13:47:58 +00001066 if (params->deviceinfo.SerialNumber != NULL) {
1067 retnumber = strdup(params->deviceinfo.SerialNumber);
Linus Walleij80124062006-03-15 10:26:09 +00001068 }
1069 return retnumber;
1070}
1071
1072/**
1073 * This retrieves the device version (hardware and firmware version) of an
1074 * MTP device.
1075 * @param device a pointer to the device to get the device version for.
1076 * @return a newly allocated UTF-8 string representing the device version.
1077 * The string must be freed by the caller after use. If the call
1078 * was unsuccessful this will contain NULL.
1079 */
1080char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
1081{
1082 char *retversion = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001083 PTPParams *params = (PTPParams *) device->params;
Linus Walleij80124062006-03-15 10:26:09 +00001084
Linus Walleij9b28da32006-03-16 13:47:58 +00001085 if (params->deviceinfo.DeviceVersion != NULL) {
1086 retversion = strdup(params->deviceinfo.DeviceVersion);
Linus Walleij80124062006-03-15 10:26:09 +00001087 }
1088 return retversion;
1089}
1090
1091
1092/**
Linus Walleijfae27482006-08-19 20:13:25 +00001093 * This retrieves the "friendly name" of an MTP device. Usually
1094 * this is simply the name of the owner or something like
Linus Walleij30658792006-08-19 22:18:55 +00001095 * "John Doe's Digital Audio Player". This property should be supported
Linus Walleijfae27482006-08-19 20:13:25 +00001096 * by all MTP devices.
1097 * @param device a pointer to the device to get the friendly name for.
1098 * @return a newly allocated UTF-8 string representing the friendly name.
Linus Walleijb9256fd2006-02-15 09:40:43 +00001099 * The string must be freed by the caller after use.
Linus Walleij30658792006-08-19 22:18:55 +00001100 * @see LIBMTP_Set_Friendlyname()
Linus Walleijb9256fd2006-02-15 09:40:43 +00001101 */
Linus Walleij30658792006-08-19 22:18:55 +00001102char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001103{
Linus Walleijb02a0662006-04-25 08:05:09 +00001104 PTPPropertyValue propval;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001105 char *retstring = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001106 PTPParams *params = (PTPParams *) device->params;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001107
Linus Walleijcf223e62006-06-19 09:31:53 +00001108 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
1109 return NULL;
1110 }
1111
Linus Walleij9b28da32006-03-16 13:47:58 +00001112 if (ptp_getdevicepropvalue(params,
Linus Walleij545c7792006-06-13 15:22:30 +00001113 PTP_DPC_MTP_DeviceFriendlyName,
Linus Walleijb02a0662006-04-25 08:05:09 +00001114 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001115 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001116 return NULL;
1117 }
Linus Walleija823a702006-08-27 21:27:46 +00001118 if (propval.str != NULL) {
1119 retstring = strdup(propval.str);
1120 free(propval.str);
1121 }
Linus Walleijfae27482006-08-19 20:13:25 +00001122 return retstring;
1123}
1124
1125/**
Linus Walleij30658792006-08-19 22:18:55 +00001126 * Sets the "friendly name" of an MTP device.
1127 * @param device a pointer to the device to set the friendly name for.
1128 * @param friendlyname the new friendly name for the device.
1129 * @return 0 on success, any other value means failure.
1130 * @see LIBMTP_Get_Ownername()
1131 */
1132int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
1133 char const * const friendlyname)
1134{
1135 PTPPropertyValue propval;
1136 PTPParams *params = (PTPParams *) device->params;
1137
1138 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
1139 return -1;
1140 }
Linus Walleija823a702006-08-27 21:27:46 +00001141 propval.str = (char *) friendlyname;
Linus Walleij30658792006-08-19 22:18:55 +00001142 if (ptp_setdevicepropvalue(params,
1143 PTP_DPC_MTP_DeviceFriendlyName,
1144 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001145 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleij30658792006-08-19 22:18:55 +00001146 return -1;
1147 }
Linus Walleij30658792006-08-19 22:18:55 +00001148 return 0;
1149}
1150
1151/**
Linus Walleijfae27482006-08-19 20:13:25 +00001152 * This retrieves the syncronization partner of an MTP device. This
1153 * property should be supported by all MTP devices.
1154 * @param device a pointer to the device to get the sync partner for.
1155 * @return a newly allocated UTF-8 string representing the synchronization
1156 * partner. The string must be freed by the caller after use.
Linus Walleij30658792006-08-19 22:18:55 +00001157 * @see LIBMTP_Set_Syncpartner()
Linus Walleijfae27482006-08-19 20:13:25 +00001158 */
1159char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
1160{
1161 PTPPropertyValue propval;
1162 char *retstring = NULL;
1163 PTPParams *params = (PTPParams *) device->params;
1164
1165 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
1166 return NULL;
1167 }
1168
1169 if (ptp_getdevicepropvalue(params,
1170 PTP_DPC_MTP_SynchronizationPartner,
1171 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001172 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleijfae27482006-08-19 20:13:25 +00001173 return NULL;
1174 }
Linus Walleija823a702006-08-27 21:27:46 +00001175 if (propval.str != NULL) {
1176 retstring = strdup(propval.str);
1177 free(propval.str);
1178 }
Linus Walleijb9256fd2006-02-15 09:40:43 +00001179 return retstring;
1180}
1181
Linus Walleij30658792006-08-19 22:18:55 +00001182
1183/**
1184 * Sets the synchronization partner of an MTP device. Note that
1185 * we have no idea what the effect of setting this to "foobar"
1186 * may be. But the general idea seems to be to tell which program
1187 * shall synchronize with this device and tell others to leave
1188 * it alone.
1189 * @param device a pointer to the device to set the sync partner for.
1190 * @param syncpartner the new synchronization partner for the device.
1191 * @return 0 on success, any other value means failure.
1192 * @see LIBMTP_Get_Syncpartner()
1193 */
1194int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
1195 char const * const syncpartner)
1196{
1197 PTPPropertyValue propval;
1198 PTPParams *params = (PTPParams *) device->params;
1199
1200 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
1201 return -1;
1202 }
Linus Walleija823a702006-08-27 21:27:46 +00001203 propval.str = (char *) syncpartner;
Linus Walleij30658792006-08-19 22:18:55 +00001204 if (ptp_setdevicepropvalue(params,
1205 PTP_DPC_MTP_SynchronizationPartner,
1206 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001207 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleij30658792006-08-19 22:18:55 +00001208 return -1;
1209 }
Linus Walleij30658792006-08-19 22:18:55 +00001210 return 0;
1211}
1212
Linus Walleij394bbbe2006-02-22 16:10:53 +00001213/**
Linus Walleijfa1374c2006-02-27 07:41:46 +00001214 * This function finds out how much storage space is currently used
1215 * and any additional storage information. Storage may be a hard disk
1216 * or flash memory or whatever.
1217 * @param device a pointer to the device to get the storage info for.
1218 * @param total a pointer to a variable that will hold the
1219 * total the total number of bytes available on this volume after
1220 * the call.
1221 * @param free a pointer to a variable that will hold the number of
1222 * free bytes available on this volume right now after the call.
1223 * @param storage_description a description of the storage. This may
1224 * be NULL after the call even if it succeeded. If it is not NULL,
1225 * it must be freed by the callee after use.
1226 * @param volume_label a volume label or similar. This may be NULL after the
1227 * call even if it succeeded. If it is not NULL, it must be
1228 * freed by the callee after use.
1229 * @return 0 if the storage info was successfully retrieved, any other
1230 * value means failure.
1231 */
1232int LIBMTP_Get_Storageinfo(LIBMTP_mtpdevice_t *device, uint64_t * const total,
1233 uint64_t * const free, char ** const storage_description,
1234 char ** const volume_label)
1235{
1236 PTPStorageInfo storageInfo;
Linus Walleij9b28da32006-03-16 13:47:58 +00001237 PTPParams *params = (PTPParams *) device->params;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001238
Linus Walleij9b28da32006-03-16 13:47:58 +00001239 if (ptp_getstorageinfo(params, device->storage_id, &storageInfo) != PTP_RC_OK) {
Linus Walleijfa1374c2006-02-27 07:41:46 +00001240 printf("LIBMTP_Get_Diskinfo(): failed to get disk info\n");
1241 *total = 0;
1242 *free = 0;
1243 *storage_description = NULL;
1244 *volume_label = NULL;
1245 return -1;
1246 }
1247 *total = storageInfo.MaxCapability;
1248 *free = storageInfo.FreeSpaceInBytes;
1249 *storage_description = storageInfo.StorageDescription;
1250 *volume_label = storageInfo.VolumeLabel;
1251
1252 return 0;
1253}
1254
1255
1256/**
1257 * This function retrieves the current battery level on the device.
1258 * @param device a pointer to the device to get the battery level for.
1259 * @param maximum_level a pointer to a variable that will hold the
1260 * maximum level of the battery if the call was successful.
1261 * @param current_level a pointer to a variable that will hold the
1262 * current level of the battery if the call was successful.
Linus Walleij545c7792006-06-13 15:22:30 +00001263 * A value of 0 means that the device is on external power.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001264 * @return 0 if the storage info was successfully retrieved, any other
Linus Walleij80439342006-09-12 10:42:26 +00001265 * means failure. A typical cause of failure is that
Linus Walleij545c7792006-06-13 15:22:30 +00001266 * the device does not support the battery level property.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001267 */
1268int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
1269 uint8_t * const maximum_level,
1270 uint8_t * const current_level)
1271{
Linus Walleijb02a0662006-04-25 08:05:09 +00001272 PTPPropertyValue propval;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001273 uint16_t ret;
Linus Walleij9b28da32006-03-16 13:47:58 +00001274 PTPParams *params = (PTPParams *) device->params;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001275
Linus Walleij545c7792006-06-13 15:22:30 +00001276 *maximum_level = 0;
1277 *current_level = 0;
1278
1279 if (!ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
1280 return -1;
1281 }
1282
Linus Walleijb02a0662006-04-25 08:05:09 +00001283 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel, &propval, PTP_DTC_UINT8);
1284 if (ret != PTP_RC_OK) {
Linus Walleijda9500d2006-08-30 13:17:06 +00001285 printf("LIBMTP_Get_Batterylevel(): could not get devcie property value.\n");
1286 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001287 return -1;
1288 }
1289
1290 *maximum_level = device->maximum_battery_level;
Linus Walleijb02a0662006-04-25 08:05:09 +00001291 *current_level = propval.u8;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001292
1293 return 0;
1294}
1295
1296/**
Linus Walleij545c7792006-06-13 15:22:30 +00001297 * Helper function to extract a unicode property off a device.
Linus Walleije46f12e2006-06-22 17:53:25 +00001298 * This is the standard way of retrieveing unicode device
1299 * properties as described by the PTP spec.
Linus Walleijcf223e62006-06-19 09:31:53 +00001300 * @param device a pointer to the device to get the property from.
1301 * @param unicstring a pointer to a pointer that will hold the
1302 * property after this call is completed.
1303 * @param property the property to retrieve.
1304 * @return 0 on success, any other value means failure.
Linus Walleij545c7792006-06-13 15:22:30 +00001305 */
Linus Walleijcf223e62006-06-19 09:31:53 +00001306static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
1307 char **unicstring, uint16_t property)
Linus Walleij545c7792006-06-13 15:22:30 +00001308{
1309 PTPPropertyValue propval;
1310 PTPParams *params = (PTPParams *) device->params;
Linus Walleij16571dc2006-08-17 20:27:46 +00001311 uint16_t *tmp;
Linus Walleij545c7792006-06-13 15:22:30 +00001312 int i;
1313
1314 if (!ptp_property_issupported(params, property)) {
1315 return -1;
1316 }
1317
Linus Walleijcf223e62006-06-19 09:31:53 +00001318 // Unicode strings are 16bit unsigned integer arrays.
Linus Walleij545c7792006-06-13 15:22:30 +00001319 if (ptp_getdevicepropvalue(params,
1320 property,
1321 &propval,
1322 PTP_DTC_AUINT16) != PTP_RC_OK) {
1323 return -1;
1324 }
1325
1326 // Extract the actual array.
Linus Walleij16571dc2006-08-17 20:27:46 +00001327 // printf("Array of %d elements\n", propval.a.count);
1328 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
Linus Walleij545c7792006-06-13 15:22:30 +00001329 for (i = 0; i < propval.a.count; i++) {
Linus Walleij16571dc2006-08-17 20:27:46 +00001330 tmp[i] = propval.a.v[i].u16;
1331 // printf("%04x ", tmp[i]);
Linus Walleij545c7792006-06-13 15:22:30 +00001332 }
Linus Walleij16571dc2006-08-17 20:27:46 +00001333 tmp[propval.a.count] = 0x0000U;
Linus Walleij545c7792006-06-13 15:22:30 +00001334 free(propval.a.v);
1335
Linus Walleij3ec86312006-08-21 13:25:24 +00001336 *unicstring = utf16_to_utf8(device, tmp);
Linus Walleij16571dc2006-08-17 20:27:46 +00001337
Linus Walleij545c7792006-06-13 15:22:30 +00001338 free(tmp);
1339
1340 return 0;
1341}
1342
1343/**
1344 * This function returns the secure time as an XML document string from
1345 * the device.
1346 * @param device a pointer to the device to get the secure time for.
1347 * @param sectime the secure time string as an XML document or NULL if the call
1348 * failed or the secure time property is not supported. This string
1349 * must be <code>free()</code>:ed by the caller after use.
1350 * @return 0 on success, any other value means failure.
1351 */
Linus Walleij8ab54262006-06-21 07:12:28 +00001352int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
Linus Walleij545c7792006-06-13 15:22:30 +00001353{
1354 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
1355}
1356
1357/**
1358 * This function returns the device (public key) certificate as an
1359 * XML document string from the device.
1360 * @param device a pointer to the device to get the device certificate for.
1361 * @param devcert the device certificate as an XML string or NULL if the call
1362 * failed or the device certificate property is not supported. This
1363 * string must be <code>free()</code>:ed by the caller after use.
1364 * @return 0 on success, any other value means failure.
1365 */
Linus Walleij8ab54262006-06-21 07:12:28 +00001366int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
Linus Walleij545c7792006-06-13 15:22:30 +00001367{
1368 return get_device_unicode_property(device, devcert, PTP_DPC_MTP_DeviceCertificate);
1369}
1370
1371/**
Linus Walleij8ab54262006-06-21 07:12:28 +00001372 * This function retrieves a list of supported file types, i.e. the file
1373 * types that this device claims it supports, e.g. audio file types that
1374 * the device can play etc. This list is mitigated to
1375 * inlcude the file types that libmtp can handle, i.e. it will not list
1376 * filetypes that libmtp will handle internally like playlists and folders.
1377 * @param device a pointer to the device to get the filetype capabilities for.
1378 * @param filetypes a pointer to a pointer that will hold the list of
1379 * supported filetypes if the call was successful. This list must
1380 * be <code>free()</code>:ed by the caller after use.
1381 * @param length a pointer to a variable that will hold the length of the
1382 * list of supported filetypes if the call was successful.
1383 * @return 0 on success, any other value means failure.
1384 * @see LIBMTP_Get_Filetype_Description()
1385 */
1386int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
1387 uint16_t * const length)
1388{
1389 PTPParams *params = (PTPParams *) device->params;
1390 uint16_t *localtypes;
1391 uint16_t localtypelen;
1392 uint32_t i;
1393
1394 // This is more memory than needed if there are unknown types, but what the heck.
1395 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
1396 localtypelen = 0;
1397
1398 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
1399 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
1400 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
1401 localtypes[localtypelen] = localtype;
1402 localtypelen++;
1403 }
1404 }
1405
1406 *filetypes = localtypes;
1407 *length = localtypelen;
1408
1409 return 0;
1410}
1411
1412
1413/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00001414 * This creates a new MTP object structure and allocates memory
raveloxd9a28642006-05-26 23:42:22 +00001415 * for it. Notice that if you add strings to this structure they
1416 * will be freed by the corresponding <code>LIBMTP_destroy_object_t</code>
1417 * operation later, so be careful of using strdup() when assigning
1418 * strings, e.g.:
1419 *
1420 * <pre>
1421 * LIBMTP_object_t *object = LIBMTP_new_object_t();
1422 * object->name = strdup(namestr);
1423 * ....
1424 * LIBMTP_destroy_object_t(file);
1425 * </pre>
1426 *
1427 * @return a pointer to the newly allocated structure.
1428 * @see LIBMTP_destroy_object_t()
1429 */
1430LIBMTP_object_t *LIBMTP_new_object_t(void)
1431{
1432 LIBMTP_object_t *new = (LIBMTP_object_t *) malloc(sizeof(LIBMTP_object_t));
1433 if (new == NULL) {
1434 return NULL;
1435 }
1436
1437 new->id = 0;
1438 new->parent = 0;
1439 new->type = LIBMTP_FILETYPE_UNKNOWN;
1440 new->size = 0;
1441 new->name = NULL;
1442 new->data = NULL;
1443 new->sibling = NULL;
1444 new->child = NULL;
1445
1446 return new;
1447}
Linus Walleijf0f3d482006-05-29 14:10:21 +00001448
raveloxd9a28642006-05-26 23:42:22 +00001449/**
Linus Walleijf6bc1782006-03-24 15:12:47 +00001450 * This creates a new file metadata structure and allocates memory
1451 * for it. Notice that if you add strings to this structure they
1452 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
1453 * operation later, so be careful of using strdup() when assigning
1454 * strings, e.g.:
1455 *
1456 * <pre>
1457 * LIBMTP_file_t *file = LIBMTP_new_file_t();
1458 * file->filename = strdup(namestr);
1459 * ....
1460 * LIBMTP_destroy_file_t(file);
1461 * </pre>
1462 *
1463 * @return a pointer to the newly allocated metadata structure.
1464 * @see LIBMTP_destroy_file_t()
1465 */
1466LIBMTP_file_t *LIBMTP_new_file_t(void)
1467{
1468 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
1469 if (new == NULL) {
1470 return NULL;
1471 }
1472 new->filename = NULL;
1473 new->filesize = 0;
1474 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
1475 new->next = NULL;
1476 return new;
1477}
1478
1479/**
1480 * This destroys a file metadata structure and deallocates the memory
1481 * used by it, including any strings. Never use a file metadata
1482 * structure again after calling this function on it.
1483 * @param file the file metadata to destroy.
1484 * @see LIBMTP_new_file_t()
1485 */
1486void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
1487{
1488 if (file == NULL) {
1489 return;
1490 }
1491 if (file->filename != NULL)
1492 free(file->filename);
1493 free(file);
1494 return;
1495}
1496
1497/**
1498 * This returns a long list of all files available
1499 * on the current MTP device. Typical usage:
1500 *
1501 * <pre>
1502 * LIBMTP_file_t *filelist;
1503 *
1504 * filelist = LIBMTP_Get_Filelisting(device);
1505 * while (filelist != NULL) {
1506 * LIBMTP_file_t *tmp;
1507 *
1508 * // Do something on each element in the list here...
1509 * tmp = filelist;
1510 * filelist = filelist->next;
1511 * LIBMTP_destroy_file_t(tmp);
1512 * }
1513 * </pre>
1514 *
1515 * @param device a pointer to the device to get the file listing for.
1516 * @return a list of files that can be followed using the <code>next</code>
1517 * field of the <code>LIBMTP_file_t</code> data structure.
1518 * Each of the metadata tags must be freed after use, and may
1519 * contain only partial metadata information, i.e. one or several
1520 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001521 * @see LIBMTP_Get_Filemetadata()
Linus Walleijf6bc1782006-03-24 15:12:47 +00001522 */
1523LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
1524{
1525 uint32_t i = 0;
1526 LIBMTP_file_t *retfiles = NULL;
1527 LIBMTP_file_t *curfile = NULL;
1528 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001529
1530 // Get all the handles if we haven't already done that
Linus Walleijf6bc1782006-03-24 15:12:47 +00001531 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00001532 flush_handles(device);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001533 }
1534
1535 for (i = 0; i < params->handles.n; i++) {
1536
1537 LIBMTP_file_t *file;
1538 PTPObjectInfo oi;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001539
1540 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleij16c51f02006-05-04 13:20:22 +00001541
Linus Walleij91405592006-05-05 14:22:51 +00001542 if (oi.ObjectFormat == PTP_OFC_Association) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00001543 // MTP use thesis object format for folders which means
Linus Walleij16c51f02006-05-04 13:20:22 +00001544 // these "files" will turn up on a folder listing instead.
1545 continue;
1546 }
1547
Linus Walleijf6bc1782006-03-24 15:12:47 +00001548 // Allocate a new file type
1549 file = LIBMTP_new_file_t();
Linus Walleijb02a0662006-04-25 08:05:09 +00001550
Linus Walleijd208f9c2006-04-27 14:16:06 +00001551 file->parent_id = oi.ParentObject;
Linus Walleij16c51f02006-05-04 13:20:22 +00001552
1553 // Set the filetype
1554 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001555
1556 // Original file-specific properties
1557 file->filesize = oi.ObjectCompressedSize;
1558 if (oi.Filename != NULL) {
1559 file->filename = strdup(oi.Filename);
1560 }
1561
1562 // This is some sort of unique ID so we can keep track of the track.
1563 file->item_id = params->handles.Handler[i];
1564
1565 // Add track to a list that will be returned afterwards.
1566 if (retfiles == NULL) {
1567 retfiles = file;
1568 curfile = file;
1569 } else {
1570 curfile->next = file;
1571 curfile = file;
1572 }
1573
1574 // Call listing callback
1575 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
1576
1577 } else {
1578 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
1579 }
1580
1581 } // Handle counting loop
1582 return retfiles;
1583}
1584
1585/**
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001586 * This function retrieves the metadata for a single file off
1587 * the device.
1588 *
1589 * Do not call this function repeatedly! The file handles are linearly
1590 * searched O(n) and the call may involve (slow) USB traffic, so use
1591 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
1592 * as an efficient data structure such as a hash list.
1593 *
1594 * @param device a pointer to the device to get the file metadata from.
1595 * @param fileid the object ID of the file that you want the metadata for.
1596 * @return a metadata entry on success or NULL on failure.
1597 * @see LIBMTP_Get_Filelisting()
1598 */
1599LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
1600{
1601 uint32_t i = 0;
1602 PTPParams *params = (PTPParams *) device->params;
1603
1604 // Get all the handles if we haven't already done that
1605 if (params->handles.Handler == NULL) {
1606 flush_handles(device);
1607 }
1608
1609 for (i = 0; i < params->handles.n; i++) {
1610 LIBMTP_file_t *file;
1611 PTPObjectInfo oi;
1612
1613 // Is this the file we're looking for?
1614 if (params->handles.Handler[i] != fileid) {
1615 continue;
1616 }
1617
1618 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
1619
1620 if (oi.ObjectFormat == PTP_OFC_Association) {
1621 // MTP use thesis object format for folders which means
1622 // these "files" will turn up on a folder listing instead.
1623 return NULL;
1624 }
1625
1626 // Allocate a new file type
1627 file = LIBMTP_new_file_t();
1628
1629 file->parent_id = oi.ParentObject;
1630
1631 // Set the filetype
1632 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
1633
1634 // Original file-specific properties
1635 file->filesize = oi.ObjectCompressedSize;
1636 if (oi.Filename != NULL) {
1637 file->filename = strdup(oi.Filename);
1638 }
1639
1640 // This is some sort of unique ID so we can keep track of the track.
1641 file->item_id = params->handles.Handler[i];
1642
1643 return file;
1644 } else {
1645 return NULL;
1646 }
1647
1648 }
1649 return NULL;
1650}
1651
1652/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00001653 * This creates a new track metadata structure and allocates memory
1654 * for it. Notice that if you add strings to this structure they
1655 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
1656 * operation later, so be careful of using strdup() when assigning
1657 * strings, e.g.:
1658 *
Linus Walleij17e39f72006-02-23 15:54:28 +00001659 * <pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001660 * LIBMTP_track_t *track = LIBMTP_new_track_t();
1661 * track->title = strdup(titlestr);
1662 * ....
1663 * LIBMTP_destroy_track_t(track);
Linus Walleij17e39f72006-02-23 15:54:28 +00001664 * </pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001665 *
1666 * @return a pointer to the newly allocated metadata structure.
1667 * @see LIBMTP_destroy_track_t()
1668 */
1669LIBMTP_track_t *LIBMTP_new_track_t(void)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001670{
1671 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
1672 if (new == NULL) {
1673 return NULL;
1674 }
1675 new->title = NULL;
1676 new->artist = NULL;
1677 new->album = NULL;
1678 new->genre = NULL;
1679 new->date = NULL;
1680 new->filename = NULL;
1681 new->duration = 0;
1682 new->tracknumber = 0;
1683 new->filesize = 0;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001684 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
Linus Walleijcf223e62006-06-19 09:31:53 +00001685 new->samplerate = 0;
1686 new->nochannels = 0;
1687 new->wavecodec = 0;
1688 new->bitrate = 0;
1689 new->bitratetype = 0;
1690 new->rating = 0;
1691 new->usecount = 0;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001692 new->next = NULL;
1693 return new;
1694}
1695
Linus Walleij394bbbe2006-02-22 16:10:53 +00001696/**
1697 * This destroys a track metadata structure and deallocates the memory
1698 * used by it, including any strings. Never use a track metadata
1699 * structure again after calling this function on it.
1700 * @param track the track metadata to destroy.
1701 * @see LIBMTP_new_track_t()
1702 */
Linus Walleijb9256fd2006-02-15 09:40:43 +00001703void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
1704{
1705 if (track == NULL) {
1706 return;
1707 }
1708 if (track->title != NULL)
1709 free(track->title);
1710 if (track->artist != NULL)
1711 free(track->artist);
1712 if (track->album != NULL)
1713 free(track->album);
1714 if (track->genre != NULL)
1715 free(track->genre);
1716 if (track->date != NULL)
1717 free(track->date);
1718 if (track->filename != NULL)
1719 free(track->filename);
1720 free(track);
1721 return;
1722}
1723
1724/**
Linus Walleij8ab54262006-06-21 07:12:28 +00001725 * This function retrieves the track metadata for a track
1726 * given by a unique ID.
1727 * @param device a pointer to the device to get the track metadata off.
1728 * @param trackid the unique ID of the track.
1729 * @param objectformat the object format of this track, so we know what it supports.
1730 * @param track a metadata set to fill in.
1731 */
1732static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
1733 LIBMTP_track_t *track)
1734{
Linus Walleij00cf0642006-07-26 20:40:59 +00001735 uint16_t ret;
1736 PTPParams *params = (PTPParams *) device->params;
1737 uint32_t i;
1738 uint16_t *props = NULL;
1739 uint32_t propcnt = 0;
1740
1741 // First see which properties can be retrieved for this object format
1742 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
1743 if (ret != PTP_RC_OK) {
1744 // Just bail out for now, nothing is ever set.
1745 return;
1746 } else {
1747 for (i=0;i<propcnt;i++) {
1748 switch (props[i]) {
1749 case PTP_OPC_Name:
Linus Walleija823a702006-08-27 21:27:46 +00001750 track->title = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Name);
Linus Walleij00cf0642006-07-26 20:40:59 +00001751 break;
1752 case PTP_OPC_Artist:
Linus Walleija823a702006-08-27 21:27:46 +00001753 track->artist = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Artist);
Linus Walleij00cf0642006-07-26 20:40:59 +00001754 break;
1755 case PTP_OPC_Duration:
1756 track->duration = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_Duration, 0);
1757 break;
1758 case PTP_OPC_Track:
1759 track->tracknumber = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_Track, 0);
1760 break;
1761 case PTP_OPC_Genre:
Linus Walleija823a702006-08-27 21:27:46 +00001762 track->genre = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Genre);
Linus Walleij00cf0642006-07-26 20:40:59 +00001763 break;
1764 case PTP_OPC_AlbumName:
Linus Walleija823a702006-08-27 21:27:46 +00001765 track->album = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_AlbumName);
Linus Walleij00cf0642006-07-26 20:40:59 +00001766 break;
1767 case PTP_OPC_OriginalReleaseDate:
Linus Walleija823a702006-08-27 21:27:46 +00001768 track->date = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
Linus Walleij00cf0642006-07-26 20:40:59 +00001769 break;
1770 // These are, well not so important.
1771 case PTP_OPC_SampleRate:
1772 track->samplerate = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_SampleRate, 0);
1773 break;
1774 case PTP_OPC_NumberOfChannels:
1775 track->nochannels = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
1776 break;
1777 case PTP_OPC_AudioWAVECodec:
1778 track->wavecodec = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
1779 break;
1780 case PTP_OPC_AudioBitRate:
1781 track->bitrate = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
1782 break;
1783 case PTP_OPC_BitRateType:
1784 track->bitratetype = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_BitRateType, 0);
1785 break;
1786 case PTP_OPC_Rating:
1787 track->rating = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_Rating, 0);
1788 break;
1789 case PTP_OPC_UseCount:
1790 track->usecount = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_UseCount, 0);
1791 break;
1792 }
1793 }
1794 free(props);
1795 }
Linus Walleij8ab54262006-06-21 07:12:28 +00001796}
1797
1798/**
Linus Walleijb9256fd2006-02-15 09:40:43 +00001799 * This returns a long list of all tracks available
Linus Walleija4982732006-02-24 15:46:02 +00001800 * on the current MTP device. Typical usage:
1801 *
1802 * <pre>
1803 * LIBMTP_track_t *tracklist;
1804 *
1805 * tracklist = LIBMTP_Get_Tracklisting(device);
1806 * while (tracklist != NULL) {
1807 * LIBMTP_track_t *tmp;
1808 *
1809 * // Do something on each element in the list here...
1810 * tmp = tracklist;
1811 * tracklist = tracklist->next;
1812 * LIBMTP_destroy_track_t(tmp);
1813 * }
1814 * </pre>
1815 *
Linus Walleijb9256fd2006-02-15 09:40:43 +00001816 * @param device a pointer to the device to get the track listing for.
Linus Walleija4982732006-02-24 15:46:02 +00001817 * @return a list of tracks that can be followed using the <code>next</code>
1818 * field of the <code>LIBMTP_track_t</code> data structure.
1819 * Each of the metadata tags must be freed after use, and may
1820 * contain only partial metadata information, i.e. one or several
1821 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001822 * @see LIBMTP_Get_Trackmetadata()
Linus Walleijb9256fd2006-02-15 09:40:43 +00001823 */
1824LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
1825{
1826 uint32_t i = 0;
1827 LIBMTP_track_t *retracks = NULL;
1828 LIBMTP_track_t *curtrack = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001829 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001830
1831 // Get all the handles if we haven't already done that
Linus Walleij9b28da32006-03-16 13:47:58 +00001832 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00001833 flush_handles(device);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001834 }
1835
Linus Walleij9b28da32006-03-16 13:47:58 +00001836 for (i = 0; i < params->handles.n; i++) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001837 LIBMTP_track_t *track;
1838 PTPObjectInfo oi;
Linus Walleij5acfa742006-05-29 14:51:59 +00001839
Linus Walleij9b28da32006-03-16 13:47:58 +00001840 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001841
1842 // Ignore stuff we don't know how to handle...
Linus Walleij8ab54262006-06-21 07:12:28 +00001843 // TODO: get this list as an intersection of the sets
1844 // supported by the device and the from the device and
1845 // all known audio track files?
Linus Walleij9c6ca022006-04-21 10:24:15 +00001846 if ( oi.ObjectFormat != PTP_OFC_WAV &&
Linus Walleijb9256fd2006-02-15 09:40:43 +00001847 oi.ObjectFormat != PTP_OFC_MP3 &&
Linus Walleij9c6ca022006-04-21 10:24:15 +00001848 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
1849 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
1850 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
1851 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
Linus Walleijafe61432006-05-05 13:51:34 +00001852 // printf("Not a music track (format: %d), skipping...\n",oi.ObjectFormat);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001853 continue;
1854 }
1855
1856 // Allocate a new track type
1857 track = LIBMTP_new_track_t();
Linus Walleij8ab54262006-06-21 07:12:28 +00001858
1859 // This is some sort of unique ID so we can keep track of the track.
1860 track->item_id = params->handles.Handler[i];
Linus Walleij5acfa742006-05-29 14:51:59 +00001861
Linus Walleij16c51f02006-05-04 13:20:22 +00001862 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
Linus Walleij5acfa742006-05-29 14:51:59 +00001863
Linus Walleijb9256fd2006-02-15 09:40:43 +00001864 // Original file-specific properties
1865 track->filesize = oi.ObjectCompressedSize;
1866 if (oi.Filename != NULL) {
1867 track->filename = strdup(oi.Filename);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001868 }
Linus Walleij8ab54262006-06-21 07:12:28 +00001869
1870 get_track_metadata(device, oi.ObjectFormat, track);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001871
1872 // Add track to a list that will be returned afterwards.
1873 if (retracks == NULL) {
1874 retracks = track;
1875 curtrack = track;
1876 } else {
1877 curtrack->next = track;
1878 curtrack = track;
1879 }
1880
1881 // Call listing callback
Linus Walleij9b28da32006-03-16 13:47:58 +00001882 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001883
1884 } else {
1885 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
1886 }
1887
1888 } // Handle counting loop
1889 return retracks;
1890}
Linus Walleijdcde6082006-02-17 16:16:34 +00001891
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001892/**
1893 * This function retrieves the metadata for a single track off
1894 * the device.
1895 *
1896 * Do not call this function repeatedly! The track handles are linearly
1897 * searched O(n) and the call may involve (slow) USB traffic, so use
1898 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
1899 * as an efficient data structure such as a hash list.
1900 *
1901 * @param device a pointer to the device to get the track metadata from.
1902 * @param trackid the object ID of the track that you want the metadata for.
1903 * @return a track metadata entry on success or NULL on failure.
1904 * @see LIBMTP_Get_Tracklisting()
1905 */
1906LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
1907{
1908 uint32_t i = 0;
1909 PTPParams *params = (PTPParams *) device->params;
1910
1911 // Get all the handles if we haven't already done that
1912 if (params->handles.Handler == NULL) {
1913 flush_handles(device);
1914 }
1915
1916 for (i = 0; i < params->handles.n; i++) {
1917 PTPObjectInfo oi;
1918
1919 // Skip if this is not the track we want.
1920 if (params->handles.Handler[i] != trackid) {
1921 continue;
1922 }
1923
1924 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
1925 LIBMTP_track_t *track;
1926
1927 // Ignore stuff we don't know how to handle...
1928 if ( oi.ObjectFormat != PTP_OFC_WAV &&
1929 oi.ObjectFormat != PTP_OFC_MP3 &&
1930 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
1931 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
1932 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
1933 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
1934 return NULL;
1935 }
1936
1937 // Allocate a new track type
1938 track = LIBMTP_new_track_t();
Linus Walleij8ab54262006-06-21 07:12:28 +00001939
1940 // This is some sort of unique ID so we can keep track of the track.
1941 track->item_id = params->handles.Handler[i];
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001942
1943 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
1944
1945 // Original file-specific properties
1946 track->filesize = oi.ObjectCompressedSize;
1947 if (oi.Filename != NULL) {
1948 track->filename = strdup(oi.Filename);
1949 }
Linus Walleij8ab54262006-06-21 07:12:28 +00001950
1951 get_track_metadata(device, oi.ObjectFormat, track);
1952
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001953 return track;
1954
1955 } else {
1956 return NULL;
1957 }
1958
1959 }
1960 return NULL;
1961}
1962
Linus Walleijf6bc1782006-03-24 15:12:47 +00001963
1964/**
1965 * This gets a file off the device to a local file identified
1966 * by a filename.
1967 * @param device a pointer to the device to get the track from.
1968 * @param id the file ID of the file to retrieve.
1969 * @param path a filename to use for the retrieved file.
1970 * @param callback a progress indicator function or NULL to ignore.
1971 * @param data a user-defined pointer that is passed along to
1972 * the <code>progress</code> function in order to
1973 * pass along some user defined data to the progress
1974 * updates. If not used, set this to NULL.
1975 * @return 0 if the transfer was successful, any other value means
1976 * failure.
1977 * @see LIBMTP_Get_File_To_File_Descriptor()
1978 */
1979int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
Linus Walleijee73ef22006-08-27 19:56:00 +00001980 char const * const path, LIBMTP_progressfunc_t const callback,
Linus Walleijf6bc1782006-03-24 15:12:47 +00001981 void const * const data)
1982{
1983 int fd = -1;
1984 int ret;
1985
1986 // Sanity check
1987 if (path == NULL) {
1988 printf("LIBMTP_Get_File_To_File(): Bad arguments, path was NULL\n");
1989 return -1;
1990 }
1991
1992 // Open file
1993#ifdef __WIN32__
flavienbfd80eb2006-06-01 22:41:49 +00001994 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU|S_IRGRP)) == -1 ) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001995#else
1996 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
1997#endif
1998 printf("LIBMTP_Get_File_To_File(): Could not create file \"%s\"\n", path);
1999 return -1;
2000 }
2001
2002 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
2003
2004 // Close file
2005 close(fd);
2006
2007 return ret;
2008}
2009
2010/**
2011 * This gets a file off the device to a file identified
2012 * by a file descriptor.
Linus Walleij0558ac52006-09-07 06:55:03 +00002013 *
2014 * This function can potentially be used for streaming
2015 * files off the device for playback or broadcast for example,
2016 * by downloading the file into a stream sink e.g. a socket.
2017 *
Linus Walleijf6bc1782006-03-24 15:12:47 +00002018 * @param device a pointer to the device to get the file from.
2019 * @param id the file ID of the file to retrieve.
2020 * @param fd a local file descriptor to write the file to.
2021 * @param callback a progress indicator function or NULL to ignore.
2022 * @param data a user-defined pointer that is passed along to
2023 * the <code>progress</code> function in order to
2024 * pass along some user defined data to the progress
2025 * updates. If not used, set this to NULL.
2026 * @return 0 if the transfer was successful, any other value means
2027 * failure.
2028 * @see LIBMTP_Get_File_To_File()
2029 */
2030int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
2031 uint32_t const id,
2032 int const fd,
Linus Walleijee73ef22006-08-27 19:56:00 +00002033 LIBMTP_progressfunc_t const callback,
Linus Walleijf6bc1782006-03-24 15:12:47 +00002034 void const * const data)
2035{
2036 PTPObjectInfo oi;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002037 uint16_t ret;
Linus Walleijf6bc1782006-03-24 15:12:47 +00002038 PTPParams *params = (PTPParams *) device->params;
Linus Walleijee73ef22006-08-27 19:56:00 +00002039 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleijf6bc1782006-03-24 15:12:47 +00002040
Linus Walleijf6bc1782006-03-24 15:12:47 +00002041 if (ptp_getobjectinfo(params, id, &oi) != PTP_RC_OK) {
2042 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get object info\n");
2043 return -1;
2044 }
2045 if (oi.ObjectFormat == PTP_OFC_Association) {
2046 printf("LIBMTP_Get_File_To_File_Descriptor(): Bad object format\n");
2047 return -1;
2048 }
Linus Walleijf6bc1782006-03-24 15:12:47 +00002049
Linus Walleijee73ef22006-08-27 19:56:00 +00002050 // Callbacks
2051 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002052 ptp_usb->current_transfer_total = oi.ObjectCompressedSize+
2053 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
Linus Walleijee73ef22006-08-27 19:56:00 +00002054 ptp_usb->current_transfer_complete = 0;
2055 ptp_usb->current_transfer_callback = callback;
2056 ptp_usb->current_transfer_callback_data = data;
2057
Linus Walleij96c62432006-08-21 10:04:02 +00002058 // This now exist in upstream
2059 ret = ptp_getobject_tofd(params, id, fd);
Linus Walleijee73ef22006-08-27 19:56:00 +00002060
2061 ptp_usb->callback_active = 0;
2062 ptp_usb->current_transfer_callback = NULL;
2063 ptp_usb->current_transfer_callback_data = NULL;
Linus Walleijc3ea3e52006-08-20 22:13:32 +00002064
Linus Walleijb02a0662006-04-25 08:05:09 +00002065 if (ret != PTP_RC_OK) {
2066 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device (%d)\n", ret);
Linus Walleijf6bc1782006-03-24 15:12:47 +00002067 return -1;
2068 }
Linus Walleijc3ea3e52006-08-20 22:13:32 +00002069
Linus Walleijf6bc1782006-03-24 15:12:47 +00002070 return 0;
2071}
2072
Linus Walleijdcde6082006-02-17 16:16:34 +00002073/**
2074 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00002075 * by a filename. This is actually just a wrapper for the
2076 * \c LIBMTP_Get_Track_To_File() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00002077 * @param device a pointer to the device to get the track from.
2078 * @param id the track ID of the track to retrieve.
2079 * @param path a filename to use for the retrieved track.
2080 * @param callback a progress indicator function or NULL to ignore.
2081 * @param data a user-defined pointer that is passed along to
2082 * the <code>progress</code> function in order to
2083 * pass along some user defined data to the progress
2084 * updates. If not used, set this to NULL.
2085 * @return 0 if the transfer was successful, any other value means
2086 * failure.
2087 * @see LIBMTP_Get_Track_To_File_Descriptor()
2088 */
Linus Walleij0cd85432006-02-20 14:37:50 +00002089int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
Linus Walleijee73ef22006-08-27 19:56:00 +00002090 char const * const path, LIBMTP_progressfunc_t const callback,
Linus Walleij0cd85432006-02-20 14:37:50 +00002091 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00002092{
Linus Walleijf6bc1782006-03-24 15:12:47 +00002093 // This is just a wrapper
2094 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00002095}
2096
2097/**
2098 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00002099 * by a file descriptor. This is actually just a wrapper for
2100 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00002101 * @param device a pointer to the device to get the track from.
2102 * @param id the track ID of the track to retrieve.
2103 * @param fd a file descriptor to write the track to.
2104 * @param callback a progress indicator function or NULL to ignore.
2105 * @param data a user-defined pointer that is passed along to
2106 * the <code>progress</code> function in order to
2107 * pass along some user defined data to the progress
2108 * updates. If not used, set this to NULL.
2109 * @return 0 if the transfer was successful, any other value means
2110 * failure.
2111 * @see LIBMTP_Get_Track_To_File()
2112 */
2113int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
Linus Walleij0cd85432006-02-20 14:37:50 +00002114 uint32_t const id,
2115 int const fd,
Linus Walleijee73ef22006-08-27 19:56:00 +00002116 LIBMTP_progressfunc_t const callback,
Linus Walleij0cd85432006-02-20 14:37:50 +00002117 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00002118{
Linus Walleijf6bc1782006-03-24 15:12:47 +00002119 // This is just a wrapper
2120 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00002121}
Linus Walleij394bbbe2006-02-22 16:10:53 +00002122
2123/**
2124 * This function sends a track from a local file to an
2125 * MTP device. A filename and a set of metadata must be
2126 * given as input.
2127 * @param device a pointer to the device to send the track to.
2128 * @param path the filename of a local file which will be sent.
2129 * @param metadata a track metadata set to be written along with the file.
2130 * @param callback a progress indicator function or NULL to ignore.
2131 * @param data a user-defined pointer that is passed along to
2132 * the <code>progress</code> function in order to
2133 * pass along some user defined data to the progress
2134 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002135 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002136 * in. Since some devices are a bit picky about where files
2137 * are placed, a default folder will be chosen if libmtp
2138 * has detected one for the current filetype and this
2139 * parameter is set to 0. If this is 0 and no default folder
2140 * can be found, the file will be stored in the root folder.
Linus Walleij394bbbe2006-02-22 16:10:53 +00002141 * @return 0 if the transfer was successful, any other value means
2142 * failure.
2143 * @see LIBMTP_Send_Track_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002144 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002145 */
2146int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
2147 char const * const path, LIBMTP_track_t * const metadata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002148 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002149 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002150{
2151 int fd;
2152 int ret;
2153
2154 // Sanity check
2155 if (path == NULL) {
2156 printf("LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL\n");
2157 return -1;
2158 }
2159
2160 // Open file
2161#ifdef __WIN32__
2162 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2163#else
2164 if ( (fd = open(path, O_RDONLY)) == -1) {
2165#endif
Linus Walleijd6a49972006-05-02 08:24:54 +00002166 printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002167 return -1;
2168 }
2169
Linus Walleijd6a49972006-05-02 08:24:54 +00002170 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data, parenthandle);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002171
2172 // Close file.
2173 close(fd);
2174
2175 return ret;
2176}
2177
Linus Walleijfa1374c2006-02-27 07:41:46 +00002178
2179/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00002180 * This function sends a track from a file descriptor to an
2181 * MTP device. A filename and a set of metadata must be
2182 * given as input.
2183 * @param device a pointer to the device to send the track to.
2184 * @param fd the filedescriptor for a local file which will be sent.
2185 * @param metadata a track metadata set to be written along with the file.
2186 * After this call the field <code>item_id</code>
2187 * will contain the new track ID.
2188 * @param callback a progress indicator function or NULL to ignore.
2189 * @param data a user-defined pointer that is passed along to
2190 * the <code>progress</code> function in order to
2191 * pass along some user defined data to the progress
2192 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002193 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002194 * in. Since some devices are a bit picky about where files
2195 * are placed, a default folder will be chosen if libmtp
2196 * has detected one for the current filetype and this
2197 * parameter is set to 0. If this is 0 and no default folder
2198 * can be found, the file will be stored in the root folder.
Linus Walleij394bbbe2006-02-22 16:10:53 +00002199 * @return 0 if the transfer was successful, any other value means
2200 * failure.
2201 * @see LIBMTP_Send_Track_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002202 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002203 */
2204int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
2205 int const fd, LIBMTP_track_t * const metadata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002206 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002207 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002208{
Linus Walleij394bbbe2006-02-22 16:10:53 +00002209 uint16_t ret;
2210 uint32_t store = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002211 int subcall_ret;
Linus Walleij394bbbe2006-02-22 16:10:53 +00002212 PTPObjectInfo new_track;
Linus Walleij9b28da32006-03-16 13:47:58 +00002213 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd6a49972006-05-02 08:24:54 +00002214 uint32_t localph = parenthandle;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002215 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij16c51f02006-05-04 13:20:22 +00002216
Linus Walleij05ccbe72006-06-13 07:46:58 +00002217 if (localph == 0) {
2218 localph = device->default_music_folder;
2219 }
2220
Linus Walleij16c51f02006-05-04 13:20:22 +00002221 // Sanity check, is this really a track?
2222 if (metadata->filetype != LIBMTP_FILETYPE_WAV &&
2223 metadata->filetype != LIBMTP_FILETYPE_MP3 &&
2224 metadata->filetype != LIBMTP_FILETYPE_WMA &&
2225 metadata->filetype != LIBMTP_FILETYPE_OGG &&
2226 metadata->filetype != LIBMTP_FILETYPE_MP4 &&
2227 metadata->filetype != LIBMTP_FILETYPE_UNDEF_AUDIO) {
2228 printf("LIBMTP_Send_Track_From_File_Descriptor: I don't think this is actually a track, strange filetype...\n");
Linus Walleij394bbbe2006-02-22 16:10:53 +00002229 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002230
Linus Walleij394bbbe2006-02-22 16:10:53 +00002231 new_track.Filename = metadata->filename;
2232 new_track.ObjectCompressedSize = metadata->filesize;
Linus Walleijab1827c2006-06-01 20:17:11 +00002233 new_track.ObjectFormat = map_libmtp_type_to_ptp_type(metadata->filetype);
Linus Walleijfcf88912006-06-05 13:23:33 +00002234
Linus Walleij394bbbe2006-02-22 16:10:53 +00002235 // Create the object
Linus Walleijd6a49972006-05-02 08:24:54 +00002236 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->item_id, &new_track);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002237 if (ret != PTP_RC_OK) {
Linus Walleij9b28da32006-03-16 13:47:58 +00002238 ptp_perror(params, ret);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002239 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object info\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00002240 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002241 return -1;
2242 }
2243
Linus Walleijee73ef22006-08-27 19:56:00 +00002244 // Callbacks
Linus Walleijd214b9b2006-08-26 22:08:37 +00002245 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002246 // The callback will deactivate itself after this amount of data has been sent
2247 // One BULK header for the request, one for the data phase. No parameters to the request.
2248 ptp_usb->current_transfer_total = metadata->filesize+PTP_USB_BULK_HDR_LEN*2;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002249 ptp_usb->current_transfer_complete = 0;
2250 ptp_usb->current_transfer_callback = callback;
2251 ptp_usb->current_transfer_callback_data = data;
2252
Linus Walleije7f44be2006-08-25 19:32:29 +00002253 ret = ptp_sendobject_fromfd(params, fd, metadata->filesize);
Linus Walleijee73ef22006-08-27 19:56:00 +00002254
2255 ptp_usb->callback_active = 0;
2256 ptp_usb->current_transfer_callback = NULL;
2257 ptp_usb->current_transfer_callback_data = NULL;
2258
Linus Walleije7f44be2006-08-25 19:32:29 +00002259 if (ret != PTP_RC_OK) {
2260 ptp_perror(params, ret);
2261 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object\n");
Linus Walleij394bbbe2006-02-22 16:10:53 +00002262 return -1;
2263 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002264
Linus Walleij17e39f72006-02-23 15:54:28 +00002265 // Set track metadata for the new fine track
2266 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
2267 if (subcall_ret != 0) {
2268 printf("LIBMTP_Send_Track_From_File_Descriptor: error setting metadata for new track\n");
Linus Walleij438bd7f2006-06-08 11:35:44 +00002269 (void) LIBMTP_Delete_Object(device, metadata->item_id);
Linus Walleij17e39f72006-02-23 15:54:28 +00002270 return -1;
2271 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002272
2273 // Added object so flush handles
2274 flush_handles(device);
Linus Walleij17e39f72006-02-23 15:54:28 +00002275
2276 return 0;
2277}
2278
Linus Walleijd6a49972006-05-02 08:24:54 +00002279/**
2280 * This function sends a local file to an MTP device.
2281 * A filename and a set of metadata must be
2282 * given as input.
2283 * @param device a pointer to the device to send the track to.
2284 * @param path the filename of a local file which will be sent.
2285 * @param filedata a file strtuct to pass in info about the file.
2286 * After this call the field <code>item_id</code>
2287 * will contain the new file ID.
2288 * @param callback a progress indicator function or NULL to ignore.
2289 * @param data a user-defined pointer that is passed along to
2290 * the <code>progress</code> function in order to
2291 * pass along some user defined data to the progress
2292 * updates. If not used, set this to NULL.
2293 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002294 * in. Since some devices are a bit picky about where files
2295 * are placed, a default folder will be chosen if libmtp
2296 * has detected one for the current filetype and this
2297 * parameter is set to 0. If this is 0 and no default folder
2298 * can be found, the file will be stored in the root folder.
Linus Walleijd6a49972006-05-02 08:24:54 +00002299 * @return 0 if the transfer was successful, any other value means
2300 * failure.
2301 * @see LIBMTP_Send_File_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002302 * @see LIBMTP_Delete_Object()
Linus Walleijd6a49972006-05-02 08:24:54 +00002303 */
2304int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
2305 char const * const path, LIBMTP_file_t * const filedata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002306 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002307 void const * const data, uint32_t const parenthandle)
2308{
2309 int fd;
2310 int ret;
2311
2312 // Sanity check
2313 if (path == NULL) {
2314 printf("LIBMTP_Send_File_From_File(): Bad arguments, path was NULL\n");
2315 return -1;
2316 }
2317
2318 // Open file
2319#ifdef __WIN32__
2320 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2321#else
2322 if ( (fd = open(path, O_RDONLY)) == -1) {
2323#endif
2324 printf("LIBMTP_Send_File_From_File(): Could not open source file \"%s\"\n", path);
2325 return -1;
2326 }
2327
2328 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data, parenthandle);
2329
2330 // Close file.
2331 close(fd);
2332
2333 return ret;
2334}
2335
Linus Walleijd208f9c2006-04-27 14:16:06 +00002336/**
2337 * This function sends a generic file from a file descriptor to an
2338 * MTP device. A filename and a set of metadata must be
2339 * given as input.
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002340 *
2341 * This can potentially be used for sending in a stream of unknown
2342 * length. Set <code>filedata->filesize = (uint64_t) -1</code> to
2343 * make libmtp send some dummy length to the device and just
2344 * accept a stream up to some device-determined max length. There
2345 * is not guarantee this will work on all devices... Remember to
2346 * set correct metadata for the track with
2347 * <code>LIBMTP_Update_Track_Metadata()</code> afterwards if it's
2348 * a music file. (This doesn't seem to work very well right now.)
2349 *
Linus Walleijd208f9c2006-04-27 14:16:06 +00002350 * @param device a pointer to the device to send the file to.
2351 * @param fd the filedescriptor for a local file which will be sent.
Linus Walleijd6a49972006-05-02 08:24:54 +00002352 * @param filedata a file strtuct to pass in info about the file.
Linus Walleijd208f9c2006-04-27 14:16:06 +00002353 * After this call the field <code>item_id</code>
2354 * will contain the new track ID.
2355 * @param callback a progress indicator function or NULL to ignore.
2356 * @param data a user-defined pointer that is passed along to
2357 * the <code>progress</code> function in order to
2358 * pass along some user defined data to the progress
2359 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002360 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002361 * in. Since some devices are a bit picky about where files
2362 * are placed, a default folder will be chosen if libmtp
2363 * has detected one for the current filetype and this
2364 * parameter is set to 0. If this is 0 and no default folder
2365 * can be found, the file will be stored in the root folder.
Linus Walleijd208f9c2006-04-27 14:16:06 +00002366 * @return 0 if the transfer was successful, any other value means
2367 * failure.
Linus Walleijd6a49972006-05-02 08:24:54 +00002368 * @see LIBMTP_Send_File_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002369 * @see LIBMTP_Delete_Object()
Linus Walleijd208f9c2006-04-27 14:16:06 +00002370 */
2371int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
2372 int const fd, LIBMTP_file_t * const filedata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002373 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002374 void const * const data, uint32_t const parenthandle)
Linus Walleijd208f9c2006-04-27 14:16:06 +00002375{
2376 uint16_t ret;
2377 uint32_t store = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +00002378 uint32_t localph = parenthandle;
Linus Walleijd208f9c2006-04-27 14:16:06 +00002379 PTPObjectInfo new_file;
2380 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002381 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij05ccbe72006-06-13 07:46:58 +00002382
Linus Walleijd208f9c2006-04-27 14:16:06 +00002383 new_file.Filename = filedata->filename;
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002384 if (filedata->filesize == (uint64_t) -1) {
2385 // This is a stream. Set a dummy length...
2386 new_file.ObjectCompressedSize = 1;
2387 } else {
2388 new_file.ObjectCompressedSize = filedata->filesize;
2389 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002390 new_file.ObjectFormat = map_libmtp_type_to_ptp_type(filedata->filetype);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002391
Linus Walleij05ccbe72006-06-13 07:46:58 +00002392 /*
2393 * If no destination folder was given, look up a default
2394 * folder if possible. Perhaps there is some way of retrieveing
2395 * the default folder for different forms of content, what
2396 * do I know, we use a fixed list in lack of any better method.
2397 * Some devices obviously need to have their files in certain
2398 * folders in order to find/display them at all (hello Creative),
2399 * so we have to have a method for this.
2400 */
2401
2402 if (localph == 0) {
2403 uint16_t of = new_file.ObjectFormat;
2404 if (of == PTP_OFC_WAV ||
2405 of == PTP_OFC_MP3 ||
2406 of == PTP_OFC_MTP_WMA ||
2407 of == PTP_OFC_MTP_OGG ||
2408 of == PTP_OFC_MTP_MP4 ||
2409 of == PTP_OFC_MTP_UndefinedAudio) {
2410 localph = device->default_music_folder;
2411 } else if (of == PTP_OFC_MTP_WMV ||
2412 of == PTP_OFC_AVI ||
2413 of == PTP_OFC_MPEG ||
2414 of == PTP_OFC_ASF ||
2415 of == PTP_OFC_QT ||
2416 of == PTP_OFC_MTP_UndefinedVideo) {
2417 localph = device->default_video_folder;
2418 } else if (of == PTP_OFC_EXIF_JPEG ||
2419 of == PTP_OFC_JFIF ||
2420 of == PTP_OFC_TIFF ||
2421 of == PTP_OFC_BMP ||
2422 of == PTP_OFC_GIF ||
2423 of == PTP_OFC_PICT ||
2424 of == PTP_OFC_PNG ||
2425 of == PTP_OFC_MTP_WindowsImageFormat) {
2426 localph = device->default_picture_folder;
2427 } else if (of == PTP_OFC_MTP_vCalendar1 ||
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002428 of == PTP_OFC_MTP_vCalendar2 ||
2429 of == PTP_OFC_MTP_UndefinedContact ||
2430 of == PTP_OFC_MTP_vCard2 ||
2431 of == PTP_OFC_MTP_vCard3 ||
2432 of == PTP_OFC_MTP_UndefinedCalendarItem) {
Linus Walleij05ccbe72006-06-13 07:46:58 +00002433 localph = device->default_organizer_folder;
2434 }
2435 }
2436
Linus Walleijd208f9c2006-04-27 14:16:06 +00002437 // Create the object
Linus Walleijd6a49972006-05-02 08:24:54 +00002438 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002439 if (ret != PTP_RC_OK) {
2440 ptp_perror(params, ret);
2441 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object info\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00002442 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002443 return -1;
2444 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002445
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002446 if (filedata->filesize != (uint64_t) -1) {
2447 // Callbacks
2448 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002449 // The callback will deactivate itself after this amount of data has been sent
2450 // One BULK header for the request, one for the data phase. No parameters to the request.
2451 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002452 ptp_usb->current_transfer_complete = 0;
2453 ptp_usb->current_transfer_callback = callback;
2454 ptp_usb->current_transfer_callback_data = data;
2455
2456 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
Linus Walleijd214b9b2006-08-26 22:08:37 +00002457
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002458 ptp_usb->callback_active = 0;
2459 ptp_usb->current_transfer_callback = NULL;
2460 ptp_usb->current_transfer_callback_data = NULL;
2461 } else {
2462 // This is a stream..
Linus Walleija9310fa2006-09-04 06:47:42 +00002463 ret = ptp_sendobject_fromfd(params, fd, 0xFFFFFFFFU-PTP_USB_BULK_HDR_LEN);
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002464 if (ret == PTP_ERROR_IO) {
2465 // That's expected. The stream ends, simply...
2466 ret = PTP_RC_OK;
2467 } else {
2468 printf("LIBMTP_Send_File_From_File_Descriptor: Error while sending stream.\n");
2469 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2470 }
2471 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002472
2473 if (ret != PTP_RC_OK) {
2474 ptp_perror(params, ret);
2475 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object\n");
2476 return -1;
2477 }
Linus Walleijd214b9b2006-08-26 22:08:37 +00002478
Linus Walleij438bd7f2006-06-08 11:35:44 +00002479 // Added object so flush handles.
2480 flush_handles(device);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002481 return 0;
2482}
2483
Linus Walleij17e39f72006-02-23 15:54:28 +00002484/**
2485 * This function updates the MTP object metadata on a single file
2486 * identified by an object ID.
Linus Walleij95698cd2006-02-24 10:40:40 +00002487 * @param device a pointer to the device to update the track
2488 * metadata on.
Linus Walleij17e39f72006-02-23 15:54:28 +00002489 * @param metadata a track metadata set to be written to the file.
2490 * notice that the <code>track_id</code> field of the
2491 * metadata structure must be correct so that the
Linus Walleija4982732006-02-24 15:46:02 +00002492 * function can update the right file. If some properties
2493 * of this metadata are set to NULL (strings) or 0
2494 * (numerical values) they will be discarded and the
2495 * track will not be tagged with these blank values.
Linus Walleij17e39f72006-02-23 15:54:28 +00002496 * @return 0 on success, any other value means failure.
2497 */
2498int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
2499 LIBMTP_track_t const * const metadata)
2500{
Linus Walleij17e39f72006-02-23 15:54:28 +00002501 uint16_t ret;
Linus Walleij00cf0642006-07-26 20:40:59 +00002502 PTPParams *params = (PTPParams *) device->params;
2503 uint32_t i;
2504 uint16_t *props = NULL;
2505 uint32_t propcnt = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002506
Linus Walleij00cf0642006-07-26 20:40:59 +00002507 // First see which properties can be set on this file format and apply accordingly
2508 // i.e only try to update this metadata for object tags that exist on the current player.
2509 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &props);
2510 if (ret != PTP_RC_OK) {
2511 // Just bail out for now, nothing is ever set.
raveloxd9a28642006-05-26 23:42:22 +00002512 return -1;
Linus Walleij00cf0642006-07-26 20:40:59 +00002513 } else {
2514 for (i=0;i<propcnt;i++) {
2515 switch (props[i]) {
2516 case PTP_OPC_Name:
2517 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00002518 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Name, metadata->title);
Linus Walleij00cf0642006-07-26 20:40:59 +00002519 if (ret != 0) {
2520 printf("LIBMTP_Update_Track_Metadata(): could not set track title\n");
2521 return -1;
2522 }
2523 break;
2524 case PTP_OPC_AlbumName:
2525 // Update album
Linus Walleija823a702006-08-27 21:27:46 +00002526 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
Linus Walleij00cf0642006-07-26 20:40:59 +00002527 if (ret != 0) {
2528 printf("LIBMTP_Update_Track_Metadata(): could not set track album name\n");
2529 return -1;
2530 }
2531 break;
2532 case PTP_OPC_Artist:
2533 // Update artist
Linus Walleija823a702006-08-27 21:27:46 +00002534 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
Linus Walleij00cf0642006-07-26 20:40:59 +00002535 if (ret != 0) {
2536 printf("LIBMTP_Update_Track_Metadata(): could not set track artist name\n");
2537 return -1;
2538 }
2539 break;
2540 case PTP_OPC_Genre:
2541 // Update genre
Linus Walleija823a702006-08-27 21:27:46 +00002542 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
Linus Walleij00cf0642006-07-26 20:40:59 +00002543 if (ret != 0) {
2544 printf("LIBMTP_Update_Track_Metadata(): could not set track genre name\n");
2545 return -1;
2546 }
2547 break;
2548 case PTP_OPC_Duration:
2549 // Update duration
2550 if (metadata->duration != 0) {
2551 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_Duration, metadata->duration);
2552 if (ret != 0) {
2553 printf("LIBMTP_Update_Track_Metadata(): could not set track duration\n");
2554 return -1;
2555 }
2556 }
2557 break;
2558 case PTP_OPC_Track:
2559 // Update track number.
2560 if (metadata->tracknumber != 0) {
2561 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Track, metadata->tracknumber);
2562 if (ret != 0) {
2563 printf("LIBMTP_Update_Track_Metadata(): could not set track tracknumber\n");
2564 return -1;
2565 }
2566 }
2567 break;
2568 case PTP_OPC_OriginalReleaseDate:
2569 // Update creation datetime
Linus Walleija823a702006-08-27 21:27:46 +00002570 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
Linus Walleij00cf0642006-07-26 20:40:59 +00002571 if (ret != 0) {
2572 printf("LIBMTP_Update_Track_Metadata(): could not set track release date\n");
2573 return -1;
2574 }
2575 break;
2576 // These are, well not so important.
2577 case PTP_OPC_SampleRate:
2578 // Update sample rate
2579 if (metadata->samplerate != 0) {
2580 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_SampleRate, metadata->samplerate);
2581 if (ret != 0) {
2582 printf("LIBMTP_Update_Track_Metadata(): could not set samplerate\n");
2583 return -1;
2584 }
2585 }
2586 break;
2587 case PTP_OPC_NumberOfChannels:
2588 // Update number of channels
2589 if (metadata->nochannels != 0) {
2590 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_NumberOfChannels, metadata->nochannels);
2591 if (ret != 0) {
2592 printf("LIBMTP_Update_Track_Metadata(): could not set number of channels\n");
2593 return -1;
2594 }
2595 }
2596 break;
2597 case PTP_OPC_AudioWAVECodec:
2598 // Update WAVE codec
2599 if (metadata->wavecodec != 0) {
2600 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, metadata->wavecodec);
2601 if (ret != 0) {
2602 printf("LIBMTP_Update_Track_Metadata(): could not set WAVE codec\n");
2603 return -1;
2604 }
2605 }
2606 break;
2607 case PTP_OPC_AudioBitRate:
2608 // Update bitrate
2609 if (metadata->bitrate != 0) {
2610 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_AudioBitRate, metadata->bitrate);
2611 if (ret != 0) {
2612 printf("LIBMTP_Update_Track_Metadata(): could not set bitrate\n");
2613 return -1;
2614 }
2615 }
2616 break;
2617 case PTP_OPC_BitRateType:
2618 // Update bitrate type
2619 if (metadata->bitratetype != 0) {
2620 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_BitRateType, metadata->bitratetype);
2621 if (ret != 0) {
2622 printf("LIBMTP_Update_Track_Metadata(): could not set bitratetype\n");
2623 return -1;
2624 }
2625 }
2626 break;
2627 case PTP_OPC_Rating:
2628 // Update user rating
2629 // TODO: shall this be set for rating 0?
2630 if (metadata->rating != 0) {
2631 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Rating, metadata->rating);
2632 if (ret != 0) {
2633 printf("LIBMTP_Update_Track_Metadata(): could not set user rating\n");
2634 return -1;
2635 }
2636 }
2637 break;
2638 case PTP_OPC_UseCount:
2639 // Update use count, set even to zero if desired.
2640 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_UseCount, metadata->usecount);
2641 if (ret != 0) {
2642 printf("LIBMTP_Update_Track_Metadata(): could not set use count\n");
2643 return -1;
2644 }
2645 break;
Linus Walleij17e39f72006-02-23 15:54:28 +00002646
Linus Walleij00cf0642006-07-26 20:40:59 +00002647 // NOTE: File size is not updated, this should not change anyway.
2648 // neither will we change the filename.
2649 }
Linus Walleija4982732006-02-24 15:46:02 +00002650 }
Linus Walleij00cf0642006-07-26 20:40:59 +00002651 return 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002652 }
Linus Walleij394bbbe2006-02-22 16:10:53 +00002653}
Linus Walleij95698cd2006-02-24 10:40:40 +00002654
2655/**
Linus Walleij438bd7f2006-06-08 11:35:44 +00002656 * This function deletes a single file, track, playlist or
2657 * any other object off the MTP device,
Linus Walleij95698cd2006-02-24 10:40:40 +00002658 * identified by an object ID.
Linus Walleijf6bc1782006-03-24 15:12:47 +00002659 * @param device a pointer to the device to delete the file or track from.
Linus Walleij95698cd2006-02-24 10:40:40 +00002660 * @param item_id the item to delete.
2661 * @return 0 on success, any other value means failure.
2662 */
Linus Walleij438bd7f2006-06-08 11:35:44 +00002663int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
2664 uint32_t object_id)
Linus Walleij95698cd2006-02-24 10:40:40 +00002665{
Linus Walleij438bd7f2006-06-08 11:35:44 +00002666 uint16_t ret;
2667 PTPParams *params = (PTPParams *) device->params;
2668
2669 ret = ptp_deleteobject(params, object_id, 0);
2670 if (ret != PTP_RC_OK) {
2671 ptp_perror(params, ret);
2672 printf("LIBMTP_Delete_Object(): could not delete object\n");
2673 return -1;
2674 }
2675 // Removed object so flush handles.
2676 flush_handles(device);
2677 return 0;
Linus Walleij95698cd2006-02-24 10:40:40 +00002678}
Linus Walleij9c6ca022006-04-21 10:24:15 +00002679
Linus Walleij9c6ca022006-04-21 10:24:15 +00002680/**
2681 * Helper function. This indicates if a track exists on the device
2682 * @param device a pointer to the device to get the track from.
2683 * @param id the track ID of the track to retrieve.
2684 * @return TRUE (1) if the track exists, FALSE (0) if not
2685 */
2686int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
2687 uint32_t const id)
2688{
2689 PTPObjectInfo oi;
2690 PTPParams *params = (PTPParams *) device->params;
2691
2692 if (ptp_getobjectinfo(params, id, &oi) == PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002693 return -1;
Linus Walleij9c6ca022006-04-21 10:24:15 +00002694 }
2695 return 0;
2696}
2697
2698/**
2699 * This creates a new folder structure and allocates memory
2700 * for it. Notice that if you add strings to this structure they
2701 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
2702 * operation later, so be careful of using strdup() when assigning
2703 * strings, e.g.:
2704 *
2705 * @return a pointer to the newly allocated folder structure.
2706 * @see LIBMTP_destroy_folder_t()
2707 */
2708LIBMTP_folder_t *LIBMTP_new_folder_t(void)
2709{
2710 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
2711 if (new == NULL) {
2712 return NULL;
2713 }
2714 new->folder_id = 0;
2715 new->parent_id = 0;
2716 new->name = NULL;
2717 new->sibling = NULL;
2718 new->child = NULL;
2719 return new;
2720}
2721
2722/**
raveloxd9a28642006-05-26 23:42:22 +00002723 *
2724 * This deletes the memory for an object structure
2725 * and makes use of the registered destructor for the object
2726 * type data.
2727 *
2728 * @param object object structure to destroy
2729 * @param recurse indicate if the call should recursively delete
2730 * the object. Specify 1 for recursion.
2731 * @see LIBMTP_new_object_t()
2732 */
2733void LIBMTP_destroy_object_t(LIBMTP_object_t *object, uint32_t recursive)
2734{
Linus Walleijf0f3d482006-05-29 14:10:21 +00002735 if(object == NULL) {
2736 return;
2737 }
2738
2739 //Destroy from the bottom up
2740 if(recursive==1) {
2741 LIBMTP_destroy_object_t(object->child, recursive);
2742 object->child = NULL;
2743 LIBMTP_destroy_object_t(object->sibling, recursive);
2744 object->sibling = NULL;
2745 }
raveloxd9a28642006-05-26 23:42:22 +00002746
Linus Walleijf0f3d482006-05-29 14:10:21 +00002747 if(object->name != NULL) free(object->name);
2748
2749 //Use the data type destructor
2750 if(object->data != NULL) {
2751 void (*destructor)(void *);
2752
2753 destructor = get_destructor(object->type);
2754
2755 if(destructor != NULL) {
2756 (*destructor)(object->data);
2757 }
2758 object->data = NULL;
2759 }
2760
2761 free(object);
raveloxd9a28642006-05-26 23:42:22 +00002762}
2763
2764/**
Linus Walleij9c6ca022006-04-21 10:24:15 +00002765 * This recursively deletes the memory for a folder structure
2766 *
2767 * @param folder folder structure to destroy
2768 * @see LIBMTP_new_folder_t()
2769 */
2770void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
2771{
2772
2773 if(folder == NULL) {
2774 return;
2775 }
2776
2777 //Destroy from the bottom up
2778 if(folder->child != NULL) {
2779 LIBMTP_destroy_folder_t(folder->child);
2780 }
2781
2782 if(folder->sibling != NULL) {
2783 LIBMTP_destroy_folder_t(folder->sibling);
2784 }
2785
2786 if(folder->name != NULL) {
2787 free(folder->name);
2788 }
2789
2790 free(folder);
2791}
2792
2793/**
2794 * Helper function. Returns a folder structure for a
2795 * specified id.
2796 *
2797 * @param folderlist list of folders to search
2798 * @id id of folder to look for
2799 * @return a folder or NULL if not found
2800 */
2801LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
2802{
2803 LIBMTP_folder_t *ret = NULL;
2804
2805 if(folderlist == NULL) {
2806 return NULL;
2807 }
2808
2809 if(folderlist->folder_id == id) {
2810 return folderlist;
2811 }
2812
2813 if(folderlist->sibling) {
2814 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
2815 }
2816
2817 if(folderlist->child && ret == NULL) {
2818 ret = LIBMTP_Find_Folder(folderlist->child, id);
2819 }
2820
2821 return ret;
2822}
2823
2824/**
2825 * This returns a list of all folders available
2826 * on the current MTP device.
2827 *
2828 * @param device a pointer to the device to get the track listing for.
2829 * @return a list of folders
2830 */
2831LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
2832{
2833 uint32_t i = 0;
2834 LIBMTP_folder_t *retfolders = NULL;
2835 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002836
2837 // Get all the handles if we haven't already done that
Linus Walleij9c6ca022006-04-21 10:24:15 +00002838 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002839 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00002840 }
2841
2842 for (i = 0; i < params->handles.n; i++) {
2843 LIBMTP_folder_t *folder;
2844 PTPObjectInfo oi;
2845
2846 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
2847 if (oi.ObjectFormat != PTP_OFC_Association) {
2848 continue;
2849 }
2850 folder = LIBMTP_new_folder_t();
2851 folder->folder_id = params->handles.Handler[i];
2852 folder->parent_id = oi.ParentObject;
2853 folder->name = (char *)strdup(oi.Filename);
2854
2855 // Work out where to put this new item
2856 if(retfolders == NULL) {
2857 retfolders = folder;
2858 continue;
2859 } else {
2860 LIBMTP_folder_t *parent_folder;
2861 LIBMTP_folder_t *current_folder;
2862
2863 parent_folder = LIBMTP_Find_Folder(retfolders, folder->parent_id);
2864
2865 if(parent_folder == NULL) {
2866 current_folder = retfolders;
2867 } else {
2868 if(parent_folder->child == NULL) {
2869 parent_folder->child = folder;
2870 continue;
2871 } else {
2872 current_folder = parent_folder->child;
2873 }
2874 }
2875
2876 while(current_folder->sibling != NULL) {
2877 current_folder=current_folder->sibling;
2878 }
2879
2880 current_folder->sibling = folder;
2881 }
2882 }
2883 }
2884 return retfolders;
2885}
2886
2887/**
Linus Walleijc86afbd2006-05-04 19:05:24 +00002888 * This create a folder on the current MTP device. The PTP name
2889 * for a folder is "association". The PTP/MTP devices does not
2890 * have an internal "folder" concept really, it contains a flat
2891 * list of all files and some file are "associations" that other
2892 * files and folders may refer to as its "parent".
Linus Walleij9c6ca022006-04-21 10:24:15 +00002893 *
Linus Walleijc86afbd2006-05-04 19:05:24 +00002894 * @param device a pointer to the device to create the folder on.
2895 * @param name the name of the new folder.
2896 * @param parent_id id of parent folder to add the new folder to,
2897 * or 0 to put it in the root directory.
2898 * @return id to new folder or 0 if an error occured
Linus Walleij9c6ca022006-04-21 10:24:15 +00002899 */
2900uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name, uint32_t parent_id)
2901{
2902 PTPParams *params = (PTPParams *) device->params;
2903 uint32_t parenthandle = 0;
2904 uint32_t store = 0;
2905 PTPObjectInfo new_folder;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002906 uint16_t ret;
Linus Walleij9c6ca022006-04-21 10:24:15 +00002907 uint32_t new_id = 0;
2908
2909 memset(&new_folder, 0, sizeof(new_folder));
2910 new_folder.Filename = name;
2911 new_folder.ObjectCompressedSize = 1;
2912 new_folder.ObjectFormat = PTP_OFC_Association;
2913 new_folder.ParentObject = parent_id;
2914
2915 parenthandle = parent_id;
2916 // Create the object
2917 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
2918 if (ret != PTP_RC_OK) {
2919 ptp_perror(params, ret);
2920 printf("LIBMTP_Create_Folder: Could not send object info\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00002921 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijc86afbd2006-05-04 19:05:24 +00002922 return 0;
Linus Walleij9c6ca022006-04-21 10:24:15 +00002923 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002924 // Created new object so flush handles
2925 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00002926 return new_id;
2927}
raveloxd9a28642006-05-26 23:42:22 +00002928
2929
2930/**
2931 * Helper function. Returns a folder structure for a
2932 * specified id.
2933 *
2934 * @param objectlist list of objects to search
2935 * @id id of object to look for
2936 * @return a object or NULL if not found
2937 */
2938LIBMTP_object_t *LIBMTP_Find_Object(LIBMTP_object_t *objectlist, uint32_t id)
2939{
2940 LIBMTP_object_t *ret = NULL;
2941
2942 if(objectlist == NULL) {
2943 return NULL;
2944 }
2945
2946 if(objectlist->id == id) {
2947 return objectlist;
2948 }
2949
2950 if(objectlist->sibling) {
2951 ret = LIBMTP_Find_Object(objectlist->sibling, id);
2952 }
2953
2954 if(objectlist->child && ret == NULL) {
2955 ret = LIBMTP_Find_Object(objectlist->child, id);
2956 }
2957
2958 return ret;
2959}
2960
2961/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00002962 * This returns a list of objects on the current MTP device,
2963 * selected by a filter based on PTP object ID:s.
raveloxd9a28642006-05-26 23:42:22 +00002964 *
Linus Walleijf0f3d482006-05-29 14:10:21 +00002965 * @param device a pointer to the device to get the object listing for.
raveloxd9a28642006-05-26 23:42:22 +00002966 * @param filter array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00002967 * to include in the list
2968 * @param filter_len length of filter array in 32-bit words
raveloxd9a28642006-05-26 23:42:22 +00002969 * @param exclusions array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00002970 * to exclude from the list
raveloxd9a28642006-05-26 23:42:22 +00002971 * @param exclusion_len length of exclusion array
2972 * @return a list of objects
2973 * @see LIBMTP_destroy_object_t()
2974 */
Linus Walleijf0f3d482006-05-29 14:10:21 +00002975LIBMTP_object_t *LIBMTP_Make_List(LIBMTP_mtpdevice_t *device, uint32_t *filter,
2976 uint32_t filter_len, uint32_t *exclusions, uint32_t exclusion_len)
raveloxd9a28642006-05-26 23:42:22 +00002977{
2978 uint32_t i = 0;
2979 LIBMTP_object_t *objectlist = NULL;
2980 PTPParams *params = (PTPParams *) device->params;
raveloxd9a28642006-05-26 23:42:22 +00002981 uint32_t max_exclusions = 0;
2982 uint32_t max_filter = 0;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002983
2984 // Get all the handles if we haven't already done that
raveloxd9a28642006-05-26 23:42:22 +00002985 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002986 flush_handles(device);
raveloxd9a28642006-05-26 23:42:22 +00002987 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00002988
raveloxd9a28642006-05-26 23:42:22 +00002989 if(filter != NULL) max_filter = filter_len;
2990 if(exclusions != NULL) max_exclusions = exclusion_len;
Linus Walleijf0f3d482006-05-29 14:10:21 +00002991
raveloxd9a28642006-05-26 23:42:22 +00002992 for (i = 0; i < params->handles.n; i++) {
2993 LIBMTP_object_t *object;
2994 PTPObjectInfo oi;
2995
2996 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00002997 uint32_t x = 0;
2998 uint32_t exclude = 0, filter_allow = 0;
2999 void (*datafunc)(LIBMTP_mtpdevice_t *, uint32_t, void *);
3000 void *(*constructor)(void);
3001
raveloxd9a28642006-05-26 23:42:22 +00003002 // Is the ObjectFormat in the list of exclusions ?
Linus Walleijf0f3d482006-05-29 14:10:21 +00003003 for(x = 0; x < max_exclusions; x++) {
3004 if (oi.ObjectFormat == exclusions[x]) {
3005 exclude = 1;
3006 break;
3007 }
raveloxd9a28642006-05-26 23:42:22 +00003008 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003009 if(exclude == 1) {
3010 continue;
3011 }
3012
3013 // Is the ObjectFormat in the filter ?
3014 for(x = 0; x < max_filter; x++) {
3015 if (oi.ObjectFormat == filter[x]) {
3016 filter_allow = 1;
3017 break;
3018 }
3019 }
3020 if(filter_allow == 0) {
3021 continue;
3022 }
3023
raveloxd9a28642006-05-26 23:42:22 +00003024 object = LIBMTP_new_object_t();
3025 object->id = params->handles.Handler[i];
3026 object->parent = oi.ParentObject;
3027 object->name = (char *)strdup(oi.Filename);
3028 object->size = oi.ObjectCompressedSize;
Linus Walleijf0f3d482006-05-29 14:10:21 +00003029 object->type = oi.ObjectFormat;
raveloxd9a28642006-05-26 23:42:22 +00003030
Linus Walleijf0f3d482006-05-29 14:10:21 +00003031 // Get the function pointers for the constructor and datafunc
3032 constructor = get_constructor(oi.ObjectFormat);
3033 datafunc = get_datafunc(oi.ObjectFormat);
3034
3035 if(constructor != NULL) {
3036 object->data = (*constructor)();
3037 if(datafunc != NULL) {
3038 (*datafunc)(device, object->id, object->data);
3039 }
3040 }
3041
raveloxd9a28642006-05-26 23:42:22 +00003042 // Work out where to put this new item
3043 if(objectlist == NULL) {
3044 objectlist = object;
3045 continue;
3046 } else {
3047 LIBMTP_object_t *parent_object;
3048 LIBMTP_object_t *current_object;
3049
3050 parent_object = LIBMTP_Find_Object(objectlist, object->parent);
3051
3052 if(parent_object == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00003053 current_object = objectlist;
raveloxd9a28642006-05-26 23:42:22 +00003054 } else {
3055 if(parent_object->child == NULL) {
3056 parent_object->child = object;
3057 continue;
3058 } else {
3059 current_object = parent_object->child;
3060 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003061 }
raveloxd9a28642006-05-26 23:42:22 +00003062
3063 while(current_object->sibling != NULL) {
3064 current_object=current_object->sibling;
3065 }
3066 current_object->sibling = object;
3067 }
3068 }
3069 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003070
raveloxd9a28642006-05-26 23:42:22 +00003071 return objectlist;
3072}
Linus Walleijf0f3d482006-05-29 14:10:21 +00003073
raveloxd9a28642006-05-26 23:42:22 +00003074/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00003075 * Debug function that dumps out some textual representation
3076 * of an object list.
raveloxd9a28642006-05-26 23:42:22 +00003077 *
3078 * @param list object list returned from LIBMTP_Make_List
3079 *
3080 * @see LIBMTP_Make_List()
3081 */
3082void LIBMTP_Dump_List(LIBMTP_object_t *list)
3083{
Linus Walleijf0f3d482006-05-29 14:10:21 +00003084 if(list == NULL) return;
3085
3086 printf("Id : %u\n", list->id);
3087 printf("Parent: %u\n", list->parent);
3088 printf("Size : %u\n", list->size);
3089 printf("Name : %s\n", (list->name ? list->name : ""));
3090 printf("Type : 0x%04x\n", list->type);
3091 printf("--\n");
3092
3093 LIBMTP_Dump_List(list->child);
3094 LIBMTP_Dump_List(list->sibling);
raveloxd9a28642006-05-26 23:42:22 +00003095}
Linus Walleij438bd7f2006-06-08 11:35:44 +00003096
3097/**
3098 * This creates a new playlist metadata structure and allocates memory
3099 * for it. Notice that if you add strings to this structure they
3100 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
3101 * operation later, so be careful of using strdup() when assigning
3102 * strings, e.g.:
3103 *
3104 * <pre>
3105 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
3106 * pl->name = strdup(str);
3107 * ....
3108 * LIBMTP_destroy_playlist_t(pl);
3109 * </pre>
3110 *
3111 * @return a pointer to the newly allocated metadata structure.
3112 * @see LIBMTP_destroy_playlist_t()
3113 */
3114LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
3115{
3116 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
3117 if (new == NULL) {
3118 return NULL;
3119 }
3120 new->playlist_id = 0;
3121 new->name = NULL;
3122 new->tracks = NULL;
3123 new->no_tracks = 0;
3124 new->next = NULL;
3125 return new;
3126}
3127
3128/**
3129 * This destroys a playlist metadata structure and deallocates the memory
3130 * used by it, including any strings. Never use a track metadata
3131 * structure again after calling this function on it.
3132 * @param playlist the playlist metadata to destroy.
3133 * @see LIBMTP_new_playlist_t()
3134 */
3135void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
3136{
3137 if (playlist == NULL) {
3138 return;
3139 }
3140 if (playlist->name != NULL)
3141 free(playlist->name);
3142 if (playlist->tracks != NULL)
3143 free(playlist->tracks);
3144 free(playlist);
3145 return;
3146}
3147
3148/**
3149 * This function returns a list of the playlists available on the
3150 * device. Typical usage:
3151 *
3152 * <pre>
3153 * </pre>
3154 *
3155 * @param device a pointer to the device to get the playlist listing from.
3156 * @return a playlist list on success, else NULL. If there are no playlists
3157 * on the device, NULL will be returned as well.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003158 * @see LIBMTP_Get_Playlist()
Linus Walleij438bd7f2006-06-08 11:35:44 +00003159 */
3160LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
3161{
3162 PTPParams *params = (PTPParams *) device->params;
3163 LIBMTP_playlist_t *retlists = NULL;
3164 LIBMTP_playlist_t *curlist = NULL;
3165 uint32_t i;
3166
3167 // Get all the handles if we haven't already done that
3168 if (params->handles.Handler == NULL) {
3169 flush_handles(device);
3170 }
3171
3172 for (i = 0; i < params->handles.n; i++) {
3173 LIBMTP_playlist_t *pl;
3174 PTPObjectInfo oi;
3175 uint16_t ret;
3176
3177 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3178 if ( ret == PTP_RC_OK) {
3179
3180 // Ignore stuff that isn't playlists
3181 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
3182 continue;
3183 }
3184
3185 // Allocate a new playlist type
3186 pl = LIBMTP_new_playlist_t();
3187
3188 // Ignoring the io.Filename field.
Linus Walleija823a702006-08-27 21:27:46 +00003189 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
Linus Walleij438bd7f2006-06-08 11:35:44 +00003190
3191 // This is some sort of unique playlist ID so we can keep track of it
3192 pl->playlist_id = params->handles.Handler[i];
3193
3194 // Then get the track listing for this playlist
3195 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
3196 if (ret != PTP_RC_OK) {
3197 printf("LIBMTP_Get_Playlist: Could not get object references\n");
3198 pl->tracks = NULL;
3199 pl->no_tracks = 0;
3200 }
3201
3202 // Add playlist to a list that will be returned afterwards.
3203 if (retlists == NULL) {
3204 retlists = pl;
3205 curlist = pl;
3206 } else {
3207 curlist->next = pl;
3208 curlist = pl;
3209 }
3210
3211 // Call callback here if we decide to add that possibility...
3212
3213 } else {
3214 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
3215 }
3216 }
3217 return retlists;
3218}
3219
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003220
3221/**
3222 * This function retrieves an individual playlist from the device.
3223 * @param device a pointer to the device to get the playlist from.
3224 * @param plid the unique ID of the playlist to retrieve.
3225 * @return a valid playlist metadata post or NULL on failure.
3226 * @see LIBMTP_Get_Playlist_List()
3227 */
3228LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
3229{
3230 PTPParams *params = (PTPParams *) device->params;
3231 uint32_t i;
3232
3233 // Get all the handles if we haven't already done that
3234 if (params->handles.Handler == NULL) {
3235 flush_handles(device);
3236 }
3237
3238 for (i = 0; i < params->handles.n; i++) {
3239 LIBMTP_playlist_t *pl;
3240 PTPObjectInfo oi;
3241 uint16_t ret;
3242
3243 if (params->handles.Handler[i] != plid) {
3244 continue;
3245 }
3246
3247 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3248 if ( ret == PTP_RC_OK) {
3249
3250 // Ignore stuff that isn't playlists
3251 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
3252 return NULL;
3253 }
3254
3255 // Allocate a new playlist type
3256 pl = LIBMTP_new_playlist_t();
3257
3258 // Ignoring the io.Filename field.
Linus Walleija823a702006-08-27 21:27:46 +00003259 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003260
3261 // This is some sort of unique playlist ID so we can keep track of it
3262 pl->playlist_id = params->handles.Handler[i];
3263
3264 // Then get the track listing for this playlist
3265 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
3266 if (ret != PTP_RC_OK) {
3267 printf("LIBMTP_Get_Playlist: Could not get object references\n");
3268 pl->tracks = NULL;
3269 pl->no_tracks = 0;
3270 }
3271
3272 return pl;
3273 } else {
3274 return NULL;
3275 }
3276 }
3277 return NULL;
3278}
3279
Linus Walleij438bd7f2006-06-08 11:35:44 +00003280/**
3281 * This routine creates a new playlist based on the metadata
3282 * supplied. If the <code>tracks</code> field of the metadata
3283 * contains a track listing, these tracks will be added to the
3284 * playlist.
3285 * @param device a pointer to the device to create the new playlist on.
3286 * @param metadata the metadata for the new playlist. If the function
3287 * exits with success, the <code>playlist_id</code> field of this
3288 * struct will contain the new playlist ID of the playlist.
3289 * @param parenthandle the parent (e.g. folder) to store this playlist
3290 * in. Pass in 0 to put the playlist in the root directory.
3291 * @return 0 on success, any other value means failure.
3292 * @see LIBMTP_Update_Playlist()
3293 * @see LIBMTP_Delete_Object()
3294 */
3295int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
3296 LIBMTP_playlist_t * const metadata,
3297 uint32_t const parenthandle)
3298{
3299 uint16_t ret;
3300 uint32_t store = 0;
3301 PTPObjectInfo new_pl;
3302 PTPParams *params = (PTPParams *) device->params;
3303 uint32_t localph = parenthandle;
3304 char fname[256];
Linus Walleijd14e84f2006-06-16 14:50:59 +00003305 uint8_t data[2];
Linus Walleij438bd7f2006-06-08 11:35:44 +00003306
Linus Walleij05ccbe72006-06-13 07:46:58 +00003307 // Use a default folder if none given
3308 if (localph == 0) {
3309 localph = device->default_playlist_folder;
3310 }
3311
Linus Walleij438bd7f2006-06-08 11:35:44 +00003312 // .zpl is the "abstract audio/video playlist "file" suffix
3313 new_pl.Filename = NULL;
3314 if (strlen(metadata->name) > 4) {
3315 char *suff = &metadata->name[strlen(metadata->name)-4];
3316 if (!strcmp(suff, ".zpl")) {
3317 // Home free.
3318 new_pl.Filename = metadata->name;
3319 }
3320 }
3321 // If it didn't end with ".zpl" then add that here.
3322 if (new_pl.Filename == NULL) {
3323 strncpy(fname, metadata->name, sizeof(fname)-5);
3324 strcat(fname, ".zpl");
3325 fname[sizeof(fname)-1] = '\0';
3326 new_pl.Filename = fname;
3327 }
3328
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003329 // Playlists created on device have size (uint32_t) -1 = 0xFFFFFFFFU, but setting:
3330 // new_pl.ObjectCompressedSize = 0; <- DOES NOT WORK! (return PTP_RC_GeneralError)
3331 // new_pl.ObjectCompressedSize = (uint32_t) -1; <- DOES NOT WORK! (return PTP_RC_MTP_Object_Too_Large)
Linus Walleijd14e84f2006-06-16 14:50:59 +00003332 new_pl.ObjectCompressedSize = 1;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003333 new_pl.ObjectFormat = PTP_OFC_MTP_AbstractAudioVideoPlaylist;
3334
3335 // Create the object
3336 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
3337 if (ret != PTP_RC_OK) {
3338 ptp_perror(params, ret);
3339 printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00003340 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +00003341 return -1;
3342 }
3343
3344 /*
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003345 * We have to send this one blank data byte.
3346 * If we don't, the handle will not be created and thus there is no playlist.
Linus Walleij438bd7f2006-06-08 11:35:44 +00003347 */
Linus Walleijd14e84f2006-06-16 14:50:59 +00003348 data[0] = '\0';
3349 data[1] = '\0';
3350 ret = ptp_sendobject(params, data, 1);
3351 if (ret != PTP_RC_OK) {
3352 ptp_perror(params, ret);
3353 printf("LIBMTP_New_Playlist(): Could not send blank object data\n");
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003354 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003355 return -1;
3356 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003357
3358 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00003359 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003360 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003361 printf("LIBMTP_New_Playlist(): could not set playlist name\n");
3362 return -1;
3363 }
3364
3365 if (metadata->no_tracks > 0) {
3366 // Add tracks to the new playlist as object references.
3367 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3368 if (ret != PTP_RC_OK) {
3369 printf("LIBMTP_New_Playlist(): could not add tracks as object references\n");
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003370 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +00003371 return -1;
3372 }
3373 }
3374
3375 // Created new item, so flush handles
3376 flush_handles(device);
3377
3378 return 0;
3379}
3380
3381/**
3382 * This routine updates a playlist based on the metadata
3383 * supplied. If the <code>tracks</code> field of the metadata
3384 * contains a track listing, these tracks will be added to the
3385 * playlist in place of those already present, i.e. the
3386 * previous track listing will be deleted.
3387 * @param device a pointer to the device to create the new playlist on.
3388 * @param metadata the metadata for the playlist to be updated.
3389 * notice that the field <code>playlist_id</code>
3390 * must contain the apropriate playlist ID.
3391 * @return 0 on success, any other value means failure.
3392 * @see LIBMTP_Create_New_Playlist()
3393 * @see LIBMTP_Delete_Object()
3394 */
3395int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
Linus Walleijf5306352006-06-08 12:00:23 +00003396 LIBMTP_playlist_t const * const metadata)
Linus Walleij438bd7f2006-06-08 11:35:44 +00003397{
3398 uint16_t ret;
Linus Walleijf5306352006-06-08 12:00:23 +00003399 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003400
3401 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00003402 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003403 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003404 printf("LIBMTP_Update_Playlist(): could not set playlist name\n");
3405 return -1;
3406 }
3407
3408 if (metadata->no_tracks > 0) {
3409 // Add tracks to the new playlist as object references.
3410 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3411 if (ret != PTP_RC_OK) {
3412 printf("LIBMTP_Update_Playlist(): could not add tracks as object references\n");
3413 return -1;
3414 }
3415 }
3416 return 0;
3417}
Linus Walleijaa4b0752006-07-26 22:21:04 +00003418
3419
3420/**
3421 * Dummy function needed to interface to upstream
3422 * ptp.c/ptp.h files.
3423 */
3424void ptp_nikon_getptpipguid (unsigned char* guid) {
3425 return;
3426}