blob: 08f2650ea730fdd94f4b8390234b72fec60193ef [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 Walleijeb8c6fe2006-02-03 09:46:22 +000019#include "libmtp.h"
Linus Walleijb9256fd2006-02-15 09:40:43 +000020#include "unicode.h"
Linus Walleij394bbbe2006-02-22 16:10:53 +000021#include "ptp.h"
Linus Walleij15e344f2006-03-06 15:15:00 +000022#include "libusb-glue.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000023
Linus Walleijc86afbd2006-05-04 19:05:24 +000024/*
25 * This is a mapping between libmtp internal MTP filetypes and
26 * the libgphoto2/PTP equivalent defines. We need this because
27 * otherwise the libmtp.h device has to be dependent on ptp.h
28 * to be installed too, and we don't want that.
29 */
raveloxd9a28642006-05-26 23:42:22 +000030typedef struct filemap_t LIBMTP_filemap_t;
raveloxd9a28642006-05-26 23:42:22 +000031struct filemap_t {
32 char *description; /**< Text description for the file type */
33 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
34 uint16_t ptp_id; /**< PTP ID for the filetype */
35 void *constructor; /**< Function to create the data structure for this file type */
36 void *destructor; /**< Function to destroy the data structure for this file type */
37 void *datafunc; /**< Function to fill in the data for this file type */
38 LIBMTP_filemap_t *next;
Linus Walleij16c51f02006-05-04 13:20:22 +000039};
Linus Walleijc86afbd2006-05-04 19:05:24 +000040
Linus Walleijf67bca92006-05-29 09:33:39 +000041// Global variables
Linus Walleij438bd7f2006-06-08 11:35:44 +000042// This holds the global filetype mapping table
Linus Walleijf67bca92006-05-29 09:33:39 +000043static LIBMTP_filemap_t *filemap = NULL;
44
45// Forward declarations of local functions
Linus Walleij438bd7f2006-06-08 11:35:44 +000046static void flush_handles(LIBMTP_mtpdevice_t *device);
Linus Walleijf67bca92006-05-29 09:33:39 +000047static int send_file_object(LIBMTP_mtpdevice_t *device,
48 int const fd, uint64_t size,
49 LIBMTP_progressfunc_t const * const callback,
50 void const * const data);
Linus Walleijf67bca92006-05-29 09:33:39 +000051static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
52static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
Linus Walleij545c7792006-06-13 15:22:30 +000053int get_device_unicode_property(LIBMTP_mtpdevice_t *device, char **unicstring, uint16_t property);
raveloxd9a28642006-05-26 23:42:22 +000054
55static LIBMTP_filemap_t *new_filemap_entry()
56{
Linus Walleijf67bca92006-05-29 09:33:39 +000057 LIBMTP_filemap_t *filemap;
58
59 filemap = (LIBMTP_filemap_t *)malloc(sizeof(LIBMTP_filemap_t));
60
61 if( filemap != NULL ) {
62 filemap->description = NULL;
63 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
64 filemap->ptp_id = PTP_OFC_Undefined;
65 filemap->constructor = NULL;
66 filemap->destructor = NULL;
67 filemap->datafunc = NULL;
68 filemap->next = NULL;
69 }
70
71 return filemap;
raveloxd9a28642006-05-26 23:42:22 +000072}
73
raveloxd9a28642006-05-26 23:42:22 +000074/**
75 * Register an MTP or PTP filetype for data retrieval
76 *
77 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +000078 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +000079 * @param ptp_id PTP filetype id
80 * @param constructor Pointer to function to create data structure for filetype
81 * @param destructor Pointer to function to destroy data structure for filetype
82 * @param datafunc Pointer to function to fill data structure
Linus Walleijf0f3d482006-05-29 14:10:21 +000083 * @return 0 for success any other value means error.
raveloxd9a28642006-05-26 23:42:22 +000084*/
Linus Walleij438bd7f2006-06-08 11:35:44 +000085int LIBMTP_Register_Filetype(char const * const description, LIBMTP_filetype_t const id,
86 uint16_t const ptp_id, void const * const constructor,
87 void const * const destructor, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +000088{
89 LIBMTP_filemap_t *new = NULL, *current;
90
91 // Has this LIBMTP filetype been registered before ?
92 current = filemap;
93 while (current != NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +000094 if(current->id == id) {
95 break;
96 }
Linus Walleijf0f3d482006-05-29 14:10:21 +000097 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +000098 }
Linus Walleijf67bca92006-05-29 09:33:39 +000099
raveloxd9a28642006-05-26 23:42:22 +0000100 // Create the entry
101 if(current == NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000102 new = new_filemap_entry();
Linus Walleijf0f3d482006-05-29 14:10:21 +0000103 if(new == NULL) {
104 return 1;
105 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000106
107 new->id = id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000108 if(description != NULL) {
109 new->description = strdup(description);
110 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000111 new->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000112 new->constructor = (void*) constructor;
113 new->destructor = (void*) destructor;
114 new->datafunc = (void*) datafunc;
Linus Walleijf67bca92006-05-29 09:33:39 +0000115
116 // Add the entry to the list
117 if(filemap == NULL) {
118 filemap = new;
119 } else {
120 current = filemap;
121 while (current->next != NULL ) current=current->next;
122 current->next = new;
123 }
124 // Update the existing entry
raveloxd9a28642006-05-26 23:42:22 +0000125 } else {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000126 if (current->description != NULL) {
127 free(current->description);
128 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000129 current->description = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000130 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000131 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000132 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000133 current->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000134 current->constructor = (void*) constructor;
135 current->destructor = (void*) destructor;
136 current->datafunc = (void*) datafunc;
raveloxd9a28642006-05-26 23:42:22 +0000137 }
138
Linus Walleijf0f3d482006-05-29 14:10:21 +0000139 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000140}
141
142/**
143 * Set the description for a MTP filetype
144 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000145 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000146 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +0000147 * @return 0 on success, any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000148*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000149int LIBMTP_Set_Filetype_Description(LIBMTP_filetype_t const id, char const * const description)
raveloxd9a28642006-05-26 23:42:22 +0000150{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000151 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000152
Linus Walleijf0f3d482006-05-29 14:10:21 +0000153 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000154 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000155 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000156
157 // Go through the filemap until an entry is found
158 current = filemap;
159
Linus Walleijf0f3d482006-05-29 14:10:21 +0000160 while(current != NULL) {
161 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000162 break;
163 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000164 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000165 }
166
Linus Walleijf0f3d482006-05-29 14:10:21 +0000167 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000168 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000169 }
170
171 if (current->description != NULL) {
172 free(current->description);
173 current->description = NULL;
174 }
175 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000176 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000177 }
178 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000179}
180
181/**
182 * Set the constructor for a MTP filetype
183 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000184 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000185 * @param constructor Pointer to a constructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000186 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000187*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000188int LIBMTP_Set_Constructor(LIBMTP_filetype_t const id, void const * const constructor)
raveloxd9a28642006-05-26 23:42:22 +0000189{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000190 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000191
Linus Walleijf0f3d482006-05-29 14:10:21 +0000192 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000193 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000194 }
195
Linus Walleijf67bca92006-05-29 09:33:39 +0000196 // Go through the filemap until an entry is found
197 current = filemap;
198
Linus Walleijf0f3d482006-05-29 14:10:21 +0000199 while(current != NULL) {
200 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000201 break;
raveloxd9a28642006-05-26 23:42:22 +0000202 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000203 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000204 }
205
Linus Walleijf0f3d482006-05-29 14:10:21 +0000206 if (current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000207 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000208 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000209
Linus Walleij438bd7f2006-06-08 11:35:44 +0000210 current->constructor = (void*) constructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000211 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000212}
213
214/**
215 * Set the destructor for a MTP filetype
216 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000217 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000218 * @param destructor Pointer to a destructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000219 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000220*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000221int LIBMTP_Set_Destructor(LIBMTP_filetype_t const id, void const * const destructor)
raveloxd9a28642006-05-26 23:42:22 +0000222{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000223 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000224
Linus Walleijf0f3d482006-05-29 14:10:21 +0000225 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000226 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000227 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000228
229 // Go through the filemap until an entry is found
230 current = filemap;
231
Linus Walleijf0f3d482006-05-29 14:10:21 +0000232 while(current != NULL) {
233 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000234 break;
raveloxd9a28642006-05-26 23:42:22 +0000235 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000236 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000237 }
238
Linus Walleijf0f3d482006-05-29 14:10:21 +0000239 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000240 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000241 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000242
Linus Walleij438bd7f2006-06-08 11:35:44 +0000243 current->destructor = (void *) destructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000244 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000245}
246
247/**
248 * Set the datafunc for a MTP filetype
249 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000250 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000251 * @param datafunc Pointer to a data function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000252 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000253*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000254int LIBMTP_Set_Datafunc(LIBMTP_filetype_t const id, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000255{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000256 LIBMTP_filemap_t *current;
Linus Walleijf67bca92006-05-29 09:33:39 +0000257
Linus Walleijf0f3d482006-05-29 14:10:21 +0000258 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000259 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000260 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000261
262 // Go through the filemap until an entry is found
263 current = filemap;
264
Linus Walleijf0f3d482006-05-29 14:10:21 +0000265 while(current != NULL) {
266 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000267 break;
raveloxd9a28642006-05-26 23:42:22 +0000268 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000269 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000270 }
271
Linus Walleijf0f3d482006-05-29 14:10:21 +0000272 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000273 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000274 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000275
Linus Walleij438bd7f2006-06-08 11:35:44 +0000276 current->datafunc = (void *) datafunc;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000277 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000278}
279
280static void init_filemap()
281{
Linus Walleijf67bca92006-05-29 09:33:39 +0000282 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 +0000283 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 +0000284 LIBMTP_Register_Filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
285 LIBMTP_Register_Filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
286 LIBMTP_Register_Filetype("Advanced Acoustic Coding", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
287 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 +0000288 LIBMTP_Register_Filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV,NULL,NULL,NULL);
289 LIBMTP_Register_Filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI,NULL,NULL,NULL);
290 LIBMTP_Register_Filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG,NULL,NULL,NULL);
291 LIBMTP_Register_Filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF,NULL,NULL,NULL);
292 LIBMTP_Register_Filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT,NULL,NULL,NULL);
293 LIBMTP_Register_Filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo,NULL,NULL,NULL);
Linus Walleij83f57eb2006-05-31 19:57:56 +0000294 LIBMTP_Register_Filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG,NULL,NULL,NULL);
295 LIBMTP_Register_Filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF,NULL,NULL,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000296 LIBMTP_Register_Filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF,NULL,NULL,NULL);
297 LIBMTP_Register_Filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP,NULL,NULL,NULL);
298 LIBMTP_Register_Filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF,NULL,NULL,NULL);
299 LIBMTP_Register_Filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT,NULL,NULL,NULL);
300 LIBMTP_Register_Filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG,NULL,NULL,NULL);
301 LIBMTP_Register_Filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat,NULL,NULL,NULL);
302 LIBMTP_Register_Filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1,NULL,NULL,NULL);
303 LIBMTP_Register_Filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2,NULL,NULL,NULL);
304 LIBMTP_Register_Filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2,NULL,NULL,NULL);
305 LIBMTP_Register_Filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3,NULL,NULL,NULL);
306 LIBMTP_Register_Filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable,NULL,NULL,NULL);
307 LIBMTP_Register_Filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text,NULL,NULL,NULL);
308 LIBMTP_Register_Filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML,NULL,NULL,NULL);
309 LIBMTP_Register_Filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined, NULL, NULL, NULL);
raveloxd9a28642006-05-26 23:42:22 +0000310}
Linus Walleij16c51f02006-05-04 13:20:22 +0000311
Linus Walleij16c51f02006-05-04 13:20:22 +0000312/**
313 * Returns the PTP filetype that maps to a certain libmtp internal file type.
314 * @param intype the MTP library interface type
315 * @return the PTP (libgphoto2) interface type
316 */
317static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
318{
raveloxd9a28642006-05-26 23:42:22 +0000319 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000320
raveloxd9a28642006-05-26 23:42:22 +0000321 current = filemap;
322
323 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000324 if(current->id == intype) {
325 return current->ptp_id;
326 }
327 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000328 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000329 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000330 return PTP_OFC_Undefined;
331}
332
333
334/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000335 * Returns the PTP internal filetype that maps to a certain libmtp
336 * interface file type.
Linus Walleij16c51f02006-05-04 13:20:22 +0000337 * @param intype the MTP library interface type
338 * @return the PTP (libgphoto2) interface type
339 */
340static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
341{
raveloxd9a28642006-05-26 23:42:22 +0000342 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000343
raveloxd9a28642006-05-26 23:42:22 +0000344 current = filemap;
345
346 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000347 if(current->ptp_id == intype) {
348 return current->id;
349 }
350 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000351 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000352 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000353 return LIBMTP_FILETYPE_UNKNOWN;
354}
355
356/**
raveloxd9a28642006-05-26 23:42:22 +0000357 * Returns the data function for the file type
358 * @param intype the PTP library interface
359 * @return pointer to the data function
360 */
361static void *get_datafunc(uint16_t intype)
362{
363 LIBMTP_filemap_t *current;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000364
raveloxd9a28642006-05-26 23:42:22 +0000365 current = filemap;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000366
raveloxd9a28642006-05-26 23:42:22 +0000367 while (current != NULL) {
368 if(current->ptp_id == intype) {
369 return current->datafunc;
370 }
371 current = current->next;
372 }
373 return NULL;
374}
375
376
377/**
378 * Returns the constructor for that file type data
379 * @param intype the PTP library interface type
380 * @return pointer to the constructor
381 */
382static void *get_constructor(uint16_t intype)
383{
384 LIBMTP_filemap_t *current;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000385
raveloxd9a28642006-05-26 23:42:22 +0000386 current = filemap;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000387
raveloxd9a28642006-05-26 23:42:22 +0000388 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000389 if(current->ptp_id == intype) {
390 return current->constructor;
391 }
392 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000393 }
394 return NULL;
395}
396
397/**
398 * Returns the destructor for that file type data
399 * @param intype the PTP library interface type
400 * @return pointer to the destructor
401 */
402static void *get_destructor(uint16_t intype)
403{
404 LIBMTP_filemap_t *current;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000405
raveloxd9a28642006-05-26 23:42:22 +0000406 current = filemap;
407
408 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000409 if(current->ptp_id == intype) {
410 return current->destructor;
411 }
412 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000413 }
414 return NULL;
415}
416
417/**
Linus Walleij16c51f02006-05-04 13:20:22 +0000418 * This helper function returns a textual description for a libmtp
419 * file type to be used in dialog boxes etc.
Linus Walleijf0f3d482006-05-29 14:10:21 +0000420 * @param intype the libmtp internal filetype to get a description for.
Linus Walleij16c51f02006-05-04 13:20:22 +0000421 * @return a string representing the filetype, this must <b>NOT</b>
422 * be free():ed by the caller!
423 */
424char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
425{
raveloxd9a28642006-05-26 23:42:22 +0000426 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000427
raveloxd9a28642006-05-26 23:42:22 +0000428 current = filemap;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000429
raveloxd9a28642006-05-26 23:42:22 +0000430 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000431 if(current->id == intype) {
432 return current->description;
433 }
434 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000435 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000436
Linus Walleij16c51f02006-05-04 13:20:22 +0000437 return "Unknown filetype";
438}
Linus Walleijfa1374c2006-02-27 07:41:46 +0000439
Linus Walleij6946ac52006-03-21 06:51:22 +0000440/**
Linus Walleijf0f3d482006-05-29 14:10:21 +0000441 * Initialize the library. You are only supposed to call this
442 * one, before using the library for the first time in a program.
443 * Never re-initialize libmtp!
444 *
raveloxd9a28642006-05-26 23:42:22 +0000445 * The only thing this does at the moment is to initialise the
446 * filetype mapping table.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000447 */
448void LIBMTP_Init(void)
449{
raveloxd9a28642006-05-26 23:42:22 +0000450 init_filemap();
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000451 return;
452}
453
454/**
raveloxd9a28642006-05-26 23:42:22 +0000455 * Retrieves a string from an object
456 *
457 * @param device a pointer to an MTP device.
458 * @param object_id Object reference
459 * @param attribute_id PTP attribute ID
460 * @param getUtf8 retrieve the string as UTF8. Specify 1 for UTF8.
Linus Walleij438bd7f2006-06-08 11:35:44 +0000461 * @return valid string or NULL on failure. The returned string
462 * must bee <code>free()</code>:ed by the caller after
463 * use.
raveloxd9a28642006-05-26 23:42:22 +0000464 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000465char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
466 uint32_t const attribute_id, uint8_t const getUtf8)
raveloxd9a28642006-05-26 23:42:22 +0000467{
468 PTPPropertyValue propval;
469 char *retstring = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000470 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000471 uint16_t ret;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000472
Linus Walleij438bd7f2006-06-08 11:35:44 +0000473 if ( device == NULL || object_id == 0) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000474 return NULL;
475 }
476
Linus Walleij438bd7f2006-06-08 11:35:44 +0000477 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval,
Linus Walleijf0f3d482006-05-29 14:10:21 +0000478 ( getUtf8 == 1 ? PTP_DTC_UNISTR : PTP_DTC_STR ));
raveloxd9a28642006-05-26 23:42:22 +0000479 if (ret == PTP_RC_OK) {
480 if (getUtf8 == 1) {
481 if (propval.unistr != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000482 retstring = ucs2_to_utf8(propval.unistr);
483 free(propval.unistr);
raveloxd9a28642006-05-26 23:42:22 +0000484 }
485 } else {
486 if (propval.str != NULL) {
Linus Walleijd14e84f2006-06-16 14:50:59 +0000487 retstring = (char *) strdup(propval.str);
raveloxd9a28642006-05-26 23:42:22 +0000488 free(propval.str);
489 }
490 }
491 }
Linus Walleij438bd7f2006-06-08 11:35:44 +0000492
raveloxd9a28642006-05-26 23:42:22 +0000493 return retstring;
494}
495
496/**
497 * Retrieves an unsigned 32-bit integer from an object attribute
498 *
499 * @param device a pointer to an MTP device.
500 * @param object_id Object reference
501 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000502 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000503 * @return the value
raveloxd9a28642006-05-26 23:42:22 +0000504 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000505uint32_t LIBMTP_Get_U32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
506 uint32_t const attribute_id, uint32_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000507{
508 PTPPropertyValue propval;
509 uint32_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000510 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000511 uint16_t ret;
512
Linus Walleijf0f3d482006-05-29 14:10:21 +0000513 if ( device == NULL ) {
514 return value_default;
515 }
raveloxd9a28642006-05-26 23:42:22 +0000516
raveloxd9a28642006-05-26 23:42:22 +0000517 ret = ptp_mtp_getobjectpropvalue(params, object_id,
518 attribute_id,
519 &propval,
520 PTP_DTC_UINT32);
521 if (ret == PTP_RC_OK) {
522 retval = propval.u32;
523 }
524
525 return retval;
526}
527
528/**
529 * Retrieves an unsigned 16-bit integer from an object attribute
530 *
531 * @param device a pointer to an MTP device.
532 * @param object_id Object reference
533 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000534 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000535 * @return a value
raveloxd9a28642006-05-26 23:42:22 +0000536 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000537uint16_t LIBMTP_Get_U16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
538 uint32_t const attribute_id, uint16_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000539{
540 PTPPropertyValue propval;
541 uint16_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000542 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000543 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000544
Linus Walleijf0f3d482006-05-29 14:10:21 +0000545 if ( device == NULL ) {
546 return value_default;
547 }
raveloxd9a28642006-05-26 23:42:22 +0000548
raveloxd9a28642006-05-26 23:42:22 +0000549 ret = ptp_mtp_getobjectpropvalue(params, object_id,
550 attribute_id,
551 &propval,
552 PTP_DTC_UINT16);
553 if (ret == PTP_RC_OK) {
554 retval = propval.u16;
555 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000556
raveloxd9a28642006-05-26 23:42:22 +0000557 return retval;
558}
559
560/**
561 * Sets an object attribute from a string
562 *
563 * @param device a pointer to an MTP device.
564 * @param object_id Object reference
565 * @param attribute_id PTP attribute ID
566 * @param string string value to set
567 * @param setUtf8 Specify string as UTF8. Set to 1 if UTF8.
Linus Walleijf0f3d482006-05-29 14:10:21 +0000568 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000569 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000570int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
571 uint32_t const attribute_id, char const * const string,
572 uint8_t const setUtf8)
raveloxd9a28642006-05-26 23:42:22 +0000573{
574 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000575 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000576 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000577
Linus Walleijf0f3d482006-05-29 14:10:21 +0000578 if (device == NULL || string == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000579 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000580 }
raveloxd9a28642006-05-26 23:42:22 +0000581
582 if (setUtf8 == 1) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000583 propval.unistr = utf8_to_ucs2((unsigned char const * const) string);
raveloxd9a28642006-05-26 23:42:22 +0000584 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UNISTR);
585 free(propval.unistr);
586 } else {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000587 propval.str = (char *) string;
raveloxd9a28642006-05-26 23:42:22 +0000588 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
589 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000590 if (ret != PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000591 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000592 }
Linus Walleij438bd7f2006-06-08 11:35:44 +0000593
Linus Walleijf0f3d482006-05-29 14:10:21 +0000594 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000595}
596
597/**
598 * Sets an object attribute from an unsigned 32-bit integer
599 *
600 * @param device a pointer to an MTP device.
601 * @param object_id Object reference
602 * @param attribute_id PTP attribute ID
603 * @param value 32-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000604 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000605 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000606int LIBMTP_Set_Object_U32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
607 uint32_t const attribute_id, uint32_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000608{
609 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000610 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000611 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000612
Linus Walleijf0f3d482006-05-29 14:10:21 +0000613 if (device == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000614 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000615 }
raveloxd9a28642006-05-26 23:42:22 +0000616
617 propval.u32 = value;
618 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000619 if (ret != PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000620 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000621 }
622
623 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000624}
625
626/**
627 * Sets an object attribute from an unsigned 16-bit integer
628 *
629 * @param device a pointer to an MTP device.
630 * @param object_id Object reference
631 * @param attribute_id PTP attribute ID
632 * @param value 16-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000633 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000634 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000635int LIBMTP_Set_Object_U16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
636 uint32_t const attribute_id, uint16_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000637{
638 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000639 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000640 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000641
Linus Walleijf0f3d482006-05-29 14:10:21 +0000642 if (device == NULL) {
643 return 1;
644 }
raveloxd9a28642006-05-26 23:42:22 +0000645
646 propval.u16 = value;
647 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000648 if (ret != PTP_RC_OK) {
649 return 1;
650 }
raveloxd9a28642006-05-26 23:42:22 +0000651
Linus Walleijf0f3d482006-05-29 14:10:21 +0000652 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000653}
654
655/**
656 * Gets an array of object ids associated with a specified object
657 *
658 * @param device a pointer to an MTP device.
659 * @param object_id Object reference
660 * @param items array of unsigned 32-bit integers
661 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000662 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000663 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000664int LIBMTP_Get_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleijf0f3d482006-05-29 14:10:21 +0000665 uint32_t **items, uint32_t *len)
raveloxd9a28642006-05-26 23:42:22 +0000666{
667 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000668 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000669
Linus Walleijf0f3d482006-05-29 14:10:21 +0000670 // A device must be attached
raveloxd9a28642006-05-26 23:42:22 +0000671 if (device == NULL ) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000672 *items = NULL;
673 *len = 0;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000674 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000675 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000676
677 ret = ptp_mtp_getobjectreferences (params, object_id, items, len);
raveloxd9a28642006-05-26 23:42:22 +0000678 if (ret != PTP_RC_OK) {
679 ptp_perror(params, ret);
680 printf("LIBMTP_Get_Object_References: Could not get object references\n");
Linus Walleijf0f3d482006-05-29 14:10:21 +0000681 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000682 }
683
Linus Walleijf0f3d482006-05-29 14:10:21 +0000684 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000685}
686
687/**
688 * Sets an array of object ids associated with a specified object
689 *
690 * @param device a pointer to an MTP device.
691 * @param object_id Object reference
692 * @param items array of unsigned 32-bit integers
693 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000694 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000695 */
Linus Walleij438bd7f2006-06-08 11:35:44 +0000696int LIBMTP_Set_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
697 uint32_t const * const items, uint32_t const len)
raveloxd9a28642006-05-26 23:42:22 +0000698{
699 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000700 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000701
702 if (device == NULL || items == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000703 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000704 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000705
Linus Walleij438bd7f2006-06-08 11:35:44 +0000706 ret = ptp_mtp_setobjectreferences (params, object_id, (uint32_t *) items, len);
raveloxd9a28642006-05-26 23:42:22 +0000707 if (ret != PTP_RC_OK) {
708 ptp_perror(params, ret);
709 printf("LIBMTP_Set_Object_References: Could not set object references\n");
Linus Walleijf0f3d482006-05-29 14:10:21 +0000710 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000711 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000712
Linus Walleijf0f3d482006-05-29 14:10:21 +0000713 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000714}
715
raveloxd9a28642006-05-26 23:42:22 +0000716/**
Linus Walleij6fd2f082006-03-28 07:19:22 +0000717 * Get a list of the supported devices.
718 *
Linus Walleijc86afbd2006-05-04 19:05:24 +0000719 * The developers depend on users of this library to constantly
720 * add in to the list of supported devices. What we need is the
721 * device name, USB Vendor ID (VID) and USB Product ID (PID).
722 * put this into a bug ticket at the project homepage, please.
723 * The VID/PID is used to let e.g. udev lift the device to
724 * console userspace access when it's plugged in.
725 *
Linus Walleij6fd2f082006-03-28 07:19:22 +0000726 * @param devices a pointer to a pointer that will hold a device
727 * list after the call to this function, if it was
728 * successful.
729 * @param numdevs a pointer to an integer that will hold the number
730 * of devices in the device list if the call was successful.
731 * @return 0 if the list was successfull retrieved, any other
732 * value means failure.
733 */
734int LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs)
735{
736 // Just dispatch to libusb glue file...
737 return get_device_list(devices, numdevs);
738}
739
740/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000741 * Get the first connected MTP device. There is currently no API for
742 * retrieveing multiple devices.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000743 * @return a device pointer.
744 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000745LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000746{
747 uint8_t interface_number;
Linus Walleij56d3e182006-02-10 15:46:54 +0000748 PTPParams *params;
749 PTP_USB *ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000750 PTPStorageIDs storageIDs;
751 unsigned storageID = 0;
752 PTPDevicePropDesc dpd;
753 uint8_t batteryLevelMax = 100;
754 uint16_t ret;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000755 uint32_t i;
Linus Walleijb9256fd2006-02-15 09:40:43 +0000756 LIBMTP_mtpdevice_t *tmpdevice;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000757
Linus Walleij56d3e182006-02-10 15:46:54 +0000758 // Allocate a parameter block
759 params = (PTPParams *) malloc(sizeof(PTPParams));
760 ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB));
761 ret = connect_first_device(params, ptp_usb, &interface_number);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000762
763 switch (ret)
764 {
765 case PTP_CD_RC_CONNECTED:
766 printf("Connected to MTP device.\n");
767 break;
768 case PTP_CD_RC_NO_DEVICES:
769 printf("No MTP devices.\n");
770 return NULL;
771 case PTP_CD_RC_ERROR_CONNECTING:
772 printf("Connection error.\n");
773 return NULL;
774 }
775
776 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000777 if (ptp_getstorageids (params, &storageIDs) == PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000778 if (storageIDs.n > 0)
779 storageID = storageIDs.Storage[0];
780 free(storageIDs.Storage);
781 }
782
783 // Make sure there are no handlers
Linus Walleij56d3e182006-02-10 15:46:54 +0000784 params->handles.Handler = NULL;
Linus Walleijb02a0662006-04-25 08:05:09 +0000785
Linus Walleij8c45b292006-04-26 14:12:44 +0000786 // Just cache the device information for any later use.
787 if (ptp_getdeviceinfo(params, &params->deviceinfo) != PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000788 goto error_handler;
789 }
790
791 // Get battery maximum level
Linus Walleij56d3e182006-02-10 15:46:54 +0000792 if (ptp_getdevicepropdesc(params, PTP_DPC_BatteryLevel, &dpd) != PTP_RC_OK) {
Linus Walleij8c45b292006-04-26 14:12:44 +0000793 printf("LIBMTP_Get_First_Device(): Unable to retrieve battery max level.\n");
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000794 goto error_handler;
795 }
796 // if is NULL, just leave as default
Linus Walleijb02a0662006-04-25 08:05:09 +0000797 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
798 batteryLevelMax = dpd.FORM.Range.MaximumValue.u8;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000799 }
800 ptp_free_devicepropdesc(&dpd);
801
802 // OK everything got this far, so it is time to create a device struct!
Linus Walleijb9256fd2006-02-15 09:40:43 +0000803 tmpdevice = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000804 tmpdevice->interface_number = interface_number;
Linus Walleij9b28da32006-03-16 13:47:58 +0000805 tmpdevice->params = (void *) params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000806 tmpdevice->usbinfo = (void *) ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000807 tmpdevice->storage_id = storageID;
808 tmpdevice->maximum_battery_level = batteryLevelMax;
809
Linus Walleij05ccbe72006-06-13 07:46:58 +0000810 // Set all default folders to 0 == root directory
811 tmpdevice->default_music_folder = 0;
812 tmpdevice->default_playlist_folder = 0;
813 tmpdevice->default_picture_folder = 0;
814 tmpdevice->default_video_folder = 0;
815 tmpdevice->default_organizer_folder = 0;
816 tmpdevice->default_zencast_folder = 0;
817
818 /*
819 * Then get the handles and try to locate the default folders.
820 * This has the desired side effect of cacheing all handles from
821 * the device which speeds up later operations.
822 */
823 flush_handles(tmpdevice);
824 for (i = 0; i < params->handles.n; i++) {
825 PTPObjectInfo oi;
826 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
827 // Ignore non-folders
828 if ( oi.ObjectFormat != PTP_OFC_Association )
829 continue;
830 if (!strcmp(oi.Filename, "Music")) {
831 tmpdevice->default_music_folder = params->handles.Handler[i];
832 continue;
833 } else if (!strcmp(oi.Filename, "My Playlists")) {
834 tmpdevice->default_playlist_folder = params->handles.Handler[i];
835 continue;
836 } else if (!strcmp(oi.Filename, "Pictures")) {
837 tmpdevice->default_picture_folder = params->handles.Handler[i];
838 continue;
839 } else if (!strcmp(oi.Filename, "Video")) {
840 tmpdevice->default_video_folder = params->handles.Handler[i];
841 continue;
842 } else if (!strcmp(oi.Filename, "My Organizer")) {
843 tmpdevice->default_organizer_folder = params->handles.Handler[i];
844 continue;
845 } else if (!strcmp(oi.Filename, "ZENcast")) {
846 tmpdevice->default_zencast_folder = params->handles.Handler[i];
847 continue;
848 }
849 } else {
850 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
851 }
852 }
853
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000854 return tmpdevice;
855
856 // Then close it again.
857 error_handler:
Linus Walleij56d3e182006-02-10 15:46:54 +0000858 close_device(ptp_usb, params, interface_number);
Linus Walleijb02a0662006-04-25 08:05:09 +0000859 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
860 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij56d3e182006-02-10 15:46:54 +0000861 if (params->handles.Handler != NULL) {
862 free(params->handles.Handler);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000863 }
864 return NULL;
865}
866
867/**
868 * This closes and releases an allocated MTP device.
Linus Walleijb9256fd2006-02-15 09:40:43 +0000869 * @param device a pointer to the MTP device to release.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000870 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000871void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000872{
Linus Walleij9b28da32006-03-16 13:47:58 +0000873 PTPParams *params = (PTPParams *) device->params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000874 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij9b28da32006-03-16 13:47:58 +0000875
Linus Walleij2d411db2006-03-22 12:13:09 +0000876 close_device(ptp_usb, params, device->interface_number);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000877 // Free the device info and any handler
Linus Walleijb02a0662006-04-25 08:05:09 +0000878 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
879 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij9b28da32006-03-16 13:47:58 +0000880 if (params->handles.Handler != NULL) {
881 free(params->handles.Handler);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000882 params->handles.Handler = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000883 }
884 free(device);
885}
Linus Walleijb9256fd2006-02-15 09:40:43 +0000886
887/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000888 * This function refresh the internal handle list whenever
889 * the items stored inside the device is altered. On operations
890 * that do not add or remove objects, this is typically not
891 * called.
892 * @param device a pointer to the MTP device to flush handles for.
893 */
894static void flush_handles(LIBMTP_mtpdevice_t *device)
895{
896 PTPParams *params = (PTPParams *) device->params;
897 uint16_t ret;
898
899 if (params->handles.Handler != NULL) {
900 free(params->handles.Handler);
901 }
902
903 // Get all the handles if we haven't already done that
904 ret = ptp_getobjecthandles(params,
905 PTP_GOH_ALL_STORAGE,
906 PTP_GOH_ALL_FORMATS,
907 PTP_GOH_ALL_ASSOCS,
908 &params->handles);
909 if (ret != PTP_RC_OK) {
910 printf("flush_handles(): LIBMTP panic: Could not get object handles...\n");
911 }
912
913 return;
914}
915
916/**
Linus Walleij8c45b292006-04-26 14:12:44 +0000917 * This function dumps out a large chunk of textual information
918 * provided from the PTP protocol and additionally some extra
919 * MTP-specific information where applicable.
920 * @param device a pointer to the MTP device to report info from.
921 */
922void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
923{
924 int i;
925 PTPParams *params = (PTPParams *) device->params;
Linus Walleijc6210fb2006-05-08 11:11:41 +0000926 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
927
928 printf("USB low-level info:\n");
929 dump_usbinfo(ptp_usb);
Linus Walleij8c45b292006-04-26 14:12:44 +0000930 /* Print out some verbose information */
931 printf("Device info:\n");
932 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
933 printf(" Model: %s\n", params->deviceinfo.Model);
934 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
935 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
936 printf(" Vendor extension ID: 0x%08x\n", params->deviceinfo.VendorExtensionID);
937 printf(" Vendor extension description: %s\n", params->deviceinfo.VendorExtensionDesc);
938 printf("Supported operations:\n");
939 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
940 printf(" 0x%04x\n", params->deviceinfo.OperationsSupported[i]);
941 }
942 printf("Events supported:\n");
943 if (params->deviceinfo.EventsSupported_len == 0) {
944 printf(" None.\n");
945 } else {
946 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
947 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
948 }
949 }
950 printf("Device Properties Supported:\n");
951 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
Linus Walleij16c51f02006-05-04 13:20:22 +0000952 char const *propdesc = ptp_get_property_description(params, params->deviceinfo.DevicePropertiesSupported[i]);
Linus Walleij545c7792006-06-13 15:22:30 +0000953
954 if (propdesc != NULL) {
955 printf(" 0x%04x: %s\n", params->deviceinfo.DevicePropertiesSupported[i], propdesc);
956 } else {
957 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
958 printf(" 0x%04x: Unknown property", prop);
959 }
Linus Walleij8c45b292006-04-26 14:12:44 +0000960 }
Linus Walleij545c7792006-06-13 15:22:30 +0000961
962 printf("Special directories:\n");
963 printf(" Default music folder: 0x%08x\n", device->default_music_folder);
964 printf(" Default playlist folder: 0x%08x\n", device->default_playlist_folder);
965 printf(" Default picture folder: 0x%08x\n", device->default_picture_folder);
966 printf(" Default video folder: 0x%08x\n", device->default_video_folder);
967 printf(" Default organizer folder: 0x%08x\n", device->default_organizer_folder);
968 printf(" Default zencast folder: 0x%08x\n", device->default_zencast_folder);
Linus Walleij8c45b292006-04-26 14:12:44 +0000969}
970
971/**
Linus Walleij80124062006-03-15 10:26:09 +0000972 * This retrieves the model name (often equal to product name)
973 * of an MTP device.
974 * @param device a pointer to the device to get the model name for.
975 * @return a newly allocated UTF-8 string representing the model name.
976 * The string must be freed by the caller after use. If the call
977 * was unsuccessful this will contain NULL.
978 */
979char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
980{
981 char *retmodel = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +0000982 PTPParams *params = (PTPParams *) device->params;
Linus Walleij80124062006-03-15 10:26:09 +0000983
Linus Walleij9b28da32006-03-16 13:47:58 +0000984 if (params->deviceinfo.Model != NULL) {
985 retmodel = strdup(params->deviceinfo.Model);
Linus Walleij80124062006-03-15 10:26:09 +0000986 }
987 return retmodel;
988}
989
990/**
991 * This retrieves the serial number of an MTP device.
992 * @param device a pointer to the device to get the serial number for.
993 * @return a newly allocated UTF-8 string representing the serial number.
994 * The string must be freed by the caller after use. If the call
995 * was unsuccessful this will contain NULL.
996 */
997char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
998{
999 char *retnumber = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001000 PTPParams *params = (PTPParams *) device->params;
Linus Walleij80124062006-03-15 10:26:09 +00001001
Linus Walleij9b28da32006-03-16 13:47:58 +00001002 if (params->deviceinfo.SerialNumber != NULL) {
1003 retnumber = strdup(params->deviceinfo.SerialNumber);
Linus Walleij80124062006-03-15 10:26:09 +00001004 }
1005 return retnumber;
1006}
1007
1008/**
1009 * This retrieves the device version (hardware and firmware version) of an
1010 * MTP device.
1011 * @param device a pointer to the device to get the device version for.
1012 * @return a newly allocated UTF-8 string representing the device version.
1013 * The string must be freed by the caller after use. If the call
1014 * was unsuccessful this will contain NULL.
1015 */
1016char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
1017{
1018 char *retversion = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001019 PTPParams *params = (PTPParams *) device->params;
Linus Walleij80124062006-03-15 10:26:09 +00001020
Linus Walleij9b28da32006-03-16 13:47:58 +00001021 if (params->deviceinfo.DeviceVersion != NULL) {
1022 retversion = strdup(params->deviceinfo.DeviceVersion);
Linus Walleij80124062006-03-15 10:26:09 +00001023 }
1024 return retversion;
1025}
1026
1027
1028/**
Linus Walleijb9256fd2006-02-15 09:40:43 +00001029 * This retrieves the owners name of an MTP device.
1030 * @param device a pointer to the device to get the owner for.
1031 * @return a newly allocated UTF-8 string representing the owner.
1032 * The string must be freed by the caller after use.
1033 */
1034char *LIBMTP_Get_Ownername(LIBMTP_mtpdevice_t *device)
1035{
Linus Walleijb02a0662006-04-25 08:05:09 +00001036 PTPPropertyValue propval;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001037 char *retstring = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001038 PTPParams *params = (PTPParams *) device->params;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001039
Linus Walleij9b28da32006-03-16 13:47:58 +00001040 if (ptp_getdevicepropvalue(params,
Linus Walleij545c7792006-06-13 15:22:30 +00001041 PTP_DPC_MTP_DeviceFriendlyName,
Linus Walleijb02a0662006-04-25 08:05:09 +00001042 &propval,
Linus Walleijb9256fd2006-02-15 09:40:43 +00001043 PTP_DTC_UNISTR) != PTP_RC_OK) {
1044 return NULL;
1045 }
1046 // Convert from UTF-16 to UTF-8
Linus Walleijb02a0662006-04-25 08:05:09 +00001047 retstring = ucs2_to_utf8((uint16_t *) propval.unistr);
1048 free(propval.unistr);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001049 return retstring;
1050}
1051
Linus Walleij394bbbe2006-02-22 16:10:53 +00001052/**
Linus Walleijfa1374c2006-02-27 07:41:46 +00001053 * This function finds out how much storage space is currently used
1054 * and any additional storage information. Storage may be a hard disk
1055 * or flash memory or whatever.
1056 * @param device a pointer to the device to get the storage info for.
1057 * @param total a pointer to a variable that will hold the
1058 * total the total number of bytes available on this volume after
1059 * the call.
1060 * @param free a pointer to a variable that will hold the number of
1061 * free bytes available on this volume right now after the call.
1062 * @param storage_description a description of the storage. This may
1063 * be NULL after the call even if it succeeded. If it is not NULL,
1064 * it must be freed by the callee after use.
1065 * @param volume_label a volume label or similar. This may be NULL after the
1066 * call even if it succeeded. If it is not NULL, it must be
1067 * freed by the callee after use.
1068 * @return 0 if the storage info was successfully retrieved, any other
1069 * value means failure.
1070 */
1071int LIBMTP_Get_Storageinfo(LIBMTP_mtpdevice_t *device, uint64_t * const total,
1072 uint64_t * const free, char ** const storage_description,
1073 char ** const volume_label)
1074{
1075 PTPStorageInfo storageInfo;
Linus Walleij9b28da32006-03-16 13:47:58 +00001076 PTPParams *params = (PTPParams *) device->params;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001077
Linus Walleij9b28da32006-03-16 13:47:58 +00001078 if (ptp_getstorageinfo(params, device->storage_id, &storageInfo) != PTP_RC_OK) {
Linus Walleijfa1374c2006-02-27 07:41:46 +00001079 printf("LIBMTP_Get_Diskinfo(): failed to get disk info\n");
1080 *total = 0;
1081 *free = 0;
1082 *storage_description = NULL;
1083 *volume_label = NULL;
1084 return -1;
1085 }
1086 *total = storageInfo.MaxCapability;
1087 *free = storageInfo.FreeSpaceInBytes;
1088 *storage_description = storageInfo.StorageDescription;
1089 *volume_label = storageInfo.VolumeLabel;
1090
1091 return 0;
1092}
1093
1094
1095/**
1096 * This function retrieves the current battery level on the device.
1097 * @param device a pointer to the device to get the battery level for.
1098 * @param maximum_level a pointer to a variable that will hold the
1099 * maximum level of the battery if the call was successful.
1100 * @param current_level a pointer to a variable that will hold the
1101 * current level of the battery if the call was successful.
Linus Walleij545c7792006-06-13 15:22:30 +00001102 * A value of 0 means that the device is on external power.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001103 * @return 0 if the storage info was successfully retrieved, any other
Linus Walleij545c7792006-06-13 15:22:30 +00001104 * value means failure. A typical cause of failure is that
1105 * the device does not support the battery level property.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001106 */
1107int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
1108 uint8_t * const maximum_level,
1109 uint8_t * const current_level)
1110{
Linus Walleijb02a0662006-04-25 08:05:09 +00001111 PTPPropertyValue propval;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001112 uint16_t ret;
Linus Walleij9b28da32006-03-16 13:47:58 +00001113 PTPParams *params = (PTPParams *) device->params;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001114
Linus Walleij545c7792006-06-13 15:22:30 +00001115 *maximum_level = 0;
1116 *current_level = 0;
1117
1118 if (!ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
1119 return -1;
1120 }
1121
Linus Walleijb02a0662006-04-25 08:05:09 +00001122 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel, &propval, PTP_DTC_UINT8);
1123 if (ret != PTP_RC_OK) {
Linus Walleijfa1374c2006-02-27 07:41:46 +00001124 return -1;
1125 }
1126
1127 *maximum_level = device->maximum_battery_level;
Linus Walleijb02a0662006-04-25 08:05:09 +00001128 *current_level = propval.u8;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001129
1130 return 0;
1131}
1132
1133/**
Linus Walleij545c7792006-06-13 15:22:30 +00001134 * Helper function to extract a unicode property off a device.
1135 */
1136int get_device_unicode_property(LIBMTP_mtpdevice_t *device, char **unicstring, uint16_t property)
1137{
1138 PTPPropertyValue propval;
1139 PTPParams *params = (PTPParams *) device->params;
1140 uint8_t *tmp;
1141 uint32_t len;
1142 int i;
1143
1144 if (!ptp_property_issupported(params, property)) {
1145 return -1;
1146 }
1147
1148 if (ptp_getdevicepropvalue(params,
1149 property,
1150 &propval,
1151 PTP_DTC_AUINT16) != PTP_RC_OK) {
1152 return -1;
1153 }
1154
1155 // Extract the actual array.
1156 len = propval.a.count * 2 + 2;
1157 tmp = malloc(len);
1158 for (i = 0; i < propval.a.count; i++) {
1159 // Force this to become a little-endian unicode string
1160 uint16_t tch = propval.a.v[i].u16;
1161 tmp[i*2] = (uint8_t) tch & 0xFF;
1162 tmp[(i*2)+1] = (uint8_t) tch >> 8;
1163 }
1164 tmp[len-1] = 0;
1165 tmp[len-2] = 0;
1166 free(propval.a.v);
1167
1168 *unicstring = ucs2_to_utf8((uint16_t *) tmp);
1169 free(tmp);
1170
1171 return 0;
1172}
1173
1174/**
1175 * This function returns the secure time as an XML document string from
1176 * the device.
1177 * @param device a pointer to the device to get the secure time for.
1178 * @param sectime the secure time string as an XML document or NULL if the call
1179 * failed or the secure time property is not supported. This string
1180 * must be <code>free()</code>:ed by the caller after use.
1181 * @return 0 on success, any other value means failure.
1182 */
1183int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char **sectime)
1184{
1185 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
1186}
1187
1188/**
1189 * This function returns the device (public key) certificate as an
1190 * XML document string from the device.
1191 * @param device a pointer to the device to get the device certificate for.
1192 * @param devcert the device certificate as an XML string or NULL if the call
1193 * failed or the device certificate property is not supported. This
1194 * string must be <code>free()</code>:ed by the caller after use.
1195 * @return 0 on success, any other value means failure.
1196 */
1197int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char **devcert)
1198{
1199 return get_device_unicode_property(device, devcert, PTP_DPC_MTP_DeviceCertificate);
1200}
1201
1202/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00001203 * This creates a new MTP object structure and allocates memory
raveloxd9a28642006-05-26 23:42:22 +00001204 * for it. Notice that if you add strings to this structure they
1205 * will be freed by the corresponding <code>LIBMTP_destroy_object_t</code>
1206 * operation later, so be careful of using strdup() when assigning
1207 * strings, e.g.:
1208 *
1209 * <pre>
1210 * LIBMTP_object_t *object = LIBMTP_new_object_t();
1211 * object->name = strdup(namestr);
1212 * ....
1213 * LIBMTP_destroy_object_t(file);
1214 * </pre>
1215 *
1216 * @return a pointer to the newly allocated structure.
1217 * @see LIBMTP_destroy_object_t()
1218 */
1219LIBMTP_object_t *LIBMTP_new_object_t(void)
1220{
1221 LIBMTP_object_t *new = (LIBMTP_object_t *) malloc(sizeof(LIBMTP_object_t));
1222 if (new == NULL) {
1223 return NULL;
1224 }
1225
1226 new->id = 0;
1227 new->parent = 0;
1228 new->type = LIBMTP_FILETYPE_UNKNOWN;
1229 new->size = 0;
1230 new->name = NULL;
1231 new->data = NULL;
1232 new->sibling = NULL;
1233 new->child = NULL;
1234
1235 return new;
1236}
Linus Walleijf0f3d482006-05-29 14:10:21 +00001237
raveloxd9a28642006-05-26 23:42:22 +00001238/**
Linus Walleijf6bc1782006-03-24 15:12:47 +00001239 * This creates a new file metadata structure and allocates memory
1240 * for it. Notice that if you add strings to this structure they
1241 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
1242 * operation later, so be careful of using strdup() when assigning
1243 * strings, e.g.:
1244 *
1245 * <pre>
1246 * LIBMTP_file_t *file = LIBMTP_new_file_t();
1247 * file->filename = strdup(namestr);
1248 * ....
1249 * LIBMTP_destroy_file_t(file);
1250 * </pre>
1251 *
1252 * @return a pointer to the newly allocated metadata structure.
1253 * @see LIBMTP_destroy_file_t()
1254 */
1255LIBMTP_file_t *LIBMTP_new_file_t(void)
1256{
1257 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
1258 if (new == NULL) {
1259 return NULL;
1260 }
1261 new->filename = NULL;
1262 new->filesize = 0;
1263 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
1264 new->next = NULL;
1265 return new;
1266}
1267
1268/**
1269 * This destroys a file metadata structure and deallocates the memory
1270 * used by it, including any strings. Never use a file metadata
1271 * structure again after calling this function on it.
1272 * @param file the file metadata to destroy.
1273 * @see LIBMTP_new_file_t()
1274 */
1275void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
1276{
1277 if (file == NULL) {
1278 return;
1279 }
1280 if (file->filename != NULL)
1281 free(file->filename);
1282 free(file);
1283 return;
1284}
1285
1286/**
1287 * This returns a long list of all files available
1288 * on the current MTP device. Typical usage:
1289 *
1290 * <pre>
1291 * LIBMTP_file_t *filelist;
1292 *
1293 * filelist = LIBMTP_Get_Filelisting(device);
1294 * while (filelist != NULL) {
1295 * LIBMTP_file_t *tmp;
1296 *
1297 * // Do something on each element in the list here...
1298 * tmp = filelist;
1299 * filelist = filelist->next;
1300 * LIBMTP_destroy_file_t(tmp);
1301 * }
1302 * </pre>
1303 *
1304 * @param device a pointer to the device to get the file listing for.
1305 * @return a list of files that can be followed using the <code>next</code>
1306 * field of the <code>LIBMTP_file_t</code> data structure.
1307 * Each of the metadata tags must be freed after use, and may
1308 * contain only partial metadata information, i.e. one or several
1309 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001310 * @see LIBMTP_Get_Filemetadata()
Linus Walleijf6bc1782006-03-24 15:12:47 +00001311 */
1312LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
1313{
1314 uint32_t i = 0;
1315 LIBMTP_file_t *retfiles = NULL;
1316 LIBMTP_file_t *curfile = NULL;
1317 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001318
1319 // Get all the handles if we haven't already done that
Linus Walleijf6bc1782006-03-24 15:12:47 +00001320 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00001321 flush_handles(device);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001322 }
1323
1324 for (i = 0; i < params->handles.n; i++) {
1325
1326 LIBMTP_file_t *file;
1327 PTPObjectInfo oi;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001328
1329 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleij16c51f02006-05-04 13:20:22 +00001330
Linus Walleij91405592006-05-05 14:22:51 +00001331 if (oi.ObjectFormat == PTP_OFC_Association) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00001332 // MTP use thesis object format for folders which means
Linus Walleij16c51f02006-05-04 13:20:22 +00001333 // these "files" will turn up on a folder listing instead.
1334 continue;
1335 }
1336
Linus Walleijf6bc1782006-03-24 15:12:47 +00001337 // Allocate a new file type
1338 file = LIBMTP_new_file_t();
Linus Walleijb02a0662006-04-25 08:05:09 +00001339
Linus Walleijd208f9c2006-04-27 14:16:06 +00001340 file->parent_id = oi.ParentObject;
Linus Walleij16c51f02006-05-04 13:20:22 +00001341
1342 // Set the filetype
1343 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001344
1345 // Original file-specific properties
1346 file->filesize = oi.ObjectCompressedSize;
1347 if (oi.Filename != NULL) {
1348 file->filename = strdup(oi.Filename);
1349 }
1350
1351 // This is some sort of unique ID so we can keep track of the track.
1352 file->item_id = params->handles.Handler[i];
1353
1354 // Add track to a list that will be returned afterwards.
1355 if (retfiles == NULL) {
1356 retfiles = file;
1357 curfile = file;
1358 } else {
1359 curfile->next = file;
1360 curfile = file;
1361 }
1362
1363 // Call listing callback
1364 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
1365
1366 } else {
1367 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
1368 }
1369
1370 } // Handle counting loop
1371 return retfiles;
1372}
1373
1374/**
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001375 * This function retrieves the metadata for a single file off
1376 * the device.
1377 *
1378 * Do not call this function repeatedly! The file handles are linearly
1379 * searched O(n) and the call may involve (slow) USB traffic, so use
1380 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
1381 * as an efficient data structure such as a hash list.
1382 *
1383 * @param device a pointer to the device to get the file metadata from.
1384 * @param fileid the object ID of the file that you want the metadata for.
1385 * @return a metadata entry on success or NULL on failure.
1386 * @see LIBMTP_Get_Filelisting()
1387 */
1388LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
1389{
1390 uint32_t i = 0;
1391 PTPParams *params = (PTPParams *) device->params;
1392
1393 // Get all the handles if we haven't already done that
1394 if (params->handles.Handler == NULL) {
1395 flush_handles(device);
1396 }
1397
1398 for (i = 0; i < params->handles.n; i++) {
1399 LIBMTP_file_t *file;
1400 PTPObjectInfo oi;
1401
1402 // Is this the file we're looking for?
1403 if (params->handles.Handler[i] != fileid) {
1404 continue;
1405 }
1406
1407 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
1408
1409 if (oi.ObjectFormat == PTP_OFC_Association) {
1410 // MTP use thesis object format for folders which means
1411 // these "files" will turn up on a folder listing instead.
1412 return NULL;
1413 }
1414
1415 // Allocate a new file type
1416 file = LIBMTP_new_file_t();
1417
1418 file->parent_id = oi.ParentObject;
1419
1420 // Set the filetype
1421 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
1422
1423 // Original file-specific properties
1424 file->filesize = oi.ObjectCompressedSize;
1425 if (oi.Filename != NULL) {
1426 file->filename = strdup(oi.Filename);
1427 }
1428
1429 // This is some sort of unique ID so we can keep track of the track.
1430 file->item_id = params->handles.Handler[i];
1431
1432 return file;
1433 } else {
1434 return NULL;
1435 }
1436
1437 }
1438 return NULL;
1439}
1440
1441/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00001442 * This creates a new track metadata structure and allocates memory
1443 * for it. Notice that if you add strings to this structure they
1444 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
1445 * operation later, so be careful of using strdup() when assigning
1446 * strings, e.g.:
1447 *
Linus Walleij17e39f72006-02-23 15:54:28 +00001448 * <pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001449 * LIBMTP_track_t *track = LIBMTP_new_track_t();
1450 * track->title = strdup(titlestr);
1451 * ....
1452 * LIBMTP_destroy_track_t(track);
Linus Walleij17e39f72006-02-23 15:54:28 +00001453 * </pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001454 *
1455 * @return a pointer to the newly allocated metadata structure.
1456 * @see LIBMTP_destroy_track_t()
1457 */
1458LIBMTP_track_t *LIBMTP_new_track_t(void)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001459{
1460 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
1461 if (new == NULL) {
1462 return NULL;
1463 }
1464 new->title = NULL;
1465 new->artist = NULL;
1466 new->album = NULL;
1467 new->genre = NULL;
1468 new->date = NULL;
1469 new->filename = NULL;
1470 new->duration = 0;
1471 new->tracknumber = 0;
1472 new->filesize = 0;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001473 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001474 new->next = NULL;
1475 return new;
1476}
1477
Linus Walleij394bbbe2006-02-22 16:10:53 +00001478/**
1479 * This destroys a track metadata structure and deallocates the memory
1480 * used by it, including any strings. Never use a track metadata
1481 * structure again after calling this function on it.
1482 * @param track the track metadata to destroy.
1483 * @see LIBMTP_new_track_t()
1484 */
Linus Walleijb9256fd2006-02-15 09:40:43 +00001485void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
1486{
1487 if (track == NULL) {
1488 return;
1489 }
1490 if (track->title != NULL)
1491 free(track->title);
1492 if (track->artist != NULL)
1493 free(track->artist);
1494 if (track->album != NULL)
1495 free(track->album);
1496 if (track->genre != NULL)
1497 free(track->genre);
1498 if (track->date != NULL)
1499 free(track->date);
1500 if (track->filename != NULL)
1501 free(track->filename);
1502 free(track);
1503 return;
1504}
1505
1506/**
1507 * This returns a long list of all tracks available
Linus Walleija4982732006-02-24 15:46:02 +00001508 * on the current MTP device. Typical usage:
1509 *
1510 * <pre>
1511 * LIBMTP_track_t *tracklist;
1512 *
1513 * tracklist = LIBMTP_Get_Tracklisting(device);
1514 * while (tracklist != NULL) {
1515 * LIBMTP_track_t *tmp;
1516 *
1517 * // Do something on each element in the list here...
1518 * tmp = tracklist;
1519 * tracklist = tracklist->next;
1520 * LIBMTP_destroy_track_t(tmp);
1521 * }
1522 * </pre>
1523 *
Linus Walleijb9256fd2006-02-15 09:40:43 +00001524 * @param device a pointer to the device to get the track listing for.
Linus Walleija4982732006-02-24 15:46:02 +00001525 * @return a list of tracks that can be followed using the <code>next</code>
1526 * field of the <code>LIBMTP_track_t</code> data structure.
1527 * Each of the metadata tags must be freed after use, and may
1528 * contain only partial metadata information, i.e. one or several
1529 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001530 * @see LIBMTP_Get_Trackmetadata()
Linus Walleijb9256fd2006-02-15 09:40:43 +00001531 */
1532LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
1533{
1534 uint32_t i = 0;
1535 LIBMTP_track_t *retracks = NULL;
1536 LIBMTP_track_t *curtrack = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001537 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001538
1539 // Get all the handles if we haven't already done that
Linus Walleij9b28da32006-03-16 13:47:58 +00001540 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00001541 flush_handles(device);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001542 }
1543
Linus Walleij9b28da32006-03-16 13:47:58 +00001544 for (i = 0; i < params->handles.n; i++) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001545 LIBMTP_track_t *track;
1546 PTPObjectInfo oi;
Linus Walleij5acfa742006-05-29 14:51:59 +00001547
Linus Walleij9b28da32006-03-16 13:47:58 +00001548 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001549
1550 // Ignore stuff we don't know how to handle...
Linus Walleij9c6ca022006-04-21 10:24:15 +00001551 if ( oi.ObjectFormat != PTP_OFC_WAV &&
Linus Walleijb9256fd2006-02-15 09:40:43 +00001552 oi.ObjectFormat != PTP_OFC_MP3 &&
Linus Walleij9c6ca022006-04-21 10:24:15 +00001553 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
1554 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
1555 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
1556 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
Linus Walleijafe61432006-05-05 13:51:34 +00001557 // printf("Not a music track (format: %d), skipping...\n",oi.ObjectFormat);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001558 continue;
1559 }
1560
1561 // Allocate a new track type
1562 track = LIBMTP_new_track_t();
Linus Walleij5acfa742006-05-29 14:51:59 +00001563
Linus Walleij16c51f02006-05-04 13:20:22 +00001564 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
Linus Walleij5acfa742006-05-29 14:51:59 +00001565
Linus Walleijb9256fd2006-02-15 09:40:43 +00001566 // Original file-specific properties
1567 track->filesize = oi.ObjectCompressedSize;
1568 if (oi.Filename != NULL) {
1569 track->filename = strdup(oi.Filename);
Linus Walleijb9256fd2006-02-15 09:40:43 +00001570 }
Linus Walleij5acfa742006-05-29 14:51:59 +00001571
1572 track->title = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name, 1);
1573 track->artist = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Artist, 1);
raveloxd9a28642006-05-26 23:42:22 +00001574 track->duration = LIBMTP_Get_U32_From_Object(device, params->handles.Handler[i], PTP_OPC_Duration, 0);
Linus Walleij5acfa742006-05-29 14:51:59 +00001575 track->tracknumber = LIBMTP_Get_U16_From_Object(device, params->handles.Handler[i], PTP_OPC_Track, 0);
Linus Walleij345a3372006-06-03 20:55:25 +00001576 track->genre = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Genre, 1);
Linus Walleij5acfa742006-05-29 14:51:59 +00001577 track->album = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_AlbumName, 1);
1578 track->date = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_OriginalReleaseDate, 0);
1579
Linus Walleijb9256fd2006-02-15 09:40:43 +00001580 // This is some sort of unique ID so we can keep track of the track.
Linus Walleij9b28da32006-03-16 13:47:58 +00001581 track->item_id = params->handles.Handler[i];
Linus Walleijb9256fd2006-02-15 09:40:43 +00001582
1583 // Add track to a list that will be returned afterwards.
1584 if (retracks == NULL) {
1585 retracks = track;
1586 curtrack = track;
1587 } else {
1588 curtrack->next = track;
1589 curtrack = track;
1590 }
1591
1592 // Call listing callback
Linus Walleij9b28da32006-03-16 13:47:58 +00001593 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001594
1595 } else {
1596 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
1597 }
1598
1599 } // Handle counting loop
1600 return retracks;
1601}
Linus Walleijdcde6082006-02-17 16:16:34 +00001602
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001603/**
1604 * This function retrieves the metadata for a single track off
1605 * the device.
1606 *
1607 * Do not call this function repeatedly! The track handles are linearly
1608 * searched O(n) and the call may involve (slow) USB traffic, so use
1609 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
1610 * as an efficient data structure such as a hash list.
1611 *
1612 * @param device a pointer to the device to get the track metadata from.
1613 * @param trackid the object ID of the track that you want the metadata for.
1614 * @return a track metadata entry on success or NULL on failure.
1615 * @see LIBMTP_Get_Tracklisting()
1616 */
1617LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
1618{
1619 uint32_t i = 0;
1620 PTPParams *params = (PTPParams *) device->params;
1621
1622 // Get all the handles if we haven't already done that
1623 if (params->handles.Handler == NULL) {
1624 flush_handles(device);
1625 }
1626
1627 for (i = 0; i < params->handles.n; i++) {
1628 PTPObjectInfo oi;
1629
1630 // Skip if this is not the track we want.
1631 if (params->handles.Handler[i] != trackid) {
1632 continue;
1633 }
1634
1635 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
1636 LIBMTP_track_t *track;
1637
1638 // Ignore stuff we don't know how to handle...
1639 if ( oi.ObjectFormat != PTP_OFC_WAV &&
1640 oi.ObjectFormat != PTP_OFC_MP3 &&
1641 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
1642 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
1643 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
1644 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
1645 return NULL;
1646 }
1647
1648 // Allocate a new track type
1649 track = LIBMTP_new_track_t();
1650
1651 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
1652
1653 // Original file-specific properties
1654 track->filesize = oi.ObjectCompressedSize;
1655 if (oi.Filename != NULL) {
1656 track->filename = strdup(oi.Filename);
1657 }
1658
1659 track->title = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name, 1);
1660 track->artist = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Artist, 1);
1661 track->duration = LIBMTP_Get_U32_From_Object(device, params->handles.Handler[i], PTP_OPC_Duration, 0);
1662 track->tracknumber = LIBMTP_Get_U16_From_Object(device, params->handles.Handler[i], PTP_OPC_Track, 0);
1663 track->genre = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Genre, 1);
1664 track->album = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_AlbumName, 1);
1665 track->date = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_OriginalReleaseDate, 0);
1666
1667 // This is some sort of unique ID so we can keep track of the track.
1668 track->item_id = params->handles.Handler[i];
1669
1670 return track;
1671
1672 } else {
1673 return NULL;
1674 }
1675
1676 }
1677 return NULL;
1678}
1679
Linus Walleijf6bc1782006-03-24 15:12:47 +00001680
1681/**
1682 * This gets a file off the device to a local file identified
1683 * by a filename.
1684 * @param device a pointer to the device to get the track from.
1685 * @param id the file ID of the file to retrieve.
1686 * @param path a filename to use for the retrieved file.
1687 * @param callback a progress indicator function or NULL to ignore.
1688 * @param data a user-defined pointer that is passed along to
1689 * the <code>progress</code> function in order to
1690 * pass along some user defined data to the progress
1691 * updates. If not used, set this to NULL.
1692 * @return 0 if the transfer was successful, any other value means
1693 * failure.
1694 * @see LIBMTP_Get_File_To_File_Descriptor()
1695 */
1696int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
1697 char const * const path, LIBMTP_progressfunc_t const * const callback,
1698 void const * const data)
1699{
1700 int fd = -1;
1701 int ret;
1702
1703 // Sanity check
1704 if (path == NULL) {
1705 printf("LIBMTP_Get_File_To_File(): Bad arguments, path was NULL\n");
1706 return -1;
1707 }
1708
1709 // Open file
1710#ifdef __WIN32__
flavienbfd80eb2006-06-01 22:41:49 +00001711 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU|S_IRGRP)) == -1 ) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001712#else
1713 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
1714#endif
1715 printf("LIBMTP_Get_File_To_File(): Could not create file \"%s\"\n", path);
1716 return -1;
1717 }
1718
1719 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
1720
1721 // Close file
1722 close(fd);
1723
1724 return ret;
1725}
1726
1727/**
1728 * This gets a file off the device to a file identified
1729 * by a file descriptor.
1730 * @param device a pointer to the device to get the file from.
1731 * @param id the file ID of the file to retrieve.
1732 * @param fd a local file descriptor to write the file to.
1733 * @param callback a progress indicator function or NULL to ignore.
1734 * @param data a user-defined pointer that is passed along to
1735 * the <code>progress</code> function in order to
1736 * pass along some user defined data to the progress
1737 * updates. If not used, set this to NULL.
1738 * @return 0 if the transfer was successful, any other value means
1739 * failure.
1740 * @see LIBMTP_Get_File_To_File()
1741 */
1742int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
1743 uint32_t const id,
1744 int const fd,
1745 LIBMTP_progressfunc_t const * const callback,
1746 void const * const data)
1747{
1748 PTPObjectInfo oi;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001749 unsigned char *image = NULL;
1750 uint16_t ret;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001751 PTPParams *params = (PTPParams *) device->params;
Linus Walleijb02a0662006-04-25 08:05:09 +00001752 ssize_t written;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001753
Linus Walleijf6bc1782006-03-24 15:12:47 +00001754 if (ptp_getobjectinfo(params, id, &oi) != PTP_RC_OK) {
1755 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get object info\n");
1756 return -1;
1757 }
1758 if (oi.ObjectFormat == PTP_OFC_Association) {
1759 printf("LIBMTP_Get_File_To_File_Descriptor(): Bad object format\n");
1760 return -1;
1761 }
Linus Walleijf6bc1782006-03-24 15:12:47 +00001762
Linus Walleijb02a0662006-04-25 08:05:09 +00001763 // Copy object to memory
1764 // We could use ptp_getpartialobject to make for progress bars etc.
Linus Walleij438bd7f2006-06-08 11:35:44 +00001765 ret = ptp_getobject(params, id, &image);
Linus Walleijb02a0662006-04-25 08:05:09 +00001766
1767 if (ret != PTP_RC_OK) {
1768 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device (%d)\n", ret);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001769 return -1;
1770 }
Linus Walleijf6bc1782006-03-24 15:12:47 +00001771
Linus Walleijb02a0662006-04-25 08:05:09 +00001772 written = write(fd, image, oi.ObjectCompressedSize);
1773 if (written != oi.ObjectCompressedSize) {
1774 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not write object properly\n");
Linus Walleijf6bc1782006-03-24 15:12:47 +00001775 }
1776
1777 return 0;
1778}
1779
Linus Walleijdcde6082006-02-17 16:16:34 +00001780/**
1781 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00001782 * by a filename. This is actually just a wrapper for the
1783 * \c LIBMTP_Get_Track_To_File() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00001784 * @param device a pointer to the device to get the track from.
1785 * @param id the track ID of the track to retrieve.
1786 * @param path a filename to use for the retrieved track.
1787 * @param callback a progress indicator function or NULL to ignore.
1788 * @param data a user-defined pointer that is passed along to
1789 * the <code>progress</code> function in order to
1790 * pass along some user defined data to the progress
1791 * updates. If not used, set this to NULL.
1792 * @return 0 if the transfer was successful, any other value means
1793 * failure.
1794 * @see LIBMTP_Get_Track_To_File_Descriptor()
1795 */
Linus Walleij0cd85432006-02-20 14:37:50 +00001796int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
1797 char const * const path, LIBMTP_progressfunc_t const * const callback,
1798 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00001799{
Linus Walleijf6bc1782006-03-24 15:12:47 +00001800 // This is just a wrapper
1801 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00001802}
1803
1804/**
1805 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00001806 * by a file descriptor. This is actually just a wrapper for
1807 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00001808 * @param device a pointer to the device to get the track from.
1809 * @param id the track ID of the track to retrieve.
1810 * @param fd a file descriptor to write the track to.
1811 * @param callback a progress indicator function or NULL to ignore.
1812 * @param data a user-defined pointer that is passed along to
1813 * the <code>progress</code> function in order to
1814 * pass along some user defined data to the progress
1815 * updates. If not used, set this to NULL.
1816 * @return 0 if the transfer was successful, any other value means
1817 * failure.
1818 * @see LIBMTP_Get_Track_To_File()
1819 */
1820int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
Linus Walleij0cd85432006-02-20 14:37:50 +00001821 uint32_t const id,
1822 int const fd,
1823 LIBMTP_progressfunc_t const * const callback,
1824 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00001825{
Linus Walleijf6bc1782006-03-24 15:12:47 +00001826 // This is just a wrapper
1827 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00001828}
Linus Walleij394bbbe2006-02-22 16:10:53 +00001829
1830/**
1831 * This function sends a track from a local file to an
1832 * MTP device. A filename and a set of metadata must be
1833 * given as input.
1834 * @param device a pointer to the device to send the track to.
1835 * @param path the filename of a local file which will be sent.
1836 * @param metadata a track metadata set to be written along with the file.
1837 * @param callback a progress indicator function or NULL to ignore.
1838 * @param data a user-defined pointer that is passed along to
1839 * the <code>progress</code> function in order to
1840 * pass along some user defined data to the progress
1841 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00001842 * @param parenthandle the parent (e.g. folder) to store this file
1843 * in. Pass in 0 to put the file in the root directory.
Linus Walleij394bbbe2006-02-22 16:10:53 +00001844 * @return 0 if the transfer was successful, any other value means
1845 * failure.
1846 * @see LIBMTP_Send_Track_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00001847 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00001848 */
1849int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
1850 char const * const path, LIBMTP_track_t * const metadata,
1851 LIBMTP_progressfunc_t const * const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00001852 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00001853{
1854 int fd;
1855 int ret;
1856
1857 // Sanity check
1858 if (path == NULL) {
1859 printf("LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL\n");
1860 return -1;
1861 }
1862
1863 // Open file
1864#ifdef __WIN32__
1865 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
1866#else
1867 if ( (fd = open(path, O_RDONLY)) == -1) {
1868#endif
Linus Walleijd6a49972006-05-02 08:24:54 +00001869 printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
Linus Walleij394bbbe2006-02-22 16:10:53 +00001870 return -1;
1871 }
1872
Linus Walleijd6a49972006-05-02 08:24:54 +00001873 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data, parenthandle);
Linus Walleij394bbbe2006-02-22 16:10:53 +00001874
1875 // Close file.
1876 close(fd);
1877
1878 return ret;
1879}
1880
Linus Walleijfa1374c2006-02-27 07:41:46 +00001881
1882/**
1883 * This is an internal function used by both the file and track
1884 * send functions. This takes care of a created object and
1885 * transfer the actual file contents to it.
1886 * @param device a pointer to the device to send the track to.
1887 * @param fd the filedescriptor for a local file which will be sent.
1888 * @param size the size of the file to be sent.
1889 * @param callback a progress indicator function or NULL to ignore.
1890 * @param data a user-defined pointer that is passed along to
1891 * the <code>progress</code> function in order to
1892 * pass along some user defined data to the progress
1893 * updates. If not used, set this to NULL.
1894 * @return 0 if the transfer was successful, any other value means
1895 * failure.
1896 */
Linus Walleijd208f9c2006-04-27 14:16:06 +00001897int send_file_object(LIBMTP_mtpdevice_t *device,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001898 int const fd, uint64_t size,
1899 LIBMTP_progressfunc_t const * const callback,
1900 void const * const data)
1901{
Linus Walleijb02a0662006-04-25 08:05:09 +00001902 void *image = NULL;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001903 uint16_t ret;
Linus Walleijb02a0662006-04-25 08:05:09 +00001904 PTPParams *params = (PTPParams *) device->params;
1905 ssize_t readb;
1906
1907 image = malloc(size);
1908 if (image == NULL) {
1909 printf("send_file_object(): Could not allocate memory.\n");
1910 return -1;
1911 }
1912 readb = read(fd, image, size);
1913 if (readb != size) {
1914 free(image);
1915 printf("send_file_object(): Could not read source file.\n");
1916 return -1;
1917 }
1918 ret = ptp_sendobject(params, image, size);
1919 free(image);
1920 if (ret != PTP_RC_OK) {
1921 printf("send_file_object(): Bad return code from ptp_sendobject(): %d.\n", ret);
1922 return -1;
1923 }
1924 return 0;
1925
1926#if 0
Linus Walleijfa1374c2006-02-27 07:41:46 +00001927 PTPContainer ptp;
1928 PTPUSBBulkContainerSend usbdata;
1929 uint16_t ret;
1930 uint8_t *buffer;
1931 uint64_t remain;
Linus Walleije8c54642006-03-28 09:45:00 +00001932 int last_chunk_size = 0; // Size of the last chunk written to the OUT endpoint
Linus Walleij9b28da32006-03-16 13:47:58 +00001933 PTPParams *params = (PTPParams *) device->params;
Linus Walleije8c54642006-03-28 09:45:00 +00001934 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001935
1936 // Nullify and configure PTP container
1937 memset(&ptp, 0, sizeof(ptp));
1938 ptp.Code = PTP_OC_SendObject;
1939 ptp.Nparam = 0;
Linus Walleij9b28da32006-03-16 13:47:58 +00001940 ptp.Transaction_ID = params->transaction_id++;
1941 ptp.SessionID = params->session_id;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001942
1943 // Send request to send an object
Linus Walleij9b28da32006-03-16 13:47:58 +00001944 ret = params->sendreq_func(params, &ptp);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001945 if (ret != PTP_RC_OK) {
Linus Walleij9b28da32006-03-16 13:47:58 +00001946 ptp_perror(params, ret);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001947 printf("send_file_object: Could not send \"send object\" request\n");
Linus Walleijfa1374c2006-02-27 07:41:46 +00001948 return -1;
1949 }
1950
1951 // build appropriate USB container
Linus Walleij9b28da32006-03-16 13:47:58 +00001952 usbdata.length = htod32p(params,sizeof(usbdata) + size);
1953 usbdata.type = htod16p(params,PTP_USB_CONTAINER_DATA);
1954 usbdata.code = htod16p(params,PTP_OC_SendObject);
1955 usbdata.trans_id = htod32p(params,ptp.Transaction_ID);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001956
1957 // Write request to USB
Linus Walleij9b28da32006-03-16 13:47:58 +00001958 ret = params->write_func((unsigned char *)&usbdata, sizeof(usbdata), params->data);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001959 if (ret != PTP_RC_OK) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001960 printf("send_file_object: Error initializing sending object\n");
Linus Walleij9b28da32006-03-16 13:47:58 +00001961 ptp_perror(params, ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001962 return -1;
1963 }
1964
1965 // This space will be used as a reading ring buffer for the transfers
1966 buffer = (uint8_t *) malloc(BLOCK_SIZE);
1967 if (buffer == NULL) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001968 printf("send_file_object: Could not allocate send buffer\n");
Linus Walleijfa1374c2006-02-27 07:41:46 +00001969 return -1;
1970 }
1971
1972 remain = size;
1973 while (remain != 0) {
1974 int readsize = (remain > BLOCK_SIZE) ? BLOCK_SIZE : (int) remain;
1975 int bytesdone = (int) (size - remain);
1976 int readbytes;
1977
1978 readbytes = read(fd, buffer, readsize);
1979 if (readbytes < readsize) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001980 printf("send_file_object: error reading source file\n");
Linus Walleijfa1374c2006-02-27 07:41:46 +00001981 printf("Wanted to read %d bytes but could only read %d.\n", readsize, readbytes);
1982 free(buffer);
1983 return -1;
1984 }
1985
1986 if (callback != NULL) {
1987 // If the callback return anything else than 0, interrupt the processing
Linus Walleij6946ac52006-03-21 06:51:22 +00001988 int callret = callback(bytesdone, size, data);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001989 if (callret != 0) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001990 printf("send_file_object: transfer interrupted by callback\n");
Linus Walleijfa1374c2006-02-27 07:41:46 +00001991 free(buffer);
1992 return -1;
1993 }
1994 }
1995
1996 // Write to USB
Linus Walleij9b28da32006-03-16 13:47:58 +00001997 ret = params->write_func(buffer, readsize, params->data);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001998 if (ret != PTP_RC_OK) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00001999 printf("send_file_object: error writing data chunk to object\n");
Linus Walleij9b28da32006-03-16 13:47:58 +00002000 ptp_perror(params, ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00002001 free(buffer);
2002 return -1;
2003 }
2004 remain -= (uint64_t) readsize;
Linus Walleije8c54642006-03-28 09:45:00 +00002005 // This is useful to keep track of last write
2006 last_chunk_size = readsize;
Linus Walleijfa1374c2006-02-27 07:41:46 +00002007 }
2008
2009 if (callback != NULL) {
2010 // This last call will not be able to abort execution and is just
Linus Walleija5483642006-03-09 09:20:38 +00002011 // done so progress bars go up to 100%
Linus Walleij6946ac52006-03-21 06:51:22 +00002012 (void) callback(size, size, data);
Linus Walleijfa1374c2006-02-27 07:41:46 +00002013 }
2014
Linus Walleije8c54642006-03-28 09:45:00 +00002015 /*
2016 * Signal to USB that this is the last transfer if the last chunk
2017 * was exactly as large as the buffer.
2018 *
2019 * On Linux you need kernel 2.6.16 or newer for this to work under
2020 * USB 2.0 since the EHCI driver did not support zerolength writes
2021 * until then. (Using a UHCI port should be OK though.)
2022 */
2023 if (last_chunk_size == ptp_usb->outep_maxpacket) {
Linus Walleij9b28da32006-03-16 13:47:58 +00002024 ret = params->write_func(NULL, 0, params->data);
Linus Walleijfa1374c2006-02-27 07:41:46 +00002025 if (ret!=PTP_RC_OK) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00002026 printf("send_file_object: error writing last zerolen data chunk for USB termination\n");
Linus Walleij9b28da32006-03-16 13:47:58 +00002027 ptp_perror(params, ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00002028 free(buffer);
2029 return -1;
2030 }
2031 }
2032
2033 // Get a response from device to make sure that the track was properly stored
Linus Walleij9b28da32006-03-16 13:47:58 +00002034 ret = params->getresp_func(params, &ptp);
Linus Walleijfa1374c2006-02-27 07:41:46 +00002035 if (ret != PTP_RC_OK) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00002036 printf("send_file_object: error getting response from device\n");
Linus Walleij9b28da32006-03-16 13:47:58 +00002037 ptp_perror(params, ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00002038 free(buffer);
2039 return -1;
2040 }
2041
2042 // Free allocated buffer
2043 free(buffer);
2044
2045 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +00002046#endif
Linus Walleijfa1374c2006-02-27 07:41:46 +00002047}
Linus Walleijfa1374c2006-02-27 07:41:46 +00002048
Linus Walleij394bbbe2006-02-22 16:10:53 +00002049/**
2050 * This function sends a track from a file descriptor to an
2051 * MTP device. A filename and a set of metadata must be
2052 * given as input.
2053 * @param device a pointer to the device to send the track to.
2054 * @param fd the filedescriptor for a local file which will be sent.
2055 * @param metadata a track metadata set to be written along with the file.
2056 * After this call the field <code>item_id</code>
2057 * will contain the new track ID.
2058 * @param callback a progress indicator function or NULL to ignore.
2059 * @param data a user-defined pointer that is passed along to
2060 * the <code>progress</code> function in order to
2061 * pass along some user defined data to the progress
2062 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002063 * @param parenthandle the parent (e.g. folder) to store this file
2064 * in. Pass in 0 to put the file in the root directory.
Linus Walleij394bbbe2006-02-22 16:10:53 +00002065 * @return 0 if the transfer was successful, any other value means
2066 * failure.
2067 * @see LIBMTP_Send_Track_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002068 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002069 */
2070int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
2071 int const fd, LIBMTP_track_t * const metadata,
2072 LIBMTP_progressfunc_t const * const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002073 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002074{
Linus Walleij394bbbe2006-02-22 16:10:53 +00002075 uint16_t ret;
2076 uint32_t store = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002077 int subcall_ret;
Linus Walleij394bbbe2006-02-22 16:10:53 +00002078 PTPObjectInfo new_track;
Linus Walleij9b28da32006-03-16 13:47:58 +00002079 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd6a49972006-05-02 08:24:54 +00002080 uint32_t localph = parenthandle;
Linus Walleij16c51f02006-05-04 13:20:22 +00002081
Linus Walleij05ccbe72006-06-13 07:46:58 +00002082 if (localph == 0) {
2083 localph = device->default_music_folder;
2084 }
2085
Linus Walleij16c51f02006-05-04 13:20:22 +00002086 // Sanity check, is this really a track?
2087 if (metadata->filetype != LIBMTP_FILETYPE_WAV &&
2088 metadata->filetype != LIBMTP_FILETYPE_MP3 &&
2089 metadata->filetype != LIBMTP_FILETYPE_WMA &&
2090 metadata->filetype != LIBMTP_FILETYPE_OGG &&
2091 metadata->filetype != LIBMTP_FILETYPE_MP4 &&
2092 metadata->filetype != LIBMTP_FILETYPE_UNDEF_AUDIO) {
2093 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 +00002094 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002095
Linus Walleij394bbbe2006-02-22 16:10:53 +00002096 new_track.Filename = metadata->filename;
2097 new_track.ObjectCompressedSize = metadata->filesize;
Linus Walleijab1827c2006-06-01 20:17:11 +00002098 new_track.ObjectFormat = map_libmtp_type_to_ptp_type(metadata->filetype);
Linus Walleijfcf88912006-06-05 13:23:33 +00002099
Linus Walleij394bbbe2006-02-22 16:10:53 +00002100 // Create the object
Linus Walleijd6a49972006-05-02 08:24:54 +00002101 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->item_id, &new_track);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002102 if (ret != PTP_RC_OK) {
Linus Walleij9b28da32006-03-16 13:47:58 +00002103 ptp_perror(params, ret);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002104 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object info\n");
2105 return -1;
2106 }
2107
Linus Walleijfa1374c2006-02-27 07:41:46 +00002108 // Call main function to transfer the track
2109 subcall_ret = send_file_object(device, fd, metadata->filesize, callback, data);
2110 if (subcall_ret != 0) {
2111 printf("LIBMTP_Send_Track_From_File_Descriptor: error sending track object\n");
Linus Walleij438bd7f2006-06-08 11:35:44 +00002112 (void) LIBMTP_Delete_Object(device, metadata->item_id);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002113 return -1;
2114 }
Linus Walleij394bbbe2006-02-22 16:10:53 +00002115
Linus Walleij17e39f72006-02-23 15:54:28 +00002116 // Set track metadata for the new fine track
2117 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
2118 if (subcall_ret != 0) {
2119 printf("LIBMTP_Send_Track_From_File_Descriptor: error setting metadata for new track\n");
Linus Walleij438bd7f2006-06-08 11:35:44 +00002120 (void) LIBMTP_Delete_Object(device, metadata->item_id);
Linus Walleij17e39f72006-02-23 15:54:28 +00002121 return -1;
2122 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002123
2124 // Added object so flush handles
2125 flush_handles(device);
Linus Walleij17e39f72006-02-23 15:54:28 +00002126
2127 return 0;
2128}
2129
Linus Walleijd6a49972006-05-02 08:24:54 +00002130/**
2131 * This function sends a local file to an MTP device.
2132 * A filename and a set of metadata must be
2133 * given as input.
2134 * @param device a pointer to the device to send the track to.
2135 * @param path the filename of a local file which will be sent.
2136 * @param filedata a file strtuct to pass in info about the file.
2137 * After this call the field <code>item_id</code>
2138 * will contain the new file ID.
2139 * @param callback a progress indicator function or NULL to ignore.
2140 * @param data a user-defined pointer that is passed along to
2141 * the <code>progress</code> function in order to
2142 * pass along some user defined data to the progress
2143 * updates. If not used, set this to NULL.
2144 * @param parenthandle the parent (e.g. folder) to store this file
2145 * in. Pass in 0 to put the file in the root directory.
2146 * @return 0 if the transfer was successful, any other value means
2147 * failure.
2148 * @see LIBMTP_Send_File_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002149 * @see LIBMTP_Delete_Object()
Linus Walleijd6a49972006-05-02 08:24:54 +00002150 */
2151int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
2152 char const * const path, LIBMTP_file_t * const filedata,
2153 LIBMTP_progressfunc_t const * const callback,
2154 void const * const data, uint32_t const parenthandle)
2155{
2156 int fd;
2157 int ret;
2158
2159 // Sanity check
2160 if (path == NULL) {
2161 printf("LIBMTP_Send_File_From_File(): Bad arguments, path was NULL\n");
2162 return -1;
2163 }
2164
2165 // Open file
2166#ifdef __WIN32__
2167 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2168#else
2169 if ( (fd = open(path, O_RDONLY)) == -1) {
2170#endif
2171 printf("LIBMTP_Send_File_From_File(): Could not open source file \"%s\"\n", path);
2172 return -1;
2173 }
2174
2175 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data, parenthandle);
2176
2177 // Close file.
2178 close(fd);
2179
2180 return ret;
2181}
2182
Linus Walleijd208f9c2006-04-27 14:16:06 +00002183/**
2184 * This function sends a generic file from a file descriptor to an
2185 * MTP device. A filename and a set of metadata must be
2186 * given as input.
2187 * @param device a pointer to the device to send the file to.
2188 * @param fd the filedescriptor for a local file which will be sent.
Linus Walleijd6a49972006-05-02 08:24:54 +00002189 * @param filedata a file strtuct to pass in info about the file.
Linus Walleijd208f9c2006-04-27 14:16:06 +00002190 * After this call the field <code>item_id</code>
2191 * will contain the new track ID.
2192 * @param callback a progress indicator function or NULL to ignore.
2193 * @param data a user-defined pointer that is passed along to
2194 * the <code>progress</code> function in order to
2195 * pass along some user defined data to the progress
2196 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002197 * @param parenthandle the parent (e.g. folder) to store this file
2198 * in. Pass in 0 to put the file in the root directory.
Linus Walleijd208f9c2006-04-27 14:16:06 +00002199 * @return 0 if the transfer was successful, any other value means
2200 * failure.
Linus Walleijd6a49972006-05-02 08:24:54 +00002201 * @see LIBMTP_Send_File_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002202 * @see LIBMTP_Delete_Object()
Linus Walleijd208f9c2006-04-27 14:16:06 +00002203 */
2204int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
2205 int const fd, LIBMTP_file_t * const filedata,
2206 LIBMTP_progressfunc_t const * const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002207 void const * const data, uint32_t const parenthandle)
Linus Walleijd208f9c2006-04-27 14:16:06 +00002208{
2209 uint16_t ret;
2210 uint32_t store = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +00002211 uint32_t localph = parenthandle;
Linus Walleijd208f9c2006-04-27 14:16:06 +00002212 int subcall_ret;
2213 PTPObjectInfo new_file;
2214 PTPParams *params = (PTPParams *) device->params;
Linus Walleij05ccbe72006-06-13 07:46:58 +00002215
Linus Walleijd208f9c2006-04-27 14:16:06 +00002216 new_file.Filename = filedata->filename;
2217 new_file.ObjectCompressedSize = filedata->filesize;
Linus Walleij16c51f02006-05-04 13:20:22 +00002218 new_file.ObjectFormat = map_libmtp_type_to_ptp_type(filedata->filetype);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002219
Linus Walleij05ccbe72006-06-13 07:46:58 +00002220 /*
2221 * If no destination folder was given, look up a default
2222 * folder if possible. Perhaps there is some way of retrieveing
2223 * the default folder for different forms of content, what
2224 * do I know, we use a fixed list in lack of any better method.
2225 * Some devices obviously need to have their files in certain
2226 * folders in order to find/display them at all (hello Creative),
2227 * so we have to have a method for this.
2228 */
2229
2230 if (localph == 0) {
2231 uint16_t of = new_file.ObjectFormat;
2232 if (of == PTP_OFC_WAV ||
2233 of == PTP_OFC_MP3 ||
2234 of == PTP_OFC_MTP_WMA ||
2235 of == PTP_OFC_MTP_OGG ||
2236 of == PTP_OFC_MTP_MP4 ||
2237 of == PTP_OFC_MTP_UndefinedAudio) {
2238 localph = device->default_music_folder;
2239 } else if (of == PTP_OFC_MTP_WMV ||
2240 of == PTP_OFC_AVI ||
2241 of == PTP_OFC_MPEG ||
2242 of == PTP_OFC_ASF ||
2243 of == PTP_OFC_QT ||
2244 of == PTP_OFC_MTP_UndefinedVideo) {
2245 localph = device->default_video_folder;
2246 } else if (of == PTP_OFC_EXIF_JPEG ||
2247 of == PTP_OFC_JFIF ||
2248 of == PTP_OFC_TIFF ||
2249 of == PTP_OFC_BMP ||
2250 of == PTP_OFC_GIF ||
2251 of == PTP_OFC_PICT ||
2252 of == PTP_OFC_PNG ||
2253 of == PTP_OFC_MTP_WindowsImageFormat) {
2254 localph = device->default_picture_folder;
2255 } else if (of == PTP_OFC_MTP_vCalendar1 ||
2256 of == PTP_OFC_MTP_vCalendar2) {
2257 localph = device->default_organizer_folder;
2258 }
2259 }
2260
Linus Walleijd208f9c2006-04-27 14:16:06 +00002261 // Create the object
Linus Walleijd6a49972006-05-02 08:24:54 +00002262 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002263 if (ret != PTP_RC_OK) {
2264 ptp_perror(params, ret);
2265 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object info\n");
2266 return -1;
2267 }
2268
2269 // Call main function to transfer the track
2270 subcall_ret = send_file_object(device, fd, filedata->filesize, callback, data);
2271 if (subcall_ret != 0) {
2272 printf("LIBMTP_Send_File_From_File_Descriptor: error sending track object\n");
Linus Walleij438bd7f2006-06-08 11:35:44 +00002273 (void) LIBMTP_Delete_Object(device, filedata->item_id);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002274 return -1;
2275 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002276
2277 // Added object so flush handles.
2278 flush_handles(device);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002279 return 0;
2280}
2281
Linus Walleij17e39f72006-02-23 15:54:28 +00002282/**
2283 * This function updates the MTP object metadata on a single file
2284 * identified by an object ID.
Linus Walleij95698cd2006-02-24 10:40:40 +00002285 * @param device a pointer to the device to update the track
2286 * metadata on.
Linus Walleij17e39f72006-02-23 15:54:28 +00002287 * @param metadata a track metadata set to be written to the file.
2288 * notice that the <code>track_id</code> field of the
2289 * metadata structure must be correct so that the
Linus Walleija4982732006-02-24 15:46:02 +00002290 * function can update the right file. If some properties
2291 * of this metadata are set to NULL (strings) or 0
2292 * (numerical values) they will be discarded and the
2293 * track will not be tagged with these blank values.
Linus Walleij17e39f72006-02-23 15:54:28 +00002294 * @return 0 on success, any other value means failure.
2295 */
2296int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
2297 LIBMTP_track_t const * const metadata)
2298{
Linus Walleij17e39f72006-02-23 15:54:28 +00002299 uint16_t ret;
2300
2301 // Update title
raveloxd9a28642006-05-26 23:42:22 +00002302 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Name, metadata->title,1);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002303 if (ret != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002304 printf("LIBMTP_Update_Track_Metadata(): could not set track title\n");
2305 return -1;
Linus Walleij17e39f72006-02-23 15:54:28 +00002306 }
2307
2308 // Update album
raveloxd9a28642006-05-26 23:42:22 +00002309 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album,1);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002310 if (ret != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002311 printf("LIBMTP_Update_Track_Metadata(): could not set track album name\n");
2312 return -1;
Linus Walleij17e39f72006-02-23 15:54:28 +00002313 }
2314
2315 // Update artist
raveloxd9a28642006-05-26 23:42:22 +00002316 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Artist, metadata->artist,1);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002317 if (ret != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002318 printf("LIBMTP_Update_Track_Metadata(): could not set track artist name\n");
2319 return -1;
Linus Walleij17e39f72006-02-23 15:54:28 +00002320 }
2321
2322 // Update genre
Linus Walleij345a3372006-06-03 20:55:25 +00002323 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Genre, metadata->genre,1);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002324 if (ret != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002325 printf("LIBMTP_Update_Track_Metadata(): could not set track genre name\n");
2326 return -1;
Linus Walleij17e39f72006-02-23 15:54:28 +00002327 }
2328
2329 // Update duration
Linus Walleija4982732006-02-24 15:46:02 +00002330 if (metadata->duration != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002331 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_Duration, metadata->duration);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002332 if (ret != 0) {
Linus Walleija4982732006-02-24 15:46:02 +00002333 printf("LIBMTP_Update_Track_Metadata(): could not set track duration\n");
2334 return -1;
2335 }
Linus Walleij17e39f72006-02-23 15:54:28 +00002336 }
2337
Linus Walleija4982732006-02-24 15:46:02 +00002338 // Update track number.
2339 if (metadata->tracknumber != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002340 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Track, metadata->tracknumber);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002341 if (ret != 0) {
Linus Walleija4982732006-02-24 15:46:02 +00002342 printf("LIBMTP_Update_Track_Metadata(): could not set track tracknumber\n");
2343 return -1;
2344 }
Linus Walleij17e39f72006-02-23 15:54:28 +00002345 }
2346
2347 // Update creation datetime
raveloxd9a28642006-05-26 23:42:22 +00002348 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date,0);
Linus Walleijd3fdd972006-05-30 15:51:37 +00002349 if (ret != 0) {
raveloxd9a28642006-05-26 23:42:22 +00002350 printf("LIBMTP_Update_Track_Metadata(): could not set track release date\n");
2351 return -1;
Linus Walleij17e39f72006-02-23 15:54:28 +00002352 }
2353
2354 // NOTE: File size is not updated, this should not change anyway.
Linus Walleija4982732006-02-24 15:46:02 +00002355 // neither will we change the filename.
Linus Walleij17e39f72006-02-23 15:54:28 +00002356
Linus Walleij394bbbe2006-02-22 16:10:53 +00002357 return 0;
2358}
Linus Walleij95698cd2006-02-24 10:40:40 +00002359
2360/**
Linus Walleij438bd7f2006-06-08 11:35:44 +00002361 * This function deletes a single file, track, playlist or
2362 * any other object off the MTP device,
Linus Walleij95698cd2006-02-24 10:40:40 +00002363 * identified by an object ID.
Linus Walleijf6bc1782006-03-24 15:12:47 +00002364 * @param device a pointer to the device to delete the file or track from.
Linus Walleij95698cd2006-02-24 10:40:40 +00002365 * @param item_id the item to delete.
2366 * @return 0 on success, any other value means failure.
2367 */
Linus Walleij438bd7f2006-06-08 11:35:44 +00002368int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
2369 uint32_t object_id)
Linus Walleij95698cd2006-02-24 10:40:40 +00002370{
Linus Walleij438bd7f2006-06-08 11:35:44 +00002371 uint16_t ret;
2372 PTPParams *params = (PTPParams *) device->params;
2373
2374 ret = ptp_deleteobject(params, object_id, 0);
2375 if (ret != PTP_RC_OK) {
2376 ptp_perror(params, ret);
2377 printf("LIBMTP_Delete_Object(): could not delete object\n");
2378 return -1;
2379 }
2380 // Removed object so flush handles.
2381 flush_handles(device);
2382 return 0;
Linus Walleij95698cd2006-02-24 10:40:40 +00002383}
Linus Walleij9c6ca022006-04-21 10:24:15 +00002384
Linus Walleij9c6ca022006-04-21 10:24:15 +00002385/**
2386 * Helper function. This indicates if a track exists on the device
2387 * @param device a pointer to the device to get the track from.
2388 * @param id the track ID of the track to retrieve.
2389 * @return TRUE (1) if the track exists, FALSE (0) if not
2390 */
2391int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
2392 uint32_t const id)
2393{
2394 PTPObjectInfo oi;
2395 PTPParams *params = (PTPParams *) device->params;
2396
2397 if (ptp_getobjectinfo(params, id, &oi) == PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002398 return -1;
Linus Walleij9c6ca022006-04-21 10:24:15 +00002399 }
2400 return 0;
2401}
2402
2403/**
2404 * This creates a new folder structure and allocates memory
2405 * for it. Notice that if you add strings to this structure they
2406 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
2407 * operation later, so be careful of using strdup() when assigning
2408 * strings, e.g.:
2409 *
2410 * @return a pointer to the newly allocated folder structure.
2411 * @see LIBMTP_destroy_folder_t()
2412 */
2413LIBMTP_folder_t *LIBMTP_new_folder_t(void)
2414{
2415 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
2416 if (new == NULL) {
2417 return NULL;
2418 }
2419 new->folder_id = 0;
2420 new->parent_id = 0;
2421 new->name = NULL;
2422 new->sibling = NULL;
2423 new->child = NULL;
2424 return new;
2425}
2426
2427/**
raveloxd9a28642006-05-26 23:42:22 +00002428 *
2429 * This deletes the memory for an object structure
2430 * and makes use of the registered destructor for the object
2431 * type data.
2432 *
2433 * @param object object structure to destroy
2434 * @param recurse indicate if the call should recursively delete
2435 * the object. Specify 1 for recursion.
2436 * @see LIBMTP_new_object_t()
2437 */
2438void LIBMTP_destroy_object_t(LIBMTP_object_t *object, uint32_t recursive)
2439{
Linus Walleijf0f3d482006-05-29 14:10:21 +00002440 if(object == NULL) {
2441 return;
2442 }
2443
2444 //Destroy from the bottom up
2445 if(recursive==1) {
2446 LIBMTP_destroy_object_t(object->child, recursive);
2447 object->child = NULL;
2448 LIBMTP_destroy_object_t(object->sibling, recursive);
2449 object->sibling = NULL;
2450 }
raveloxd9a28642006-05-26 23:42:22 +00002451
Linus Walleijf0f3d482006-05-29 14:10:21 +00002452 if(object->name != NULL) free(object->name);
2453
2454 //Use the data type destructor
2455 if(object->data != NULL) {
2456 void (*destructor)(void *);
2457
2458 destructor = get_destructor(object->type);
2459
2460 if(destructor != NULL) {
2461 (*destructor)(object->data);
2462 }
2463 object->data = NULL;
2464 }
2465
2466 free(object);
raveloxd9a28642006-05-26 23:42:22 +00002467}
2468
2469/**
Linus Walleij9c6ca022006-04-21 10:24:15 +00002470 * This recursively deletes the memory for a folder structure
2471 *
2472 * @param folder folder structure to destroy
2473 * @see LIBMTP_new_folder_t()
2474 */
2475void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
2476{
2477
2478 if(folder == NULL) {
2479 return;
2480 }
2481
2482 //Destroy from the bottom up
2483 if(folder->child != NULL) {
2484 LIBMTP_destroy_folder_t(folder->child);
2485 }
2486
2487 if(folder->sibling != NULL) {
2488 LIBMTP_destroy_folder_t(folder->sibling);
2489 }
2490
2491 if(folder->name != NULL) {
2492 free(folder->name);
2493 }
2494
2495 free(folder);
2496}
2497
2498/**
2499 * Helper function. Returns a folder structure for a
2500 * specified id.
2501 *
2502 * @param folderlist list of folders to search
2503 * @id id of folder to look for
2504 * @return a folder or NULL if not found
2505 */
2506LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
2507{
2508 LIBMTP_folder_t *ret = NULL;
2509
2510 if(folderlist == NULL) {
2511 return NULL;
2512 }
2513
2514 if(folderlist->folder_id == id) {
2515 return folderlist;
2516 }
2517
2518 if(folderlist->sibling) {
2519 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
2520 }
2521
2522 if(folderlist->child && ret == NULL) {
2523 ret = LIBMTP_Find_Folder(folderlist->child, id);
2524 }
2525
2526 return ret;
2527}
2528
2529/**
2530 * This returns a list of all folders available
2531 * on the current MTP device.
2532 *
2533 * @param device a pointer to the device to get the track listing for.
2534 * @return a list of folders
2535 */
2536LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
2537{
2538 uint32_t i = 0;
2539 LIBMTP_folder_t *retfolders = NULL;
2540 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002541
2542 // Get all the handles if we haven't already done that
Linus Walleij9c6ca022006-04-21 10:24:15 +00002543 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002544 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00002545 }
2546
2547 for (i = 0; i < params->handles.n; i++) {
2548 LIBMTP_folder_t *folder;
2549 PTPObjectInfo oi;
2550
2551 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
2552 if (oi.ObjectFormat != PTP_OFC_Association) {
2553 continue;
2554 }
2555 folder = LIBMTP_new_folder_t();
2556 folder->folder_id = params->handles.Handler[i];
2557 folder->parent_id = oi.ParentObject;
2558 folder->name = (char *)strdup(oi.Filename);
2559
2560 // Work out where to put this new item
2561 if(retfolders == NULL) {
2562 retfolders = folder;
2563 continue;
2564 } else {
2565 LIBMTP_folder_t *parent_folder;
2566 LIBMTP_folder_t *current_folder;
2567
2568 parent_folder = LIBMTP_Find_Folder(retfolders, folder->parent_id);
2569
2570 if(parent_folder == NULL) {
2571 current_folder = retfolders;
2572 } else {
2573 if(parent_folder->child == NULL) {
2574 parent_folder->child = folder;
2575 continue;
2576 } else {
2577 current_folder = parent_folder->child;
2578 }
2579 }
2580
2581 while(current_folder->sibling != NULL) {
2582 current_folder=current_folder->sibling;
2583 }
2584
2585 current_folder->sibling = folder;
2586 }
2587 }
2588 }
2589 return retfolders;
2590}
2591
2592/**
Linus Walleijc86afbd2006-05-04 19:05:24 +00002593 * This create a folder on the current MTP device. The PTP name
2594 * for a folder is "association". The PTP/MTP devices does not
2595 * have an internal "folder" concept really, it contains a flat
2596 * list of all files and some file are "associations" that other
2597 * files and folders may refer to as its "parent".
Linus Walleij9c6ca022006-04-21 10:24:15 +00002598 *
Linus Walleijc86afbd2006-05-04 19:05:24 +00002599 * @param device a pointer to the device to create the folder on.
2600 * @param name the name of the new folder.
2601 * @param parent_id id of parent folder to add the new folder to,
2602 * or 0 to put it in the root directory.
2603 * @return id to new folder or 0 if an error occured
Linus Walleij9c6ca022006-04-21 10:24:15 +00002604 */
2605uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name, uint32_t parent_id)
2606{
2607 PTPParams *params = (PTPParams *) device->params;
2608 uint32_t parenthandle = 0;
2609 uint32_t store = 0;
2610 PTPObjectInfo new_folder;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002611 uint16_t ret;
Linus Walleij9c6ca022006-04-21 10:24:15 +00002612 uint32_t new_id = 0;
2613
2614 memset(&new_folder, 0, sizeof(new_folder));
2615 new_folder.Filename = name;
2616 new_folder.ObjectCompressedSize = 1;
2617 new_folder.ObjectFormat = PTP_OFC_Association;
2618 new_folder.ParentObject = parent_id;
2619
2620 parenthandle = parent_id;
2621 // Create the object
2622 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
2623 if (ret != PTP_RC_OK) {
2624 ptp_perror(params, ret);
2625 printf("LIBMTP_Create_Folder: Could not send object info\n");
Linus Walleijc86afbd2006-05-04 19:05:24 +00002626 return 0;
Linus Walleij9c6ca022006-04-21 10:24:15 +00002627 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002628 // Created new object so flush handles
2629 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00002630 return new_id;
2631}
raveloxd9a28642006-05-26 23:42:22 +00002632
2633
2634/**
2635 * Helper function. Returns a folder structure for a
2636 * specified id.
2637 *
2638 * @param objectlist list of objects to search
2639 * @id id of object to look for
2640 * @return a object or NULL if not found
2641 */
2642LIBMTP_object_t *LIBMTP_Find_Object(LIBMTP_object_t *objectlist, uint32_t id)
2643{
2644 LIBMTP_object_t *ret = NULL;
2645
2646 if(objectlist == NULL) {
2647 return NULL;
2648 }
2649
2650 if(objectlist->id == id) {
2651 return objectlist;
2652 }
2653
2654 if(objectlist->sibling) {
2655 ret = LIBMTP_Find_Object(objectlist->sibling, id);
2656 }
2657
2658 if(objectlist->child && ret == NULL) {
2659 ret = LIBMTP_Find_Object(objectlist->child, id);
2660 }
2661
2662 return ret;
2663}
2664
2665/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00002666 * This returns a list of objects on the current MTP device,
2667 * selected by a filter based on PTP object ID:s.
raveloxd9a28642006-05-26 23:42:22 +00002668 *
Linus Walleijf0f3d482006-05-29 14:10:21 +00002669 * @param device a pointer to the device to get the object listing for.
raveloxd9a28642006-05-26 23:42:22 +00002670 * @param filter array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00002671 * to include in the list
2672 * @param filter_len length of filter array in 32-bit words
raveloxd9a28642006-05-26 23:42:22 +00002673 * @param exclusions array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00002674 * to exclude from the list
raveloxd9a28642006-05-26 23:42:22 +00002675 * @param exclusion_len length of exclusion array
2676 * @return a list of objects
2677 * @see LIBMTP_destroy_object_t()
2678 */
Linus Walleijf0f3d482006-05-29 14:10:21 +00002679LIBMTP_object_t *LIBMTP_Make_List(LIBMTP_mtpdevice_t *device, uint32_t *filter,
2680 uint32_t filter_len, uint32_t *exclusions, uint32_t exclusion_len)
raveloxd9a28642006-05-26 23:42:22 +00002681{
2682 uint32_t i = 0;
2683 LIBMTP_object_t *objectlist = NULL;
2684 PTPParams *params = (PTPParams *) device->params;
raveloxd9a28642006-05-26 23:42:22 +00002685 uint32_t max_exclusions = 0;
2686 uint32_t max_filter = 0;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002687
2688 // Get all the handles if we haven't already done that
raveloxd9a28642006-05-26 23:42:22 +00002689 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002690 flush_handles(device);
raveloxd9a28642006-05-26 23:42:22 +00002691 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00002692
raveloxd9a28642006-05-26 23:42:22 +00002693 if(filter != NULL) max_filter = filter_len;
2694 if(exclusions != NULL) max_exclusions = exclusion_len;
Linus Walleijf0f3d482006-05-29 14:10:21 +00002695
raveloxd9a28642006-05-26 23:42:22 +00002696 for (i = 0; i < params->handles.n; i++) {
2697 LIBMTP_object_t *object;
2698 PTPObjectInfo oi;
2699
2700 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00002701 uint32_t x = 0;
2702 uint32_t exclude = 0, filter_allow = 0;
2703 void (*datafunc)(LIBMTP_mtpdevice_t *, uint32_t, void *);
2704 void *(*constructor)(void);
2705
raveloxd9a28642006-05-26 23:42:22 +00002706 // Is the ObjectFormat in the list of exclusions ?
Linus Walleijf0f3d482006-05-29 14:10:21 +00002707 for(x = 0; x < max_exclusions; x++) {
2708 if (oi.ObjectFormat == exclusions[x]) {
2709 exclude = 1;
2710 break;
2711 }
raveloxd9a28642006-05-26 23:42:22 +00002712 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00002713 if(exclude == 1) {
2714 continue;
2715 }
2716
2717 // Is the ObjectFormat in the filter ?
2718 for(x = 0; x < max_filter; x++) {
2719 if (oi.ObjectFormat == filter[x]) {
2720 filter_allow = 1;
2721 break;
2722 }
2723 }
2724 if(filter_allow == 0) {
2725 continue;
2726 }
2727
raveloxd9a28642006-05-26 23:42:22 +00002728 object = LIBMTP_new_object_t();
2729 object->id = params->handles.Handler[i];
2730 object->parent = oi.ParentObject;
2731 object->name = (char *)strdup(oi.Filename);
2732 object->size = oi.ObjectCompressedSize;
Linus Walleijf0f3d482006-05-29 14:10:21 +00002733 object->type = oi.ObjectFormat;
raveloxd9a28642006-05-26 23:42:22 +00002734
Linus Walleijf0f3d482006-05-29 14:10:21 +00002735 // Get the function pointers for the constructor and datafunc
2736 constructor = get_constructor(oi.ObjectFormat);
2737 datafunc = get_datafunc(oi.ObjectFormat);
2738
2739 if(constructor != NULL) {
2740 object->data = (*constructor)();
2741 if(datafunc != NULL) {
2742 (*datafunc)(device, object->id, object->data);
2743 }
2744 }
2745
raveloxd9a28642006-05-26 23:42:22 +00002746 // Work out where to put this new item
2747 if(objectlist == NULL) {
2748 objectlist = object;
2749 continue;
2750 } else {
2751 LIBMTP_object_t *parent_object;
2752 LIBMTP_object_t *current_object;
2753
2754 parent_object = LIBMTP_Find_Object(objectlist, object->parent);
2755
2756 if(parent_object == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00002757 current_object = objectlist;
raveloxd9a28642006-05-26 23:42:22 +00002758 } else {
2759 if(parent_object->child == NULL) {
2760 parent_object->child = object;
2761 continue;
2762 } else {
2763 current_object = parent_object->child;
2764 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00002765 }
raveloxd9a28642006-05-26 23:42:22 +00002766
2767 while(current_object->sibling != NULL) {
2768 current_object=current_object->sibling;
2769 }
2770 current_object->sibling = object;
2771 }
2772 }
2773 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00002774
raveloxd9a28642006-05-26 23:42:22 +00002775 return objectlist;
2776}
Linus Walleijf0f3d482006-05-29 14:10:21 +00002777
raveloxd9a28642006-05-26 23:42:22 +00002778/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00002779 * Debug function that dumps out some textual representation
2780 * of an object list.
raveloxd9a28642006-05-26 23:42:22 +00002781 *
2782 * @param list object list returned from LIBMTP_Make_List
2783 *
2784 * @see LIBMTP_Make_List()
2785 */
2786void LIBMTP_Dump_List(LIBMTP_object_t *list)
2787{
Linus Walleijf0f3d482006-05-29 14:10:21 +00002788 if(list == NULL) return;
2789
2790 printf("Id : %u\n", list->id);
2791 printf("Parent: %u\n", list->parent);
2792 printf("Size : %u\n", list->size);
2793 printf("Name : %s\n", (list->name ? list->name : ""));
2794 printf("Type : 0x%04x\n", list->type);
2795 printf("--\n");
2796
2797 LIBMTP_Dump_List(list->child);
2798 LIBMTP_Dump_List(list->sibling);
raveloxd9a28642006-05-26 23:42:22 +00002799}
Linus Walleij438bd7f2006-06-08 11:35:44 +00002800
2801/**
2802 * This creates a new playlist metadata structure and allocates memory
2803 * for it. Notice that if you add strings to this structure they
2804 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
2805 * operation later, so be careful of using strdup() when assigning
2806 * strings, e.g.:
2807 *
2808 * <pre>
2809 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
2810 * pl->name = strdup(str);
2811 * ....
2812 * LIBMTP_destroy_playlist_t(pl);
2813 * </pre>
2814 *
2815 * @return a pointer to the newly allocated metadata structure.
2816 * @see LIBMTP_destroy_playlist_t()
2817 */
2818LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
2819{
2820 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
2821 if (new == NULL) {
2822 return NULL;
2823 }
2824 new->playlist_id = 0;
2825 new->name = NULL;
2826 new->tracks = NULL;
2827 new->no_tracks = 0;
2828 new->next = NULL;
2829 return new;
2830}
2831
2832/**
2833 * This destroys a playlist metadata structure and deallocates the memory
2834 * used by it, including any strings. Never use a track metadata
2835 * structure again after calling this function on it.
2836 * @param playlist the playlist metadata to destroy.
2837 * @see LIBMTP_new_playlist_t()
2838 */
2839void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
2840{
2841 if (playlist == NULL) {
2842 return;
2843 }
2844 if (playlist->name != NULL)
2845 free(playlist->name);
2846 if (playlist->tracks != NULL)
2847 free(playlist->tracks);
2848 free(playlist);
2849 return;
2850}
2851
2852/**
2853 * This function returns a list of the playlists available on the
2854 * device. Typical usage:
2855 *
2856 * <pre>
2857 * </pre>
2858 *
2859 * @param device a pointer to the device to get the playlist listing from.
2860 * @return a playlist list on success, else NULL. If there are no playlists
2861 * on the device, NULL will be returned as well.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002862 * @see LIBMTP_Get_Playlist()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002863 */
2864LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
2865{
2866 PTPParams *params = (PTPParams *) device->params;
2867 LIBMTP_playlist_t *retlists = NULL;
2868 LIBMTP_playlist_t *curlist = NULL;
2869 uint32_t i;
2870
2871 // Get all the handles if we haven't already done that
2872 if (params->handles.Handler == NULL) {
2873 flush_handles(device);
2874 }
2875
2876 for (i = 0; i < params->handles.n; i++) {
2877 LIBMTP_playlist_t *pl;
2878 PTPObjectInfo oi;
2879 uint16_t ret;
2880
2881 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
2882 if ( ret == PTP_RC_OK) {
2883
2884 // Ignore stuff that isn't playlists
2885 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
2886 continue;
2887 }
2888
2889 // Allocate a new playlist type
2890 pl = LIBMTP_new_playlist_t();
2891
2892 // Ignoring the io.Filename field.
2893 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name, 1);
2894
2895 // This is some sort of unique playlist ID so we can keep track of it
2896 pl->playlist_id = params->handles.Handler[i];
2897
2898 // Then get the track listing for this playlist
2899 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
2900 if (ret != PTP_RC_OK) {
2901 printf("LIBMTP_Get_Playlist: Could not get object references\n");
2902 pl->tracks = NULL;
2903 pl->no_tracks = 0;
2904 }
2905
2906 // Add playlist to a list that will be returned afterwards.
2907 if (retlists == NULL) {
2908 retlists = pl;
2909 curlist = pl;
2910 } else {
2911 curlist->next = pl;
2912 curlist = pl;
2913 }
2914
2915 // Call callback here if we decide to add that possibility...
2916
2917 } else {
2918 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
2919 }
2920 }
2921 return retlists;
2922}
2923
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002924
2925/**
2926 * This function retrieves an individual playlist from the device.
2927 * @param device a pointer to the device to get the playlist from.
2928 * @param plid the unique ID of the playlist to retrieve.
2929 * @return a valid playlist metadata post or NULL on failure.
2930 * @see LIBMTP_Get_Playlist_List()
2931 */
2932LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
2933{
2934 PTPParams *params = (PTPParams *) device->params;
2935 uint32_t i;
2936
2937 // Get all the handles if we haven't already done that
2938 if (params->handles.Handler == NULL) {
2939 flush_handles(device);
2940 }
2941
2942 for (i = 0; i < params->handles.n; i++) {
2943 LIBMTP_playlist_t *pl;
2944 PTPObjectInfo oi;
2945 uint16_t ret;
2946
2947 if (params->handles.Handler[i] != plid) {
2948 continue;
2949 }
2950
2951 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
2952 if ( ret == PTP_RC_OK) {
2953
2954 // Ignore stuff that isn't playlists
2955 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
2956 return NULL;
2957 }
2958
2959 // Allocate a new playlist type
2960 pl = LIBMTP_new_playlist_t();
2961
2962 // Ignoring the io.Filename field.
2963 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name, 1);
2964
2965 // This is some sort of unique playlist ID so we can keep track of it
2966 pl->playlist_id = params->handles.Handler[i];
2967
2968 // Then get the track listing for this playlist
2969 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
2970 if (ret != PTP_RC_OK) {
2971 printf("LIBMTP_Get_Playlist: Could not get object references\n");
2972 pl->tracks = NULL;
2973 pl->no_tracks = 0;
2974 }
2975
2976 return pl;
2977 } else {
2978 return NULL;
2979 }
2980 }
2981 return NULL;
2982}
2983
Linus Walleij438bd7f2006-06-08 11:35:44 +00002984/**
2985 * This routine creates a new playlist based on the metadata
2986 * supplied. If the <code>tracks</code> field of the metadata
2987 * contains a track listing, these tracks will be added to the
2988 * playlist.
2989 * @param device a pointer to the device to create the new playlist on.
2990 * @param metadata the metadata for the new playlist. If the function
2991 * exits with success, the <code>playlist_id</code> field of this
2992 * struct will contain the new playlist ID of the playlist.
2993 * @param parenthandle the parent (e.g. folder) to store this playlist
2994 * in. Pass in 0 to put the playlist in the root directory.
2995 * @return 0 on success, any other value means failure.
2996 * @see LIBMTP_Update_Playlist()
2997 * @see LIBMTP_Delete_Object()
2998 */
2999int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
3000 LIBMTP_playlist_t * const metadata,
3001 uint32_t const parenthandle)
3002{
3003 uint16_t ret;
3004 uint32_t store = 0;
3005 PTPObjectInfo new_pl;
3006 PTPParams *params = (PTPParams *) device->params;
3007 uint32_t localph = parenthandle;
3008 char fname[256];
Linus Walleijd14e84f2006-06-16 14:50:59 +00003009 uint8_t data[2];
Linus Walleij438bd7f2006-06-08 11:35:44 +00003010
Linus Walleij05ccbe72006-06-13 07:46:58 +00003011 // Use a default folder if none given
3012 if (localph == 0) {
3013 localph = device->default_playlist_folder;
3014 }
3015
Linus Walleij438bd7f2006-06-08 11:35:44 +00003016 // .zpl is the "abstract audio/video playlist "file" suffix
3017 new_pl.Filename = NULL;
3018 if (strlen(metadata->name) > 4) {
3019 char *suff = &metadata->name[strlen(metadata->name)-4];
3020 if (!strcmp(suff, ".zpl")) {
3021 // Home free.
3022 new_pl.Filename = metadata->name;
3023 }
3024 }
3025 // If it didn't end with ".zpl" then add that here.
3026 if (new_pl.Filename == NULL) {
3027 strncpy(fname, metadata->name, sizeof(fname)-5);
3028 strcat(fname, ".zpl");
3029 fname[sizeof(fname)-1] = '\0';
3030 new_pl.Filename = fname;
3031 }
3032
3033 // Means size = -1, probably N/A
Linus Walleijd14e84f2006-06-16 14:50:59 +00003034 // new_pl.ObjectCompressedSize = 0xFFFFFFFFU; <- DOES NOT WORK!
3035 new_pl.ObjectCompressedSize = 1;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003036 new_pl.ObjectFormat = PTP_OFC_MTP_AbstractAudioVideoPlaylist;
3037
3038 // Create the object
3039 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
3040 if (ret != PTP_RC_OK) {
3041 ptp_perror(params, ret);
3042 printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
3043 return -1;
3044 }
3045
3046 /*
3047 * TODO: determine if we really have to send this "blank" data or if we can
Linus Walleijd14e84f2006-06-16 14:50:59 +00003048 * just pass in an object of size -1 as info. (Failed when I tried it!)
Linus Walleij438bd7f2006-06-08 11:35:44 +00003049 */
Linus Walleijd14e84f2006-06-16 14:50:59 +00003050 data[0] = '\0';
3051 data[1] = '\0';
3052 ret = ptp_sendobject(params, data, 1);
3053 if (ret != PTP_RC_OK) {
3054 ptp_perror(params, ret);
3055 printf("LIBMTP_New_Playlist(): Could not send blank object data\n");
3056 return -1;
3057 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003058
3059 // Update title
3060 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name, 1);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003061 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003062 printf("LIBMTP_New_Playlist(): could not set playlist name\n");
3063 return -1;
3064 }
3065
3066 if (metadata->no_tracks > 0) {
3067 // Add tracks to the new playlist as object references.
3068 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3069 if (ret != PTP_RC_OK) {
3070 printf("LIBMTP_New_Playlist(): could not add tracks as object references\n");
3071 return -1;
3072 }
3073 }
3074
3075 // Created new item, so flush handles
3076 flush_handles(device);
3077
3078 return 0;
3079}
3080
3081/**
3082 * This routine updates a playlist based on the metadata
3083 * supplied. If the <code>tracks</code> field of the metadata
3084 * contains a track listing, these tracks will be added to the
3085 * playlist in place of those already present, i.e. the
3086 * previous track listing will be deleted.
3087 * @param device a pointer to the device to create the new playlist on.
3088 * @param metadata the metadata for the playlist to be updated.
3089 * notice that the field <code>playlist_id</code>
3090 * must contain the apropriate playlist ID.
3091 * @return 0 on success, any other value means failure.
3092 * @see LIBMTP_Create_New_Playlist()
3093 * @see LIBMTP_Delete_Object()
3094 */
3095int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
Linus Walleijf5306352006-06-08 12:00:23 +00003096 LIBMTP_playlist_t const * const metadata)
Linus Walleij438bd7f2006-06-08 11:35:44 +00003097{
3098 uint16_t ret;
Linus Walleijf5306352006-06-08 12:00:23 +00003099 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003100
3101 // Update title
3102 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name, 1);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003103 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003104 printf("LIBMTP_Update_Playlist(): could not set playlist name\n");
3105 return -1;
3106 }
3107
3108 if (metadata->no_tracks > 0) {
3109 // Add tracks to the new playlist as object references.
3110 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3111 if (ret != PTP_RC_OK) {
3112 printf("LIBMTP_Update_Playlist(): could not add tracks as object references\n");
3113 return -1;
3114 }
3115 }
3116 return 0;
3117}