blob: 3146eb07ce7c48ce45eb7319d9cb5a3c59c81a9c [file] [log] [blame]
Linus Walleij10c58422006-06-02 08:51:53 +00001/**
2 * \file libmtp.c
3 * This file provides an interface "glue" to the underlying
4 * PTP implementation from libgphoto2. It uses some local
5 * code to convert from/to UTF-8 (stored in unicode.c/.h)
6 * and some small utility functions, mainly for debugging
7 * (stored in util.c/.h).
8 *
mopoke96143402006-10-30 04:37:26 +00009 * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
Linus Walleij10c58422006-06-02 08:51:53 +000010 * plain copied from the libhphoto2 codebase.
11 *
12 * The files libusb-glue.c/.h are just what they say: an
13 * interface to libusb for the actual, physical USB traffic.
14 */
Linus Walleijb9256fd2006-02-15 09:40:43 +000015#include <string.h>
Linus Walleijdcde6082006-02-17 16:16:34 +000016#include <sys/types.h>
Linus Walleij3ff2cf82006-02-20 15:03:26 +000017#include <sys/stat.h>
Linus Walleijdcde6082006-02-17 16:16:34 +000018#include <fcntl.h>
Linus Walleij2eb884b2006-08-04 19:17:36 +000019#include <sys/mman.h>
20
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000021#include "libmtp.h"
Linus Walleijb9256fd2006-02-15 09:40:43 +000022#include "unicode.h"
Linus Walleij394bbbe2006-02-22 16:10:53 +000023#include "ptp.h"
Linus Walleij15e344f2006-03-06 15:15:00 +000024#include "libusb-glue.h"
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000025
Linus Walleij3fcfea52006-11-13 07:07:36 +000026/* Enable enhanced MTP commands */
27#define ENABLE_MTP_ENHANCED
28
Linus Walleijc86afbd2006-05-04 19:05:24 +000029/*
mopoke96143402006-10-30 04:37:26 +000030 * On MacOS (Darwin) and *BSD we're not using glibc, but libiconv.
31 * glibc knows that UCS-2 is to be in the local machine endianness,
32 * whereas libiconv does not. So we construct this macro to get
Linus Walleijf82dcea2006-09-11 11:23:47 +000033 * things right. Reportedly, glibc 2.1.3 has a bug so that UCS-2
mopoke96143402006-10-30 04:37:26 +000034 * is always bigendian though, we would need to work around that
Linus Walleijf82dcea2006-09-11 11:23:47 +000035 * too...
Linus Walleijd5d51c82006-09-11 06:57:50 +000036 */
37#ifndef __GLIBC__
Linus Walleijf82dcea2006-09-11 11:23:47 +000038#define UCS_2_INTERNAL "UCS-2-INTERNAL"
Linus Walleijd5d51c82006-09-11 06:57:50 +000039#else
Linus Walleijf82dcea2006-09-11 11:23:47 +000040#if (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 )
41#error "Too old glibc. This versions iconv() implementation cannot be trusted."
42#endif
43#define UCS_2_INTERNAL "UCS-2"
Linus Walleijd5d51c82006-09-11 06:57:50 +000044#endif
45
46/*
Linus Walleijc86afbd2006-05-04 19:05:24 +000047 * This is a mapping between libmtp internal MTP filetypes and
48 * the libgphoto2/PTP equivalent defines. We need this because
49 * otherwise the libmtp.h device has to be dependent on ptp.h
50 * to be installed too, and we don't want that.
51 */
raveloxd9a28642006-05-26 23:42:22 +000052typedef struct filemap_t LIBMTP_filemap_t;
raveloxd9a28642006-05-26 23:42:22 +000053struct filemap_t {
54 char *description; /**< Text description for the file type */
55 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
56 uint16_t ptp_id; /**< PTP ID for the filetype */
57 void *constructor; /**< Function to create the data structure for this file type */
58 void *destructor; /**< Function to destroy the data structure for this file type */
59 void *datafunc; /**< Function to fill in the data for this file type */
60 LIBMTP_filemap_t *next;
Linus Walleij16c51f02006-05-04 13:20:22 +000061};
Linus Walleijc86afbd2006-05-04 19:05:24 +000062
Linus Walleijf67bca92006-05-29 09:33:39 +000063// Global variables
Linus Walleij438bd7f2006-06-08 11:35:44 +000064// This holds the global filetype mapping table
Linus Walleijf67bca92006-05-29 09:33:39 +000065static LIBMTP_filemap_t *filemap = NULL;
66
67// Forward declarations of local functions
Linus Walleij438bd7f2006-06-08 11:35:44 +000068static void flush_handles(LIBMTP_mtpdevice_t *device);
Linus Walleijf67bca92006-05-29 09:33:39 +000069static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
70static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
mopoke96143402006-10-30 04:37:26 +000071static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
Linus Walleijcf223e62006-06-19 09:31:53 +000072 char **unicstring, uint16_t property);
Linus Walleij8ab54262006-06-21 07:12:28 +000073static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
74 LIBMTP_track_t *track);
Linus Walleij3fcfea52006-11-13 07:07:36 +000075static MTPPropList *New_MTP_Prop_Entry();
76static void Destroy_MTP_Prop_Entry(MTPPropList *prop);
raveloxd9a28642006-05-26 23:42:22 +000077
78static LIBMTP_filemap_t *new_filemap_entry()
79{
Linus Walleijf67bca92006-05-29 09:33:39 +000080 LIBMTP_filemap_t *filemap;
mopoke96143402006-10-30 04:37:26 +000081
Linus Walleijf67bca92006-05-29 09:33:39 +000082 filemap = (LIBMTP_filemap_t *)malloc(sizeof(LIBMTP_filemap_t));
mopoke96143402006-10-30 04:37:26 +000083
Linus Walleijf67bca92006-05-29 09:33:39 +000084 if( filemap != NULL ) {
85 filemap->description = NULL;
86 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
87 filemap->ptp_id = PTP_OFC_Undefined;
88 filemap->constructor = NULL;
89 filemap->destructor = NULL;
90 filemap->datafunc = NULL;
91 filemap->next = NULL;
92 }
mopoke96143402006-10-30 04:37:26 +000093
Linus Walleijf67bca92006-05-29 09:33:39 +000094 return filemap;
raveloxd9a28642006-05-26 23:42:22 +000095}
96
raveloxd9a28642006-05-26 23:42:22 +000097/**
98 * Register an MTP or PTP filetype for data retrieval
99 *
100 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +0000101 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000102 * @param ptp_id PTP filetype id
103 * @param constructor Pointer to function to create data structure for filetype
104 * @param destructor Pointer to function to destroy data structure for filetype
105 * @param datafunc Pointer to function to fill data structure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000106 * @return 0 for success any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000107*/
mopoke96143402006-10-30 04:37:26 +0000108int LIBMTP_Register_Filetype(char const * const description, LIBMTP_filetype_t const id,
109 uint16_t const ptp_id, void const * const constructor,
Linus Walleij438bd7f2006-06-08 11:35:44 +0000110 void const * const destructor, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000111{
112 LIBMTP_filemap_t *new = NULL, *current;
113
114 // Has this LIBMTP filetype been registered before ?
115 current = filemap;
116 while (current != NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000117 if(current->id == id) {
118 break;
119 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000120 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000121 }
mopoke96143402006-10-30 04:37:26 +0000122
raveloxd9a28642006-05-26 23:42:22 +0000123 // Create the entry
124 if(current == NULL) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000125 new = new_filemap_entry();
Linus Walleijf0f3d482006-05-29 14:10:21 +0000126 if(new == NULL) {
127 return 1;
128 }
mopoke96143402006-10-30 04:37:26 +0000129
Linus Walleijf67bca92006-05-29 09:33:39 +0000130 new->id = id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000131 if(description != NULL) {
132 new->description = strdup(description);
133 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000134 new->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000135 new->constructor = (void*) constructor;
136 new->destructor = (void*) destructor;
137 new->datafunc = (void*) datafunc;
mopoke96143402006-10-30 04:37:26 +0000138
Linus Walleijf67bca92006-05-29 09:33:39 +0000139 // Add the entry to the list
140 if(filemap == NULL) {
141 filemap = new;
142 } else {
143 current = filemap;
144 while (current->next != NULL ) current=current->next;
145 current->next = new;
146 }
147 // Update the existing entry
raveloxd9a28642006-05-26 23:42:22 +0000148 } else {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000149 if (current->description != NULL) {
150 free(current->description);
151 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000152 current->description = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000153 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000154 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000155 }
Linus Walleijf67bca92006-05-29 09:33:39 +0000156 current->ptp_id = ptp_id;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000157 current->constructor = (void*) constructor;
158 current->destructor = (void*) destructor;
159 current->datafunc = (void*) datafunc;
raveloxd9a28642006-05-26 23:42:22 +0000160 }
161
Linus Walleijf0f3d482006-05-29 14:10:21 +0000162 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000163}
164
165/**
166 * Set the description for a MTP filetype
167 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000168 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000169 * @param description Text description of filetype
Linus Walleijf0f3d482006-05-29 14:10:21 +0000170 * @return 0 on success, any other value means error.
raveloxd9a28642006-05-26 23:42:22 +0000171*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000172int LIBMTP_Set_Filetype_Description(LIBMTP_filetype_t const id, char const * const description)
raveloxd9a28642006-05-26 23:42:22 +0000173{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000174 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000175
Linus Walleijf0f3d482006-05-29 14:10:21 +0000176 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000177 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000178 }
mopoke96143402006-10-30 04:37:26 +0000179
Linus Walleijf67bca92006-05-29 09:33:39 +0000180 // Go through the filemap until an entry is found
181 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000182
Linus Walleijf0f3d482006-05-29 14:10:21 +0000183 while(current != NULL) {
184 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000185 break;
186 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000187 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000188 }
mopoke96143402006-10-30 04:37:26 +0000189
Linus Walleijf0f3d482006-05-29 14:10:21 +0000190 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000191 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000192 }
193
194 if (current->description != NULL) {
195 free(current->description);
196 current->description = NULL;
197 }
198 if(description != NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000199 current->description = strdup(description);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000200 }
201 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000202}
203
204/**
205 * Set the constructor for a MTP filetype
206 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000207 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000208 * @param constructor Pointer to a constructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000209 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000210*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000211int LIBMTP_Set_Constructor(LIBMTP_filetype_t const id, void const * const constructor)
raveloxd9a28642006-05-26 23:42:22 +0000212{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000213 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000214
Linus Walleijf0f3d482006-05-29 14:10:21 +0000215 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000216 return -1;
mopoke96143402006-10-30 04:37:26 +0000217 }
218
Linus Walleijf67bca92006-05-29 09:33:39 +0000219 // Go through the filemap until an entry is found
220 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000221
Linus Walleijf0f3d482006-05-29 14:10:21 +0000222 while(current != NULL) {
223 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000224 break;
raveloxd9a28642006-05-26 23:42:22 +0000225 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000226 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000227 }
mopoke96143402006-10-30 04:37:26 +0000228
Linus Walleijf0f3d482006-05-29 14:10:21 +0000229 if (current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000230 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000231 }
mopoke96143402006-10-30 04:37:26 +0000232
Linus Walleij438bd7f2006-06-08 11:35:44 +0000233 current->constructor = (void*) constructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000234 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000235}
236
237/**
238 * Set the destructor for a MTP filetype
239 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000240 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000241 * @param destructor Pointer to a destructor function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000242 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000243*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000244int LIBMTP_Set_Destructor(LIBMTP_filetype_t const id, void const * const destructor)
raveloxd9a28642006-05-26 23:42:22 +0000245{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000246 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000247
Linus Walleijf0f3d482006-05-29 14:10:21 +0000248 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000249 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000250 }
mopoke96143402006-10-30 04:37:26 +0000251
Linus Walleijf67bca92006-05-29 09:33:39 +0000252 // Go through the filemap until an entry is found
253 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000254
Linus Walleijf0f3d482006-05-29 14:10:21 +0000255 while(current != NULL) {
256 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000257 break;
raveloxd9a28642006-05-26 23:42:22 +0000258 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000259 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000260 }
mopoke96143402006-10-30 04:37:26 +0000261
Linus Walleijf0f3d482006-05-29 14:10:21 +0000262 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000263 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000264 }
mopoke96143402006-10-30 04:37:26 +0000265
Linus Walleij438bd7f2006-06-08 11:35:44 +0000266 current->destructor = (void *) destructor;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000267 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000268}
269
270/**
271 * Set the datafunc for a MTP filetype
272 *
Linus Walleijf0f3d482006-05-29 14:10:21 +0000273 * @param id libmtp internal filetype id
raveloxd9a28642006-05-26 23:42:22 +0000274 * @param datafunc Pointer to a data function
Linus Walleijf0f3d482006-05-29 14:10:21 +0000275 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000276*/
Linus Walleij438bd7f2006-06-08 11:35:44 +0000277int LIBMTP_Set_Datafunc(LIBMTP_filetype_t const id, void const * const datafunc)
raveloxd9a28642006-05-26 23:42:22 +0000278{
Linus Walleijf0f3d482006-05-29 14:10:21 +0000279 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000280
Linus Walleijf0f3d482006-05-29 14:10:21 +0000281 if (filemap == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000282 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000283 }
mopoke96143402006-10-30 04:37:26 +0000284
Linus Walleijf67bca92006-05-29 09:33:39 +0000285 // Go through the filemap until an entry is found
286 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000287
Linus Walleijf0f3d482006-05-29 14:10:21 +0000288 while(current != NULL) {
289 if(current->id == id) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000290 break;
raveloxd9a28642006-05-26 23:42:22 +0000291 }
Linus Walleijf0f3d482006-05-29 14:10:21 +0000292 current = current->next;
Linus Walleijf67bca92006-05-29 09:33:39 +0000293 }
mopoke96143402006-10-30 04:37:26 +0000294
Linus Walleijf0f3d482006-05-29 14:10:21 +0000295 if(current == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000296 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000297 }
mopoke96143402006-10-30 04:37:26 +0000298
Linus Walleij438bd7f2006-06-08 11:35:44 +0000299 current->datafunc = (void *) datafunc;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000300 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000301}
302
303static void init_filemap()
304{
Linus Walleijf67bca92006-05-29 09:33:39 +0000305 LIBMTP_Register_Filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000306 LIBMTP_Register_Filetype("ISO MPEG Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
Linus Walleijf67bca92006-05-29 09:33:39 +0000307 LIBMTP_Register_Filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
308 LIBMTP_Register_Filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
Linus Walleije46f12e2006-06-22 17:53:25 +0000309 LIBMTP_Register_Filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
Linus Walleijf67bca92006-05-29 09:33:39 +0000310 LIBMTP_Register_Filetype("Advanced Acoustic Coding", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
311 LIBMTP_Register_Filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio,LIBMTP_new_track_t,LIBMTP_destroy_track_t,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000312 LIBMTP_Register_Filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV,NULL,NULL,NULL);
313 LIBMTP_Register_Filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI,NULL,NULL,NULL);
314 LIBMTP_Register_Filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG,NULL,NULL,NULL);
315 LIBMTP_Register_Filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF,NULL,NULL,NULL);
316 LIBMTP_Register_Filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT,NULL,NULL,NULL);
317 LIBMTP_Register_Filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo,NULL,NULL,NULL);
Linus Walleij83f57eb2006-05-31 19:57:56 +0000318 LIBMTP_Register_Filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG,NULL,NULL,NULL);
319 LIBMTP_Register_Filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF,NULL,NULL,NULL);
raveloxd9a28642006-05-26 23:42:22 +0000320 LIBMTP_Register_Filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF,NULL,NULL,NULL);
321 LIBMTP_Register_Filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP,NULL,NULL,NULL);
322 LIBMTP_Register_Filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF,NULL,NULL,NULL);
323 LIBMTP_Register_Filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT,NULL,NULL,NULL);
324 LIBMTP_Register_Filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG,NULL,NULL,NULL);
325 LIBMTP_Register_Filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat,NULL,NULL,NULL);
326 LIBMTP_Register_Filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1,NULL,NULL,NULL);
327 LIBMTP_Register_Filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2,NULL,NULL,NULL);
328 LIBMTP_Register_Filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2,NULL,NULL,NULL);
329 LIBMTP_Register_Filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3,NULL,NULL,NULL);
330 LIBMTP_Register_Filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable,NULL,NULL,NULL);
331 LIBMTP_Register_Filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text,NULL,NULL,NULL);
332 LIBMTP_Register_Filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML,NULL,NULL,NULL);
333 LIBMTP_Register_Filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined, NULL, NULL, NULL);
raveloxd9a28642006-05-26 23:42:22 +0000334}
Linus Walleij16c51f02006-05-04 13:20:22 +0000335
Linus Walleij16c51f02006-05-04 13:20:22 +0000336/**
337 * Returns the PTP filetype that maps to a certain libmtp internal file type.
338 * @param intype the MTP library interface type
339 * @return the PTP (libgphoto2) interface type
340 */
341static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
342{
raveloxd9a28642006-05-26 23:42:22 +0000343 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000344
raveloxd9a28642006-05-26 23:42:22 +0000345 current = filemap;
346
347 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000348 if(current->id == intype) {
349 return current->ptp_id;
350 }
351 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000352 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000353 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000354 return PTP_OFC_Undefined;
355}
356
357
358/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000359 * Returns the PTP internal filetype that maps to a certain libmtp
360 * interface file type.
mopoke96143402006-10-30 04:37:26 +0000361 * @param intype the PTP (libgphoto2) interface type
Linus Walleij8ab54262006-06-21 07:12:28 +0000362 * @return the MTP library interface type
Linus Walleij16c51f02006-05-04 13:20:22 +0000363 */
364static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
365{
raveloxd9a28642006-05-26 23:42:22 +0000366 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000367
raveloxd9a28642006-05-26 23:42:22 +0000368 current = filemap;
369
370 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000371 if(current->ptp_id == intype) {
372 return current->id;
373 }
374 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000375 }
Linus Walleij1fd2d272006-05-08 09:22:01 +0000376 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
Linus Walleij16c51f02006-05-04 13:20:22 +0000377 return LIBMTP_FILETYPE_UNKNOWN;
378}
379
380/**
raveloxd9a28642006-05-26 23:42:22 +0000381 * Returns the data function for the file type
382 * @param intype the PTP library interface
383 * @return pointer to the data function
384 */
385static void *get_datafunc(uint16_t intype)
386{
387 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000388
raveloxd9a28642006-05-26 23:42:22 +0000389 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000390
raveloxd9a28642006-05-26 23:42:22 +0000391 while (current != NULL) {
392 if(current->ptp_id == intype) {
393 return current->datafunc;
394 }
395 current = current->next;
396 }
397 return NULL;
398}
399
400
401/**
402 * Returns the constructor for that file type data
403 * @param intype the PTP library interface type
404 * @return pointer to the constructor
405 */
406static void *get_constructor(uint16_t intype)
407{
408 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000409
raveloxd9a28642006-05-26 23:42:22 +0000410 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000411
raveloxd9a28642006-05-26 23:42:22 +0000412 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000413 if(current->ptp_id == intype) {
414 return current->constructor;
415 }
416 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000417 }
418 return NULL;
419}
420
421/**
422 * Returns the destructor for that file type data
423 * @param intype the PTP library interface type
424 * @return pointer to the destructor
425 */
426static void *get_destructor(uint16_t intype)
427{
428 LIBMTP_filemap_t *current;
mopoke96143402006-10-30 04:37:26 +0000429
raveloxd9a28642006-05-26 23:42:22 +0000430 current = filemap;
431
432 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000433 if(current->ptp_id == intype) {
434 return current->destructor;
435 }
436 current = current->next;
raveloxd9a28642006-05-26 23:42:22 +0000437 }
438 return NULL;
439}
440
441/**
Linus Walleij16c51f02006-05-04 13:20:22 +0000442 * This helper function returns a textual description for a libmtp
443 * file type to be used in dialog boxes etc.
Linus Walleijf0f3d482006-05-29 14:10:21 +0000444 * @param intype the libmtp internal filetype to get a description for.
Linus Walleij16c51f02006-05-04 13:20:22 +0000445 * @return a string representing the filetype, this must <b>NOT</b>
446 * be free():ed by the caller!
447 */
448char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
449{
raveloxd9a28642006-05-26 23:42:22 +0000450 LIBMTP_filemap_t *current;
Linus Walleij16c51f02006-05-04 13:20:22 +0000451
raveloxd9a28642006-05-26 23:42:22 +0000452 current = filemap;
mopoke96143402006-10-30 04:37:26 +0000453
raveloxd9a28642006-05-26 23:42:22 +0000454 while (current != NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000455 if(current->id == intype) {
456 return current->description;
457 }
458 current = current->next;
Linus Walleij16c51f02006-05-04 13:20:22 +0000459 }
mopoke96143402006-10-30 04:37:26 +0000460
Linus Walleij16c51f02006-05-04 13:20:22 +0000461 return "Unknown filetype";
462}
Linus Walleijfa1374c2006-02-27 07:41:46 +0000463
Linus Walleij6946ac52006-03-21 06:51:22 +0000464/**
Linus Walleijf0f3d482006-05-29 14:10:21 +0000465 * Initialize the library. You are only supposed to call this
466 * one, before using the library for the first time in a program.
467 * Never re-initialize libmtp!
468 *
raveloxd9a28642006-05-26 23:42:22 +0000469 * The only thing this does at the moment is to initialise the
470 * filetype mapping table.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000471 */
472void LIBMTP_Init(void)
473{
raveloxd9a28642006-05-26 23:42:22 +0000474 init_filemap();
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000475 return;
476}
477
478/**
raveloxd9a28642006-05-26 23:42:22 +0000479 * Retrieves a string from an object
480 *
481 * @param device a pointer to an MTP device.
482 * @param object_id Object reference
483 * @param attribute_id PTP attribute ID
Linus Walleij438bd7f2006-06-08 11:35:44 +0000484 * @return valid string or NULL on failure. The returned string
485 * must bee <code>free()</code>:ed by the caller after
486 * use.
raveloxd9a28642006-05-26 23:42:22 +0000487 */
mopoke96143402006-10-30 04:37:26 +0000488char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000489 uint16_t const attribute_id)
raveloxd9a28642006-05-26 23:42:22 +0000490{
491 PTPPropertyValue propval;
492 char *retstring = NULL;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000493 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000494 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +0000495
Linus Walleij438bd7f2006-06-08 11:35:44 +0000496 if ( device == NULL || object_id == 0) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000497 return NULL;
498 }
mopoke96143402006-10-30 04:37:26 +0000499
Linus Walleija823a702006-08-27 21:27:46 +0000500 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
raveloxd9a28642006-05-26 23:42:22 +0000501 if (ret == PTP_RC_OK) {
Linus Walleija823a702006-08-27 21:27:46 +0000502 if (propval.str != NULL) {
503 retstring = (char *) strdup(propval.str);
504 free(propval.str);
raveloxd9a28642006-05-26 23:42:22 +0000505 }
506 }
mopoke96143402006-10-30 04:37:26 +0000507
raveloxd9a28642006-05-26 23:42:22 +0000508 return retstring;
509}
510
511/**
512 * Retrieves an unsigned 32-bit integer from an object attribute
513 *
514 * @param device a pointer to an MTP device.
515 * @param object_id Object reference
516 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000517 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000518 * @return the value
raveloxd9a28642006-05-26 23:42:22 +0000519 */
mopoke96143402006-10-30 04:37:26 +0000520uint32_t LIBMTP_Get_U32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000521 uint16_t const attribute_id, uint32_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000522{
523 PTPPropertyValue propval;
524 uint32_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000525 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000526 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +0000527
Linus Walleijf0f3d482006-05-29 14:10:21 +0000528 if ( device == NULL ) {
529 return value_default;
530 }
raveloxd9a28642006-05-26 23:42:22 +0000531
raveloxd9a28642006-05-26 23:42:22 +0000532 ret = ptp_mtp_getobjectpropvalue(params, object_id,
533 attribute_id,
534 &propval,
535 PTP_DTC_UINT32);
536 if (ret == PTP_RC_OK) {
537 retval = propval.u32;
538 }
539
540 return retval;
541}
542
543/**
544 * Retrieves an unsigned 16-bit integer from an object attribute
545 *
546 * @param device a pointer to an MTP device.
547 * @param object_id Object reference
548 * @param attribute_id PTP attribute ID
Linus Walleij5acfa742006-05-29 14:51:59 +0000549 * @param value_default Default value to return on failure
Linus Walleijf0f3d482006-05-29 14:10:21 +0000550 * @return a value
raveloxd9a28642006-05-26 23:42:22 +0000551 */
mopoke96143402006-10-30 04:37:26 +0000552uint16_t LIBMTP_Get_U16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000553 uint16_t const attribute_id, uint16_t const value_default)
raveloxd9a28642006-05-26 23:42:22 +0000554{
555 PTPPropertyValue propval;
556 uint16_t retval = value_default;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000557 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000558 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000559
Linus Walleijf0f3d482006-05-29 14:10:21 +0000560 if ( device == NULL ) {
561 return value_default;
562 }
raveloxd9a28642006-05-26 23:42:22 +0000563
raveloxd9a28642006-05-26 23:42:22 +0000564 ret = ptp_mtp_getobjectpropvalue(params, object_id,
565 attribute_id,
566 &propval,
567 PTP_DTC_UINT16);
568 if (ret == PTP_RC_OK) {
569 retval = propval.u16;
570 }
mopoke96143402006-10-30 04:37:26 +0000571
raveloxd9a28642006-05-26 23:42:22 +0000572 return retval;
573}
574
575/**
Linus Walleij99310d42006-11-01 08:29:39 +0000576 * Retrieves an unsigned 8-bit integer from an object attribute
577 *
578 * @param device a pointer to an MTP device.
579 * @param object_id Object reference
580 * @param attribute_id PTP attribute ID
581 * @param value_default Default value to return on failure
582 * @return a value
583 */
584uint8_t LIBMTP_Get_U8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
585 uint16_t const attribute_id, uint8_t const value_default)
586{
587 PTPPropertyValue propval;
588 uint8_t retval = value_default;
589 PTPParams *params = (PTPParams *) device->params;
590 uint16_t ret;
591
592 if ( device == NULL ) {
593 return value_default;
594 }
595
596 ret = ptp_mtp_getobjectpropvalue(params, object_id,
597 attribute_id,
598 &propval,
599 PTP_DTC_UINT8);
600 if (ret == PTP_RC_OK) {
601 retval = propval.u8;
602 }
603
604 return retval;
605}
606
607/**
raveloxd9a28642006-05-26 23:42:22 +0000608 * Sets an object attribute from a string
609 *
610 * @param device a pointer to an MTP device.
611 * @param object_id Object reference
612 * @param attribute_id PTP attribute ID
613 * @param string string value to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000614 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000615 */
mopoke96143402006-10-30 04:37:26 +0000616int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000617 uint16_t const attribute_id, char const * const string)
raveloxd9a28642006-05-26 23:42:22 +0000618{
619 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000620 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000621 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000622
Linus Walleijf0f3d482006-05-29 14:10:21 +0000623 if (device == NULL || string == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000624 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000625 }
raveloxd9a28642006-05-26 23:42:22 +0000626
Linus Walleija823a702006-08-27 21:27:46 +0000627 propval.str = (char *) string;
628 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000629 if (ret != PTP_RC_OK) {
Linus Walleijda9500d2006-08-30 13:17:06 +0000630 printf("LIBMTP_Set_Object_String(): could not set object string.\n");
631 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000632 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000633 }
mopoke96143402006-10-30 04:37:26 +0000634
Linus Walleijf0f3d482006-05-29 14:10:21 +0000635 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000636}
637
638/**
639 * Sets an object attribute from an unsigned 32-bit integer
640 *
641 * @param device a pointer to an MTP device.
642 * @param object_id Object reference
643 * @param attribute_id PTP attribute ID
644 * @param value 32-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000645 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000646 */
mopoke96143402006-10-30 04:37:26 +0000647int LIBMTP_Set_Object_U32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000648 uint16_t const attribute_id, uint32_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000649{
650 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000651 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000652 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000653
Linus Walleijf0f3d482006-05-29 14:10:21 +0000654 if (device == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +0000655 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000656 }
raveloxd9a28642006-05-26 23:42:22 +0000657
658 propval.u32 = value;
659 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000660 if (ret != PTP_RC_OK) {
Linus Walleija52c93e2006-09-13 04:40:48 +0000661 printf("LIBMTP_Set_Object_U32(): could not set unsigned 32bit integer property.\n");
662 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000663 return -1;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000664 }
mopoke96143402006-10-30 04:37:26 +0000665
Linus Walleijf0f3d482006-05-29 14:10:21 +0000666 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000667}
668
669/**
670 * Sets an object attribute from an unsigned 16-bit integer
671 *
672 * @param device a pointer to an MTP device.
673 * @param object_id Object reference
674 * @param attribute_id PTP attribute ID
675 * @param value 16-bit unsigned integer to set
Linus Walleijf0f3d482006-05-29 14:10:21 +0000676 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000677 */
mopoke96143402006-10-30 04:37:26 +0000678int LIBMTP_Set_Object_U16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij4ef39e62006-09-19 14:11:52 +0000679 uint16_t const attribute_id, uint16_t const value)
raveloxd9a28642006-05-26 23:42:22 +0000680{
681 PTPPropertyValue propval;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000682 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000683 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000684
Linus Walleijf0f3d482006-05-29 14:10:21 +0000685 if (device == NULL) {
686 return 1;
687 }
raveloxd9a28642006-05-26 23:42:22 +0000688
689 propval.u16 = value;
690 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000691 if (ret != PTP_RC_OK) {
Linus Walleija52c93e2006-09-13 04:40:48 +0000692 printf("LIBMTP_Set_Object_U16(): could not set unsigned 16bit integer property.\n");
693 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000694 return 1;
695 }
raveloxd9a28642006-05-26 23:42:22 +0000696
Linus Walleijf0f3d482006-05-29 14:10:21 +0000697 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000698}
699
700/**
Linus Walleij99310d42006-11-01 08:29:39 +0000701 * Sets an object attribute from an unsigned 8-bit integer
702 *
703 * @param device a pointer to an MTP device.
704 * @param object_id Object reference
705 * @param attribute_id PTP attribute ID
706 * @param value 8-bit unsigned integer to set
707 * @return 0 on success, any other value means failure
708 */
709int LIBMTP_Set_Object_U8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
710 uint16_t const attribute_id, uint8_t const value)
711{
712 PTPPropertyValue propval;
713 PTPParams *params = (PTPParams *) device->params;
714 uint16_t ret;
715
716 if (device == NULL) {
717 return 1;
718 }
719
720 propval.u8 = value;
721 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
722 if (ret != PTP_RC_OK) {
723 printf("LIBMTP_Set_Object_U8(): could not set unsigned 8bit integer property.\n");
724 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
725 return 1;
726 }
727
728 return 0;
729}
730
731/**
raveloxd9a28642006-05-26 23:42:22 +0000732 * Gets an array of object ids associated with a specified object
733 *
734 * @param device a pointer to an MTP device.
735 * @param object_id Object reference
736 * @param items array of unsigned 32-bit integers
737 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000738 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000739 */
mopoke96143402006-10-30 04:37:26 +0000740int LIBMTP_Get_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleijf0f3d482006-05-29 14:10:21 +0000741 uint32_t **items, uint32_t *len)
raveloxd9a28642006-05-26 23:42:22 +0000742{
743 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000744 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000745
Linus Walleijf0f3d482006-05-29 14:10:21 +0000746 // A device must be attached
raveloxd9a28642006-05-26 23:42:22 +0000747 if (device == NULL ) {
Linus Walleijf67bca92006-05-29 09:33:39 +0000748 *items = NULL;
749 *len = 0;
Linus Walleijf0f3d482006-05-29 14:10:21 +0000750 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000751 }
mopoke96143402006-10-30 04:37:26 +0000752
Linus Walleijf67bca92006-05-29 09:33:39 +0000753 ret = ptp_mtp_getobjectreferences (params, object_id, items, len);
raveloxd9a28642006-05-26 23:42:22 +0000754 if (ret != PTP_RC_OK) {
755 ptp_perror(params, ret);
756 printf("LIBMTP_Get_Object_References: Could not get object references\n");
Linus Walleijf0f3d482006-05-29 14:10:21 +0000757 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000758 }
759
Linus Walleijf0f3d482006-05-29 14:10:21 +0000760 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000761}
762
763/**
764 * Sets an array of object ids associated with a specified object
765 *
766 * @param device a pointer to an MTP device.
767 * @param object_id Object reference
768 * @param items array of unsigned 32-bit integers
769 * @param len length of array
Linus Walleijf0f3d482006-05-29 14:10:21 +0000770 * @return 0 on success, any other value means failure
raveloxd9a28642006-05-26 23:42:22 +0000771 */
mopoke96143402006-10-30 04:37:26 +0000772int LIBMTP_Set_Object_References(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
Linus Walleij438bd7f2006-06-08 11:35:44 +0000773 uint32_t const * const items, uint32_t const len)
raveloxd9a28642006-05-26 23:42:22 +0000774{
775 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +0000776 uint16_t ret;
raveloxd9a28642006-05-26 23:42:22 +0000777
778 if (device == NULL || items == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +0000779 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000780 }
mopoke96143402006-10-30 04:37:26 +0000781
Linus Walleij438bd7f2006-06-08 11:35:44 +0000782 ret = ptp_mtp_setobjectreferences (params, object_id, (uint32_t *) items, len);
raveloxd9a28642006-05-26 23:42:22 +0000783 if (ret != PTP_RC_OK) {
784 ptp_perror(params, ret);
785 printf("LIBMTP_Set_Object_References: Could not set object references\n");
Linus Walleija52c93e2006-09-13 04:40:48 +0000786 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijf0f3d482006-05-29 14:10:21 +0000787 return 1;
raveloxd9a28642006-05-26 23:42:22 +0000788 }
mopoke96143402006-10-30 04:37:26 +0000789
Linus Walleijf0f3d482006-05-29 14:10:21 +0000790 return 0;
raveloxd9a28642006-05-26 23:42:22 +0000791}
792
raveloxd9a28642006-05-26 23:42:22 +0000793/**
Linus Walleij6fd2f082006-03-28 07:19:22 +0000794 * Get a list of the supported devices.
795 *
Linus Walleijc86afbd2006-05-04 19:05:24 +0000796 * The developers depend on users of this library to constantly
797 * add in to the list of supported devices. What we need is the
798 * device name, USB Vendor ID (VID) and USB Product ID (PID).
799 * put this into a bug ticket at the project homepage, please.
800 * The VID/PID is used to let e.g. udev lift the device to
801 * console userspace access when it's plugged in.
802 *
Linus Walleij6fd2f082006-03-28 07:19:22 +0000803 * @param devices a pointer to a pointer that will hold a device
804 * list after the call to this function, if it was
805 * successful.
806 * @param numdevs a pointer to an integer that will hold the number
807 * of devices in the device list if the call was successful.
808 * @return 0 if the list was successfull retrieved, any other
809 * value means failure.
810 */
811int LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs)
812{
813 // Just dispatch to libusb glue file...
814 return get_device_list(devices, numdevs);
815}
816
817/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000818 * Get the first connected MTP device. There is currently no API for
819 * retrieveing multiple devices.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000820 * @return a device pointer.
821 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000822LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000823{
824 uint8_t interface_number;
Linus Walleij56d3e182006-02-10 15:46:54 +0000825 PTPParams *params;
826 PTP_USB *ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000827 PTPStorageIDs storageIDs;
Linus Walleijee01b642006-09-13 12:01:22 +0000828 uint32_t storageID = 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000829 PTPDevicePropDesc dpd;
Linus Walleijd31e6192006-09-12 07:55:27 +0000830 uint8_t batteryLevelMax = 100; // Some default
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000831 uint16_t ret;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000832 uint32_t i;
Linus Walleijb9256fd2006-02-15 09:40:43 +0000833 LIBMTP_mtpdevice_t *tmpdevice;
Richard Low43fdb882006-09-06 16:19:05 +0000834 uint8_t remaining_directories;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000835
Linus Walleij56d3e182006-02-10 15:46:54 +0000836 // Allocate a parameter block
837 params = (PTPParams *) malloc(sizeof(PTPParams));
Linus Walleijd5d51c82006-09-11 06:57:50 +0000838 params->cd_locale_to_ucs2 = iconv_open(UCS_2_INTERNAL, "UTF-8");
839 params->cd_ucs2_to_locale = iconv_open("UTF-8", UCS_2_INTERNAL);
Linus Walleija823a702006-08-27 21:27:46 +0000840 if (params->cd_locale_to_ucs2 == (iconv_t) -1 || params->cd_ucs2_to_locale == (iconv_t) -1) {
Linus Walleijd5d51c82006-09-11 06:57:50 +0000841 printf("LIBMTP panic: could not open iconv() converters to/from UCS-2!\n");
Linus Walleija823a702006-08-27 21:27:46 +0000842 return NULL;
843 }
mopoke96143402006-10-30 04:37:26 +0000844
Linus Walleij56d3e182006-02-10 15:46:54 +0000845 ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB));
Linus Walleijd214b9b2006-08-26 22:08:37 +0000846 // Callbacks and stuff
847 ptp_usb->callback_active = 0;
848 ptp_usb->current_transfer_total = 0;
849 ptp_usb->current_transfer_complete = 0;
850 ptp_usb->current_transfer_callback = NULL;
mopoke96143402006-10-30 04:37:26 +0000851
Linus Walleijd214b9b2006-08-26 22:08:37 +0000852 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000853 ret = connect_first_device(params, ptp_usb, &interface_number);
mopoke96143402006-10-30 04:37:26 +0000854
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000855 switch (ret)
856 {
857 case PTP_CD_RC_CONNECTED:
858 printf("Connected to MTP device.\n");
859 break;
860 case PTP_CD_RC_NO_DEVICES:
861 printf("No MTP devices.\n");
862 return NULL;
863 case PTP_CD_RC_ERROR_CONNECTING:
864 printf("Connection error.\n");
865 return NULL;
866 }
867
868 // get storage ID
Linus Walleij56d3e182006-02-10 15:46:54 +0000869 if (ptp_getstorageids (params, &storageIDs) == PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000870 if (storageIDs.n > 0)
871 storageID = storageIDs.Storage[0];
872 free(storageIDs.Storage);
873 }
mopoke96143402006-10-30 04:37:26 +0000874
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000875 // Make sure there are no handlers
Linus Walleij56d3e182006-02-10 15:46:54 +0000876 params->handles.Handler = NULL;
Linus Walleijb02a0662006-04-25 08:05:09 +0000877
Linus Walleij8c45b292006-04-26 14:12:44 +0000878 // Just cache the device information for any later use.
879 if (ptp_getdeviceinfo(params, &params->deviceinfo) != PTP_RC_OK) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000880 goto error_handler;
881 }
mopoke96143402006-10-30 04:37:26 +0000882
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000883 // Get battery maximum level
Linus Walleijd31e6192006-09-12 07:55:27 +0000884 if (ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
885 if (ptp_getdevicepropdesc(params, PTP_DPC_BatteryLevel, &dpd) != PTP_RC_OK) {
886 printf("LIBMTP_Get_First_Device(): Unable to retrieve battery max level.\n");
887 goto error_handler;
888 }
889 // if is NULL, just leave as default
890 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
891 batteryLevelMax = dpd.FORM.Range.MaximumValue.u8;
892 }
893 ptp_free_devicepropdesc(&dpd);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000894 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000895
896 // OK everything got this far, so it is time to create a device struct!
Linus Walleijb9256fd2006-02-15 09:40:43 +0000897 tmpdevice = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000898 tmpdevice->interface_number = interface_number;
Linus Walleij9b28da32006-03-16 13:47:58 +0000899 tmpdevice->params = (void *) params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000900 tmpdevice->usbinfo = (void *) ptp_usb;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000901 tmpdevice->storage_id = storageID;
902 tmpdevice->maximum_battery_level = batteryLevelMax;
903
Linus Walleij05ccbe72006-06-13 07:46:58 +0000904 // Set all default folders to 0 == root directory
905 tmpdevice->default_music_folder = 0;
906 tmpdevice->default_playlist_folder = 0;
907 tmpdevice->default_picture_folder = 0;
908 tmpdevice->default_video_folder = 0;
909 tmpdevice->default_organizer_folder = 0;
910 tmpdevice->default_zencast_folder = 0;
911
912 /*
913 * Then get the handles and try to locate the default folders.
914 * This has the desired side effect of cacheing all handles from
915 * the device which speeds up later operations.
916 */
917 flush_handles(tmpdevice);
Linus Walleij0558ac52006-09-07 06:55:03 +0000918 /*
919 * Remaining directories to get the handles to.
920 * We can stop when done this to save time
921 */
922 remaining_directories = 6;
Richard Low43fdb882006-09-06 16:19:05 +0000923 for (i = 0; i < params->handles.n && remaining_directories > 0; i++) {
Linus Walleij05ccbe72006-06-13 07:46:58 +0000924 PTPObjectInfo oi;
925 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
926 // Ignore non-folders
927 if ( oi.ObjectFormat != PTP_OFC_Association )
928 continue;
Linus Walleij97c7a342006-09-11 07:03:03 +0000929 if ( oi.Filename == NULL)
930 continue;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000931 if (!strcmp(oi.Filename, "Music")) {
932 tmpdevice->default_music_folder = params->handles.Handler[i];
Linus Walleij0558ac52006-09-07 06:55:03 +0000933 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000934 continue;
935 } else if (!strcmp(oi.Filename, "My Playlists")) {
936 tmpdevice->default_playlist_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000937 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000938 continue;
939 } else if (!strcmp(oi.Filename, "Pictures")) {
940 tmpdevice->default_picture_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000941 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000942 continue;
943 } else if (!strcmp(oi.Filename, "Video")) {
944 tmpdevice->default_video_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000945 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000946 continue;
947 } else if (!strcmp(oi.Filename, "My Organizer")) {
948 tmpdevice->default_organizer_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000949 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000950 continue;
951 } else if (!strcmp(oi.Filename, "ZENcast")) {
952 tmpdevice->default_zencast_folder = params->handles.Handler[i];
Richard Low43fdb882006-09-06 16:19:05 +0000953 remaining_directories--;
Linus Walleij05ccbe72006-06-13 07:46:58 +0000954 continue;
955 }
956 } else {
957 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
958 }
959 }
960
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000961 return tmpdevice;
mopoke96143402006-10-30 04:37:26 +0000962
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000963 // Then close it again.
964 error_handler:
Linus Walleij56d3e182006-02-10 15:46:54 +0000965 close_device(ptp_usb, params, interface_number);
Linus Walleijb02a0662006-04-25 08:05:09 +0000966 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
967 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij56d3e182006-02-10 15:46:54 +0000968 if (params->handles.Handler != NULL) {
969 free(params->handles.Handler);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000970 }
971 return NULL;
972}
973
974/**
975 * This closes and releases an allocated MTP device.
Linus Walleijb9256fd2006-02-15 09:40:43 +0000976 * @param device a pointer to the MTP device to release.
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000977 */
Linus Walleijb9256fd2006-02-15 09:40:43 +0000978void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000979{
Linus Walleij9b28da32006-03-16 13:47:58 +0000980 PTPParams *params = (PTPParams *) device->params;
Linus Walleij2d411db2006-03-22 12:13:09 +0000981 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij9b28da32006-03-16 13:47:58 +0000982
Linus Walleij2d411db2006-03-22 12:13:09 +0000983 close_device(ptp_usb, params, device->interface_number);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000984 // Free the device info and any handler
Linus Walleijb02a0662006-04-25 08:05:09 +0000985 // TODO: libgphoto2 does not seem to be able to free the deviceinfo
986 // ptp_free_deviceinfo(&params->deviceinfo);
Linus Walleij9b28da32006-03-16 13:47:58 +0000987 if (params->handles.Handler != NULL) {
988 free(params->handles.Handler);
Linus Walleij438bd7f2006-06-08 11:35:44 +0000989 params->handles.Handler = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000990 }
Linus Walleij3ec86312006-08-21 13:25:24 +0000991 // Free iconv() converters...
Linus Walleija823a702006-08-27 21:27:46 +0000992 iconv_close(params->cd_locale_to_ucs2);
993 iconv_close(params->cd_ucs2_to_locale);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000994 free(device);
995}
Linus Walleijb9256fd2006-02-15 09:40:43 +0000996
997/**
Linus Walleij438bd7f2006-06-08 11:35:44 +0000998 * This function refresh the internal handle list whenever
999 * the items stored inside the device is altered. On operations
1000 * that do not add or remove objects, this is typically not
1001 * called.
1002 * @param device a pointer to the MTP device to flush handles for.
1003 */
1004static void flush_handles(LIBMTP_mtpdevice_t *device)
1005{
1006 PTPParams *params = (PTPParams *) device->params;
1007 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +00001008
Linus Walleij438bd7f2006-06-08 11:35:44 +00001009 if (params->handles.Handler != NULL) {
1010 free(params->handles.Handler);
1011 }
1012
1013 // Get all the handles if we haven't already done that
1014 ret = ptp_getobjecthandles(params,
mopoke96143402006-10-30 04:37:26 +00001015 PTP_GOH_ALL_STORAGE,
1016 PTP_GOH_ALL_FORMATS,
1017 PTP_GOH_ALL_ASSOCS,
Linus Walleij438bd7f2006-06-08 11:35:44 +00001018 &params->handles);
1019 if (ret != PTP_RC_OK) {
1020 printf("flush_handles(): LIBMTP panic: Could not get object handles...\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00001021 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +00001022 }
1023
1024 return;
1025}
1026
1027/**
Linus Walleij8c45b292006-04-26 14:12:44 +00001028 * This function dumps out a large chunk of textual information
1029 * provided from the PTP protocol and additionally some extra
1030 * MTP-specific information where applicable.
1031 * @param device a pointer to the MTP device to report info from.
1032 */
1033void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
1034{
1035 int i;
1036 PTPParams *params = (PTPParams *) device->params;
Linus Walleijc6210fb2006-05-08 11:11:41 +00001037 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
mopoke96143402006-10-30 04:37:26 +00001038
Linus Walleijc6210fb2006-05-08 11:11:41 +00001039 printf("USB low-level info:\n");
1040 dump_usbinfo(ptp_usb);
Linus Walleij8c45b292006-04-26 14:12:44 +00001041 /* Print out some verbose information */
1042 printf("Device info:\n");
1043 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
1044 printf(" Model: %s\n", params->deviceinfo.Model);
1045 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
1046 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
1047 printf(" Vendor extension ID: 0x%08x\n", params->deviceinfo.VendorExtensionID);
1048 printf(" Vendor extension description: %s\n", params->deviceinfo.VendorExtensionDesc);
1049 printf("Supported operations:\n");
1050 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
Linus Walleij4f40d112006-09-21 07:44:53 +00001051 char txt[256];
1052
1053 (void) ptp_render_opcode (params, params->deviceinfo.OperationsSupported[i], sizeof(txt), txt);
1054 printf(" %04x: %s\n", params->deviceinfo.OperationsSupported[i], txt);
Linus Walleij8c45b292006-04-26 14:12:44 +00001055 }
1056 printf("Events supported:\n");
1057 if (params->deviceinfo.EventsSupported_len == 0) {
1058 printf(" None.\n");
1059 } else {
1060 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
1061 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
1062 }
1063 }
1064 printf("Device Properties Supported:\n");
1065 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
Linus Walleij16c51f02006-05-04 13:20:22 +00001066 char const *propdesc = ptp_get_property_description(params, params->deviceinfo.DevicePropertiesSupported[i]);
mopoke96143402006-10-30 04:37:26 +00001067
Linus Walleij545c7792006-06-13 15:22:30 +00001068 if (propdesc != NULL) {
1069 printf(" 0x%04x: %s\n", params->deviceinfo.DevicePropertiesSupported[i], propdesc);
1070 } else {
1071 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
Linus Walleijcf223e62006-06-19 09:31:53 +00001072 printf(" 0x%04x: Unknown property\n", prop);
Linus Walleij545c7792006-06-13 15:22:30 +00001073 }
Linus Walleij8c45b292006-04-26 14:12:44 +00001074 }
Linus Walleij0af979a2006-06-19 11:49:10 +00001075
1076 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
1077 printf("Playable File (Object) Types and Object Properties Supported:\n");
1078 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
1079 char txt[256];
1080 uint16_t ret;
1081 uint16_t *props = NULL;
1082 uint32_t propcnt = 0;
1083 int j;
mopoke96143402006-10-30 04:37:26 +00001084
Linus Walleij0af979a2006-06-19 11:49:10 +00001085 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i], sizeof(txt), txt);
1086 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
mopoke96143402006-10-30 04:37:26 +00001087
Linus Walleij0af979a2006-06-19 11:49:10 +00001088 ret = ptp_mtp_getobjectpropssupported (params, params->deviceinfo.ImageFormats[i], &propcnt, &props);
1089 if (ret != PTP_RC_OK) {
1090 printf(" Error on query for object properties.\n");
Linus Walleijda9500d2006-08-30 13:17:06 +00001091 printf(" Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij0af979a2006-06-19 11:49:10 +00001092 } else {
1093 for (j=0;j<propcnt;j++) {
1094 (void) ptp_render_mtp_propname(props[j],sizeof(txt),txt);
1095 printf(" %04x: %s\n", props[j], txt);
1096 }
1097 free(props);
1098 }
1099 }
1100 }
mopoke96143402006-10-30 04:37:26 +00001101
Linus Walleij545c7792006-06-13 15:22:30 +00001102 printf("Special directories:\n");
1103 printf(" Default music folder: 0x%08x\n", device->default_music_folder);
1104 printf(" Default playlist folder: 0x%08x\n", device->default_playlist_folder);
1105 printf(" Default picture folder: 0x%08x\n", device->default_picture_folder);
1106 printf(" Default video folder: 0x%08x\n", device->default_video_folder);
1107 printf(" Default organizer folder: 0x%08x\n", device->default_organizer_folder);
1108 printf(" Default zencast folder: 0x%08x\n", device->default_zencast_folder);
Linus Walleij8c45b292006-04-26 14:12:44 +00001109}
1110
1111/**
mopoke96143402006-10-30 04:37:26 +00001112 * This retrieves the model name (often equal to product name)
Linus Walleij80124062006-03-15 10:26:09 +00001113 * of an MTP device.
1114 * @param device a pointer to the device to get the model name for.
1115 * @return a newly allocated UTF-8 string representing the model name.
1116 * The string must be freed by the caller after use. If the call
1117 * was unsuccessful this will contain NULL.
1118 */
1119char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
1120{
1121 char *retmodel = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001122 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001123
Linus Walleij9b28da32006-03-16 13:47:58 +00001124 if (params->deviceinfo.Model != NULL) {
1125 retmodel = strdup(params->deviceinfo.Model);
Linus Walleij80124062006-03-15 10:26:09 +00001126 }
1127 return retmodel;
1128}
1129
1130/**
1131 * This retrieves the serial number of an MTP device.
1132 * @param device a pointer to the device to get the serial number for.
1133 * @return a newly allocated UTF-8 string representing the serial number.
1134 * The string must be freed by the caller after use. If the call
1135 * was unsuccessful this will contain NULL.
1136 */
1137char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
1138{
1139 char *retnumber = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001140 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001141
Linus Walleij9b28da32006-03-16 13:47:58 +00001142 if (params->deviceinfo.SerialNumber != NULL) {
1143 retnumber = strdup(params->deviceinfo.SerialNumber);
Linus Walleij80124062006-03-15 10:26:09 +00001144 }
1145 return retnumber;
1146}
1147
1148/**
mopoke96143402006-10-30 04:37:26 +00001149 * This retrieves the device version (hardware and firmware version) of an
Linus Walleij80124062006-03-15 10:26:09 +00001150 * MTP device.
1151 * @param device a pointer to the device to get the device version for.
1152 * @return a newly allocated UTF-8 string representing the device version.
1153 * The string must be freed by the caller after use. If the call
1154 * was unsuccessful this will contain NULL.
1155 */
1156char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
1157{
1158 char *retversion = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001159 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001160
Linus Walleij9b28da32006-03-16 13:47:58 +00001161 if (params->deviceinfo.DeviceVersion != NULL) {
1162 retversion = strdup(params->deviceinfo.DeviceVersion);
Linus Walleij80124062006-03-15 10:26:09 +00001163 }
1164 return retversion;
1165}
1166
1167
1168/**
Linus Walleijfae27482006-08-19 20:13:25 +00001169 * This retrieves the "friendly name" of an MTP device. Usually
1170 * this is simply the name of the owner or something like
Linus Walleij30658792006-08-19 22:18:55 +00001171 * "John Doe's Digital Audio Player". This property should be supported
Linus Walleijfae27482006-08-19 20:13:25 +00001172 * by all MTP devices.
1173 * @param device a pointer to the device to get the friendly name for.
mopoke96143402006-10-30 04:37:26 +00001174 * @return a newly allocated UTF-8 string representing the friendly name.
Linus Walleijb9256fd2006-02-15 09:40:43 +00001175 * The string must be freed by the caller after use.
Linus Walleij30658792006-08-19 22:18:55 +00001176 * @see LIBMTP_Set_Friendlyname()
Linus Walleijb9256fd2006-02-15 09:40:43 +00001177 */
Linus Walleij30658792006-08-19 22:18:55 +00001178char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001179{
Linus Walleijb02a0662006-04-25 08:05:09 +00001180 PTPPropertyValue propval;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001181 char *retstring = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00001182 PTPParams *params = (PTPParams *) device->params;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001183
Linus Walleijcf223e62006-06-19 09:31:53 +00001184 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
1185 return NULL;
1186 }
1187
mopoke96143402006-10-30 04:37:26 +00001188 if (ptp_getdevicepropvalue(params,
1189 PTP_DPC_MTP_DeviceFriendlyName,
1190 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001191 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleijb9256fd2006-02-15 09:40:43 +00001192 return NULL;
1193 }
Linus Walleija823a702006-08-27 21:27:46 +00001194 if (propval.str != NULL) {
1195 retstring = strdup(propval.str);
1196 free(propval.str);
1197 }
Linus Walleijfae27482006-08-19 20:13:25 +00001198 return retstring;
1199}
1200
1201/**
Linus Walleij30658792006-08-19 22:18:55 +00001202 * Sets the "friendly name" of an MTP device.
1203 * @param device a pointer to the device to set the friendly name for.
1204 * @param friendlyname the new friendly name for the device.
1205 * @return 0 on success, any other value means failure.
1206 * @see LIBMTP_Get_Ownername()
1207 */
1208int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
1209 char const * const friendlyname)
1210{
1211 PTPPropertyValue propval;
1212 PTPParams *params = (PTPParams *) device->params;
1213
1214 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
1215 return -1;
1216 }
Linus Walleija823a702006-08-27 21:27:46 +00001217 propval.str = (char *) friendlyname;
Linus Walleij30658792006-08-19 22:18:55 +00001218 if (ptp_setdevicepropvalue(params,
mopoke96143402006-10-30 04:37:26 +00001219 PTP_DPC_MTP_DeviceFriendlyName,
1220 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001221 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleij30658792006-08-19 22:18:55 +00001222 return -1;
1223 }
Linus Walleij30658792006-08-19 22:18:55 +00001224 return 0;
1225}
1226
1227/**
Linus Walleijfae27482006-08-19 20:13:25 +00001228 * This retrieves the syncronization partner of an MTP device. This
1229 * property should be supported by all MTP devices.
1230 * @param device a pointer to the device to get the sync partner for.
1231 * @return a newly allocated UTF-8 string representing the synchronization
1232 * partner. The string must be freed by the caller after use.
Linus Walleij30658792006-08-19 22:18:55 +00001233 * @see LIBMTP_Set_Syncpartner()
Linus Walleijfae27482006-08-19 20:13:25 +00001234 */
1235char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
1236{
1237 PTPPropertyValue propval;
1238 char *retstring = NULL;
1239 PTPParams *params = (PTPParams *) device->params;
1240
1241 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
1242 return NULL;
1243 }
1244
mopoke96143402006-10-30 04:37:26 +00001245 if (ptp_getdevicepropvalue(params,
1246 PTP_DPC_MTP_SynchronizationPartner,
1247 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001248 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleijfae27482006-08-19 20:13:25 +00001249 return NULL;
1250 }
Linus Walleija823a702006-08-27 21:27:46 +00001251 if (propval.str != NULL) {
1252 retstring = strdup(propval.str);
1253 free(propval.str);
1254 }
Linus Walleijb9256fd2006-02-15 09:40:43 +00001255 return retstring;
1256}
1257
Linus Walleij30658792006-08-19 22:18:55 +00001258
1259/**
1260 * Sets the synchronization partner of an MTP device. Note that
1261 * we have no idea what the effect of setting this to "foobar"
1262 * may be. But the general idea seems to be to tell which program
1263 * shall synchronize with this device and tell others to leave
1264 * it alone.
1265 * @param device a pointer to the device to set the sync partner for.
1266 * @param syncpartner the new synchronization partner for the device.
1267 * @return 0 on success, any other value means failure.
1268 * @see LIBMTP_Get_Syncpartner()
1269 */
1270int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
1271 char const * const syncpartner)
1272{
1273 PTPPropertyValue propval;
1274 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001275
Linus Walleij30658792006-08-19 22:18:55 +00001276 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
1277 return -1;
1278 }
Linus Walleija823a702006-08-27 21:27:46 +00001279 propval.str = (char *) syncpartner;
Linus Walleij30658792006-08-19 22:18:55 +00001280 if (ptp_setdevicepropvalue(params,
mopoke96143402006-10-30 04:37:26 +00001281 PTP_DPC_MTP_SynchronizationPartner,
1282 &propval,
Linus Walleija823a702006-08-27 21:27:46 +00001283 PTP_DTC_STR) != PTP_RC_OK) {
Linus Walleij30658792006-08-19 22:18:55 +00001284 return -1;
1285 }
Linus Walleij30658792006-08-19 22:18:55 +00001286 return 0;
1287}
1288
Linus Walleij394bbbe2006-02-22 16:10:53 +00001289/**
Linus Walleijfa1374c2006-02-27 07:41:46 +00001290 * This function finds out how much storage space is currently used
1291 * and any additional storage information. Storage may be a hard disk
1292 * or flash memory or whatever.
1293 * @param device a pointer to the device to get the storage info for.
mopoke96143402006-10-30 04:37:26 +00001294 * @param total a pointer to a variable that will hold the
Linus Walleijfa1374c2006-02-27 07:41:46 +00001295 * total the total number of bytes available on this volume after
1296 * the call.
mopoke96143402006-10-30 04:37:26 +00001297 * @param free a pointer to a variable that will hold the number of
Linus Walleijfa1374c2006-02-27 07:41:46 +00001298 * free bytes available on this volume right now after the call.
mopoke96143402006-10-30 04:37:26 +00001299 * @param storage_description a description of the storage. This may
1300 * be NULL after the call even if it succeeded. If it is not NULL,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001301 * it must be freed by the callee after use.
1302 * @param volume_label a volume label or similar. This may be NULL after the
1303 * call even if it succeeded. If it is not NULL, it must be
1304 * freed by the callee after use.
1305 * @return 0 if the storage info was successfully retrieved, any other
1306 * value means failure.
1307 */
mopoke96143402006-10-30 04:37:26 +00001308int LIBMTP_Get_Storageinfo(LIBMTP_mtpdevice_t *device, uint64_t * const total,
1309 uint64_t * const free, char ** const storage_description,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001310 char ** const volume_label)
1311{
1312 PTPStorageInfo storageInfo;
Linus Walleij9b28da32006-03-16 13:47:58 +00001313 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001314
Linus Walleij9b28da32006-03-16 13:47:58 +00001315 if (ptp_getstorageinfo(params, device->storage_id, &storageInfo) != PTP_RC_OK) {
Linus Walleijfa1374c2006-02-27 07:41:46 +00001316 printf("LIBMTP_Get_Diskinfo(): failed to get disk info\n");
1317 *total = 0;
1318 *free = 0;
1319 *storage_description = NULL;
1320 *volume_label = NULL;
1321 return -1;
1322 }
1323 *total = storageInfo.MaxCapability;
1324 *free = storageInfo.FreeSpaceInBytes;
1325 *storage_description = storageInfo.StorageDescription;
1326 *volume_label = storageInfo.VolumeLabel;
1327
1328 return 0;
1329}
1330
1331
1332/**
1333 * This function retrieves the current battery level on the device.
1334 * @param device a pointer to the device to get the battery level for.
mopoke96143402006-10-30 04:37:26 +00001335 * @param maximum_level a pointer to a variable that will hold the
Linus Walleijfa1374c2006-02-27 07:41:46 +00001336 * maximum level of the battery if the call was successful.
mopoke96143402006-10-30 04:37:26 +00001337 * @param current_level a pointer to a variable that will hold the
Linus Walleijfa1374c2006-02-27 07:41:46 +00001338 * current level of the battery if the call was successful.
Linus Walleij545c7792006-06-13 15:22:30 +00001339 * A value of 0 means that the device is on external power.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001340 * @return 0 if the storage info was successfully retrieved, any other
Linus Walleij80439342006-09-12 10:42:26 +00001341 * means failure. A typical cause of failure is that
Linus Walleij545c7792006-06-13 15:22:30 +00001342 * the device does not support the battery level property.
Linus Walleijfa1374c2006-02-27 07:41:46 +00001343 */
mopoke96143402006-10-30 04:37:26 +00001344int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
1345 uint8_t * const maximum_level,
Linus Walleijfa1374c2006-02-27 07:41:46 +00001346 uint8_t * const current_level)
1347{
Linus Walleijb02a0662006-04-25 08:05:09 +00001348 PTPPropertyValue propval;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001349 uint16_t ret;
Linus Walleij9b28da32006-03-16 13:47:58 +00001350 PTPParams *params = (PTPParams *) device->params;
Linus Walleijfa1374c2006-02-27 07:41:46 +00001351
Linus Walleij545c7792006-06-13 15:22:30 +00001352 *maximum_level = 0;
1353 *current_level = 0;
1354
1355 if (!ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
1356 return -1;
1357 }
mopoke96143402006-10-30 04:37:26 +00001358
Linus Walleijb02a0662006-04-25 08:05:09 +00001359 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel, &propval, PTP_DTC_UINT8);
1360 if (ret != PTP_RC_OK) {
Linus Walleijda9500d2006-08-30 13:17:06 +00001361 printf("LIBMTP_Get_Batterylevel(): could not get devcie property value.\n");
1362 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijfa1374c2006-02-27 07:41:46 +00001363 return -1;
1364 }
mopoke96143402006-10-30 04:37:26 +00001365
Linus Walleijfa1374c2006-02-27 07:41:46 +00001366 *maximum_level = device->maximum_battery_level;
Linus Walleijb02a0662006-04-25 08:05:09 +00001367 *current_level = propval.u8;
mopoke96143402006-10-30 04:37:26 +00001368
Linus Walleijfa1374c2006-02-27 07:41:46 +00001369 return 0;
1370}
1371
Linus Walleij13374a42006-09-13 11:55:30 +00001372
1373/**
1374 * Formats device storage (if the device supports the operation).
1375 * WARNING: This WILL delete all data from the device. Make sure you've
1376 * got confirmation from the user BEFORE you call this function.
1377 *
1378 * @param device a pointer to the device to format.
1379 * @return 0 on success, any other value means failure.
1380 */
1381int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device)
1382{
1383 uint16_t ret;
1384 PTPParams *params = (PTPParams *) device->params;
mopoke96143402006-10-30 04:37:26 +00001385
Linus Walleij13374a42006-09-13 11:55:30 +00001386 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
1387 printf("LIBMTP_Format_Storage(): device cannot format storage\n");
1388 return -1;
1389 }
1390 ret = ptp_formatstore(params, device->storage_id);
1391 if (ret != PTP_RC_OK) {
1392 printf("LIBMTP_Format_Storage(): failed to format storage\n");
1393 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
1394 return -1;
1395 }
1396 return 0;
1397}
1398
Linus Walleijfa1374c2006-02-27 07:41:46 +00001399/**
Linus Walleij545c7792006-06-13 15:22:30 +00001400 * Helper function to extract a unicode property off a device.
Linus Walleije46f12e2006-06-22 17:53:25 +00001401 * This is the standard way of retrieveing unicode device
1402 * properties as described by the PTP spec.
Linus Walleijcf223e62006-06-19 09:31:53 +00001403 * @param device a pointer to the device to get the property from.
mopoke96143402006-10-30 04:37:26 +00001404 * @param unicstring a pointer to a pointer that will hold the
Linus Walleijcf223e62006-06-19 09:31:53 +00001405 * property after this call is completed.
1406 * @param property the property to retrieve.
1407 * @return 0 on success, any other value means failure.
Linus Walleij545c7792006-06-13 15:22:30 +00001408 */
mopoke96143402006-10-30 04:37:26 +00001409static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
Linus Walleijcf223e62006-06-19 09:31:53 +00001410 char **unicstring, uint16_t property)
Linus Walleij545c7792006-06-13 15:22:30 +00001411{
1412 PTPPropertyValue propval;
1413 PTPParams *params = (PTPParams *) device->params;
Linus Walleij16571dc2006-08-17 20:27:46 +00001414 uint16_t *tmp;
Linus Walleij545c7792006-06-13 15:22:30 +00001415 int i;
1416
1417 if (!ptp_property_issupported(params, property)) {
1418 return -1;
1419 }
1420
Linus Walleijcf223e62006-06-19 09:31:53 +00001421 // Unicode strings are 16bit unsigned integer arrays.
mopoke96143402006-10-30 04:37:26 +00001422 if (ptp_getdevicepropvalue(params,
1423 property,
1424 &propval,
Linus Walleij545c7792006-06-13 15:22:30 +00001425 PTP_DTC_AUINT16) != PTP_RC_OK) {
1426 return -1;
1427 }
1428
1429 // Extract the actual array.
Linus Walleij16571dc2006-08-17 20:27:46 +00001430 // printf("Array of %d elements\n", propval.a.count);
1431 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
Linus Walleij545c7792006-06-13 15:22:30 +00001432 for (i = 0; i < propval.a.count; i++) {
Linus Walleij16571dc2006-08-17 20:27:46 +00001433 tmp[i] = propval.a.v[i].u16;
1434 // printf("%04x ", tmp[i]);
Linus Walleij545c7792006-06-13 15:22:30 +00001435 }
Linus Walleij16571dc2006-08-17 20:27:46 +00001436 tmp[propval.a.count] = 0x0000U;
Linus Walleij545c7792006-06-13 15:22:30 +00001437 free(propval.a.v);
1438
Linus Walleij3ec86312006-08-21 13:25:24 +00001439 *unicstring = utf16_to_utf8(device, tmp);
Linus Walleij16571dc2006-08-17 20:27:46 +00001440
Linus Walleij545c7792006-06-13 15:22:30 +00001441 free(tmp);
1442
1443 return 0;
1444}
1445
1446/**
1447 * This function returns the secure time as an XML document string from
1448 * the device.
1449 * @param device a pointer to the device to get the secure time for.
1450 * @param sectime the secure time string as an XML document or NULL if the call
1451 * failed or the secure time property is not supported. This string
1452 * must be <code>free()</code>:ed by the caller after use.
1453 * @return 0 on success, any other value means failure.
1454 */
Linus Walleij8ab54262006-06-21 07:12:28 +00001455int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
Linus Walleij545c7792006-06-13 15:22:30 +00001456{
1457 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
1458}
1459
1460/**
mopoke96143402006-10-30 04:37:26 +00001461 * This function returns the device (public key) certificate as an
Linus Walleij545c7792006-06-13 15:22:30 +00001462 * XML document string from the device.
1463 * @param device a pointer to the device to get the device certificate for.
1464 * @param devcert the device certificate as an XML string or NULL if the call
1465 * failed or the device certificate property is not supported. This
1466 * string must be <code>free()</code>:ed by the caller after use.
1467 * @return 0 on success, any other value means failure.
1468 */
Linus Walleij8ab54262006-06-21 07:12:28 +00001469int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
Linus Walleij545c7792006-06-13 15:22:30 +00001470{
1471 return get_device_unicode_property(device, devcert, PTP_DPC_MTP_DeviceCertificate);
1472}
1473
1474/**
Linus Walleij8ab54262006-06-21 07:12:28 +00001475 * This function retrieves a list of supported file types, i.e. the file
1476 * types that this device claims it supports, e.g. audio file types that
1477 * the device can play etc. This list is mitigated to
1478 * inlcude the file types that libmtp can handle, i.e. it will not list
1479 * filetypes that libmtp will handle internally like playlists and folders.
1480 * @param device a pointer to the device to get the filetype capabilities for.
1481 * @param filetypes a pointer to a pointer that will hold the list of
1482 * supported filetypes if the call was successful. This list must
1483 * be <code>free()</code>:ed by the caller after use.
1484 * @param length a pointer to a variable that will hold the length of the
1485 * list of supported filetypes if the call was successful.
1486 * @return 0 on success, any other value means failure.
1487 * @see LIBMTP_Get_Filetype_Description()
1488 */
mopoke96143402006-10-30 04:37:26 +00001489int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
Linus Walleij8ab54262006-06-21 07:12:28 +00001490 uint16_t * const length)
1491{
1492 PTPParams *params = (PTPParams *) device->params;
1493 uint16_t *localtypes;
1494 uint16_t localtypelen;
1495 uint32_t i;
mopoke96143402006-10-30 04:37:26 +00001496
Linus Walleij8ab54262006-06-21 07:12:28 +00001497 // This is more memory than needed if there are unknown types, but what the heck.
1498 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
1499 localtypelen = 0;
mopoke96143402006-10-30 04:37:26 +00001500
Linus Walleij8ab54262006-06-21 07:12:28 +00001501 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
1502 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
1503 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
1504 localtypes[localtypelen] = localtype;
1505 localtypelen++;
1506 }
1507 }
1508
1509 *filetypes = localtypes;
1510 *length = localtypelen;
1511
1512 return 0;
1513}
1514
1515
1516/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00001517 * This creates a new MTP object structure and allocates memory
raveloxd9a28642006-05-26 23:42:22 +00001518 * for it. Notice that if you add strings to this structure they
1519 * will be freed by the corresponding <code>LIBMTP_destroy_object_t</code>
mopoke96143402006-10-30 04:37:26 +00001520 * operation later, so be careful of using strdup() when assigning
raveloxd9a28642006-05-26 23:42:22 +00001521 * strings, e.g.:
1522 *
1523 * <pre>
1524 * LIBMTP_object_t *object = LIBMTP_new_object_t();
1525 * object->name = strdup(namestr);
1526 * ....
1527 * LIBMTP_destroy_object_t(file);
1528 * </pre>
1529 *
1530 * @return a pointer to the newly allocated structure.
1531 * @see LIBMTP_destroy_object_t()
1532 */
1533LIBMTP_object_t *LIBMTP_new_object_t(void)
1534{
1535 LIBMTP_object_t *new = (LIBMTP_object_t *) malloc(sizeof(LIBMTP_object_t));
1536 if (new == NULL) {
1537 return NULL;
1538 }
1539
1540 new->id = 0;
1541 new->parent = 0;
1542 new->type = LIBMTP_FILETYPE_UNKNOWN;
1543 new->size = 0;
1544 new->name = NULL;
1545 new->data = NULL;
1546 new->sibling = NULL;
1547 new->child = NULL;
1548
1549 return new;
1550}
Linus Walleijf0f3d482006-05-29 14:10:21 +00001551
raveloxd9a28642006-05-26 23:42:22 +00001552/**
Linus Walleijf6bc1782006-03-24 15:12:47 +00001553 * This creates a new file metadata structure and allocates memory
1554 * for it. Notice that if you add strings to this structure they
1555 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
mopoke96143402006-10-30 04:37:26 +00001556 * operation later, so be careful of using strdup() when assigning
Linus Walleijf6bc1782006-03-24 15:12:47 +00001557 * strings, e.g.:
1558 *
1559 * <pre>
1560 * LIBMTP_file_t *file = LIBMTP_new_file_t();
1561 * file->filename = strdup(namestr);
1562 * ....
1563 * LIBMTP_destroy_file_t(file);
1564 * </pre>
1565 *
1566 * @return a pointer to the newly allocated metadata structure.
1567 * @see LIBMTP_destroy_file_t()
1568 */
1569LIBMTP_file_t *LIBMTP_new_file_t(void)
1570{
1571 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
1572 if (new == NULL) {
1573 return NULL;
1574 }
1575 new->filename = NULL;
1576 new->filesize = 0;
1577 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
1578 new->next = NULL;
1579 return new;
1580}
1581
1582/**
1583 * This destroys a file metadata structure and deallocates the memory
mopoke96143402006-10-30 04:37:26 +00001584 * used by it, including any strings. Never use a file metadata
Linus Walleijf6bc1782006-03-24 15:12:47 +00001585 * structure again after calling this function on it.
1586 * @param file the file metadata to destroy.
1587 * @see LIBMTP_new_file_t()
1588 */
1589void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
1590{
1591 if (file == NULL) {
1592 return;
1593 }
1594 if (file->filename != NULL)
1595 free(file->filename);
1596 free(file);
1597 return;
1598}
1599
1600/**
Richard Lowdc0b6c72006-11-13 09:22:23 +00001601* THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
1602 * NOT TO USE IT.
1603 * @see LIBMTP_Get_Filelisting_With_Callback()
1604 */
1605LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
1606{
1607 printf("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
1608 printf("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
1609 return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
1610}
1611
1612/**
Linus Walleijf6bc1782006-03-24 15:12:47 +00001613 * This returns a long list of all files available
1614 * on the current MTP device. Typical usage:
1615 *
1616 * <pre>
1617 * LIBMTP_file_t *filelist;
1618 *
Richard Lowdc0b6c72006-11-13 09:22:23 +00001619 * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001620 * while (filelist != NULL) {
1621 * LIBMTP_file_t *tmp;
1622 *
1623 * // Do something on each element in the list here...
1624 * tmp = filelist;
1625 * filelist = filelist->next;
1626 * LIBMTP_destroy_file_t(tmp);
1627 * }
1628 * </pre>
1629 *
1630 * @param device a pointer to the device to get the file listing for.
Richard Lowdc0b6c72006-11-13 09:22:23 +00001631 * @param callback a function to be called during the tracklisting retrieveal
1632 * for displaying progress bars etc, or NULL if you don't want
1633 * any callbacks.
1634 * @param data a user-defined pointer that is passed along to
1635 * the <code>progress</code> function in order to
1636 * pass along some user defined data to the progress
1637 * updates. If not used, set this to NULL.
Linus Walleijf6bc1782006-03-24 15:12:47 +00001638 * @return a list of files that can be followed using the <code>next</code>
1639 * field of the <code>LIBMTP_file_t</code> data structure.
1640 * Each of the metadata tags must be freed after use, and may
1641 * contain only partial metadata information, i.e. one or several
1642 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001643 * @see LIBMTP_Get_Filemetadata()
Linus Walleijf6bc1782006-03-24 15:12:47 +00001644 */
Richard Lowdc0b6c72006-11-13 09:22:23 +00001645LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
1646 LIBMTP_progressfunc_t const callback,
1647 void const * const data)
Linus Walleijf6bc1782006-03-24 15:12:47 +00001648{
1649 uint32_t i = 0;
1650 LIBMTP_file_t *retfiles = NULL;
1651 LIBMTP_file_t *curfile = NULL;
1652 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00001653
mopoke96143402006-10-30 04:37:26 +00001654 // Get all the handles if we haven't already done that
Linus Walleijf6bc1782006-03-24 15:12:47 +00001655 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00001656 flush_handles(device);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001657 }
mopoke96143402006-10-30 04:37:26 +00001658
Linus Walleijf6bc1782006-03-24 15:12:47 +00001659 for (i = 0; i < params->handles.n; i++) {
1660
Richard Lowdc0b6c72006-11-13 09:22:23 +00001661 if (callback != NULL)
1662 callback(i, params->handles.n, data);
1663
Linus Walleijf6bc1782006-03-24 15:12:47 +00001664 LIBMTP_file_t *file;
1665 PTPObjectInfo oi;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001666
1667 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleij16c51f02006-05-04 13:20:22 +00001668
Linus Walleij91405592006-05-05 14:22:51 +00001669 if (oi.ObjectFormat == PTP_OFC_Association) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00001670 // MTP use thesis object format for folders which means
Linus Walleij16c51f02006-05-04 13:20:22 +00001671 // these "files" will turn up on a folder listing instead.
1672 continue;
1673 }
1674
Linus Walleijf6bc1782006-03-24 15:12:47 +00001675 // Allocate a new file type
1676 file = LIBMTP_new_file_t();
Linus Walleijb02a0662006-04-25 08:05:09 +00001677
Linus Walleijd208f9c2006-04-27 14:16:06 +00001678 file->parent_id = oi.ParentObject;
Linus Walleij16c51f02006-05-04 13:20:22 +00001679
1680 // Set the filetype
1681 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
Linus Walleijf6bc1782006-03-24 15:12:47 +00001682
1683 // Original file-specific properties
1684 file->filesize = oi.ObjectCompressedSize;
1685 if (oi.Filename != NULL) {
1686 file->filename = strdup(oi.Filename);
1687 }
1688
1689 // This is some sort of unique ID so we can keep track of the track.
1690 file->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00001691
Linus Walleijf6bc1782006-03-24 15:12:47 +00001692 // Add track to a list that will be returned afterwards.
1693 if (retfiles == NULL) {
1694 retfiles = file;
1695 curfile = file;
1696 } else {
1697 curfile->next = file;
1698 curfile = file;
1699 }
mopoke96143402006-10-30 04:37:26 +00001700
Linus Walleijf6bc1782006-03-24 15:12:47 +00001701 // Call listing callback
1702 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
1703
1704 } else {
1705 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
1706 }
1707
1708 } // Handle counting loop
1709 return retfiles;
1710}
1711
1712/**
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001713 * This function retrieves the metadata for a single file off
1714 * the device.
1715 *
1716 * Do not call this function repeatedly! The file handles are linearly
1717 * searched O(n) and the call may involve (slow) USB traffic, so use
1718 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
1719 * as an efficient data structure such as a hash list.
1720 *
1721 * @param device a pointer to the device to get the file metadata from.
1722 * @param fileid the object ID of the file that you want the metadata for.
1723 * @return a metadata entry on success or NULL on failure.
1724 * @see LIBMTP_Get_Filelisting()
1725 */
1726LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
1727{
1728 uint32_t i = 0;
1729 PTPParams *params = (PTPParams *) device->params;
1730
mopoke96143402006-10-30 04:37:26 +00001731 // Get all the handles if we haven't already done that
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001732 if (params->handles.Handler == NULL) {
1733 flush_handles(device);
1734 }
1735
1736 for (i = 0; i < params->handles.n; i++) {
1737 LIBMTP_file_t *file;
1738 PTPObjectInfo oi;
1739
1740 // Is this the file we're looking for?
1741 if (params->handles.Handler[i] != fileid) {
1742 continue;
1743 }
1744
1745 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
1746
1747 if (oi.ObjectFormat == PTP_OFC_Association) {
1748 // MTP use thesis object format for folders which means
1749 // these "files" will turn up on a folder listing instead.
1750 return NULL;
1751 }
1752
1753 // Allocate a new file type
1754 file = LIBMTP_new_file_t();
mopoke96143402006-10-30 04:37:26 +00001755
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001756 file->parent_id = oi.ParentObject;
mopoke96143402006-10-30 04:37:26 +00001757
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001758 // Set the filetype
1759 file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00001760
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001761 // Original file-specific properties
1762 file->filesize = oi.ObjectCompressedSize;
1763 if (oi.Filename != NULL) {
1764 file->filename = strdup(oi.Filename);
1765 }
mopoke96143402006-10-30 04:37:26 +00001766
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001767 // This is some sort of unique ID so we can keep track of the track.
1768 file->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00001769
Linus Walleij2e4b5f92006-06-16 14:00:49 +00001770 return file;
1771 } else {
1772 return NULL;
1773 }
1774
1775 }
1776 return NULL;
1777}
1778
1779/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00001780 * This creates a new track metadata structure and allocates memory
1781 * for it. Notice that if you add strings to this structure they
1782 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
mopoke96143402006-10-30 04:37:26 +00001783 * operation later, so be careful of using strdup() when assigning
Linus Walleij394bbbe2006-02-22 16:10:53 +00001784 * strings, e.g.:
1785 *
Linus Walleij17e39f72006-02-23 15:54:28 +00001786 * <pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001787 * LIBMTP_track_t *track = LIBMTP_new_track_t();
1788 * track->title = strdup(titlestr);
1789 * ....
1790 * LIBMTP_destroy_track_t(track);
Linus Walleij17e39f72006-02-23 15:54:28 +00001791 * </pre>
Linus Walleij394bbbe2006-02-22 16:10:53 +00001792 *
1793 * @return a pointer to the newly allocated metadata structure.
1794 * @see LIBMTP_destroy_track_t()
1795 */
1796LIBMTP_track_t *LIBMTP_new_track_t(void)
Linus Walleijb9256fd2006-02-15 09:40:43 +00001797{
1798 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
1799 if (new == NULL) {
1800 return NULL;
1801 }
1802 new->title = NULL;
1803 new->artist = NULL;
1804 new->album = NULL;
1805 new->genre = NULL;
1806 new->date = NULL;
1807 new->filename = NULL;
1808 new->duration = 0;
1809 new->tracknumber = 0;
1810 new->filesize = 0;
Linus Walleijf6bc1782006-03-24 15:12:47 +00001811 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
Linus Walleijcf223e62006-06-19 09:31:53 +00001812 new->samplerate = 0;
1813 new->nochannels = 0;
1814 new->wavecodec = 0;
1815 new->bitrate = 0;
1816 new->bitratetype = 0;
1817 new->rating = 0;
1818 new->usecount = 0;
Linus Walleijb9256fd2006-02-15 09:40:43 +00001819 new->next = NULL;
1820 return new;
1821}
1822
Linus Walleij394bbbe2006-02-22 16:10:53 +00001823/**
1824 * This destroys a track metadata structure and deallocates the memory
mopoke96143402006-10-30 04:37:26 +00001825 * used by it, including any strings. Never use a track metadata
Linus Walleij394bbbe2006-02-22 16:10:53 +00001826 * structure again after calling this function on it.
1827 * @param track the track metadata to destroy.
1828 * @see LIBMTP_new_track_t()
1829 */
Linus Walleijb9256fd2006-02-15 09:40:43 +00001830void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
1831{
1832 if (track == NULL) {
1833 return;
1834 }
1835 if (track->title != NULL)
1836 free(track->title);
1837 if (track->artist != NULL)
1838 free(track->artist);
1839 if (track->album != NULL)
1840 free(track->album);
1841 if (track->genre != NULL)
1842 free(track->genre);
1843 if (track->date != NULL)
1844 free(track->date);
1845 if (track->filename != NULL)
1846 free(track->filename);
1847 free(track);
1848 return;
1849}
1850
1851/**
Linus Walleij8ab54262006-06-21 07:12:28 +00001852 * This function retrieves the track metadata for a track
1853 * given by a unique ID.
1854 * @param device a pointer to the device to get the track metadata off.
1855 * @param trackid the unique ID of the track.
1856 * @param objectformat the object format of this track, so we know what it supports.
1857 * @param track a metadata set to fill in.
1858 */
1859static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
1860 LIBMTP_track_t *track)
1861{
Linus Walleij00cf0642006-07-26 20:40:59 +00001862 uint16_t ret;
1863 PTPParams *params = (PTPParams *) device->params;
1864 uint32_t i;
Linus Walleij00cf0642006-07-26 20:40:59 +00001865
Linus Walleij3fcfea52006-11-13 07:07:36 +00001866#if 0 // #ifdef ENABLE_MTP_ENHANCED
1867 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)) {
1868 MTPPropList *proplist = NULL;
1869 MTPPropList *prop;
1870 MTPPropList *tmpprop;
1871
1872 ret = ptp_mtp_getobjectproplist(params, track->item_id, &proplist);
1873 prop = proplist;
1874 while (prop != NULL) {
1875 switch (prop->property) {
Linus Walleij00cf0642006-07-26 20:40:59 +00001876 case PTP_OPC_Name:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001877 track->title = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001878 break;
1879 case PTP_OPC_Artist:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001880 track->artist = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001881 break;
1882 case PTP_OPC_Duration:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001883 track->duration = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001884 break;
1885 case PTP_OPC_Track:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001886 track->tracknumber = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001887 break;
1888 case PTP_OPC_Genre:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001889 track->genre = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001890 break;
1891 case PTP_OPC_AlbumName:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001892 track->album = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001893 break;
1894 case PTP_OPC_OriginalReleaseDate:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001895 track->date = strdup(prop->propval.str);
Linus Walleij00cf0642006-07-26 20:40:59 +00001896 break;
1897 // These are, well not so important.
1898 case PTP_OPC_SampleRate:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001899 track->samplerate = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001900 break;
1901 case PTP_OPC_NumberOfChannels:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001902 track->nochannels = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001903 break;
1904 case PTP_OPC_AudioWAVECodec:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001905 track->wavecodec = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001906 break;
1907 case PTP_OPC_AudioBitRate:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001908 track->bitrate = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001909 break;
1910 case PTP_OPC_BitRateType:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001911 track->bitratetype = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001912 break;
1913 case PTP_OPC_Rating:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001914 track->rating = prop->propval.u16;
Linus Walleij00cf0642006-07-26 20:40:59 +00001915 break;
1916 case PTP_OPC_UseCount:
Linus Walleij3fcfea52006-11-13 07:07:36 +00001917 track->usecount = prop->propval.u32;
Linus Walleij00cf0642006-07-26 20:40:59 +00001918 break;
1919 }
Linus Walleij3fcfea52006-11-13 07:07:36 +00001920 tmpprop = prop;
1921 prop = prop->next;
1922 Destroy_MTP_Prop_Entry(tmpprop);
Linus Walleij00cf0642006-07-26 20:40:59 +00001923 }
Linus Walleij3fcfea52006-11-13 07:07:36 +00001924 } else {
1925#else
1926 {
1927#endif
1928 uint16_t *props = NULL;
1929 uint32_t propcnt = 0;
1930
1931 // First see which properties can be retrieved for this object format
1932 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
1933 if (ret != PTP_RC_OK) {
1934 // Just bail out for now, nothing is ever set.
1935 return;
1936 } else {
1937 for (i=0;i<propcnt;i++) {
1938 switch (props[i]) {
1939 case PTP_OPC_Name:
1940 track->title = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Name);
1941 break;
1942 case PTP_OPC_Artist:
1943 track->artist = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Artist);
1944 break;
1945 case PTP_OPC_Duration:
1946 track->duration = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_Duration, 0);
1947 break;
1948 case PTP_OPC_Track:
1949 track->tracknumber = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_Track, 0);
1950 break;
1951 case PTP_OPC_Genre:
1952 track->genre = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_Genre);
1953 break;
1954 case PTP_OPC_AlbumName:
1955 track->album = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_AlbumName);
1956 break;
1957 case PTP_OPC_OriginalReleaseDate:
1958 track->date = LIBMTP_Get_String_From_Object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
1959 break;
1960 // These are, well not so important.
1961 case PTP_OPC_SampleRate:
1962 track->samplerate = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_SampleRate, 0);
1963 break;
1964 case PTP_OPC_NumberOfChannels:
1965 track->nochannels = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
1966 break;
1967 case PTP_OPC_AudioWAVECodec:
1968 track->wavecodec = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
1969 break;
1970 case PTP_OPC_AudioBitRate:
1971 track->bitrate = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
1972 break;
1973 case PTP_OPC_BitRateType:
1974 track->bitratetype = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_BitRateType, 0);
1975 break;
1976 case PTP_OPC_Rating:
1977 track->rating = LIBMTP_Get_U16_From_Object(device, track->item_id, PTP_OPC_Rating, 0);
1978 break;
1979 case PTP_OPC_UseCount:
1980 track->usecount = LIBMTP_Get_U32_From_Object(device, track->item_id, PTP_OPC_UseCount, 0);
1981 break;
1982 }
1983 }
1984 free(props);
1985 }
Linus Walleij00cf0642006-07-26 20:40:59 +00001986 }
Linus Walleij8ab54262006-06-21 07:12:28 +00001987}
1988
1989/**
Linus Walleij3fcfea52006-11-13 07:07:36 +00001990 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
1991 * NOT TO USE IT.
1992 * @see LIBMTP_Get_Tracklisting_With_Callback()
1993 */
1994LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
1995{
1996 printf("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
1997 printf("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
Richard Lowdc0b6c72006-11-13 09:22:23 +00001998 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
Linus Walleij3fcfea52006-11-13 07:07:36 +00001999}
2000
2001/**
Linus Walleijb9256fd2006-02-15 09:40:43 +00002002 * This returns a long list of all tracks available
Linus Walleija4982732006-02-24 15:46:02 +00002003 * on the current MTP device. Typical usage:
2004 *
2005 * <pre>
2006 * LIBMTP_track_t *tracklist;
2007 *
Richard Lowdc0b6c72006-11-13 09:22:23 +00002008 * tracklist = LIBMTP_Get_Tracklisting(device, callback, data);
Linus Walleija4982732006-02-24 15:46:02 +00002009 * while (tracklist != NULL) {
2010 * LIBMTP_track_t *tmp;
2011 *
2012 * // Do something on each element in the list here...
2013 * tmp = tracklist;
2014 * tracklist = tracklist->next;
2015 * LIBMTP_destroy_track_t(tmp);
2016 * }
2017 * </pre>
2018 *
Linus Walleijb9256fd2006-02-15 09:40:43 +00002019 * @param device a pointer to the device to get the track listing for.
Linus Walleij3fcfea52006-11-13 07:07:36 +00002020 * @param callback a function to be called during the tracklisting retrieveal
2021 * for displaying progress bars etc, or NULL if you don't want
2022 * any callbacks.
Richard Lowdc0b6c72006-11-13 09:22:23 +00002023 * @param data a user-defined pointer that is passed along to
2024 * the <code>progress</code> function in order to
2025 * pass along some user defined data to the progress
2026 * updates. If not used, set this to NULL.
Linus Walleija4982732006-02-24 15:46:02 +00002027 * @return a list of tracks that can be followed using the <code>next</code>
2028 * field of the <code>LIBMTP_track_t</code> data structure.
2029 * Each of the metadata tags must be freed after use, and may
2030 * contain only partial metadata information, i.e. one or several
2031 * fields may be NULL or 0.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002032 * @see LIBMTP_Get_Trackmetadata()
Linus Walleijb9256fd2006-02-15 09:40:43 +00002033 */
Richard Lowdc0b6c72006-11-13 09:22:23 +00002034LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
2035 LIBMTP_progressfunc_t const callback,
2036 void const * const data)
Linus Walleijb9256fd2006-02-15 09:40:43 +00002037{
2038 uint32_t i = 0;
2039 LIBMTP_track_t *retracks = NULL;
2040 LIBMTP_track_t *curtrack = NULL;
Linus Walleij9b28da32006-03-16 13:47:58 +00002041 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002042
mopoke96143402006-10-30 04:37:26 +00002043 // Get all the handles if we haven't already done that
Linus Walleij9b28da32006-03-16 13:47:58 +00002044 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00002045 flush_handles(device);
Linus Walleijb9256fd2006-02-15 09:40:43 +00002046 }
mopoke96143402006-10-30 04:37:26 +00002047
Linus Walleij9b28da32006-03-16 13:47:58 +00002048 for (i = 0; i < params->handles.n; i++) {
Richard Lowdc0b6c72006-11-13 09:22:23 +00002049
2050 if (callback != NULL)
2051 callback(i, params->handles.n, data);
2052
Linus Walleijb9256fd2006-02-15 09:40:43 +00002053 LIBMTP_track_t *track;
2054 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00002055
Linus Walleij9b28da32006-03-16 13:47:58 +00002056 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
mopoke96143402006-10-30 04:37:26 +00002057
Linus Walleijb9256fd2006-02-15 09:40:43 +00002058 // Ignore stuff we don't know how to handle...
Linus Walleij8ab54262006-06-21 07:12:28 +00002059 // TODO: get this list as an intersection of the sets
2060 // supported by the device and the from the device and
2061 // all known audio track files?
mopoke96143402006-10-30 04:37:26 +00002062 if ( oi.ObjectFormat != PTP_OFC_WAV &&
2063 oi.ObjectFormat != PTP_OFC_MP3 &&
Linus Walleij9c6ca022006-04-21 10:24:15 +00002064 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
mopoke96143402006-10-30 04:37:26 +00002065 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
Linus Walleij9c6ca022006-04-21 10:24:15 +00002066 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
2067 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
Linus Walleijafe61432006-05-05 13:51:34 +00002068 // printf("Not a music track (format: %d), skipping...\n",oi.ObjectFormat);
Linus Walleijb9256fd2006-02-15 09:40:43 +00002069 continue;
2070 }
mopoke96143402006-10-30 04:37:26 +00002071
Linus Walleijb9256fd2006-02-15 09:40:43 +00002072 // Allocate a new track type
2073 track = LIBMTP_new_track_t();
Linus Walleij8ab54262006-06-21 07:12:28 +00002074
2075 // This is some sort of unique ID so we can keep track of the track.
2076 track->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00002077
Linus Walleij16c51f02006-05-04 13:20:22 +00002078 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00002079
Linus Walleijb9256fd2006-02-15 09:40:43 +00002080 // Original file-specific properties
2081 track->filesize = oi.ObjectCompressedSize;
2082 if (oi.Filename != NULL) {
2083 track->filename = strdup(oi.Filename);
Linus Walleijb9256fd2006-02-15 09:40:43 +00002084 }
Linus Walleij8ab54262006-06-21 07:12:28 +00002085
2086 get_track_metadata(device, oi.ObjectFormat, track);
mopoke96143402006-10-30 04:37:26 +00002087
Linus Walleijb9256fd2006-02-15 09:40:43 +00002088 // Add track to a list that will be returned afterwards.
2089 if (retracks == NULL) {
2090 retracks = track;
2091 curtrack = track;
2092 } else {
2093 curtrack->next = track;
2094 curtrack = track;
2095 }
mopoke96143402006-10-30 04:37:26 +00002096
Linus Walleijb9256fd2006-02-15 09:40:43 +00002097 // Call listing callback
Linus Walleij9b28da32006-03-16 13:47:58 +00002098 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
Linus Walleijb9256fd2006-02-15 09:40:43 +00002099
2100 } else {
2101 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
2102 }
2103
2104 } // Handle counting loop
2105 return retracks;
2106}
Linus Walleijdcde6082006-02-17 16:16:34 +00002107
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002108/**
2109 * This function retrieves the metadata for a single track off
2110 * the device.
2111 *
2112 * Do not call this function repeatedly! The track handles are linearly
2113 * searched O(n) and the call may involve (slow) USB traffic, so use
2114 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
2115 * as an efficient data structure such as a hash list.
2116 *
2117 * @param device a pointer to the device to get the track metadata from.
2118 * @param trackid the object ID of the track that you want the metadata for.
2119 * @return a track metadata entry on success or NULL on failure.
2120 * @see LIBMTP_Get_Tracklisting()
2121 */
2122LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
2123{
2124 uint32_t i = 0;
2125 PTPParams *params = (PTPParams *) device->params;
2126
mopoke96143402006-10-30 04:37:26 +00002127 // Get all the handles if we haven't already done that
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002128 if (params->handles.Handler == NULL) {
2129 flush_handles(device);
2130 }
2131
2132 for (i = 0; i < params->handles.n; i++) {
2133 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00002134
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002135 // Skip if this is not the track we want.
2136 if (params->handles.Handler[i] != trackid) {
2137 continue;
2138 }
2139
2140 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
2141 LIBMTP_track_t *track;
mopoke96143402006-10-30 04:37:26 +00002142
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002143 // Ignore stuff we don't know how to handle...
mopoke96143402006-10-30 04:37:26 +00002144 if ( oi.ObjectFormat != PTP_OFC_WAV &&
2145 oi.ObjectFormat != PTP_OFC_MP3 &&
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002146 oi.ObjectFormat != PTP_OFC_MTP_WMA &&
mopoke96143402006-10-30 04:37:26 +00002147 oi.ObjectFormat != PTP_OFC_MTP_OGG &&
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002148 oi.ObjectFormat != PTP_OFC_MTP_MP4 &&
2149 oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {
2150 return NULL;
2151 }
mopoke96143402006-10-30 04:37:26 +00002152
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002153 // Allocate a new track type
2154 track = LIBMTP_new_track_t();
Linus Walleij8ab54262006-06-21 07:12:28 +00002155
2156 // This is some sort of unique ID so we can keep track of the track.
2157 track->item_id = params->handles.Handler[i];
mopoke96143402006-10-30 04:37:26 +00002158
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002159 track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00002160
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002161 // Original file-specific properties
2162 track->filesize = oi.ObjectCompressedSize;
2163 if (oi.Filename != NULL) {
2164 track->filename = strdup(oi.Filename);
2165 }
Linus Walleij8ab54262006-06-21 07:12:28 +00002166
2167 get_track_metadata(device, oi.ObjectFormat, track);
mopoke96143402006-10-30 04:37:26 +00002168
Linus Walleij2e4b5f92006-06-16 14:00:49 +00002169 return track;
2170
2171 } else {
2172 return NULL;
2173 }
2174
2175 }
2176 return NULL;
2177}
2178
Linus Walleijf6bc1782006-03-24 15:12:47 +00002179
2180/**
2181 * This gets a file off the device to a local file identified
2182 * by a filename.
2183 * @param device a pointer to the device to get the track from.
2184 * @param id the file ID of the file to retrieve.
2185 * @param path a filename to use for the retrieved file.
2186 * @param callback a progress indicator function or NULL to ignore.
2187 * @param data a user-defined pointer that is passed along to
2188 * the <code>progress</code> function in order to
2189 * pass along some user defined data to the progress
2190 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002191 * @return 0 if the transfer was successful, any other value means
Linus Walleijf6bc1782006-03-24 15:12:47 +00002192 * failure.
2193 * @see LIBMTP_Get_File_To_File_Descriptor()
2194 */
mopoke96143402006-10-30 04:37:26 +00002195int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
Linus Walleijee73ef22006-08-27 19:56:00 +00002196 char const * const path, LIBMTP_progressfunc_t const callback,
Linus Walleijf6bc1782006-03-24 15:12:47 +00002197 void const * const data)
2198{
2199 int fd = -1;
2200 int ret;
2201
2202 // Sanity check
2203 if (path == NULL) {
2204 printf("LIBMTP_Get_File_To_File(): Bad arguments, path was NULL\n");
2205 return -1;
2206 }
2207
2208 // Open file
2209#ifdef __WIN32__
flavienbfd80eb2006-06-01 22:41:49 +00002210 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU|S_IRGRP)) == -1 ) {
Linus Walleijf6bc1782006-03-24 15:12:47 +00002211#else
2212 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
2213#endif
2214 printf("LIBMTP_Get_File_To_File(): Could not create file \"%s\"\n", path);
2215 return -1;
2216 }
mopoke96143402006-10-30 04:37:26 +00002217
Linus Walleijf6bc1782006-03-24 15:12:47 +00002218 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
2219
2220 // Close file
2221 close(fd);
mopoke96143402006-10-30 04:37:26 +00002222
Linus Walleijf6bc1782006-03-24 15:12:47 +00002223 return ret;
2224}
2225
2226/**
2227 * This gets a file off the device to a file identified
2228 * by a file descriptor.
Linus Walleij0558ac52006-09-07 06:55:03 +00002229 *
mopoke96143402006-10-30 04:37:26 +00002230 * This function can potentially be used for streaming
2231 * files off the device for playback or broadcast for example,
Linus Walleij0558ac52006-09-07 06:55:03 +00002232 * by downloading the file into a stream sink e.g. a socket.
2233 *
Linus Walleijf6bc1782006-03-24 15:12:47 +00002234 * @param device a pointer to the device to get the file from.
2235 * @param id the file ID of the file to retrieve.
2236 * @param fd a local file descriptor to write the file to.
2237 * @param callback a progress indicator function or NULL to ignore.
2238 * @param data a user-defined pointer that is passed along to
2239 * the <code>progress</code> function in order to
2240 * pass along some user defined data to the progress
2241 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002242 * @return 0 if the transfer was successful, any other value means
Linus Walleijf6bc1782006-03-24 15:12:47 +00002243 * failure.
2244 * @see LIBMTP_Get_File_To_File()
2245 */
mopoke96143402006-10-30 04:37:26 +00002246int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
2247 uint32_t const id,
2248 int const fd,
Linus Walleijee73ef22006-08-27 19:56:00 +00002249 LIBMTP_progressfunc_t const callback,
Linus Walleijf6bc1782006-03-24 15:12:47 +00002250 void const * const data)
2251{
2252 PTPObjectInfo oi;
Linus Walleij438bd7f2006-06-08 11:35:44 +00002253 uint16_t ret;
Linus Walleijf6bc1782006-03-24 15:12:47 +00002254 PTPParams *params = (PTPParams *) device->params;
Linus Walleijee73ef22006-08-27 19:56:00 +00002255 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleijf6bc1782006-03-24 15:12:47 +00002256
Linus Walleijf6bc1782006-03-24 15:12:47 +00002257 if (ptp_getobjectinfo(params, id, &oi) != PTP_RC_OK) {
2258 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get object info\n");
2259 return -1;
2260 }
2261 if (oi.ObjectFormat == PTP_OFC_Association) {
2262 printf("LIBMTP_Get_File_To_File_Descriptor(): Bad object format\n");
2263 return -1;
2264 }
Linus Walleijf6bc1782006-03-24 15:12:47 +00002265
Linus Walleijee73ef22006-08-27 19:56:00 +00002266 // Callbacks
2267 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002268 ptp_usb->current_transfer_total = oi.ObjectCompressedSize+
2269 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
Linus Walleijee73ef22006-08-27 19:56:00 +00002270 ptp_usb->current_transfer_complete = 0;
2271 ptp_usb->current_transfer_callback = callback;
2272 ptp_usb->current_transfer_callback_data = data;
mopoke96143402006-10-30 04:37:26 +00002273
Linus Walleij96c62432006-08-21 10:04:02 +00002274 // This now exist in upstream
2275 ret = ptp_getobject_tofd(params, id, fd);
Linus Walleijee73ef22006-08-27 19:56:00 +00002276
2277 ptp_usb->callback_active = 0;
2278 ptp_usb->current_transfer_callback = NULL;
2279 ptp_usb->current_transfer_callback_data = NULL;
mopoke96143402006-10-30 04:37:26 +00002280
Linus Walleijb02a0662006-04-25 08:05:09 +00002281 if (ret != PTP_RC_OK) {
2282 printf("LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device (%d)\n", ret);
Linus Walleijf6bc1782006-03-24 15:12:47 +00002283 return -1;
2284 }
mopoke96143402006-10-30 04:37:26 +00002285
Linus Walleijf6bc1782006-03-24 15:12:47 +00002286 return 0;
2287}
2288
Linus Walleijdcde6082006-02-17 16:16:34 +00002289/**
2290 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00002291 * by a filename. This is actually just a wrapper for the
2292 * \c LIBMTP_Get_Track_To_File() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00002293 * @param device a pointer to the device to get the track from.
2294 * @param id the track ID of the track to retrieve.
2295 * @param path a filename to use for the retrieved track.
2296 * @param callback a progress indicator function or NULL to ignore.
2297 * @param data a user-defined pointer that is passed along to
2298 * the <code>progress</code> function in order to
2299 * pass along some user defined data to the progress
2300 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002301 * @return 0 if the transfer was successful, any other value means
Linus Walleijdcde6082006-02-17 16:16:34 +00002302 * failure.
2303 * @see LIBMTP_Get_Track_To_File_Descriptor()
2304 */
mopoke96143402006-10-30 04:37:26 +00002305int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
Linus Walleijee73ef22006-08-27 19:56:00 +00002306 char const * const path, LIBMTP_progressfunc_t const callback,
Linus Walleij0cd85432006-02-20 14:37:50 +00002307 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00002308{
Linus Walleijf6bc1782006-03-24 15:12:47 +00002309 // This is just a wrapper
2310 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00002311}
2312
2313/**
2314 * This gets a track off the device to a file identified
Linus Walleijf6bc1782006-03-24 15:12:47 +00002315 * by a file descriptor. This is actually just a wrapper for
2316 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
Linus Walleijdcde6082006-02-17 16:16:34 +00002317 * @param device a pointer to the device to get the track from.
2318 * @param id the track ID of the track to retrieve.
2319 * @param fd a file descriptor to write the track to.
2320 * @param callback a progress indicator function or NULL to ignore.
2321 * @param data a user-defined pointer that is passed along to
2322 * the <code>progress</code> function in order to
2323 * pass along some user defined data to the progress
2324 * updates. If not used, set this to NULL.
mopoke96143402006-10-30 04:37:26 +00002325 * @return 0 if the transfer was successful, any other value means
Linus Walleijdcde6082006-02-17 16:16:34 +00002326 * failure.
2327 * @see LIBMTP_Get_Track_To_File()
2328 */
mopoke96143402006-10-30 04:37:26 +00002329int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
2330 uint32_t const id,
2331 int const fd,
Linus Walleijee73ef22006-08-27 19:56:00 +00002332 LIBMTP_progressfunc_t const callback,
Linus Walleij0cd85432006-02-20 14:37:50 +00002333 void const * const data)
Linus Walleijdcde6082006-02-17 16:16:34 +00002334{
Linus Walleijf6bc1782006-03-24 15:12:47 +00002335 // This is just a wrapper
2336 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
Linus Walleijdcde6082006-02-17 16:16:34 +00002337}
Linus Walleij394bbbe2006-02-22 16:10:53 +00002338
2339/**
2340 * This function sends a track from a local file to an
2341 * MTP device. A filename and a set of metadata must be
2342 * given as input.
2343 * @param device a pointer to the device to send the track to.
2344 * @param path the filename of a local file which will be sent.
2345 * @param metadata a track metadata set to be written along with the file.
2346 * @param callback a progress indicator function or NULL to ignore.
2347 * @param data a user-defined pointer that is passed along to
2348 * the <code>progress</code> function in order to
2349 * pass along some user defined data to the progress
2350 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002351 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002352 * in. Since some devices are a bit picky about where files
2353 * are placed, a default folder will be chosen if libmtp
2354 * has detected one for the current filetype and this
2355 * parameter is set to 0. If this is 0 and no default folder
2356 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002357 * @return 0 if the transfer was successful, any other value means
Linus Walleij394bbbe2006-02-22 16:10:53 +00002358 * failure.
2359 * @see LIBMTP_Send_Track_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002360 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002361 */
mopoke96143402006-10-30 04:37:26 +00002362int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
Linus Walleij394bbbe2006-02-22 16:10:53 +00002363 char const * const path, LIBMTP_track_t * const metadata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002364 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002365 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002366{
2367 int fd;
2368 int ret;
2369
2370 // Sanity check
2371 if (path == NULL) {
2372 printf("LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL\n");
2373 return -1;
2374 }
2375
2376 // Open file
2377#ifdef __WIN32__
2378 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2379#else
2380 if ( (fd = open(path, O_RDONLY)) == -1) {
2381#endif
Linus Walleijd6a49972006-05-02 08:24:54 +00002382 printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
Linus Walleij394bbbe2006-02-22 16:10:53 +00002383 return -1;
2384 }
2385
Linus Walleijd6a49972006-05-02 08:24:54 +00002386 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data, parenthandle);
mopoke96143402006-10-30 04:37:26 +00002387
Linus Walleij394bbbe2006-02-22 16:10:53 +00002388 // Close file.
2389 close(fd);
2390
2391 return ret;
2392}
2393
Linus Walleijfa1374c2006-02-27 07:41:46 +00002394
Linus Walleij99310d42006-11-01 08:29:39 +00002395static MTPPropList *New_MTP_Prop_Entry()
2396{
2397 MTPPropList *prop;
2398 prop = (MTPPropList *) malloc(sizeof(MTPPropList));
2399 prop->property = PTP_OPC_StorageID; /* Should be "unknown" */
2400 prop->datatype = PTP_DTC_UNDEF;
2401 prop->next = NULL;
2402 return prop;
2403}
2404
2405static void Destroy_MTP_Prop_Entry(MTPPropList *prop)
2406{
2407 if (prop->datatype == PTP_DTC_STR) {
2408 free(prop->propval.str);
2409 }
2410 free(prop);
2411}
2412
Linus Walleijfa1374c2006-02-27 07:41:46 +00002413/**
Linus Walleij394bbbe2006-02-22 16:10:53 +00002414 * This function sends a track from a file descriptor to an
2415 * MTP device. A filename and a set of metadata must be
2416 * given as input.
2417 * @param device a pointer to the device to send the track to.
2418 * @param fd the filedescriptor for a local file which will be sent.
2419 * @param metadata a track metadata set to be written along with the file.
2420 * After this call the field <code>item_id</code>
2421 * will contain the new track ID.
2422 * @param callback a progress indicator function or NULL to ignore.
2423 * @param data a user-defined pointer that is passed along to
2424 * the <code>progress</code> function in order to
2425 * pass along some user defined data to the progress
2426 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002427 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002428 * in. Since some devices are a bit picky about where files
2429 * are placed, a default folder will be chosen if libmtp
2430 * has detected one for the current filetype and this
2431 * parameter is set to 0. If this is 0 and no default folder
2432 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002433 * @return 0 if the transfer was successful, any other value means
Linus Walleij394bbbe2006-02-22 16:10:53 +00002434 * failure.
2435 * @see LIBMTP_Send_Track_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002436 * @see LIBMTP_Delete_Object()
Linus Walleij394bbbe2006-02-22 16:10:53 +00002437 */
mopoke96143402006-10-30 04:37:26 +00002438int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
Linus Walleij394bbbe2006-02-22 16:10:53 +00002439 int const fd, LIBMTP_track_t * const metadata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002440 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002441 void const * const data, uint32_t const parenthandle)
Linus Walleij394bbbe2006-02-22 16:10:53 +00002442{
Linus Walleij394bbbe2006-02-22 16:10:53 +00002443 uint16_t ret;
2444 uint32_t store = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002445 int subcall_ret;
Linus Walleij9b28da32006-03-16 13:47:58 +00002446 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd6a49972006-05-02 08:24:54 +00002447 uint32_t localph = parenthandle;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002448 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij99310d42006-11-01 08:29:39 +00002449 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
Richard Low4c60f6e2006-11-07 20:36:42 +00002450 uint16_t *props = NULL;
2451 uint32_t propcnt = 0;
2452 uint32_t i = 0;
2453
Linus Walleij05ccbe72006-06-13 07:46:58 +00002454 if (localph == 0) {
2455 localph = device->default_music_folder;
2456 }
2457
Linus Walleij16c51f02006-05-04 13:20:22 +00002458 // Sanity check, is this really a track?
2459 if (metadata->filetype != LIBMTP_FILETYPE_WAV &&
2460 metadata->filetype != LIBMTP_FILETYPE_MP3 &&
2461 metadata->filetype != LIBMTP_FILETYPE_WMA &&
2462 metadata->filetype != LIBMTP_FILETYPE_OGG &&
2463 metadata->filetype != LIBMTP_FILETYPE_MP4 &&
2464 metadata->filetype != LIBMTP_FILETYPE_UNDEF_AUDIO) {
2465 printf("LIBMTP_Send_Track_From_File_Descriptor: I don't think this is actually a track, strange filetype...\n");
Linus Walleij99310d42006-11-01 08:29:39 +00002466 nonconsumable = 0x01U; /* Not suitable for consumption */
Linus Walleij394bbbe2006-02-22 16:10:53 +00002467 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002468
Linus Walleij99310d42006-11-01 08:29:39 +00002469 if (metadata->filetype == LIBMTP_FILETYPE_UNDEF_AUDIO) {
2470 nonconsumable = 0x01U; /* Not suitable for consumption */
2471 }
Linus Walleij37253292006-10-11 08:38:14 +00002472
Linus Walleij99310d42006-11-01 08:29:39 +00002473#ifdef ENABLE_MTP_ENHANCED
2474 if (ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
2475 /*
2476 * MTP enhanched does it this way (from a sniff):
2477 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
2478 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
2479 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
2480 * Length: 0x00000020
2481 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
2482 * Code: 0x9808
2483 * Transaction ID: 0x0000001B
2484 * Param1: 0x00010001 <- store
2485 * Param2: 0xffffffff <- parent handle (-1 ?)
2486 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
2487 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
2488 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
2489 *
2490 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
2491 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
2492 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
2493 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
2494 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
2495 * 00 4F DC 02 00 01 - dc4f = non consumable
2496 * Length: 0x00000046
2497 * Type: 0x0002 PTP_USB_CONTAINER_DATA
2498 * Code: 0x9808
2499 * Transaction ID: 0x0000001B
2500 * Metadata....
2501 * 0x00000003 <- Number of metadata items
2502 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
2503 * 0xdc07 <- metadata type: file name
2504 * 0xffff <- metadata type: string
2505 * 0x0d <- number of (uint16_t) characters
2506 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
2507 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
2508 * 0xdc03 <- metadata type: protection status
2509 * 0x0004 <- metadata type: uint16_t
2510 * 0x0000 <- not protected
2511 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
2512 * 0xdc4f <- non consumable
2513 * 0x0002 <- metadata type: uint8_t
2514 * 0x01 <- non-consumable (this device cannot display PDF)
2515 *
2516 * <- Read 0x18 bytes back
2517 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
2518 * 00 00 00 00 01 40 00 00
2519 * Length: 0x000000018
2520 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
2521 * Code: 0x2001 PTP_OK
2522 * Transaction ID: 0x0000001B
2523 * Param1: 0x00010001 <- store
2524 * Param2: 0x00000000 <- parent handle
2525 * Param3: 0x00004001 <- new file/object ID
2526 *
2527 * -> PTP_OC_SendObject (0x100d)
2528 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
2529 * -> ... all the bytes ...
2530 * <- Read 0x0c bytes back
2531 * 0C 00 00 00 03 00 01 20 1C 00 00 00
2532 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
2533 */
Richard Low4c60f6e2006-11-07 20:36:42 +00002534 MTPPropList *proplist = NULL;
2535 MTPPropList *prop = NULL;
2536 MTPPropList *previous = NULL;
Linus Walleij37253292006-10-11 08:38:14 +00002537
Linus Walleij99310d42006-11-01 08:29:39 +00002538 /* Send an object property list of that is supported */
2539 localph = 0xFFFFFFFFU; // Set to -1
2540 metadata->item_id = 0x00000000U;
Richard Low4c60f6e2006-11-07 20:36:42 +00002541
2542 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &props);
2543
2544 if (ret == PTP_RC_OK)
2545 {
2546 for (i=0;i<propcnt;i++) {
2547 switch (props[i]) {
2548 case PTP_OPC_ObjectFileName:
2549 prop = New_MTP_Prop_Entry();
2550 prop->property = PTP_OPC_ObjectFileName;
2551 prop->datatype = PTP_DTC_STR;
2552 prop->propval.str = strdup(metadata->filename);
mopoke96143402006-10-30 04:37:26 +00002553
Richard Low4c60f6e2006-11-07 20:36:42 +00002554 if (previous != NULL)
2555 previous->next = prop;
2556 else
2557 proplist = prop;
2558 previous = prop;
2559 prop->next = NULL;
2560 break;
2561 case PTP_OPC_ProtectionStatus:
2562 prop = New_MTP_Prop_Entry();
2563 prop->property = PTP_OPC_ProtectionStatus;
2564 prop->datatype = PTP_DTC_UINT16;
2565 prop->propval.u16 = 0x0000U; /* Not protected */
Linus Walleij99310d42006-11-01 08:29:39 +00002566
Richard Low4c60f6e2006-11-07 20:36:42 +00002567 if (previous != NULL)
2568 previous->next = prop;
2569 else
2570 proplist = prop;
2571 previous = prop;
2572 prop->next = NULL;
2573 break;
2574 case PTP_OPC_NonConsumable:
2575 prop = New_MTP_Prop_Entry();
2576 prop->property = PTP_OPC_NonConsumable;
2577 prop->datatype = PTP_DTC_UINT8;
2578 prop->propval.u8 = nonconsumable;
2579
2580 if (previous != NULL)
2581 previous->next = prop;
2582 else
2583 proplist = prop;
2584 previous = prop;
2585 prop->next = NULL;
2586 break;
2587 }
2588 }
Linus Walleij3fcfea52006-11-13 07:07:36 +00002589 free(props);
Richard Low4c60f6e2006-11-07 20:36:42 +00002590 }
2591
Richard Low4c60f6e2006-11-07 20:36:42 +00002592
Linus Walleij99310d42006-11-01 08:29:39 +00002593 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &metadata->item_id,
2594 map_libmtp_type_to_ptp_type(metadata->filetype),
2595 metadata->filesize, proplist);
2596
2597 /* Free property list */
2598 prop = proplist;
2599 while (prop != NULL) {
Linus Walleij3fcfea52006-11-13 07:07:36 +00002600 previous = prop;
Linus Walleij99310d42006-11-01 08:29:39 +00002601 prop = prop->next;
Linus Walleij3fcfea52006-11-13 07:07:36 +00002602 Destroy_MTP_Prop_Entry(previous);
Linus Walleij99310d42006-11-01 08:29:39 +00002603 }
2604
2605 if (ret != PTP_RC_OK) {
2606 ptp_perror(params, ret);
2607 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object property list.\n");
2608 if (ret == PTP_RC_AccessDenied) {
2609 printf("ACCESS DENIED.\n");
2610 } else {
2611 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2612 }
2613 return -1;
2614 }
2615 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
2616#else // !ENABLE_MTP_ENHANCED
2617 {
2618#endif // ENABLE_MTP_ENHANCED
2619 PTPObjectInfo new_track;
2620
2621 /* Else use the fallback compatibility mode */
2622 new_track.Filename = metadata->filename;
2623 new_track.ObjectCompressedSize = metadata->filesize;
2624 new_track.ObjectFormat = map_libmtp_type_to_ptp_type(metadata->filetype);
2625
2626 // Create the object
2627 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->item_id, &new_track);
2628 if (ret != PTP_RC_OK) {
2629 ptp_perror(params, ret);
2630 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object info.\n");
2631 if (ret == PTP_RC_AccessDenied) {
2632 printf("ACCESS DENIED.\n");
2633 } else {
2634 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2635 }
2636 return -1;
2637 }
Linus Walleij394bbbe2006-02-22 16:10:53 +00002638 }
2639
Linus Walleijee73ef22006-08-27 19:56:00 +00002640 // Callbacks
Linus Walleijd214b9b2006-08-26 22:08:37 +00002641 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002642 // The callback will deactivate itself after this amount of data has been sent
2643 // One BULK header for the request, one for the data phase. No parameters to the request.
2644 ptp_usb->current_transfer_total = metadata->filesize+PTP_USB_BULK_HDR_LEN*2;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002645 ptp_usb->current_transfer_complete = 0;
2646 ptp_usb->current_transfer_callback = callback;
2647 ptp_usb->current_transfer_callback_data = data;
mopoke96143402006-10-30 04:37:26 +00002648
Linus Walleije7f44be2006-08-25 19:32:29 +00002649 ret = ptp_sendobject_fromfd(params, fd, metadata->filesize);
mopoke96143402006-10-30 04:37:26 +00002650
Linus Walleijee73ef22006-08-27 19:56:00 +00002651 ptp_usb->callback_active = 0;
2652 ptp_usb->current_transfer_callback = NULL;
2653 ptp_usb->current_transfer_callback_data = NULL;
2654
Linus Walleije7f44be2006-08-25 19:32:29 +00002655 if (ret != PTP_RC_OK) {
2656 ptp_perror(params, ret);
2657 printf("LIBMTP_Send_Track_From_File_Descriptor: Could not send object\n");
Linus Walleij394bbbe2006-02-22 16:10:53 +00002658 return -1;
2659 }
mopoke96143402006-10-30 04:37:26 +00002660
Linus Walleij17e39f72006-02-23 15:54:28 +00002661 // Set track metadata for the new fine track
2662 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
2663 if (subcall_ret != 0) {
2664 printf("LIBMTP_Send_Track_From_File_Descriptor: error setting metadata for new track\n");
Linus Walleij438bd7f2006-06-08 11:35:44 +00002665 (void) LIBMTP_Delete_Object(device, metadata->item_id);
Linus Walleij17e39f72006-02-23 15:54:28 +00002666 return -1;
2667 }
Linus Walleij99310d42006-11-01 08:29:39 +00002668 if (nonconsumable != 0x00U) {
2669 /* Flag it as non-consumable if it is */
2670 subcall_ret = LIBMTP_Set_Object_U8(device, metadata->item_id, PTP_OPC_NonConsumable, nonconsumable);
2671 if (subcall_ret != 0) {
2672 printf("LIBMTP_Update_Track_Metadata(): could not set non-consumable status.\n");
2673 return -1;
2674 }
2675 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00002676
2677 // Added object so flush handles
2678 flush_handles(device);
mopoke96143402006-10-30 04:37:26 +00002679
Linus Walleij17e39f72006-02-23 15:54:28 +00002680 return 0;
2681}
2682
Linus Walleijd6a49972006-05-02 08:24:54 +00002683/**
mopoke96143402006-10-30 04:37:26 +00002684 * This function sends a local file to an MTP device.
Linus Walleijd6a49972006-05-02 08:24:54 +00002685 * A filename and a set of metadata must be
2686 * given as input.
2687 * @param device a pointer to the device to send the track to.
2688 * @param path the filename of a local file which will be sent.
2689 * @param filedata a file strtuct to pass in info about the file.
2690 * After this call the field <code>item_id</code>
2691 * will contain the new file ID.
2692 * @param callback a progress indicator function or NULL to ignore.
2693 * @param data a user-defined pointer that is passed along to
2694 * the <code>progress</code> function in order to
2695 * pass along some user defined data to the progress
2696 * updates. If not used, set this to NULL.
2697 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002698 * in. Since some devices are a bit picky about where files
2699 * are placed, a default folder will be chosen if libmtp
2700 * has detected one for the current filetype and this
2701 * parameter is set to 0. If this is 0 and no default folder
2702 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002703 * @return 0 if the transfer was successful, any other value means
Linus Walleijd6a49972006-05-02 08:24:54 +00002704 * failure.
2705 * @see LIBMTP_Send_File_From_File_Descriptor()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002706 * @see LIBMTP_Delete_Object()
Linus Walleijd6a49972006-05-02 08:24:54 +00002707 */
mopoke96143402006-10-30 04:37:26 +00002708int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
Linus Walleijd6a49972006-05-02 08:24:54 +00002709 char const * const path, LIBMTP_file_t * const filedata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002710 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002711 void const * const data, uint32_t const parenthandle)
2712{
2713 int fd;
2714 int ret;
2715
2716 // Sanity check
2717 if (path == NULL) {
2718 printf("LIBMTP_Send_File_From_File(): Bad arguments, path was NULL\n");
2719 return -1;
2720 }
2721
2722 // Open file
2723#ifdef __WIN32__
2724 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1 ) {
2725#else
2726 if ( (fd = open(path, O_RDONLY)) == -1) {
2727#endif
2728 printf("LIBMTP_Send_File_From_File(): Could not open source file \"%s\"\n", path);
2729 return -1;
2730 }
2731
2732 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data, parenthandle);
mopoke96143402006-10-30 04:37:26 +00002733
Linus Walleijd6a49972006-05-02 08:24:54 +00002734 // Close file.
2735 close(fd);
2736
2737 return ret;
2738}
2739
Linus Walleijd208f9c2006-04-27 14:16:06 +00002740/**
2741 * This function sends a generic file from a file descriptor to an
2742 * MTP device. A filename and a set of metadata must be
2743 * given as input.
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002744 *
2745 * This can potentially be used for sending in a stream of unknown
2746 * length. Set <code>filedata->filesize = (uint64_t) -1</code> to
2747 * make libmtp send some dummy length to the device and just
2748 * accept a stream up to some device-determined max length. There
2749 * is not guarantee this will work on all devices... Remember to
2750 * set correct metadata for the track with
2751 * <code>LIBMTP_Update_Track_Metadata()</code> afterwards if it's
2752 * a music file. (This doesn't seem to work very well right now.)
2753 *
Linus Walleijd208f9c2006-04-27 14:16:06 +00002754 * @param device a pointer to the device to send the file to.
2755 * @param fd the filedescriptor for a local file which will be sent.
Linus Walleijd6a49972006-05-02 08:24:54 +00002756 * @param filedata a file strtuct to pass in info about the file.
Linus Walleijd208f9c2006-04-27 14:16:06 +00002757 * After this call the field <code>item_id</code>
2758 * will contain the new track ID.
2759 * @param callback a progress indicator function or NULL to ignore.
2760 * @param data a user-defined pointer that is passed along to
2761 * the <code>progress</code> function in order to
2762 * pass along some user defined data to the progress
2763 * updates. If not used, set this to NULL.
Linus Walleijd6a49972006-05-02 08:24:54 +00002764 * @param parenthandle the parent (e.g. folder) to store this file
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002765 * in. Since some devices are a bit picky about where files
2766 * are placed, a default folder will be chosen if libmtp
2767 * has detected one for the current filetype and this
2768 * parameter is set to 0. If this is 0 and no default folder
2769 * can be found, the file will be stored in the root folder.
mopoke96143402006-10-30 04:37:26 +00002770 * @return 0 if the transfer was successful, any other value means
Linus Walleijd208f9c2006-04-27 14:16:06 +00002771 * failure.
Linus Walleijd6a49972006-05-02 08:24:54 +00002772 * @see LIBMTP_Send_File_From_File()
Linus Walleij438bd7f2006-06-08 11:35:44 +00002773 * @see LIBMTP_Delete_Object()
Linus Walleijd208f9c2006-04-27 14:16:06 +00002774 */
mopoke96143402006-10-30 04:37:26 +00002775int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
Linus Walleijd208f9c2006-04-27 14:16:06 +00002776 int const fd, LIBMTP_file_t * const filedata,
Linus Walleijee73ef22006-08-27 19:56:00 +00002777 LIBMTP_progressfunc_t const callback,
Linus Walleijd6a49972006-05-02 08:24:54 +00002778 void const * const data, uint32_t const parenthandle)
Linus Walleijd208f9c2006-04-27 14:16:06 +00002779{
2780 uint16_t ret;
2781 uint32_t store = 0;
Linus Walleijd6a49972006-05-02 08:24:54 +00002782 uint32_t localph = parenthandle;
Linus Walleijd208f9c2006-04-27 14:16:06 +00002783 PTPObjectInfo new_file;
2784 PTPParams *params = (PTPParams *) device->params;
Linus Walleijd214b9b2006-08-26 22:08:37 +00002785 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
Linus Walleij05ccbe72006-06-13 07:46:58 +00002786
Linus Walleijd208f9c2006-04-27 14:16:06 +00002787 new_file.Filename = filedata->filename;
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002788 if (filedata->filesize == (uint64_t) -1) {
2789 // This is a stream. Set a dummy length...
2790 new_file.ObjectCompressedSize = 1;
2791 } else {
2792 new_file.ObjectCompressedSize = filedata->filesize;
2793 }
Linus Walleij16c51f02006-05-04 13:20:22 +00002794 new_file.ObjectFormat = map_libmtp_type_to_ptp_type(filedata->filetype);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002795
mopoke96143402006-10-30 04:37:26 +00002796 /*
Linus Walleij05ccbe72006-06-13 07:46:58 +00002797 * If no destination folder was given, look up a default
2798 * folder if possible. Perhaps there is some way of retrieveing
2799 * the default folder for different forms of content, what
2800 * do I know, we use a fixed list in lack of any better method.
2801 * Some devices obviously need to have their files in certain
mopoke96143402006-10-30 04:37:26 +00002802 * folders in order to find/display them at all (hello Creative),
Linus Walleij05ccbe72006-06-13 07:46:58 +00002803 * so we have to have a method for this.
2804 */
2805
2806 if (localph == 0) {
2807 uint16_t of = new_file.ObjectFormat;
2808 if (of == PTP_OFC_WAV ||
2809 of == PTP_OFC_MP3 ||
2810 of == PTP_OFC_MTP_WMA ||
2811 of == PTP_OFC_MTP_OGG ||
2812 of == PTP_OFC_MTP_MP4 ||
2813 of == PTP_OFC_MTP_UndefinedAudio) {
2814 localph = device->default_music_folder;
2815 } else if (of == PTP_OFC_MTP_WMV ||
2816 of == PTP_OFC_AVI ||
2817 of == PTP_OFC_MPEG ||
2818 of == PTP_OFC_ASF ||
2819 of == PTP_OFC_QT ||
2820 of == PTP_OFC_MTP_UndefinedVideo) {
2821 localph = device->default_video_folder;
2822 } else if (of == PTP_OFC_EXIF_JPEG ||
2823 of == PTP_OFC_JFIF ||
2824 of == PTP_OFC_TIFF ||
2825 of == PTP_OFC_BMP ||
2826 of == PTP_OFC_GIF ||
2827 of == PTP_OFC_PICT ||
2828 of == PTP_OFC_PNG ||
2829 of == PTP_OFC_MTP_WindowsImageFormat) {
2830 localph = device->default_picture_folder;
2831 } else if (of == PTP_OFC_MTP_vCalendar1 ||
Linus Walleijd7aa5b22006-09-02 11:52:31 +00002832 of == PTP_OFC_MTP_vCalendar2 ||
2833 of == PTP_OFC_MTP_UndefinedContact ||
2834 of == PTP_OFC_MTP_vCard2 ||
2835 of == PTP_OFC_MTP_vCard3 ||
2836 of == PTP_OFC_MTP_UndefinedCalendarItem) {
Linus Walleij05ccbe72006-06-13 07:46:58 +00002837 localph = device->default_organizer_folder;
2838 }
2839 }
2840
Linus Walleijd208f9c2006-04-27 14:16:06 +00002841 // Create the object
Linus Walleijd6a49972006-05-02 08:24:54 +00002842 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002843 if (ret != PTP_RC_OK) {
2844 ptp_perror(params, ret);
2845 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object info\n");
Linus Walleij99310d42006-11-01 08:29:39 +00002846 if (ret == PTP_RC_AccessDenied) {
2847 printf("ACCESS DENIED.\n");
2848 } else {
2849 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2850 }
Linus Walleijd208f9c2006-04-27 14:16:06 +00002851 return -1;
2852 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002853
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002854 if (filedata->filesize != (uint64_t) -1) {
2855 // Callbacks
2856 ptp_usb->callback_active = 1;
Linus Walleij7f0c72e2006-09-06 13:01:58 +00002857 // The callback will deactivate itself after this amount of data has been sent
2858 // One BULK header for the request, one for the data phase. No parameters to the request.
2859 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002860 ptp_usb->current_transfer_complete = 0;
2861 ptp_usb->current_transfer_callback = callback;
2862 ptp_usb->current_transfer_callback_data = data;
mopoke96143402006-10-30 04:37:26 +00002863
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002864 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
mopoke96143402006-10-30 04:37:26 +00002865
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002866 ptp_usb->callback_active = 0;
2867 ptp_usb->current_transfer_callback = NULL;
2868 ptp_usb->current_transfer_callback_data = NULL;
2869 } else {
2870 // This is a stream..
Linus Walleija9310fa2006-09-04 06:47:42 +00002871 ret = ptp_sendobject_fromfd(params, fd, 0xFFFFFFFFU-PTP_USB_BULK_HDR_LEN);
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00002872 if (ret == PTP_ERROR_IO) {
2873 // That's expected. The stream ends, simply...
2874 ret = PTP_RC_OK;
2875 } else {
2876 printf("LIBMTP_Send_File_From_File_Descriptor: Error while sending stream.\n");
2877 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
2878 }
2879 }
Linus Walleijee73ef22006-08-27 19:56:00 +00002880
2881 if (ret != PTP_RC_OK) {
2882 ptp_perror(params, ret);
2883 printf("LIBMTP_Send_File_From_File_Descriptor: Could not send object\n");
2884 return -1;
2885 }
mopoke96143402006-10-30 04:37:26 +00002886
Linus Walleij438bd7f2006-06-08 11:35:44 +00002887 // Added object so flush handles.
2888 flush_handles(device);
Linus Walleijd208f9c2006-04-27 14:16:06 +00002889 return 0;
2890}
2891
Linus Walleij17e39f72006-02-23 15:54:28 +00002892/**
2893 * This function updates the MTP object metadata on a single file
2894 * identified by an object ID.
mopoke96143402006-10-30 04:37:26 +00002895 * @param device a pointer to the device to update the track
Linus Walleij95698cd2006-02-24 10:40:40 +00002896 * metadata on.
Linus Walleij17e39f72006-02-23 15:54:28 +00002897 * @param metadata a track metadata set to be written to the file.
2898 * notice that the <code>track_id</code> field of the
2899 * metadata structure must be correct so that the
Linus Walleija4982732006-02-24 15:46:02 +00002900 * function can update the right file. If some properties
2901 * of this metadata are set to NULL (strings) or 0
2902 * (numerical values) they will be discarded and the
2903 * track will not be tagged with these blank values.
Linus Walleij17e39f72006-02-23 15:54:28 +00002904 * @return 0 on success, any other value means failure.
2905 */
mopoke96143402006-10-30 04:37:26 +00002906int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
Linus Walleij17e39f72006-02-23 15:54:28 +00002907 LIBMTP_track_t const * const metadata)
2908{
Linus Walleij17e39f72006-02-23 15:54:28 +00002909 uint16_t ret;
Linus Walleij00cf0642006-07-26 20:40:59 +00002910 PTPParams *params = (PTPParams *) device->params;
2911 uint32_t i;
2912 uint16_t *props = NULL;
2913 uint32_t propcnt = 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00002914
mopoke96143402006-10-30 04:37:26 +00002915 // First see which properties can be set on this file format and apply accordingly
Linus Walleij00cf0642006-07-26 20:40:59 +00002916 // i.e only try to update this metadata for object tags that exist on the current player.
2917 ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &props);
2918 if (ret != PTP_RC_OK) {
2919 // Just bail out for now, nothing is ever set.
raveloxd9a28642006-05-26 23:42:22 +00002920 return -1;
Linus Walleij00cf0642006-07-26 20:40:59 +00002921 } else {
2922 for (i=0;i<propcnt;i++) {
2923 switch (props[i]) {
2924 case PTP_OPC_Name:
2925 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00002926 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Name, metadata->title);
Linus Walleij00cf0642006-07-26 20:40:59 +00002927 if (ret != 0) {
2928 printf("LIBMTP_Update_Track_Metadata(): could not set track title\n");
2929 return -1;
2930 }
2931 break;
2932 case PTP_OPC_AlbumName:
2933 // Update album
Linus Walleija823a702006-08-27 21:27:46 +00002934 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
Linus Walleij00cf0642006-07-26 20:40:59 +00002935 if (ret != 0) {
2936 printf("LIBMTP_Update_Track_Metadata(): could not set track album name\n");
2937 return -1;
2938 }
2939 break;
2940 case PTP_OPC_Artist:
2941 // Update artist
Linus Walleija823a702006-08-27 21:27:46 +00002942 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
Linus Walleij00cf0642006-07-26 20:40:59 +00002943 if (ret != 0) {
2944 printf("LIBMTP_Update_Track_Metadata(): could not set track artist name\n");
2945 return -1;
2946 }
2947 break;
2948 case PTP_OPC_Genre:
2949 // Update genre
Linus Walleija823a702006-08-27 21:27:46 +00002950 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
Linus Walleij00cf0642006-07-26 20:40:59 +00002951 if (ret != 0) {
2952 printf("LIBMTP_Update_Track_Metadata(): could not set track genre name\n");
2953 return -1;
2954 }
2955 break;
2956 case PTP_OPC_Duration:
2957 // Update duration
2958 if (metadata->duration != 0) {
2959 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_Duration, metadata->duration);
2960 if (ret != 0) {
2961 printf("LIBMTP_Update_Track_Metadata(): could not set track duration\n");
2962 return -1;
2963 }
2964 }
2965 break;
2966 case PTP_OPC_Track:
2967 // Update track number.
2968 if (metadata->tracknumber != 0) {
2969 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Track, metadata->tracknumber);
2970 if (ret != 0) {
2971 printf("LIBMTP_Update_Track_Metadata(): could not set track tracknumber\n");
2972 return -1;
2973 }
2974 }
2975 break;
2976 case PTP_OPC_OriginalReleaseDate:
2977 // Update creation datetime
Linus Walleija823a702006-08-27 21:27:46 +00002978 ret = LIBMTP_Set_Object_String(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
Linus Walleij00cf0642006-07-26 20:40:59 +00002979 if (ret != 0) {
2980 printf("LIBMTP_Update_Track_Metadata(): could not set track release date\n");
2981 return -1;
2982 }
2983 break;
2984 // These are, well not so important.
2985 case PTP_OPC_SampleRate:
2986 // Update sample rate
2987 if (metadata->samplerate != 0) {
2988 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_SampleRate, metadata->samplerate);
2989 if (ret != 0) {
2990 printf("LIBMTP_Update_Track_Metadata(): could not set samplerate\n");
2991 return -1;
2992 }
2993 }
2994 break;
2995 case PTP_OPC_NumberOfChannels:
2996 // Update number of channels
2997 if (metadata->nochannels != 0) {
2998 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_NumberOfChannels, metadata->nochannels);
2999 if (ret != 0) {
3000 printf("LIBMTP_Update_Track_Metadata(): could not set number of channels\n");
3001 return -1;
3002 }
3003 }
3004 break;
3005 case PTP_OPC_AudioWAVECodec:
3006 // Update WAVE codec
3007 if (metadata->wavecodec != 0) {
3008 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, metadata->wavecodec);
3009 if (ret != 0) {
3010 printf("LIBMTP_Update_Track_Metadata(): could not set WAVE codec\n");
3011 return -1;
3012 }
3013 }
3014 break;
3015 case PTP_OPC_AudioBitRate:
3016 // Update bitrate
3017 if (metadata->bitrate != 0) {
3018 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_AudioBitRate, metadata->bitrate);
3019 if (ret != 0) {
3020 printf("LIBMTP_Update_Track_Metadata(): could not set bitrate\n");
3021 return -1;
3022 }
3023 }
3024 break;
3025 case PTP_OPC_BitRateType:
3026 // Update bitrate type
3027 if (metadata->bitratetype != 0) {
3028 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_BitRateType, metadata->bitratetype);
3029 if (ret != 0) {
3030 printf("LIBMTP_Update_Track_Metadata(): could not set bitratetype\n");
3031 return -1;
3032 }
3033 }
3034 break;
3035 case PTP_OPC_Rating:
3036 // Update user rating
3037 // TODO: shall this be set for rating 0?
3038 if (metadata->rating != 0) {
3039 ret = LIBMTP_Set_Object_U16(device, metadata->item_id, PTP_OPC_Rating, metadata->rating);
3040 if (ret != 0) {
3041 printf("LIBMTP_Update_Track_Metadata(): could not set user rating\n");
3042 return -1;
3043 }
3044 }
3045 break;
3046 case PTP_OPC_UseCount:
3047 // Update use count, set even to zero if desired.
3048 ret = LIBMTP_Set_Object_U32(device, metadata->item_id, PTP_OPC_UseCount, metadata->usecount);
3049 if (ret != 0) {
3050 printf("LIBMTP_Update_Track_Metadata(): could not set use count\n");
3051 return -1;
3052 }
3053 break;
Linus Walleij17e39f72006-02-23 15:54:28 +00003054
Linus Walleij00cf0642006-07-26 20:40:59 +00003055 // NOTE: File size is not updated, this should not change anyway.
3056 // neither will we change the filename.
3057 }
Linus Walleija4982732006-02-24 15:46:02 +00003058 }
Linus Walleij00cf0642006-07-26 20:40:59 +00003059 return 0;
Linus Walleij17e39f72006-02-23 15:54:28 +00003060 }
Linus Walleij394bbbe2006-02-22 16:10:53 +00003061}
Linus Walleij95698cd2006-02-24 10:40:40 +00003062
3063/**
Linus Walleij438bd7f2006-06-08 11:35:44 +00003064 * This function deletes a single file, track, playlist or
3065 * any other object off the MTP device,
Linus Walleij95698cd2006-02-24 10:40:40 +00003066 * identified by an object ID.
Linus Walleijf6bc1782006-03-24 15:12:47 +00003067 * @param device a pointer to the device to delete the file or track from.
Linus Walleij95698cd2006-02-24 10:40:40 +00003068 * @param item_id the item to delete.
3069 * @return 0 on success, any other value means failure.
3070 */
mopoke96143402006-10-30 04:37:26 +00003071int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
Linus Walleij438bd7f2006-06-08 11:35:44 +00003072 uint32_t object_id)
Linus Walleij95698cd2006-02-24 10:40:40 +00003073{
Linus Walleij438bd7f2006-06-08 11:35:44 +00003074 uint16_t ret;
3075 PTPParams *params = (PTPParams *) device->params;
3076
3077 ret = ptp_deleteobject(params, object_id, 0);
3078 if (ret != PTP_RC_OK) {
3079 ptp_perror(params, ret);
3080 printf("LIBMTP_Delete_Object(): could not delete object\n");
3081 return -1;
3082 }
3083 // Removed object so flush handles.
3084 flush_handles(device);
3085 return 0;
Linus Walleij95698cd2006-02-24 10:40:40 +00003086}
Linus Walleij9c6ca022006-04-21 10:24:15 +00003087
Linus Walleij9c6ca022006-04-21 10:24:15 +00003088/**
3089 * Helper function. This indicates if a track exists on the device
3090 * @param device a pointer to the device to get the track from.
3091 * @param id the track ID of the track to retrieve.
3092 * @return TRUE (1) if the track exists, FALSE (0) if not
3093 */
3094int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
3095 uint32_t const id)
3096{
3097 PTPObjectInfo oi;
3098 PTPParams *params = (PTPParams *) device->params;
3099
3100 if (ptp_getobjectinfo(params, id, &oi) == PTP_RC_OK) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003101 return -1;
Linus Walleij9c6ca022006-04-21 10:24:15 +00003102 }
3103 return 0;
3104}
3105
3106/**
3107 * This creates a new folder structure and allocates memory
3108 * for it. Notice that if you add strings to this structure they
3109 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
3110 * operation later, so be careful of using strdup() when assigning
3111 * strings, e.g.:
3112 *
3113 * @return a pointer to the newly allocated folder structure.
3114 * @see LIBMTP_destroy_folder_t()
3115 */
3116LIBMTP_folder_t *LIBMTP_new_folder_t(void)
3117{
3118 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
3119 if (new == NULL) {
3120 return NULL;
3121 }
3122 new->folder_id = 0;
3123 new->parent_id = 0;
3124 new->name = NULL;
3125 new->sibling = NULL;
3126 new->child = NULL;
3127 return new;
3128}
3129
3130/**
raveloxd9a28642006-05-26 23:42:22 +00003131 *
3132 * This deletes the memory for an object structure
3133 * and makes use of the registered destructor for the object
3134 * type data.
3135 *
3136 * @param object object structure to destroy
3137 * @param recurse indicate if the call should recursively delete
3138 * the object. Specify 1 for recursion.
3139 * @see LIBMTP_new_object_t()
3140 */
3141void LIBMTP_destroy_object_t(LIBMTP_object_t *object, uint32_t recursive)
3142{
Linus Walleijf0f3d482006-05-29 14:10:21 +00003143 if(object == NULL) {
3144 return;
3145 }
mopoke96143402006-10-30 04:37:26 +00003146
Linus Walleijf0f3d482006-05-29 14:10:21 +00003147 //Destroy from the bottom up
3148 if(recursive==1) {
3149 LIBMTP_destroy_object_t(object->child, recursive);
3150 object->child = NULL;
3151 LIBMTP_destroy_object_t(object->sibling, recursive);
3152 object->sibling = NULL;
3153 }
raveloxd9a28642006-05-26 23:42:22 +00003154
Linus Walleijf0f3d482006-05-29 14:10:21 +00003155 if(object->name != NULL) free(object->name);
mopoke96143402006-10-30 04:37:26 +00003156
Linus Walleijf0f3d482006-05-29 14:10:21 +00003157 //Use the data type destructor
3158 if(object->data != NULL) {
3159 void (*destructor)(void *);
mopoke96143402006-10-30 04:37:26 +00003160
Linus Walleijf0f3d482006-05-29 14:10:21 +00003161 destructor = get_destructor(object->type);
mopoke96143402006-10-30 04:37:26 +00003162
Linus Walleijf0f3d482006-05-29 14:10:21 +00003163 if(destructor != NULL) {
3164 (*destructor)(object->data);
3165 }
3166 object->data = NULL;
3167 }
mopoke96143402006-10-30 04:37:26 +00003168
Linus Walleijf0f3d482006-05-29 14:10:21 +00003169 free(object);
raveloxd9a28642006-05-26 23:42:22 +00003170}
3171
3172/**
Linus Walleij9c6ca022006-04-21 10:24:15 +00003173 * This recursively deletes the memory for a folder structure
3174 *
3175 * @param folder folder structure to destroy
3176 * @see LIBMTP_new_folder_t()
3177 */
3178void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
3179{
3180
3181 if(folder == NULL) {
3182 return;
3183 }
3184
3185 //Destroy from the bottom up
3186 if(folder->child != NULL) {
3187 LIBMTP_destroy_folder_t(folder->child);
3188 }
3189
3190 if(folder->sibling != NULL) {
3191 LIBMTP_destroy_folder_t(folder->sibling);
3192 }
3193
3194 if(folder->name != NULL) {
3195 free(folder->name);
3196 }
3197
3198 free(folder);
3199}
3200
3201/**
3202 * Helper function. Returns a folder structure for a
3203 * specified id.
3204 *
3205 * @param folderlist list of folders to search
3206 * @id id of folder to look for
3207 * @return a folder or NULL if not found
3208 */
3209LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
3210{
3211 LIBMTP_folder_t *ret = NULL;
mopoke96143402006-10-30 04:37:26 +00003212
Linus Walleij9c6ca022006-04-21 10:24:15 +00003213 if(folderlist == NULL) {
3214 return NULL;
3215 }
mopoke96143402006-10-30 04:37:26 +00003216
Linus Walleij9c6ca022006-04-21 10:24:15 +00003217 if(folderlist->folder_id == id) {
3218 return folderlist;
3219 }
mopoke96143402006-10-30 04:37:26 +00003220
Linus Walleij9c6ca022006-04-21 10:24:15 +00003221 if(folderlist->sibling) {
3222 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
3223 }
mopoke96143402006-10-30 04:37:26 +00003224
Linus Walleij9c6ca022006-04-21 10:24:15 +00003225 if(folderlist->child && ret == NULL) {
3226 ret = LIBMTP_Find_Folder(folderlist->child, id);
3227 }
mopoke96143402006-10-30 04:37:26 +00003228
Linus Walleij9c6ca022006-04-21 10:24:15 +00003229 return ret;
3230}
3231
3232/**
3233 * This returns a list of all folders available
3234 * on the current MTP device.
3235 *
3236 * @param device a pointer to the device to get the track listing for.
3237 * @return a list of folders
3238 */
3239LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
3240{
3241 uint32_t i = 0;
3242 LIBMTP_folder_t *retfolders = NULL;
3243 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003244
mopoke96143402006-10-30 04:37:26 +00003245 // Get all the handles if we haven't already done that
Linus Walleij9c6ca022006-04-21 10:24:15 +00003246 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003247 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00003248 }
mopoke96143402006-10-30 04:37:26 +00003249
Linus Walleij9c6ca022006-04-21 10:24:15 +00003250 for (i = 0; i < params->handles.n; i++) {
3251 LIBMTP_folder_t *folder;
3252 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00003253
Linus Walleij9c6ca022006-04-21 10:24:15 +00003254 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
3255 if (oi.ObjectFormat != PTP_OFC_Association) {
3256 continue;
3257 }
3258 folder = LIBMTP_new_folder_t();
3259 folder->folder_id = params->handles.Handler[i];
3260 folder->parent_id = oi.ParentObject;
Richard Low64fa3992006-11-06 21:24:11 +00003261 if (oi.Filename != NULL)
3262 folder->name = (char *)strdup(oi.Filename);
3263 else
3264 folder->name = NULL;
Richard Low4c60f6e2006-11-07 20:36:42 +00003265
Linus Walleij9c6ca022006-04-21 10:24:15 +00003266 // Work out where to put this new item
3267 if(retfolders == NULL) {
3268 retfolders = folder;
3269 continue;
3270 } else {
3271 LIBMTP_folder_t *parent_folder;
3272 LIBMTP_folder_t *current_folder;
mopoke96143402006-10-30 04:37:26 +00003273
Linus Walleij9c6ca022006-04-21 10:24:15 +00003274 parent_folder = LIBMTP_Find_Folder(retfolders, folder->parent_id);
mopoke96143402006-10-30 04:37:26 +00003275
Linus Walleij9c6ca022006-04-21 10:24:15 +00003276 if(parent_folder == NULL) {
3277 current_folder = retfolders;
3278 } else {
3279 if(parent_folder->child == NULL) {
3280 parent_folder->child = folder;
3281 continue;
3282 } else {
3283 current_folder = parent_folder->child;
3284 }
3285 }
mopoke96143402006-10-30 04:37:26 +00003286
Linus Walleij9c6ca022006-04-21 10:24:15 +00003287 while(current_folder->sibling != NULL) {
3288 current_folder=current_folder->sibling;
3289 }
mopoke96143402006-10-30 04:37:26 +00003290
Linus Walleij9c6ca022006-04-21 10:24:15 +00003291 current_folder->sibling = folder;
3292 }
3293 }
3294 }
3295 return retfolders;
3296}
3297
3298/**
Linus Walleijc86afbd2006-05-04 19:05:24 +00003299 * This create a folder on the current MTP device. The PTP name
3300 * for a folder is "association". The PTP/MTP devices does not
3301 * have an internal "folder" concept really, it contains a flat
3302 * list of all files and some file are "associations" that other
3303 * files and folders may refer to as its "parent".
Linus Walleij9c6ca022006-04-21 10:24:15 +00003304 *
Linus Walleijc86afbd2006-05-04 19:05:24 +00003305 * @param device a pointer to the device to create the folder on.
3306 * @param name the name of the new folder.
3307 * @param parent_id id of parent folder to add the new folder to,
3308 * or 0 to put it in the root directory.
3309 * @return id to new folder or 0 if an error occured
Linus Walleij9c6ca022006-04-21 10:24:15 +00003310 */
3311uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name, uint32_t parent_id)
3312{
3313 PTPParams *params = (PTPParams *) device->params;
3314 uint32_t parenthandle = 0;
3315 uint32_t store = 0;
3316 PTPObjectInfo new_folder;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003317 uint16_t ret;
Linus Walleij9c6ca022006-04-21 10:24:15 +00003318 uint32_t new_id = 0;
3319
3320 memset(&new_folder, 0, sizeof(new_folder));
3321 new_folder.Filename = name;
3322 new_folder.ObjectCompressedSize = 1;
3323 new_folder.ObjectFormat = PTP_OFC_Association;
3324 new_folder.ParentObject = parent_id;
3325
3326 parenthandle = parent_id;
3327 // Create the object
3328 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
3329 if (ret != PTP_RC_OK) {
3330 ptp_perror(params, ret);
3331 printf("LIBMTP_Create_Folder: Could not send object info\n");
Linus Walleij99310d42006-11-01 08:29:39 +00003332 if (ret == PTP_RC_AccessDenied) {
3333 printf("ACCESS DENIED.\n");
3334 } else {
3335 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
3336 }
Linus Walleijc86afbd2006-05-04 19:05:24 +00003337 return 0;
Linus Walleij9c6ca022006-04-21 10:24:15 +00003338 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003339 // Created new object so flush handles
3340 flush_handles(device);
Linus Walleij9c6ca022006-04-21 10:24:15 +00003341 return new_id;
3342}
raveloxd9a28642006-05-26 23:42:22 +00003343
3344
3345/**
3346 * Helper function. Returns a folder structure for a
3347 * specified id.
3348 *
3349 * @param objectlist list of objects to search
3350 * @id id of object to look for
3351 * @return a object or NULL if not found
3352 */
3353LIBMTP_object_t *LIBMTP_Find_Object(LIBMTP_object_t *objectlist, uint32_t id)
3354{
3355 LIBMTP_object_t *ret = NULL;
3356
3357 if(objectlist == NULL) {
3358 return NULL;
3359 }
3360
3361 if(objectlist->id == id) {
3362 return objectlist;
3363 }
3364
3365 if(objectlist->sibling) {
3366 ret = LIBMTP_Find_Object(objectlist->sibling, id);
3367 }
3368
3369 if(objectlist->child && ret == NULL) {
3370 ret = LIBMTP_Find_Object(objectlist->child, id);
3371 }
3372
3373 return ret;
3374}
3375
3376/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00003377 * This returns a list of objects on the current MTP device,
3378 * selected by a filter based on PTP object ID:s.
raveloxd9a28642006-05-26 23:42:22 +00003379 *
Linus Walleijf0f3d482006-05-29 14:10:21 +00003380 * @param device a pointer to the device to get the object listing for.
raveloxd9a28642006-05-26 23:42:22 +00003381 * @param filter array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00003382 * to include in the list
3383 * @param filter_len length of filter array in 32-bit words
raveloxd9a28642006-05-26 23:42:22 +00003384 * @param exclusions array of unsigned 32-bit integers specifying which types
Linus Walleijf0f3d482006-05-29 14:10:21 +00003385 * to exclude from the list
raveloxd9a28642006-05-26 23:42:22 +00003386 * @param exclusion_len length of exclusion array
3387 * @return a list of objects
3388 * @see LIBMTP_destroy_object_t()
3389 */
mopoke96143402006-10-30 04:37:26 +00003390LIBMTP_object_t *LIBMTP_Make_List(LIBMTP_mtpdevice_t *device, uint32_t *filter,
Linus Walleijf0f3d482006-05-29 14:10:21 +00003391 uint32_t filter_len, uint32_t *exclusions, uint32_t exclusion_len)
raveloxd9a28642006-05-26 23:42:22 +00003392{
3393 uint32_t i = 0;
3394 LIBMTP_object_t *objectlist = NULL;
3395 PTPParams *params = (PTPParams *) device->params;
raveloxd9a28642006-05-26 23:42:22 +00003396 uint32_t max_exclusions = 0;
3397 uint32_t max_filter = 0;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003398
mopoke96143402006-10-30 04:37:26 +00003399 // Get all the handles if we haven't already done that
raveloxd9a28642006-05-26 23:42:22 +00003400 if (params->handles.Handler == NULL) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003401 flush_handles(device);
raveloxd9a28642006-05-26 23:42:22 +00003402 }
mopoke96143402006-10-30 04:37:26 +00003403
raveloxd9a28642006-05-26 23:42:22 +00003404 if(filter != NULL) max_filter = filter_len;
3405 if(exclusions != NULL) max_exclusions = exclusion_len;
mopoke96143402006-10-30 04:37:26 +00003406
raveloxd9a28642006-05-26 23:42:22 +00003407 for (i = 0; i < params->handles.n; i++) {
3408 LIBMTP_object_t *object;
3409 PTPObjectInfo oi;
mopoke96143402006-10-30 04:37:26 +00003410
raveloxd9a28642006-05-26 23:42:22 +00003411 if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00003412 uint32_t x = 0;
3413 uint32_t exclude = 0, filter_allow = 0;
3414 void (*datafunc)(LIBMTP_mtpdevice_t *, uint32_t, void *);
3415 void *(*constructor)(void);
mopoke96143402006-10-30 04:37:26 +00003416
raveloxd9a28642006-05-26 23:42:22 +00003417 // Is the ObjectFormat in the list of exclusions ?
Linus Walleijf0f3d482006-05-29 14:10:21 +00003418 for(x = 0; x < max_exclusions; x++) {
3419 if (oi.ObjectFormat == exclusions[x]) {
3420 exclude = 1;
3421 break;
3422 }
raveloxd9a28642006-05-26 23:42:22 +00003423 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003424 if(exclude == 1) {
3425 continue;
3426 }
mopoke96143402006-10-30 04:37:26 +00003427
Linus Walleijf0f3d482006-05-29 14:10:21 +00003428 // Is the ObjectFormat in the filter ?
3429 for(x = 0; x < max_filter; x++) {
3430 if (oi.ObjectFormat == filter[x]) {
3431 filter_allow = 1;
3432 break;
3433 }
3434 }
3435 if(filter_allow == 0) {
3436 continue;
3437 }
mopoke96143402006-10-30 04:37:26 +00003438
raveloxd9a28642006-05-26 23:42:22 +00003439 object = LIBMTP_new_object_t();
3440 object->id = params->handles.Handler[i];
3441 object->parent = oi.ParentObject;
3442 object->name = (char *)strdup(oi.Filename);
3443 object->size = oi.ObjectCompressedSize;
Linus Walleijf0f3d482006-05-29 14:10:21 +00003444 object->type = oi.ObjectFormat;
mopoke96143402006-10-30 04:37:26 +00003445
Linus Walleijf0f3d482006-05-29 14:10:21 +00003446 // Get the function pointers for the constructor and datafunc
3447 constructor = get_constructor(oi.ObjectFormat);
3448 datafunc = get_datafunc(oi.ObjectFormat);
mopoke96143402006-10-30 04:37:26 +00003449
Linus Walleijf0f3d482006-05-29 14:10:21 +00003450 if(constructor != NULL) {
3451 object->data = (*constructor)();
3452 if(datafunc != NULL) {
3453 (*datafunc)(device, object->id, object->data);
3454 }
3455 }
mopoke96143402006-10-30 04:37:26 +00003456
raveloxd9a28642006-05-26 23:42:22 +00003457 // Work out where to put this new item
3458 if(objectlist == NULL) {
3459 objectlist = object;
3460 continue;
3461 } else {
3462 LIBMTP_object_t *parent_object;
3463 LIBMTP_object_t *current_object;
mopoke96143402006-10-30 04:37:26 +00003464
raveloxd9a28642006-05-26 23:42:22 +00003465 parent_object = LIBMTP_Find_Object(objectlist, object->parent);
mopoke96143402006-10-30 04:37:26 +00003466
raveloxd9a28642006-05-26 23:42:22 +00003467 if(parent_object == NULL) {
Linus Walleijf0f3d482006-05-29 14:10:21 +00003468 current_object = objectlist;
raveloxd9a28642006-05-26 23:42:22 +00003469 } else {
3470 if(parent_object->child == NULL) {
3471 parent_object->child = object;
3472 continue;
3473 } else {
3474 current_object = parent_object->child;
3475 }
Linus Walleijf0f3d482006-05-29 14:10:21 +00003476 }
mopoke96143402006-10-30 04:37:26 +00003477
raveloxd9a28642006-05-26 23:42:22 +00003478 while(current_object->sibling != NULL) {
3479 current_object=current_object->sibling;
3480 }
3481 current_object->sibling = object;
3482 }
3483 }
3484 }
mopoke96143402006-10-30 04:37:26 +00003485
raveloxd9a28642006-05-26 23:42:22 +00003486 return objectlist;
3487}
mopoke96143402006-10-30 04:37:26 +00003488
raveloxd9a28642006-05-26 23:42:22 +00003489/**
Linus Walleijf0f3d482006-05-29 14:10:21 +00003490 * Debug function that dumps out some textual representation
3491 * of an object list.
raveloxd9a28642006-05-26 23:42:22 +00003492 *
3493 * @param list object list returned from LIBMTP_Make_List
3494 *
3495 * @see LIBMTP_Make_List()
3496 */
3497void LIBMTP_Dump_List(LIBMTP_object_t *list)
3498{
Linus Walleijf0f3d482006-05-29 14:10:21 +00003499 if(list == NULL) return;
mopoke96143402006-10-30 04:37:26 +00003500
Linus Walleijf0f3d482006-05-29 14:10:21 +00003501 printf("Id : %u\n", list->id);
3502 printf("Parent: %u\n", list->parent);
3503 printf("Size : %u\n", list->size);
3504 printf("Name : %s\n", (list->name ? list->name : ""));
3505 printf("Type : 0x%04x\n", list->type);
3506 printf("--\n");
mopoke96143402006-10-30 04:37:26 +00003507
Linus Walleijf0f3d482006-05-29 14:10:21 +00003508 LIBMTP_Dump_List(list->child);
3509 LIBMTP_Dump_List(list->sibling);
raveloxd9a28642006-05-26 23:42:22 +00003510}
Linus Walleij438bd7f2006-06-08 11:35:44 +00003511
3512/**
3513 * This creates a new playlist metadata structure and allocates memory
3514 * for it. Notice that if you add strings to this structure they
3515 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
mopoke96143402006-10-30 04:37:26 +00003516 * operation later, so be careful of using strdup() when assigning
Linus Walleij438bd7f2006-06-08 11:35:44 +00003517 * strings, e.g.:
3518 *
3519 * <pre>
3520 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
3521 * pl->name = strdup(str);
3522 * ....
3523 * LIBMTP_destroy_playlist_t(pl);
3524 * </pre>
3525 *
3526 * @return a pointer to the newly allocated metadata structure.
3527 * @see LIBMTP_destroy_playlist_t()
3528 */
3529LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
3530{
3531 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
3532 if (new == NULL) {
3533 return NULL;
3534 }
3535 new->playlist_id = 0;
3536 new->name = NULL;
3537 new->tracks = NULL;
3538 new->no_tracks = 0;
3539 new->next = NULL;
3540 return new;
3541}
3542
3543/**
3544 * This destroys a playlist metadata structure and deallocates the memory
mopoke96143402006-10-30 04:37:26 +00003545 * used by it, including any strings. Never use a track metadata
Linus Walleij438bd7f2006-06-08 11:35:44 +00003546 * structure again after calling this function on it.
3547 * @param playlist the playlist metadata to destroy.
3548 * @see LIBMTP_new_playlist_t()
3549 */
3550void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
3551{
3552 if (playlist == NULL) {
3553 return;
3554 }
3555 if (playlist->name != NULL)
3556 free(playlist->name);
3557 if (playlist->tracks != NULL)
3558 free(playlist->tracks);
3559 free(playlist);
3560 return;
3561}
3562
3563/**
3564 * This function returns a list of the playlists available on the
3565 * device. Typical usage:
3566 *
3567 * <pre>
3568 * </pre>
3569 *
3570 * @param device a pointer to the device to get the playlist listing from.
3571 * @return a playlist list on success, else NULL. If there are no playlists
3572 * on the device, NULL will be returned as well.
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003573 * @see LIBMTP_Get_Playlist()
Linus Walleij438bd7f2006-06-08 11:35:44 +00003574 */
3575LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
3576{
3577 PTPParams *params = (PTPParams *) device->params;
3578 LIBMTP_playlist_t *retlists = NULL;
3579 LIBMTP_playlist_t *curlist = NULL;
3580 uint32_t i;
3581
3582 // Get all the handles if we haven't already done that
3583 if (params->handles.Handler == NULL) {
3584 flush_handles(device);
3585 }
3586
3587 for (i = 0; i < params->handles.n; i++) {
3588 LIBMTP_playlist_t *pl;
3589 PTPObjectInfo oi;
3590 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +00003591
Linus Walleij438bd7f2006-06-08 11:35:44 +00003592 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3593 if ( ret == PTP_RC_OK) {
mopoke96143402006-10-30 04:37:26 +00003594
Linus Walleij438bd7f2006-06-08 11:35:44 +00003595 // Ignore stuff that isn't playlists
3596 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
3597 continue;
3598 }
mopoke96143402006-10-30 04:37:26 +00003599
Linus Walleij438bd7f2006-06-08 11:35:44 +00003600 // Allocate a new playlist type
3601 pl = LIBMTP_new_playlist_t();
mopoke96143402006-10-30 04:37:26 +00003602
Linus Walleij438bd7f2006-06-08 11:35:44 +00003603 // Ignoring the io.Filename field.
Linus Walleija823a702006-08-27 21:27:46 +00003604 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
mopoke96143402006-10-30 04:37:26 +00003605
Linus Walleij438bd7f2006-06-08 11:35:44 +00003606 // This is some sort of unique playlist ID so we can keep track of it
3607 pl->playlist_id = params->handles.Handler[i];
3608
3609 // Then get the track listing for this playlist
3610 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
3611 if (ret != PTP_RC_OK) {
3612 printf("LIBMTP_Get_Playlist: Could not get object references\n");
3613 pl->tracks = NULL;
3614 pl->no_tracks = 0;
3615 }
mopoke96143402006-10-30 04:37:26 +00003616
Linus Walleij438bd7f2006-06-08 11:35:44 +00003617 // Add playlist to a list that will be returned afterwards.
3618 if (retlists == NULL) {
3619 retlists = pl;
3620 curlist = pl;
3621 } else {
3622 curlist->next = pl;
3623 curlist = pl;
3624 }
mopoke96143402006-10-30 04:37:26 +00003625
Linus Walleij438bd7f2006-06-08 11:35:44 +00003626 // Call callback here if we decide to add that possibility...
3627
3628 } else {
3629 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
3630 }
mopoke96143402006-10-30 04:37:26 +00003631 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003632 return retlists;
3633}
3634
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003635
3636/**
3637 * This function retrieves an individual playlist from the device.
3638 * @param device a pointer to the device to get the playlist from.
3639 * @param plid the unique ID of the playlist to retrieve.
3640 * @return a valid playlist metadata post or NULL on failure.
3641 * @see LIBMTP_Get_Playlist_List()
3642 */
3643LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
3644{
3645 PTPParams *params = (PTPParams *) device->params;
3646 uint32_t i;
3647
3648 // Get all the handles if we haven't already done that
3649 if (params->handles.Handler == NULL) {
3650 flush_handles(device);
3651 }
3652
3653 for (i = 0; i < params->handles.n; i++) {
3654 LIBMTP_playlist_t *pl;
3655 PTPObjectInfo oi;
3656 uint16_t ret;
mopoke96143402006-10-30 04:37:26 +00003657
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003658 if (params->handles.Handler[i] != plid) {
3659 continue;
3660 }
3661
3662 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3663 if ( ret == PTP_RC_OK) {
mopoke96143402006-10-30 04:37:26 +00003664
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003665 // Ignore stuff that isn't playlists
3666 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
3667 return NULL;
3668 }
mopoke96143402006-10-30 04:37:26 +00003669
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003670 // Allocate a new playlist type
3671 pl = LIBMTP_new_playlist_t();
mopoke96143402006-10-30 04:37:26 +00003672
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003673 // Ignoring the io.Filename field.
Linus Walleija823a702006-08-27 21:27:46 +00003674 pl->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
mopoke96143402006-10-30 04:37:26 +00003675
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003676 // This is some sort of unique playlist ID so we can keep track of it
3677 pl->playlist_id = params->handles.Handler[i];
3678
3679 // Then get the track listing for this playlist
3680 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
3681 if (ret != PTP_RC_OK) {
3682 printf("LIBMTP_Get_Playlist: Could not get object references\n");
3683 pl->tracks = NULL;
3684 pl->no_tracks = 0;
3685 }
mopoke96143402006-10-30 04:37:26 +00003686
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003687 return pl;
3688 } else {
3689 return NULL;
3690 }
mopoke96143402006-10-30 04:37:26 +00003691 }
Linus Walleij2e4b5f92006-06-16 14:00:49 +00003692 return NULL;
3693}
3694
Linus Walleij438bd7f2006-06-08 11:35:44 +00003695/**
3696 * This routine creates a new playlist based on the metadata
3697 * supplied. If the <code>tracks</code> field of the metadata
3698 * contains a track listing, these tracks will be added to the
3699 * playlist.
3700 * @param device a pointer to the device to create the new playlist on.
3701 * @param metadata the metadata for the new playlist. If the function
3702 * exits with success, the <code>playlist_id</code> field of this
3703 * struct will contain the new playlist ID of the playlist.
3704 * @param parenthandle the parent (e.g. folder) to store this playlist
3705 * in. Pass in 0 to put the playlist in the root directory.
3706 * @return 0 on success, any other value means failure.
3707 * @see LIBMTP_Update_Playlist()
3708 * @see LIBMTP_Delete_Object()
3709 */
mopoke96143402006-10-30 04:37:26 +00003710int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
Linus Walleij438bd7f2006-06-08 11:35:44 +00003711 LIBMTP_playlist_t * const metadata,
3712 uint32_t const parenthandle)
3713{
3714 uint16_t ret;
3715 uint32_t store = 0;
3716 PTPObjectInfo new_pl;
3717 PTPParams *params = (PTPParams *) device->params;
3718 uint32_t localph = parenthandle;
3719 char fname[256];
Linus Walleijd14e84f2006-06-16 14:50:59 +00003720 uint8_t data[2];
Linus Walleij438bd7f2006-06-08 11:35:44 +00003721
Linus Walleij05ccbe72006-06-13 07:46:58 +00003722 // Use a default folder if none given
3723 if (localph == 0) {
3724 localph = device->default_playlist_folder;
3725 }
3726
Linus Walleij438bd7f2006-06-08 11:35:44 +00003727 // .zpl is the "abstract audio/video playlist "file" suffix
3728 new_pl.Filename = NULL;
3729 if (strlen(metadata->name) > 4) {
3730 char *suff = &metadata->name[strlen(metadata->name)-4];
3731 if (!strcmp(suff, ".zpl")) {
3732 // Home free.
3733 new_pl.Filename = metadata->name;
3734 }
3735 }
3736 // If it didn't end with ".zpl" then add that here.
3737 if (new_pl.Filename == NULL) {
3738 strncpy(fname, metadata->name, sizeof(fname)-5);
3739 strcat(fname, ".zpl");
3740 fname[sizeof(fname)-1] = '\0';
3741 new_pl.Filename = fname;
3742 }
3743
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003744 // Playlists created on device have size (uint32_t) -1 = 0xFFFFFFFFU, but setting:
3745 // new_pl.ObjectCompressedSize = 0; <- DOES NOT WORK! (return PTP_RC_GeneralError)
3746 // new_pl.ObjectCompressedSize = (uint32_t) -1; <- DOES NOT WORK! (return PTP_RC_MTP_Object_Too_Large)
Linus Walleijd14e84f2006-06-16 14:50:59 +00003747 new_pl.ObjectCompressedSize = 1;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003748 new_pl.ObjectFormat = PTP_OFC_MTP_AbstractAudioVideoPlaylist;
mopoke96143402006-10-30 04:37:26 +00003749
Linus Walleij438bd7f2006-06-08 11:35:44 +00003750 // Create the object
3751 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
3752 if (ret != PTP_RC_OK) {
3753 ptp_perror(params, ret);
3754 printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
Linus Walleij99310d42006-11-01 08:29:39 +00003755 if (ret == PTP_RC_AccessDenied) {
3756 printf("ACCESS DENIED.\n");
3757 } else {
3758 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
3759 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003760 return -1;
3761 }
mopoke96143402006-10-30 04:37:26 +00003762
Linus Walleij438bd7f2006-06-08 11:35:44 +00003763 /*
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003764 * We have to send this one blank data byte.
3765 * If we don't, the handle will not be created and thus there is no playlist.
Linus Walleij438bd7f2006-06-08 11:35:44 +00003766 */
Linus Walleijd14e84f2006-06-16 14:50:59 +00003767 data[0] = '\0';
3768 data[1] = '\0';
3769 ret = ptp_sendobject(params, data, 1);
3770 if (ret != PTP_RC_OK) {
3771 ptp_perror(params, ret);
3772 printf("LIBMTP_New_Playlist(): Could not send blank object data\n");
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003773 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003774 return -1;
3775 }
Linus Walleij438bd7f2006-06-08 11:35:44 +00003776
3777 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00003778 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003779 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003780 printf("LIBMTP_New_Playlist(): could not set playlist name\n");
3781 return -1;
3782 }
3783
3784 if (metadata->no_tracks > 0) {
3785 // Add tracks to the new playlist as object references.
3786 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3787 if (ret != PTP_RC_OK) {
3788 printf("LIBMTP_New_Playlist(): could not add tracks as object references\n");
Linus Walleijcd3eb3d2006-09-02 21:33:22 +00003789 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
Linus Walleij438bd7f2006-06-08 11:35:44 +00003790 return -1;
3791 }
3792 }
mopoke96143402006-10-30 04:37:26 +00003793
Linus Walleij438bd7f2006-06-08 11:35:44 +00003794 // Created new item, so flush handles
3795 flush_handles(device);
3796
3797 return 0;
3798}
3799
3800/**
3801 * This routine updates a playlist based on the metadata
3802 * supplied. If the <code>tracks</code> field of the metadata
3803 * contains a track listing, these tracks will be added to the
3804 * playlist in place of those already present, i.e. the
3805 * previous track listing will be deleted.
3806 * @param device a pointer to the device to create the new playlist on.
3807 * @param metadata the metadata for the playlist to be updated.
mopoke96143402006-10-30 04:37:26 +00003808 * notice that the field <code>playlist_id</code>
Linus Walleij438bd7f2006-06-08 11:35:44 +00003809 * must contain the apropriate playlist ID.
3810 * @return 0 on success, any other value means failure.
3811 * @see LIBMTP_Create_New_Playlist()
3812 * @see LIBMTP_Delete_Object()
3813 */
mopoke96143402006-10-30 04:37:26 +00003814int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
Linus Walleijf5306352006-06-08 12:00:23 +00003815 LIBMTP_playlist_t const * const metadata)
Linus Walleij438bd7f2006-06-08 11:35:44 +00003816{
3817 uint16_t ret;
Linus Walleijf5306352006-06-08 12:00:23 +00003818 PTPParams *params = (PTPParams *) device->params;
Linus Walleij438bd7f2006-06-08 11:35:44 +00003819
3820 // Update title
Linus Walleija823a702006-08-27 21:27:46 +00003821 ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
Linus Walleijd14e84f2006-06-16 14:50:59 +00003822 if (ret != 0) {
Linus Walleij438bd7f2006-06-08 11:35:44 +00003823 printf("LIBMTP_Update_Playlist(): could not set playlist name\n");
3824 return -1;
3825 }
3826
3827 if (metadata->no_tracks > 0) {
3828 // Add tracks to the new playlist as object references.
3829 ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
3830 if (ret != PTP_RC_OK) {
3831 printf("LIBMTP_Update_Playlist(): could not add tracks as object references\n");
3832 return -1;
3833 }
3834 }
3835 return 0;
3836}
Linus Walleijaa4b0752006-07-26 22:21:04 +00003837
Linus Walleij0c33ec02006-10-27 10:15:40 +00003838/**
3839 * This creates a new album metadata structure and allocates memory
3840 * for it. Notice that if you add strings to this structure they
3841 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
3842 * operation later, so be careful of using strdup() when assigning
3843 * strings.
3844 *
3845 * @return a pointer to the newly allocated metadata structure.
3846 * @see LIBMTP_destroy_album_t()
3847 */
3848LIBMTP_album_t *LIBMTP_new_album_t(void)
3849{
3850 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
3851 if (new == NULL) {
3852 return NULL;
3853 }
3854 new->album_id = 0;
3855 new->name = NULL;
3856 new->tracks = NULL;
3857 new->no_tracks = 0;
3858 new->next = NULL;
3859 return new;
3860}
3861
3862/**
3863 * This recursively deletes the memory for an album structure
3864 *
3865 * @param album structure to destroy
3866 * @see LIBMTP_new_album_t()
3867 */
3868void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
3869{
3870 if (album == NULL) {
3871 return;
3872 }
3873 if (album->name != NULL)
3874 free(album->name);
3875 if (album->tracks != NULL)
3876 free(album->tracks);
3877 free(album);
3878 return;
3879}
3880
3881/**
3882 * This function returns a list of the albums available on the
3883 * device.
3884 *
3885 * @param device a pointer to the device to get the album listing from.
3886 * @return an album list on success, else NULL. If there are no albums
3887 * on the device, NULL will be returned as well.
3888 * @see LIBMTP_Get_Album()
3889 */
3890LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
3891{
3892 PTPParams *params = (PTPParams *) device->params;
3893 LIBMTP_album_t *retalbums = NULL;
3894 LIBMTP_album_t *curalbum = NULL;
3895 uint32_t i;
3896
3897 // Get all the handles if we haven't already done that
3898 if (params->handles.Handler == NULL) {
3899 flush_handles(device);
3900 }
3901
3902 for (i = 0; i < params->handles.n; i++) {
3903 LIBMTP_album_t *alb;
3904 PTPObjectInfo oi;
3905 uint16_t ret;
3906
3907 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3908 if ( ret == PTP_RC_OK) {
3909
3910 // Ignore stuff that isn't an album
3911 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
3912 continue;
3913 }
3914
3915 // Allocate a new album type
3916 alb = LIBMTP_new_album_t();
3917 alb->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
3918 alb->album_id = params->handles.Handler[i];
3919
3920 // Then get the track listing for this album
3921 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
3922 if (ret != PTP_RC_OK) {
3923 printf("LIBMTP_Get_Album: Could not get object references\n");
3924 alb->tracks = NULL;
3925 alb->no_tracks = 0;
3926 }
3927
3928 // Add album to a list that will be returned afterwards.
3929 if (retalbums == NULL) {
3930 retalbums = alb;
3931 curalbum = alb;
3932 } else {
3933 curalbum->next = alb;
3934 curalbum = alb;
3935 }
3936
3937 } else {
3938 printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");
3939 }
3940 }
3941 return retalbums;
3942}
3943
3944/**
3945 * This function retrieves an individual album from the device.
3946 * @param device a pointer to the device to get the album from.
3947 * @param albid the unique ID of the album to retrieve.
3948 * @return a valid album metadata or NULL on failure.
3949 * @see LIBMTP_Get_Album_List()
3950 */
3951LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
3952{
3953 PTPParams *params = (PTPParams *) device->params;
3954 uint32_t i;
3955
3956 // Get all the handles if we haven't already done that
3957 if (params->handles.Handler == NULL) {
3958 flush_handles(device);
3959 }
3960
3961 for (i = 0; i < params->handles.n; i++) {
3962 LIBMTP_album_t *alb;
3963 PTPObjectInfo oi;
3964 uint16_t ret;
3965
3966 if (params->handles.Handler[i] != albid) {
3967 continue;
3968 }
3969
3970 ret = ptp_getobjectinfo(params, params->handles.Handler[i], &oi);
3971 if ( ret == PTP_RC_OK) {
3972
3973 // Ignore stuff that isn't an album
3974 if ( oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
3975 return NULL;
3976 }
3977
3978 // Allocate a new album type
3979 alb = LIBMTP_new_album_t();
3980 alb->name = LIBMTP_Get_String_From_Object(device, params->handles.Handler[i], PTP_OPC_Name);
3981 alb->album_id = params->handles.Handler[i];
3982 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
3983 if (ret != PTP_RC_OK) {
3984 printf("LIBMTP_Get_Album: Could not get object references\n");
3985 alb->tracks = NULL;
3986 alb->no_tracks = 0;
3987 }
3988
3989 return alb;
3990 } else {
3991 return NULL;
3992 }
3993 }
3994 return NULL;
3995}
3996
3997/**
3998 * This routine creates a new album based on the metadata
3999 * supplied. If the <code>tracks</code> field of the metadata
4000 * contains a track listing, these tracks will be added to the
4001 * album.
4002 * @param device a pointer to the device to create the new album on.
4003 * @param metadata the metadata for the new album. If the function
4004 * exits with success, the <code>album_id</code> field of this
4005 * struct will contain the new ID of the album.
4006 * @param parenthandle the parent (e.g. folder) to store this album
4007 * in. Pass in 0 to put the album in the default music directory.
4008 * @return 0 on success, any other value means failure.
4009 * @see LIBMTP_Update_Album()
4010 * @see LIBMTP_Delete_Object()
4011 */
4012int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
4013 LIBMTP_album_t * const metadata,
4014 uint32_t const parenthandle)
4015{
4016 uint16_t ret;
4017 uint32_t store = 0;
4018 PTPObjectInfo new_alb;
4019 PTPParams *params = (PTPParams *) device->params;
4020 uint32_t localph = parenthandle;
4021 char fname[256];
4022 uint8_t data[1];
4023
Linus Walleij622a22a2006-10-30 09:21:45 +00004024 // Check if we can create an object of type PTP_OFC_MTP_AbstractAudioAlbum
mopoke96143402006-10-30 04:37:26 +00004025 int i;
4026 int supported = 0;
4027 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
Linus Walleij622a22a2006-10-30 09:21:45 +00004028 if (params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_AbstractAudioAlbum) {
mopoke96143402006-10-30 04:37:26 +00004029 supported = 1;
Linus Walleij622a22a2006-10-30 09:21:45 +00004030 break;
4031 }
mopoke96143402006-10-30 04:37:26 +00004032 }
4033 if (!supported) {
4034 printf("LIBMTP_Create_New_Album(): Player does not support the AbstractAudioAlbum type\n");
4035 return -1;
4036 }
4037
Linus Walleij0c33ec02006-10-27 10:15:40 +00004038 // Use a default folder if none given
4039 if (localph == 0) {
4040 localph = device->default_music_folder;
4041 }
4042
4043 new_alb.Filename = NULL;
4044 if (strlen(metadata->name) > 4) {
4045 char *suff = &metadata->name[strlen(metadata->name)-4];
4046 if (!strcmp(suff, ".alb")) {
4047 new_alb.Filename = metadata->name;
4048 }
4049 }
4050 // If it didn't end with ".alb" then add that here.
4051 if (new_alb.Filename == NULL) {
4052 strncpy(fname, metadata->name, sizeof(fname)-5);
4053 strcat(fname, ".alb");
4054 fname[sizeof(fname)-1] = '\0';
4055 new_alb.Filename = fname;
4056 }
4057
4058 new_alb.ObjectCompressedSize = 1;
4059 new_alb.ObjectFormat = PTP_OFC_MTP_AbstractAudioAlbum;
4060
4061 // Create the object
4062 ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->album_id, &new_alb);
4063 if (ret != PTP_RC_OK) {
4064 ptp_perror(params, ret);
4065 printf("LIBMTP_New_Album(): Could not send object info (the album itself)\n");
4066 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4067 return -1;
4068 }
4069 data[0] = '\0';
4070 ret = ptp_sendobject(params, data, 1);
4071 if (ret != PTP_RC_OK) {
4072 ptp_perror(params, ret);
4073 printf("LIBMTP_New_Album(): Could not send blank object data\n");
4074 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4075 return -1;
4076 }
4077
4078 // Update title
4079 ret = LIBMTP_Set_Object_String(device, metadata->album_id, PTP_OPC_Name, metadata->name);
4080 if (ret != 0) {
4081 printf("LIBMTP_New_Album(): could not set album name\n");
4082 return -1;
4083 }
4084
4085 if (metadata->no_tracks > 0) {
4086 // Add tracks to the new album as object references.
4087 ret = ptp_mtp_setobjectreferences (params, metadata->album_id, metadata->tracks, metadata->no_tracks);
4088 if (ret != PTP_RC_OK) {
4089 printf("LIBMTP_New_Album(): could not add tracks as object references\n");
4090 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4091 return -1;
4092 }
4093 }
4094
4095 // Created new item, so flush handles
4096 flush_handles(device);
4097
4098 return 0;
4099}
4100
4101/**
4102 * This routine sends cover art for an album object. This uses the
4103 * RepresentativeSampleData property of the album, if the device
4104 * supports it. The data should be of a format acceptable to the
4105 * player (for iRiver and Creative, this seems to be JPEG) and
4106 * must not be too large. (for a Creative, max seems to be about 20KB.)
4107 * TODO: there must be a way to find the max size for an ObjectPropertyValue.
4108 * @param device a pointer to the device which the album is on.
4109 * @param id unique id of the album object.
4110 * @param imagedata pointer to an array of uint8_t containing the image data.
4111 * @param imagesize number of bytes in the image.
4112 * @return 0 on success, any other value means failure.
4113 * @see LIBMTP_Create_New_Album()
4114 */
4115int LIBMTP_Send_Album_Art(LIBMTP_mtpdevice_t *device,
4116 uint32_t const id,
4117 uint8_t * const imagedata,
4118 uint32_t const imagesize)
4119{
4120 uint16_t ret;
4121 PTPParams *params = (PTPParams *) device->params;
4122 PTPPropertyValue propval;
4123
4124 int i;
4125 propval.a.count = imagesize;
4126 propval.a.v = malloc(sizeof(PTPPropertyValue) * imagesize);
4127 for (i = 0; i < imagesize; i++) {
4128 propval.a.v[i].u8 = imagedata[i];
4129 }
4130
4131 // check that we can send album art
4132 uint16_t *props = NULL;
4133 uint32_t propcnt = 0;
4134 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
4135 if (ret != PTP_RC_OK) {
4136 printf("LIBMTP_Send_Album_Art(): could not get object properties\n");
4137 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4138 return -1;
4139 }
4140 int supported = 0;
4141 for (i = 0; i < propcnt; i++) {
4142 if (props[i] == PTP_OPC_RepresentativeSampleData)
4143 supported = 1;
4144 }
4145 if (!supported) {
4146 printf("LIBMTP_Send_Album_Art(): device doesn't support RepresentativeSampleData\n");
4147 return -1;
4148 }
4149
4150 // go ahead and send the data
4151 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
4152 &propval,PTP_DTC_AUINT8);
4153 if (ret != PTP_RC_OK) {
4154 printf("LIBMTP_Send_Album_Art(): could not send album art\n");
4155 printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
4156 return -1;
4157 }
4158 return 0;
4159}
4160
4161/**
4162 * This routine updates an album based on the metadata
4163 * supplied. If the <code>tracks</code> field of the metadata
4164 * contains a track listing, these tracks will be added to the
4165 * album in place of those already present, i.e. the
4166 * previous track listing will be deleted.
4167 * @param device a pointer to the device to create the new album on.
4168 * @param metadata the metadata for the album to be updated.
4169 * notice that the field <code>album_id</code>
4170 * must contain the apropriate album ID.
4171 * @return 0 on success, any other value means failure.
4172 * @see LIBMTP_Create_New_Album()
4173 * @see LIBMTP_Delete_Object()
4174 */
4175int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
4176 LIBMTP_album_t const * const metadata)
4177{
4178 uint16_t ret;
4179 PTPParams *params = (PTPParams *) device->params;
4180
4181 // Update title
4182 ret = LIBMTP_Set_Object_String(device, metadata->album_id, PTP_OPC_Name, metadata->name);
4183 if (ret != 0) {
4184 printf("LIBMTP_Update_Album(): could not set album name\n");
4185 return -1;
4186 }
4187
4188 if (metadata->no_tracks > 0) {
4189 // Add tracks to the new album as object references.
4190 ret = ptp_mtp_setobjectreferences (params, metadata->album_id, metadata->tracks, metadata->no_tracks);
4191 if (ret != PTP_RC_OK) {
4192 printf("LIBMTP_Update_Album(): could not add tracks as object references\n");
4193 return -1;
4194 }
4195 }
4196 return 0;
4197}
Linus Walleijaa4b0752006-07-26 22:21:04 +00004198
4199/**
4200 * Dummy function needed to interface to upstream
4201 * ptp.c/ptp.h files.
4202 */
4203void ptp_nikon_getptpipguid (unsigned char* guid) {
4204 return;
4205}