• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * \file libmtp.c
3  *
4  * Copyright (C) 2005-2011 Linus Walleij <triad@df.lth.se>
5  * Copyright (C) 2005-2008 Richard A. Low <richard@wentnet.com>
6  * Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
7  * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
8  * Copyright (C) 2008 Florent Mertens <flomertens@gmail.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  * This file provides an interface "glue" to the underlying
26  * PTP implementation from libgphoto2. It uses some local
27  * code to convert from/to UTF-8 (stored in unicode.c/.h)
28  * and some small utility functions, mainly for debugging
29  * (stored in util.c/.h).
30  *
31  * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
32  * plain copied from the libhphoto2 codebase.
33  *
34  * The files libusb-glue.c/.h are just what they say: an
35  * interface to libusb for the actual, physical USB traffic.
36  */
37 #include "config.h"
38 #include "libmtp.h"
39 #include "unicode.h"
40 #include "ptp.h"
41 #include "libusb-glue.h"
42 #include "device-flags.h"
43 #include "playlist-spl.h"
44 #include "util.h"
45 
46 #include "mtpz.h"
47 
48 #include <stdarg.h>
49 #include <stdlib.h>
50 #include <limits.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <fcntl.h>
56 #include <time.h>
57 #include <errno.h>
58 #ifdef _MSC_VER // For MSVC++
59 #define USE_WINDOWS_IO_H
60 #include <io.h>
61 #endif
62 
63 
64 /**
65  * Global debug level
66  * We use a flag system to enable a part of logs.
67  *
68  * The LIBMTP_DEBUG environment variable sets the debug flags for any binary
69  * that uses libmtp and calls LIBMTP_Init. The value can be given in decimal
70  * (must not start with "0" or it will be interpreted in octal), or in
71  * hexadecimal (must start with "0x").
72  *
73  * The value "-1" enables all debug flags.
74  *
75  * Some of the utilities in examples/ also take a command-line flag "-d" that
76  * enables LIBMTP_DEBUG_PTP and LIBMTP_DEBUG_DATA (same as setting
77  * LIBMTP_DEBUG=9).
78  *
79  * Flags (combine by adding the hex values):
80  *  0x00 [0000 0000] : LIBMTP_DEBUG_NONE  : no debug (default)
81  *  0x01 [0000 0001] : LIBMTP_DEBUG_PTP   : PTP debug
82  *  0x02 [0000 0010] : LIBMTP_DEBUG_PLST  : Playlist debug
83  *  0x04 [0000 0100] : LIBMTP_DEBUG_USB   : USB debug
84  *  0x08 [0000 1000] : LIBMTP_DEBUG_DATA  : USB data debug
85  *
86  * (Please keep this list in sync with libmtp.h.)
87  */
88 int LIBMTP_debug = LIBMTP_DEBUG_NONE;
89 
90 
91 /*
92  * This is a mapping between libmtp internal MTP filetypes and
93  * the libgphoto2/PTP equivalent defines. We need this because
94  * otherwise the libmtp.h device has to be dependent on ptp.h
95  * to be installed too, and we don't want that.
96  */
97 //typedef struct filemap_struct filemap_t;
98 typedef struct filemap_struct {
99   char *description; /**< Text description for the file type */
100   LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
101   uint16_t ptp_id; /**< PTP ID for the filetype */
102   struct filemap_struct *next;
103 } filemap_t;
104 
105 /*
106  * This is a mapping between libmtp internal MTP properties and
107  * the libgphoto2/PTP equivalent defines. We need this because
108  * otherwise the libmtp.h device has to be dependent on ptp.h
109  * to be installed too, and we don't want that.
110  */
111 typedef struct propertymap_struct {
112   char *description; /**< Text description for the property */
113   LIBMTP_property_t id; /**< LIBMTP internal type for the property */
114   uint16_t ptp_id; /**< PTP ID for the property */
115   struct propertymap_struct *next;
116 } propertymap_t;
117 
118 /*
119  * This is a simple container for holding our callback and user_data
120  * for parsing onwards to the usb_event_async function.
121  */
122 typedef struct event_cb_data_struct {
123   LIBMTP_event_cb_fn cb;
124   void *user_data;
125 } event_cb_data_t;
126 
127 // Global variables
128 // This holds the global filetype mapping table
129 static filemap_t *g_filemap = NULL;
130 // This holds the global property mapping table
131 static propertymap_t *g_propertymap = NULL;
132 
133 static int load_cache_on_demand = 0;
134 /*
135  * Forward declarations of local (static) functions.
136  */
137 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
138 			     uint16_t const ptp_id);
139 static void init_filemap();
140 static int register_property(char const * const description, LIBMTP_property_t const id,
141 			     uint16_t const ptp_id);
142 static void init_propertymap();
143 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
144 				    LIBMTP_error_number_t errornumber,
145 				    char const * const error_text);
146 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
147 					uint16_t ptp_error,
148 					char const * const error_text);
149 static void flush_handles(LIBMTP_mtpdevice_t *device);
150 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
151 				    PTPParams *params,
152 				    uint32_t storageid,
153 				    uint32_t parent);
154 static void free_storage_list(LIBMTP_mtpdevice_t *device);
155 static int sort_storage_by(LIBMTP_mtpdevice_t *device, int const sortby);
156 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
157 					uint64_t fitsize);
158 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
159 				 LIBMTP_devicestorage_t *storage,
160 				 uint64_t *freespace);
161 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
162 			      LIBMTP_devicestorage_t *storage,
163 			      uint64_t const filesize);
164 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
165 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
166 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty);
167 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t intype);
168 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
169 				       char **unicstring, uint16_t property);
170 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd);
171 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd);
172 static char *get_iso8601_stamp(void);
173 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
174 				    uint16_t const attribute_id);
175 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
176                                     uint16_t const attribute_id, uint64_t const value_default);
177 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
178 				    uint16_t const attribute_id, uint32_t const value_default);
179 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
180 				    uint16_t const attribute_id, uint16_t const value_default);
181 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
182 				  uint16_t const attribute_id, uint8_t const value_default);
183 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
184 			     uint16_t const attribute_id, char const * const string);
185 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
186 			  uint16_t const attribute_id, uint32_t const value);
187 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
188 			  uint16_t const attribute_id, uint16_t const value);
189 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
190 			 uint16_t const attribute_id, uint8_t const value);
191 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
192 			       LIBMTP_track_t *track);
193 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent);
194 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
195 				    char const * const name,
196 				    char const * const artist,
197 				    char const * const composer,
198 				    char const * const genre,
199 				    uint32_t const parenthandle,
200 				    uint32_t const storageid,
201 				    uint16_t const objectformat,
202 				    char const * const suffix,
203 				    uint32_t * const newid,
204 				    uint32_t const * const tracks,
205 				    uint32_t const no_tracks);
206 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
207 				char const * const name,
208 				char const * const artist,
209 				char const * const composer,
210 				char const * const genre,
211 				uint32_t const objecthandle,
212 				uint16_t const objectformat,
213 				uint32_t const * const tracks,
214 				uint32_t const no_tracks);
215 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata);
216 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
217 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
218 static int set_object_filename(LIBMTP_mtpdevice_t *device,
219 		uint32_t object_id,
220 		uint16_t ptp_type,
221                 const char **newname);
222 static char *generate_unique_filename(PTPParams* params, char const * const filename);
223 static int check_filename_exists(PTPParams* params, char const * const filename);
224 static void LIBMTP_Handle_Event(PTPContainer *ptp_event,
225                                 LIBMTP_event_t *event, uint32_t *out1);
226 
227 /**
228  * These are to wrap the get/put handlers to convert from the MTP types to PTP types
229  * in a reliable way
230  */
231 typedef struct _MTPDataHandler {
232 	MTPDataGetFunc		getfunc;
233 	MTPDataPutFunc		putfunc;
234 	void			*priv;
235 } MTPDataHandler;
236 
237 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen);
238 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data);
239 
240 /**
241  * Checks if a filename ends with ".ogg". Used in various
242  * situations when the device has no idea that it support
243  * OGG but still does.
244  *
245  * @param name string to be checked.
246  * @return 0 if this does not end with ogg, any other
247  *           value means it does.
248  */
has_ogg_extension(char * name)249 static int has_ogg_extension(char *name) {
250   char *ptype;
251 
252   if (name == NULL)
253     return 0;
254   ptype = strrchr(name,'.');
255   if (ptype == NULL)
256     return 0;
257   if (!strcasecmp (ptype, ".ogg"))
258     return 1;
259   return 0;
260 }
261 
262 /**
263  * Checks if a filename ends with ".flac". Used in various
264  * situations when the device has no idea that it support
265  * FLAC but still does.
266  *
267  * @param name string to be checked.
268  * @return 0 if this does not end with flac, any other
269  *           value means it does.
270  */
has_flac_extension(char * name)271 static int has_flac_extension(char *name) {
272   char *ptype;
273 
274   if (name == NULL)
275     return 0;
276   ptype = strrchr(name,'.');
277   if (ptype == NULL)
278     return 0;
279   if (!strcasecmp (ptype, ".flac"))
280     return 1;
281   return 0;
282 }
283 
284 
285 
286 /**
287  * Create a new file mapping entry
288  * @return a newly allocated filemapping entry.
289  */
new_filemap_entry()290 static filemap_t *new_filemap_entry()
291 {
292   filemap_t *filemap;
293 
294   filemap = (filemap_t *)malloc(sizeof(filemap_t));
295 
296   if( filemap != NULL ) {
297     filemap->description = NULL;
298     filemap->id = LIBMTP_FILETYPE_UNKNOWN;
299     filemap->ptp_id = PTP_OFC_Undefined;
300     filemap->next = NULL;
301   }
302 
303   return filemap;
304 }
305 
306 /**
307  * Register an MTP or PTP filetype for data retrieval
308  *
309  * @param description Text description of filetype
310  * @param id libmtp internal filetype id
311  * @param ptp_id PTP filetype id
312  * @return 0 for success any other value means error.
313 */
register_filetype(char const * const description,LIBMTP_filetype_t const id,uint16_t const ptp_id)314 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
315 			     uint16_t const ptp_id)
316 {
317   filemap_t *new = NULL, *current;
318 
319   // Has this LIBMTP filetype been registered before ?
320   current = g_filemap;
321   while (current != NULL) {
322     if(current->id == id) {
323       break;
324     }
325     current = current->next;
326   }
327 
328   // Create the entry
329   if(current == NULL) {
330     new = new_filemap_entry();
331     if(new == NULL) {
332       return 1;
333     }
334 
335     new->id = id;
336     if(description != NULL) {
337       new->description = strdup(description);
338     }
339     new->ptp_id = ptp_id;
340 
341     // Add the entry to the list
342     if(g_filemap == NULL) {
343       g_filemap = new;
344     } else {
345       current = g_filemap;
346       while (current->next != NULL ) current=current->next;
347       current->next = new;
348     }
349     // Update the existing entry
350   } else {
351     if (current->description != NULL) {
352       free(current->description);
353     }
354     current->description = NULL;
355     if(description != NULL) {
356       current->description = strdup(description);
357     }
358     current->ptp_id = ptp_id;
359   }
360 
361   return 0;
362 }
363 
init_filemap()364 static void init_filemap()
365 {
366   register_filetype("Folder", LIBMTP_FILETYPE_FOLDER, PTP_OFC_Association);
367   register_filetype("MediaCard", LIBMTP_FILETYPE_MEDIACARD, PTP_OFC_MTP_MediaCard);
368   register_filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV);
369   register_filetype("ISO MPEG-1 Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3);
370   register_filetype("ISO MPEG-1 Audio Layer 2", LIBMTP_FILETYPE_MP2, PTP_OFC_MTP_MP2);
371   register_filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA);
372   register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);
373   register_filetype("Free Lossless Audio Codec (FLAC)", LIBMTP_FILETYPE_FLAC, PTP_OFC_MTP_FLAC);
374   register_filetype("Advanced Audio Coding (AAC)/MPEG-2 Part 7/MPEG-4 Part 3", LIBMTP_FILETYPE_AAC, PTP_OFC_MTP_AAC);
375   register_filetype("MPEG-4 Part 14 Container Format (Audio Emphasis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
376   register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Emphasis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
377   register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);
378   register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);
379   register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);
380   register_filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI);
381   register_filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG);
382   register_filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF);
383   register_filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT);
384   register_filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo);
385   register_filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG);
386   register_filetype("JP2 file", LIBMTP_FILETYPE_JP2, PTP_OFC_JP2);
387   register_filetype("JPX file", LIBMTP_FILETYPE_JPX, PTP_OFC_JPX);
388   register_filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF);
389   register_filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF);
390   register_filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP);
391   register_filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF);
392   register_filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT);
393   register_filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG);
394   register_filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat);
395   register_filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1);
396   register_filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2);
397   register_filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2);
398   register_filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3);
399   register_filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable);
400   register_filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text);
401   register_filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML);
402   register_filetype("XML file", LIBMTP_FILETYPE_XML, PTP_OFC_MTP_XMLDocument);
403   register_filetype("DOC file", LIBMTP_FILETYPE_DOC, PTP_OFC_MTP_MSWordDocument);
404   register_filetype("XLS file", LIBMTP_FILETYPE_XLS, PTP_OFC_MTP_MSExcelSpreadsheetXLS);
405   register_filetype("PPT file", LIBMTP_FILETYPE_PPT, PTP_OFC_MTP_MSPowerpointPresentationPPT);
406   register_filetype("MHT file", LIBMTP_FILETYPE_MHT, PTP_OFC_MTP_MHTCompiledHTMLDocument);
407   register_filetype("Firmware file", LIBMTP_FILETYPE_FIRMWARE, PTP_OFC_MTP_Firmware);
408   register_filetype("Abstract Album file", LIBMTP_FILETYPE_ALBUM, PTP_OFC_MTP_AbstractAudioAlbum);
409   register_filetype("Abstract Playlist file", LIBMTP_FILETYPE_PLAYLIST, PTP_OFC_MTP_AbstractAudioVideoPlaylist);
410   register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);
411 }
412 
413 /**
414  * Returns the PTP filetype that maps to a certain libmtp internal file type.
415  * @param intype the MTP library interface type
416  * @return the PTP (libgphoto2) interface type
417  */
map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)418 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
419 {
420   filemap_t *current;
421 
422   current = g_filemap;
423 
424   while (current != NULL) {
425     if(current->id == intype) {
426       return current->ptp_id;
427     }
428     current = current->next;
429   }
430   // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
431   return PTP_OFC_Undefined;
432 }
433 
434 
435 /**
436  * Returns the MTP internal interface type that maps to a certain ptp
437  * interface type.
438  * @param intype the PTP (libgphoto2) interface type
439  * @return the MTP library interface type
440  */
map_ptp_type_to_libmtp_type(uint16_t intype)441 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
442 {
443   filemap_t *current;
444 
445   current = g_filemap;
446 
447   while (current != NULL) {
448     if(current->ptp_id == intype) {
449       return current->id;
450     }
451     current = current->next;
452   }
453   // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
454   return LIBMTP_FILETYPE_UNKNOWN;
455 }
456 
457 /**
458  * Create a new property mapping entry
459  * @return a newly allocated propertymapping entry.
460  */
new_propertymap_entry()461 static propertymap_t *new_propertymap_entry()
462 {
463   propertymap_t *propertymap;
464 
465   propertymap = (propertymap_t *)malloc(sizeof(propertymap_t));
466 
467   if( propertymap != NULL ) {
468     propertymap->description = NULL;
469     propertymap->id = LIBMTP_PROPERTY_UNKNOWN;
470     propertymap->ptp_id = 0;
471     propertymap->next = NULL;
472   }
473 
474   return propertymap;
475 }
476 
477 /**
478  * Register an MTP or PTP property for data retrieval
479  *
480  * @param description Text description of property
481  * @param id libmtp internal property id
482  * @param ptp_id PTP property id
483  * @return 0 for success any other value means error.
484 */
register_property(char const * const description,LIBMTP_property_t const id,uint16_t const ptp_id)485 static int register_property(char const * const description, LIBMTP_property_t const id,
486 			     uint16_t const ptp_id)
487 {
488   propertymap_t *new = NULL, *current;
489 
490   // Has this LIBMTP propety been registered before ?
491   current = g_propertymap;
492   while (current != NULL) {
493     if(current->id == id) {
494       break;
495     }
496     current = current->next;
497   }
498 
499   // Create the entry
500   if(current == NULL) {
501     new = new_propertymap_entry();
502     if(new == NULL) {
503       return 1;
504     }
505 
506     new->id = id;
507     if(description != NULL) {
508       new->description = strdup(description);
509     }
510     new->ptp_id = ptp_id;
511 
512     // Add the entry to the list
513     if(g_propertymap == NULL) {
514       g_propertymap = new;
515     } else {
516       current = g_propertymap;
517       while (current->next != NULL ) current=current->next;
518       current->next = new;
519     }
520     // Update the existing entry
521   } else {
522     if (current->description != NULL) {
523       free(current->description);
524     }
525     current->description = NULL;
526     if(description != NULL) {
527       current->description = strdup(description);
528     }
529     current->ptp_id = ptp_id;
530   }
531 
532   return 0;
533 }
534 
init_propertymap()535 static void init_propertymap()
536 {
537   register_property("Storage ID", LIBMTP_PROPERTY_StorageID, PTP_OPC_StorageID);
538   register_property("Object Format", LIBMTP_PROPERTY_ObjectFormat, PTP_OPC_ObjectFormat);
539   register_property("Protection Status", LIBMTP_PROPERTY_ProtectionStatus, PTP_OPC_ProtectionStatus);
540   register_property("Object Size", LIBMTP_PROPERTY_ObjectSize, PTP_OPC_ObjectSize);
541   register_property("Association Type", LIBMTP_PROPERTY_AssociationType, PTP_OPC_AssociationType);
542   register_property("Association Desc", LIBMTP_PROPERTY_AssociationDesc, PTP_OPC_AssociationDesc);
543   register_property("Object File Name", LIBMTP_PROPERTY_ObjectFileName, PTP_OPC_ObjectFileName);
544   register_property("Date Created", LIBMTP_PROPERTY_DateCreated, PTP_OPC_DateCreated);
545   register_property("Date Modified", LIBMTP_PROPERTY_DateModified, PTP_OPC_DateModified);
546   register_property("Keywords", LIBMTP_PROPERTY_Keywords, PTP_OPC_Keywords);
547   register_property("Parent Object", LIBMTP_PROPERTY_ParentObject, PTP_OPC_ParentObject);
548   register_property("Allowed Folder Contents", LIBMTP_PROPERTY_AllowedFolderContents, PTP_OPC_AllowedFolderContents);
549   register_property("Hidden", LIBMTP_PROPERTY_Hidden, PTP_OPC_Hidden);
550   register_property("System Object", LIBMTP_PROPERTY_SystemObject, PTP_OPC_SystemObject);
551   register_property("Persistant Unique Object Identifier", LIBMTP_PROPERTY_PersistantUniqueObjectIdentifier, PTP_OPC_PersistantUniqueObjectIdentifier);
552   register_property("Sync ID", LIBMTP_PROPERTY_SyncID, PTP_OPC_SyncID);
553   register_property("Property Bag", LIBMTP_PROPERTY_PropertyBag, PTP_OPC_PropertyBag);
554   register_property("Name", LIBMTP_PROPERTY_Name, PTP_OPC_Name);
555   register_property("Created By", LIBMTP_PROPERTY_CreatedBy, PTP_OPC_CreatedBy);
556   register_property("Artist", LIBMTP_PROPERTY_Artist, PTP_OPC_Artist);
557   register_property("Date Authored", LIBMTP_PROPERTY_DateAuthored, PTP_OPC_DateAuthored);
558   register_property("Description", LIBMTP_PROPERTY_Description, PTP_OPC_Description);
559   register_property("URL Reference", LIBMTP_PROPERTY_URLReference, PTP_OPC_URLReference);
560   register_property("Language Locale", LIBMTP_PROPERTY_LanguageLocale, PTP_OPC_LanguageLocale);
561   register_property("Copyright Information", LIBMTP_PROPERTY_CopyrightInformation, PTP_OPC_CopyrightInformation);
562   register_property("Source", LIBMTP_PROPERTY_Source, PTP_OPC_Source);
563   register_property("Origin Location", LIBMTP_PROPERTY_OriginLocation, PTP_OPC_OriginLocation);
564   register_property("Date Added", LIBMTP_PROPERTY_DateAdded, PTP_OPC_DateAdded);
565   register_property("Non Consumable", LIBMTP_PROPERTY_NonConsumable, PTP_OPC_NonConsumable);
566   register_property("Corrupt Or Unplayable", LIBMTP_PROPERTY_CorruptOrUnplayable, PTP_OPC_CorruptOrUnplayable);
567   register_property("Producer Serial Number", LIBMTP_PROPERTY_ProducerSerialNumber, PTP_OPC_ProducerSerialNumber);
568   register_property("Representative Sample Format", LIBMTP_PROPERTY_RepresentativeSampleFormat, PTP_OPC_RepresentativeSampleFormat);
569   register_property("Representative Sample Sise", LIBMTP_PROPERTY_RepresentativeSampleSize, PTP_OPC_RepresentativeSampleSize);
570   register_property("Representative Sample Height", LIBMTP_PROPERTY_RepresentativeSampleHeight, PTP_OPC_RepresentativeSampleHeight);
571   register_property("Representative Sample Width", LIBMTP_PROPERTY_RepresentativeSampleWidth, PTP_OPC_RepresentativeSampleWidth);
572   register_property("Representative Sample Duration", LIBMTP_PROPERTY_RepresentativeSampleDuration, PTP_OPC_RepresentativeSampleDuration);
573   register_property("Representative Sample Data", LIBMTP_PROPERTY_RepresentativeSampleData, PTP_OPC_RepresentativeSampleData);
574   register_property("Width", LIBMTP_PROPERTY_Width, PTP_OPC_Width);
575   register_property("Height", LIBMTP_PROPERTY_Height, PTP_OPC_Height);
576   register_property("Duration", LIBMTP_PROPERTY_Duration, PTP_OPC_Duration);
577   register_property("Rating", LIBMTP_PROPERTY_Rating, PTP_OPC_Rating);
578   register_property("Track", LIBMTP_PROPERTY_Track, PTP_OPC_Track);
579   register_property("Genre", LIBMTP_PROPERTY_Genre, PTP_OPC_Genre);
580   register_property("Credits", LIBMTP_PROPERTY_Credits, PTP_OPC_Credits);
581   register_property("Lyrics", LIBMTP_PROPERTY_Lyrics, PTP_OPC_Lyrics);
582   register_property("Subscription Content ID", LIBMTP_PROPERTY_SubscriptionContentID, PTP_OPC_SubscriptionContentID);
583   register_property("Produced By", LIBMTP_PROPERTY_ProducedBy, PTP_OPC_ProducedBy);
584   register_property("Use Count", LIBMTP_PROPERTY_UseCount, PTP_OPC_UseCount);
585   register_property("Skip Count", LIBMTP_PROPERTY_SkipCount, PTP_OPC_SkipCount);
586   register_property("Last Accessed", LIBMTP_PROPERTY_LastAccessed, PTP_OPC_LastAccessed);
587   register_property("Parental Rating", LIBMTP_PROPERTY_ParentalRating, PTP_OPC_ParentalRating);
588   register_property("Meta Genre", LIBMTP_PROPERTY_MetaGenre, PTP_OPC_MetaGenre);
589   register_property("Composer", LIBMTP_PROPERTY_Composer, PTP_OPC_Composer);
590   register_property("Effective Rating", LIBMTP_PROPERTY_EffectiveRating, PTP_OPC_EffectiveRating);
591   register_property("Subtitle", LIBMTP_PROPERTY_Subtitle, PTP_OPC_Subtitle);
592   register_property("Original Release Date", LIBMTP_PROPERTY_OriginalReleaseDate, PTP_OPC_OriginalReleaseDate);
593   register_property("Album Name", LIBMTP_PROPERTY_AlbumName, PTP_OPC_AlbumName);
594   register_property("Album Artist", LIBMTP_PROPERTY_AlbumArtist, PTP_OPC_AlbumArtist);
595   register_property("Mood", LIBMTP_PROPERTY_Mood, PTP_OPC_Mood);
596   register_property("DRM Status", LIBMTP_PROPERTY_DRMStatus, PTP_OPC_DRMStatus);
597   register_property("Sub Description", LIBMTP_PROPERTY_SubDescription, PTP_OPC_SubDescription);
598   register_property("Is Cropped", LIBMTP_PROPERTY_IsCropped, PTP_OPC_IsCropped);
599   register_property("Is Color Corrected", LIBMTP_PROPERTY_IsColorCorrected, PTP_OPC_IsColorCorrected);
600   register_property("Image Bit Depth", LIBMTP_PROPERTY_ImageBitDepth, PTP_OPC_ImageBitDepth);
601   register_property("f Number", LIBMTP_PROPERTY_Fnumber, PTP_OPC_Fnumber);
602   register_property("Exposure Time", LIBMTP_PROPERTY_ExposureTime, PTP_OPC_ExposureTime);
603   register_property("Exposure Index", LIBMTP_PROPERTY_ExposureIndex, PTP_OPC_ExposureIndex);
604   register_property("Display Name", LIBMTP_PROPERTY_DisplayName, PTP_OPC_DisplayName);
605   register_property("Body Text", LIBMTP_PROPERTY_BodyText, PTP_OPC_BodyText);
606   register_property("Subject", LIBMTP_PROPERTY_Subject, PTP_OPC_Subject);
607   register_property("Priority", LIBMTP_PROPERTY_Priority, PTP_OPC_Priority);
608   register_property("Given Name", LIBMTP_PROPERTY_GivenName, PTP_OPC_GivenName);
609   register_property("Middle Names", LIBMTP_PROPERTY_MiddleNames, PTP_OPC_MiddleNames);
610   register_property("Family Name", LIBMTP_PROPERTY_FamilyName, PTP_OPC_FamilyName);
611   register_property("Prefix", LIBMTP_PROPERTY_Prefix, PTP_OPC_Prefix);
612   register_property("Suffix", LIBMTP_PROPERTY_Suffix, PTP_OPC_Suffix);
613   register_property("Phonetic Given Name", LIBMTP_PROPERTY_PhoneticGivenName, PTP_OPC_PhoneticGivenName);
614   register_property("Phonetic Family Name", LIBMTP_PROPERTY_PhoneticFamilyName, PTP_OPC_PhoneticFamilyName);
615   register_property("Email: Primary", LIBMTP_PROPERTY_EmailPrimary, PTP_OPC_EmailPrimary);
616   register_property("Email: Personal 1", LIBMTP_PROPERTY_EmailPersonal1, PTP_OPC_EmailPersonal1);
617   register_property("Email: Personal 2", LIBMTP_PROPERTY_EmailPersonal2, PTP_OPC_EmailPersonal2);
618   register_property("Email: Business 1", LIBMTP_PROPERTY_EmailBusiness1, PTP_OPC_EmailBusiness1);
619   register_property("Email: Business 2", LIBMTP_PROPERTY_EmailBusiness2, PTP_OPC_EmailBusiness2);
620   register_property("Email: Others", LIBMTP_PROPERTY_EmailOthers, PTP_OPC_EmailOthers);
621   register_property("Phone Number: Primary", LIBMTP_PROPERTY_PhoneNumberPrimary, PTP_OPC_PhoneNumberPrimary);
622   register_property("Phone Number: Personal", LIBMTP_PROPERTY_PhoneNumberPersonal, PTP_OPC_PhoneNumberPersonal);
623   register_property("Phone Number: Personal 2", LIBMTP_PROPERTY_PhoneNumberPersonal2, PTP_OPC_PhoneNumberPersonal2);
624   register_property("Phone Number: Business", LIBMTP_PROPERTY_PhoneNumberBusiness, PTP_OPC_PhoneNumberBusiness);
625   register_property("Phone Number: Business 2", LIBMTP_PROPERTY_PhoneNumberBusiness2, PTP_OPC_PhoneNumberBusiness2);
626   register_property("Phone Number: Mobile", LIBMTP_PROPERTY_PhoneNumberMobile, PTP_OPC_PhoneNumberMobile);
627   register_property("Phone Number: Mobile 2", LIBMTP_PROPERTY_PhoneNumberMobile2, PTP_OPC_PhoneNumberMobile2);
628   register_property("Fax Number: Primary", LIBMTP_PROPERTY_FaxNumberPrimary, PTP_OPC_FaxNumberPrimary);
629   register_property("Fax Number: Personal", LIBMTP_PROPERTY_FaxNumberPersonal, PTP_OPC_FaxNumberPersonal);
630   register_property("Fax Number: Business", LIBMTP_PROPERTY_FaxNumberBusiness, PTP_OPC_FaxNumberBusiness);
631   register_property("Pager Number", LIBMTP_PROPERTY_PagerNumber, PTP_OPC_PagerNumber);
632   register_property("Phone Number: Others", LIBMTP_PROPERTY_PhoneNumberOthers, PTP_OPC_PhoneNumberOthers);
633   register_property("Primary Web Address", LIBMTP_PROPERTY_PrimaryWebAddress, PTP_OPC_PrimaryWebAddress);
634   register_property("Personal Web Address", LIBMTP_PROPERTY_PersonalWebAddress, PTP_OPC_PersonalWebAddress);
635   register_property("Business Web Address", LIBMTP_PROPERTY_BusinessWebAddress, PTP_OPC_BusinessWebAddress);
636   register_property("Instant Messenger Address 1", LIBMTP_PROPERTY_InstantMessengerAddress, PTP_OPC_InstantMessengerAddress);
637   register_property("Instant Messenger Address 2", LIBMTP_PROPERTY_InstantMessengerAddress2, PTP_OPC_InstantMessengerAddress2);
638   register_property("Instant Messenger Address 3", LIBMTP_PROPERTY_InstantMessengerAddress3, PTP_OPC_InstantMessengerAddress3);
639   register_property("Postal Address: Personal: Full", LIBMTP_PROPERTY_PostalAddressPersonalFull, PTP_OPC_PostalAddressPersonalFull);
640   register_property("Postal Address: Personal: Line 1", LIBMTP_PROPERTY_PostalAddressPersonalFullLine1, PTP_OPC_PostalAddressPersonalFullLine1);
641   register_property("Postal Address: Personal: Line 2", LIBMTP_PROPERTY_PostalAddressPersonalFullLine2, PTP_OPC_PostalAddressPersonalFullLine2);
642   register_property("Postal Address: Personal: City", LIBMTP_PROPERTY_PostalAddressPersonalFullCity, PTP_OPC_PostalAddressPersonalFullCity);
643   register_property("Postal Address: Personal: Region", LIBMTP_PROPERTY_PostalAddressPersonalFullRegion, PTP_OPC_PostalAddressPersonalFullRegion);
644   register_property("Postal Address: Personal: Postal Code", LIBMTP_PROPERTY_PostalAddressPersonalFullPostalCode, PTP_OPC_PostalAddressPersonalFullPostalCode);
645   register_property("Postal Address: Personal: Country", LIBMTP_PROPERTY_PostalAddressPersonalFullCountry, PTP_OPC_PostalAddressPersonalFullCountry);
646   register_property("Postal Address: Business: Full", LIBMTP_PROPERTY_PostalAddressBusinessFull, PTP_OPC_PostalAddressBusinessFull);
647   register_property("Postal Address: Business: Line 1", LIBMTP_PROPERTY_PostalAddressBusinessLine1, PTP_OPC_PostalAddressBusinessLine1);
648   register_property("Postal Address: Business: Line 2", LIBMTP_PROPERTY_PostalAddressBusinessLine2, PTP_OPC_PostalAddressBusinessLine2);
649   register_property("Postal Address: Business: City", LIBMTP_PROPERTY_PostalAddressBusinessCity, PTP_OPC_PostalAddressBusinessCity);
650   register_property("Postal Address: Business: Region", LIBMTP_PROPERTY_PostalAddressBusinessRegion, PTP_OPC_PostalAddressBusinessRegion);
651   register_property("Postal Address: Business: Postal Code", LIBMTP_PROPERTY_PostalAddressBusinessPostalCode, PTP_OPC_PostalAddressBusinessPostalCode);
652   register_property("Postal Address: Business: Country", LIBMTP_PROPERTY_PostalAddressBusinessCountry, PTP_OPC_PostalAddressBusinessCountry);
653   register_property("Postal Address: Other: Full", LIBMTP_PROPERTY_PostalAddressOtherFull, PTP_OPC_PostalAddressOtherFull);
654   register_property("Postal Address: Other: Line 1", LIBMTP_PROPERTY_PostalAddressOtherLine1, PTP_OPC_PostalAddressOtherLine1);
655   register_property("Postal Address: Other: Line 2", LIBMTP_PROPERTY_PostalAddressOtherLine2, PTP_OPC_PostalAddressOtherLine2);
656   register_property("Postal Address: Other: City", LIBMTP_PROPERTY_PostalAddressOtherCity, PTP_OPC_PostalAddressOtherCity);
657   register_property("Postal Address: Other: Region", LIBMTP_PROPERTY_PostalAddressOtherRegion, PTP_OPC_PostalAddressOtherRegion);
658   register_property("Postal Address: Other: Postal Code", LIBMTP_PROPERTY_PostalAddressOtherPostalCode, PTP_OPC_PostalAddressOtherPostalCode);
659   register_property("Postal Address: Other: Counrtry", LIBMTP_PROPERTY_PostalAddressOtherCountry, PTP_OPC_PostalAddressOtherCountry);
660   register_property("Organization Name", LIBMTP_PROPERTY_OrganizationName, PTP_OPC_OrganizationName);
661   register_property("Phonetic Organization Name", LIBMTP_PROPERTY_PhoneticOrganizationName, PTP_OPC_PhoneticOrganizationName);
662   register_property("Role", LIBMTP_PROPERTY_Role, PTP_OPC_Role);
663   register_property("Birthdate", LIBMTP_PROPERTY_Birthdate, PTP_OPC_Birthdate);
664   register_property("Message To", LIBMTP_PROPERTY_MessageTo, PTP_OPC_MessageTo);
665   register_property("Message CC", LIBMTP_PROPERTY_MessageCC, PTP_OPC_MessageCC);
666   register_property("Message BCC", LIBMTP_PROPERTY_MessageBCC, PTP_OPC_MessageBCC);
667   register_property("Message Read", LIBMTP_PROPERTY_MessageRead, PTP_OPC_MessageRead);
668   register_property("Message Received Time", LIBMTP_PROPERTY_MessageReceivedTime, PTP_OPC_MessageReceivedTime);
669   register_property("Message Sender", LIBMTP_PROPERTY_MessageSender, PTP_OPC_MessageSender);
670   register_property("Activity Begin Time", LIBMTP_PROPERTY_ActivityBeginTime, PTP_OPC_ActivityBeginTime);
671   register_property("Activity End Time", LIBMTP_PROPERTY_ActivityEndTime, PTP_OPC_ActivityEndTime);
672   register_property("Activity Location", LIBMTP_PROPERTY_ActivityLocation, PTP_OPC_ActivityLocation);
673   register_property("Activity Required Attendees", LIBMTP_PROPERTY_ActivityRequiredAttendees, PTP_OPC_ActivityRequiredAttendees);
674   register_property("Optional Attendees", LIBMTP_PROPERTY_ActivityOptionalAttendees, PTP_OPC_ActivityOptionalAttendees);
675   register_property("Activity Resources", LIBMTP_PROPERTY_ActivityResources, PTP_OPC_ActivityResources);
676   register_property("Activity Accepted", LIBMTP_PROPERTY_ActivityAccepted, PTP_OPC_ActivityAccepted);
677   register_property("Owner", LIBMTP_PROPERTY_Owner, PTP_OPC_Owner);
678   register_property("Editor", LIBMTP_PROPERTY_Editor, PTP_OPC_Editor);
679   register_property("Webmaster", LIBMTP_PROPERTY_Webmaster, PTP_OPC_Webmaster);
680   register_property("URL Source", LIBMTP_PROPERTY_URLSource, PTP_OPC_URLSource);
681   register_property("URL Destination", LIBMTP_PROPERTY_URLDestination, PTP_OPC_URLDestination);
682   register_property("Time Bookmark", LIBMTP_PROPERTY_TimeBookmark, PTP_OPC_TimeBookmark);
683   register_property("Object Bookmark", LIBMTP_PROPERTY_ObjectBookmark, PTP_OPC_ObjectBookmark);
684   register_property("Byte Bookmark", LIBMTP_PROPERTY_ByteBookmark, PTP_OPC_ByteBookmark);
685   register_property("Last Build Date", LIBMTP_PROPERTY_LastBuildDate, PTP_OPC_LastBuildDate);
686   register_property("Time To Live", LIBMTP_PROPERTY_TimetoLive, PTP_OPC_TimetoLive);
687   register_property("Media GUID", LIBMTP_PROPERTY_MediaGUID, PTP_OPC_MediaGUID);
688   register_property("Total Bit Rate", LIBMTP_PROPERTY_TotalBitRate, PTP_OPC_TotalBitRate);
689   register_property("Bit Rate Type", LIBMTP_PROPERTY_BitRateType, PTP_OPC_BitRateType);
690   register_property("Sample Rate", LIBMTP_PROPERTY_SampleRate, PTP_OPC_SampleRate);
691   register_property("Number Of Channels", LIBMTP_PROPERTY_NumberOfChannels, PTP_OPC_NumberOfChannels);
692   register_property("Audio Bit Depth", LIBMTP_PROPERTY_AudioBitDepth, PTP_OPC_AudioBitDepth);
693   register_property("Scan Depth", LIBMTP_PROPERTY_ScanDepth, PTP_OPC_ScanDepth);
694   register_property("Audio WAVE Codec", LIBMTP_PROPERTY_AudioWAVECodec, PTP_OPC_AudioWAVECodec);
695   register_property("Audio Bit Rate", LIBMTP_PROPERTY_AudioBitRate, PTP_OPC_AudioBitRate);
696   register_property("Video Four CC Codec", LIBMTP_PROPERTY_VideoFourCCCodec, PTP_OPC_VideoFourCCCodec);
697   register_property("Video Bit Rate", LIBMTP_PROPERTY_VideoBitRate, PTP_OPC_VideoBitRate);
698   register_property("Frames Per Thousand Seconds", LIBMTP_PROPERTY_FramesPerThousandSeconds, PTP_OPC_FramesPerThousandSeconds);
699   register_property("Key Frame Distance", LIBMTP_PROPERTY_KeyFrameDistance, PTP_OPC_KeyFrameDistance);
700   register_property("Buffer Size", LIBMTP_PROPERTY_BufferSize, PTP_OPC_BufferSize);
701   register_property("Encoding Quality", LIBMTP_PROPERTY_EncodingQuality, PTP_OPC_EncodingQuality);
702   register_property("Encoding Profile", LIBMTP_PROPERTY_EncodingProfile, PTP_OPC_EncodingProfile);
703   register_property("Buy flag", LIBMTP_PROPERTY_BuyFlag, PTP_OPC_BuyFlag);
704   register_property("Unknown property", LIBMTP_PROPERTY_UNKNOWN, 0);
705 }
706 
707 /**
708  * Returns the PTP property that maps to a certain libmtp internal property type.
709  * @param inproperty the MTP library interface property
710  * @return the PTP (libgphoto2) property type
711  */
map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)712 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)
713 {
714   propertymap_t *current;
715 
716   current = g_propertymap;
717 
718   while (current != NULL) {
719     if(current->id == inproperty) {
720       return current->ptp_id;
721     }
722     current = current->next;
723   }
724   return 0;
725 }
726 
727 
728 /**
729  * Returns the MTP internal interface property that maps to a certain ptp
730  * interface property.
731  * @param inproperty the PTP (libgphoto2) interface property
732  * @return the MTP library interface property
733  */
map_ptp_property_to_libmtp_property(uint16_t inproperty)734 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t inproperty)
735 {
736   propertymap_t *current;
737 
738   current = g_propertymap;
739 
740   while (current != NULL) {
741     if(current->ptp_id == inproperty) {
742       return current->id;
743     }
744     current = current->next;
745   }
746   // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
747   return LIBMTP_PROPERTY_UNKNOWN;
748 }
749 
750 
751 /**
752  * Set the debug level.
753  *
754  * By default, the debug level is set to '0' (disable).
755  */
LIBMTP_Set_Debug(int level)756 void LIBMTP_Set_Debug(int level)
757 {
758   if (LIBMTP_debug || level)
759     LIBMTP_ERROR("LIBMTP_Set_Debug: Setting debugging level to %d (0x%02x) "
760                  "(%s)\n", level, level, level ? "on" : "off");
761 
762   LIBMTP_debug = level;
763 }
764 
765 
766 /**
767  * Initialize the library. You are only supposed to call this
768  * one, before using the library for the first time in a program.
769  * Never re-initialize libmtp!
770  *
771  * The only thing this does at the moment is to initialise the
772  * filetype mapping table, as well as load MTPZ data if necessary.
773  */
LIBMTP_Init(void)774 void LIBMTP_Init(void)
775 {
776   const char *env_debug = getenv("LIBMTP_DEBUG");
777   if (env_debug) {
778     const long debug_flags = strtol(env_debug, NULL, 0);
779     if (debug_flags != LONG_MIN && debug_flags != LONG_MAX &&
780         INT_MIN <= debug_flags && debug_flags <= INT_MAX) {
781       LIBMTP_Set_Debug(debug_flags);
782     } else {
783       fprintf(stderr, "LIBMTP_Init: error setting debug flags from environment "
784                       "value \"%s\"\n", env_debug);
785     }
786   }
787 
788   init_filemap();
789   init_propertymap();
790 
791   if (mtpz_loaddata() == -1)
792     use_mtpz = 0;
793   else
794     use_mtpz = 1;
795 
796   return;
797 }
798 
799 
800 /**
801  * This helper function returns a textual description for a libmtp
802  * file type to be used in dialog boxes etc.
803  * @param intype the libmtp internal filetype to get a description for.
804  * @return a string representing the filetype, this must <b>NOT</b>
805  *         be free():ed by the caller!
806  */
LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)807 char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
808 {
809   filemap_t *current;
810 
811   current = g_filemap;
812 
813   while (current != NULL) {
814     if(current->id == intype) {
815       return current->description;
816     }
817     current = current->next;
818   }
819 
820   return "Unknown filetype";
821 }
822 
823 /**
824  * This helper function returns a textual description for a libmtp
825  * property to be used in dialog boxes etc.
826  * @param inproperty the libmtp internal property to get a description for.
827  * @return a string representing the filetype, this must <b>NOT</b>
828  *         be free():ed by the caller!
829  */
LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)830 char const * LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)
831 {
832   propertymap_t *current;
833 
834   current = g_propertymap;
835 
836   while (current != NULL) {
837     if(current->id == inproperty) {
838       return current->description;
839     }
840     current = current->next;
841   }
842 
843   return "Unknown property";
844 }
845 
846 /**
847  * This function will do its best to fit a 16bit
848  * value into a PTP object property if the property
849  * is limited in range or step sizes.
850  */
adjust_u16(uint16_t val,PTPObjectPropDesc * opd)851 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd)
852 {
853   switch (opd->FormFlag) {
854   case PTP_DPFF_Range:
855     if (val < opd->FORM.Range.MinimumValue.u16) {
856       return opd->FORM.Range.MinimumValue.u16;
857     }
858     if (val > opd->FORM.Range.MaximumValue.u16) {
859       return opd->FORM.Range.MaximumValue.u16;
860     }
861     // Round down to last step.
862     if (val % opd->FORM.Range.StepSize.u16 != 0) {
863       return val - (val % opd->FORM.Range.StepSize.u16);
864     }
865     return val;
866     break;
867   case PTP_DPFF_Enumeration:
868     {
869       int i;
870       uint16_t bestfit = opd->FORM.Enum.SupportedValue[0].u16;
871 
872       for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
873 	if (val == opd->FORM.Enum.SupportedValue[i].u16) {
874 	  return val;
875 	}
876 	// Rough guess of best fit
877 	if (opd->FORM.Enum.SupportedValue[i].u16 < val) {
878 	  bestfit = opd->FORM.Enum.SupportedValue[i].u16;
879 	}
880       }
881       // Just some default that'll work.
882       return bestfit;
883     }
884   default:
885     // Will accept any value
886     break;
887   }
888   return val;
889 }
890 
891 /**
892  * This function will do its best to fit a 32bit
893  * value into a PTP object property if the property
894  * is limited in range or step sizes.
895  */
adjust_u32(uint32_t val,PTPObjectPropDesc * opd)896 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd)
897 {
898   switch (opd->FormFlag) {
899   case PTP_DPFF_Range:
900     if (val < opd->FORM.Range.MinimumValue.u32) {
901       return opd->FORM.Range.MinimumValue.u32;
902     }
903     if (val > opd->FORM.Range.MaximumValue.u32) {
904       return opd->FORM.Range.MaximumValue.u32;
905     }
906     // Round down to last step.
907     if (val % opd->FORM.Range.StepSize.u32 != 0) {
908       return val - (val % opd->FORM.Range.StepSize.u32);
909     }
910     return val;
911     break;
912   case PTP_DPFF_Enumeration:
913     {
914       int i;
915       uint32_t bestfit = opd->FORM.Enum.SupportedValue[0].u32;
916 
917       for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
918 	if (val == opd->FORM.Enum.SupportedValue[i].u32) {
919 	  return val;
920 	}
921 	// Rough guess of best fit
922 	if (opd->FORM.Enum.SupportedValue[i].u32 < val) {
923 	  bestfit = opd->FORM.Enum.SupportedValue[i].u32;
924 	}
925       }
926       // Just some default that'll work.
927       return bestfit;
928     }
929   default:
930     // Will accept any value
931     break;
932   }
933   return val;
934 }
935 
936 /**
937  * This function returns a newly created ISO 8601 timestamp with the
938  * current time in as high precision as possible. It even adds
939  * the time zone if it can.
940  */
get_iso8601_stamp(void)941 static char *get_iso8601_stamp(void)
942 {
943   time_t curtime;
944   struct tm *loctime;
945   char tmp[64];
946 
947   curtime = time(NULL);
948   loctime = localtime(&curtime);
949   strftime (tmp, sizeof(tmp), "%Y%m%dT%H%M%S.0%z", loctime);
950   return strdup(tmp);
951 }
952 
953 /**
954  * Gets the allowed values (range or enum) for a property
955  * @param device a pointer to an MTP device
956  * @param property the property to query
957  * @param filetype the filetype of the object you want to set values for
958  * @param allowed_vals pointer to a LIBMTP_allowed_values_t struct to
959  *        receive the allowed values.  Call LIBMTP_destroy_allowed_values_t
960  *        on this on successful completion.
961  * @return 0 on success, any other value means failure
962  */
LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t * device,LIBMTP_property_t const property,LIBMTP_filetype_t const filetype,LIBMTP_allowed_values_t * allowed_vals)963 int LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
964             LIBMTP_filetype_t const filetype, LIBMTP_allowed_values_t *allowed_vals)
965 {
966   PTPObjectPropDesc opd;
967   uint16_t ret = 0;
968 
969   ret = ptp_mtp_getobjectpropdesc(device->params, map_libmtp_property_to_ptp_property(property), map_libmtp_type_to_ptp_type(filetype), &opd);
970   if (ret != PTP_RC_OK) {
971     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Allowed_Property_Values(): could not get property description.");
972     return -1;
973   }
974 
975   if (opd.FormFlag == PTP_OPFF_Enumeration) {
976     int i = 0;
977 
978     allowed_vals->is_range = 0;
979     allowed_vals->num_entries = opd.FORM.Enum.NumberOfValues;
980 
981     switch (opd.DataType)
982     {
983       case PTP_DTC_INT8:
984         allowed_vals->i8vals = malloc(sizeof(int8_t) * opd.FORM.Enum.NumberOfValues);
985         allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
986         break;
987       case PTP_DTC_UINT8:
988         allowed_vals->u8vals = malloc(sizeof(uint8_t) * opd.FORM.Enum.NumberOfValues);
989         allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
990         break;
991       case PTP_DTC_INT16:
992         allowed_vals->i16vals = malloc(sizeof(int16_t) * opd.FORM.Enum.NumberOfValues);
993         allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
994         break;
995       case PTP_DTC_UINT16:
996         allowed_vals->u16vals = malloc(sizeof(uint16_t) * opd.FORM.Enum.NumberOfValues);
997         allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
998         break;
999       case PTP_DTC_INT32:
1000         allowed_vals->i32vals = malloc(sizeof(int32_t) * opd.FORM.Enum.NumberOfValues);
1001         allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1002         break;
1003       case PTP_DTC_UINT32:
1004         allowed_vals->u32vals = malloc(sizeof(uint32_t) * opd.FORM.Enum.NumberOfValues);
1005         allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1006         break;
1007       case PTP_DTC_INT64:
1008         allowed_vals->i64vals = malloc(sizeof(int64_t) * opd.FORM.Enum.NumberOfValues);
1009         allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1010         break;
1011       case PTP_DTC_UINT64:
1012         allowed_vals->u64vals = malloc(sizeof(uint64_t) * opd.FORM.Enum.NumberOfValues);
1013         allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1014         break;
1015     }
1016 
1017     for (i = 0; i < opd.FORM.Enum.NumberOfValues; i++) {
1018       switch (opd.DataType)
1019       {
1020         case PTP_DTC_INT8:
1021           allowed_vals->i8vals[i] = opd.FORM.Enum.SupportedValue[i].i8;
1022           break;
1023         case PTP_DTC_UINT8:
1024           allowed_vals->u8vals[i] = opd.FORM.Enum.SupportedValue[i].u8;
1025           break;
1026         case PTP_DTC_INT16:
1027           allowed_vals->i16vals[i] = opd.FORM.Enum.SupportedValue[i].i16;
1028           break;
1029         case PTP_DTC_UINT16:
1030           allowed_vals->u16vals[i] = opd.FORM.Enum.SupportedValue[i].u16;
1031           break;
1032         case PTP_DTC_INT32:
1033           allowed_vals->i32vals[i] = opd.FORM.Enum.SupportedValue[i].i32;
1034           break;
1035         case PTP_DTC_UINT32:
1036           allowed_vals->u32vals[i] = opd.FORM.Enum.SupportedValue[i].u32;
1037           break;
1038         case PTP_DTC_INT64:
1039           allowed_vals->i64vals[i] = opd.FORM.Enum.SupportedValue[i].i64;
1040           break;
1041         case PTP_DTC_UINT64:
1042           allowed_vals->u64vals[i] = opd.FORM.Enum.SupportedValue[i].u64;
1043           break;
1044       }
1045     }
1046     ptp_free_objectpropdesc(&opd);
1047     return 0;
1048   } else if (opd.FormFlag == PTP_OPFF_Range) {
1049     allowed_vals->is_range = 1;
1050 
1051     switch (opd.DataType)
1052     {
1053       case PTP_DTC_INT8:
1054         allowed_vals->i8min = opd.FORM.Range.MinimumValue.i8;
1055         allowed_vals->i8max = opd.FORM.Range.MaximumValue.i8;
1056         allowed_vals->i8step = opd.FORM.Range.StepSize.i8;
1057         allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
1058         break;
1059       case PTP_DTC_UINT8:
1060         allowed_vals->u8min = opd.FORM.Range.MinimumValue.u8;
1061         allowed_vals->u8max = opd.FORM.Range.MaximumValue.u8;
1062         allowed_vals->u8step = opd.FORM.Range.StepSize.u8;
1063         allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
1064         break;
1065       case PTP_DTC_INT16:
1066         allowed_vals->i16min = opd.FORM.Range.MinimumValue.i16;
1067         allowed_vals->i16max = opd.FORM.Range.MaximumValue.i16;
1068         allowed_vals->i16step = opd.FORM.Range.StepSize.i16;
1069         allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
1070         break;
1071       case PTP_DTC_UINT16:
1072         allowed_vals->u16min = opd.FORM.Range.MinimumValue.u16;
1073         allowed_vals->u16max = opd.FORM.Range.MaximumValue.u16;
1074         allowed_vals->u16step = opd.FORM.Range.StepSize.u16;
1075         allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
1076         break;
1077       case PTP_DTC_INT32:
1078         allowed_vals->i32min = opd.FORM.Range.MinimumValue.i32;
1079         allowed_vals->i32max = opd.FORM.Range.MaximumValue.i32;
1080         allowed_vals->i32step = opd.FORM.Range.StepSize.i32;
1081         allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1082         break;
1083       case PTP_DTC_UINT32:
1084         allowed_vals->u32min = opd.FORM.Range.MinimumValue.u32;
1085         allowed_vals->u32max = opd.FORM.Range.MaximumValue.u32;
1086         allowed_vals->u32step = opd.FORM.Range.StepSize.u32;
1087         allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1088         break;
1089       case PTP_DTC_INT64:
1090         allowed_vals->i64min = opd.FORM.Range.MinimumValue.i64;
1091         allowed_vals->i64max = opd.FORM.Range.MaximumValue.i64;
1092         allowed_vals->i64step = opd.FORM.Range.StepSize.i64;
1093         allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1094         break;
1095       case PTP_DTC_UINT64:
1096         allowed_vals->u64min = opd.FORM.Range.MinimumValue.u64;
1097         allowed_vals->u64max = opd.FORM.Range.MaximumValue.u64;
1098         allowed_vals->u64step = opd.FORM.Range.StepSize.u64;
1099         allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1100         break;
1101     }
1102     return 0;
1103   } else
1104     return -1;
1105 }
1106 
1107 /**
1108  * Destroys a LIBMTP_allowed_values_t struct
1109  * @param allowed_vals the struct to destroy
1110  */
LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t * allowed_vals)1111 void LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t *allowed_vals)
1112 {
1113   if (!allowed_vals->is_range)
1114   {
1115     switch (allowed_vals->datatype)
1116     {
1117       case LIBMTP_DATATYPE_INT8:
1118         if (allowed_vals->i8vals)
1119           free(allowed_vals->i8vals);
1120         break;
1121       case LIBMTP_DATATYPE_UINT8:
1122         if (allowed_vals->u8vals)
1123           free(allowed_vals->u8vals);
1124         break;
1125       case LIBMTP_DATATYPE_INT16:
1126         if (allowed_vals->i16vals)
1127           free(allowed_vals->i16vals);
1128         break;
1129       case LIBMTP_DATATYPE_UINT16:
1130         if (allowed_vals->u16vals)
1131           free(allowed_vals->u16vals);
1132         break;
1133       case LIBMTP_DATATYPE_INT32:
1134         if (allowed_vals->i32vals)
1135           free(allowed_vals->i32vals);
1136         break;
1137       case LIBMTP_DATATYPE_UINT32:
1138         if (allowed_vals->u32vals)
1139           free(allowed_vals->u32vals);
1140         break;
1141       case LIBMTP_DATATYPE_INT64:
1142         if (allowed_vals->i64vals)
1143           free(allowed_vals->i64vals);
1144         break;
1145       case LIBMTP_DATATYPE_UINT64:
1146         if (allowed_vals->u64vals)
1147           free(allowed_vals->u64vals);
1148         break;
1149     }
1150   }
1151 }
1152 
1153 /**
1154  * Determine if a property is supported for a given file type
1155  * @param device a pointer to an MTP device
1156  * @param property the property to query
1157  * @param filetype the filetype of the object you want to set values for
1158  * @return 0 if not supported, positive if supported, negative on error
1159  */
LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t * device,LIBMTP_property_t const property,LIBMTP_filetype_t const filetype)1160 int LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
1161             LIBMTP_filetype_t const filetype)
1162 {
1163   uint16_t *props = NULL;
1164   uint32_t propcnt = 0;
1165   uint16_t ret = 0;
1166   int i = 0;
1167   int supported = 0;
1168   uint16_t ptp_prop = map_libmtp_property_to_ptp_property(property);
1169 
1170   if (!ptp_operation_issupported(device->params, PTP_OC_MTP_GetObjectPropsSupported))
1171     return 0;
1172 
1173   ret = ptp_mtp_getobjectpropssupported(device->params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
1174   if (ret != PTP_RC_OK) {
1175     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Is_Property_Supported(): could not get properties supported.");
1176     return -1;
1177   }
1178 
1179 	for (i = 0; i < propcnt; i++) {
1180     if (props[i] == ptp_prop) {
1181       supported = 1;
1182       break;
1183     }
1184   }
1185 
1186   free(props);
1187 
1188   return supported;
1189 }
1190 
1191 /**
1192  * Retrieves a string from an object
1193  *
1194  * @param device a pointer to an MTP device.
1195  * @param object_id Object reference
1196  * @param attribute_id MTP attribute ID
1197  * @return valid string or NULL on failure. The returned string
1198  *         must bee <code>free()</code>:ed by the caller after
1199  *         use.
1200  */
LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id)1201 char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1202 				    LIBMTP_property_t const attribute_id)
1203 {
1204   return get_string_from_object(device, object_id, attribute_id);
1205 }
1206 
1207 /**
1208 * Retrieves an unsigned 64-bit integer from an object attribute
1209  *
1210  * @param device a pointer to an MTP device.
1211  * @param object_id Object reference
1212  * @param attribute_id MTP attribute ID
1213  * @param value_default Default value to return on failure
1214  * @return the value
1215  */
LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint64_t const value_default)1216 uint64_t LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1217                                     LIBMTP_property_t const attribute_id, uint64_t const value_default)
1218 {
1219   return get_u64_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1220 }
1221 
1222 /**
1223  * Retrieves an unsigned 32-bit integer from an object attribute
1224  *
1225  * @param device a pointer to an MTP device.
1226  * @param object_id Object reference
1227  * @param attribute_id MTP attribute ID
1228  * @param value_default Default value to return on failure
1229  * @return the value
1230  */
LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint32_t const value_default)1231 uint32_t LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1232 				    LIBMTP_property_t const attribute_id, uint32_t const value_default)
1233 {
1234   return get_u32_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1235 }
1236 
1237 /**
1238  * Retrieves an unsigned 16-bit integer from an object attribute
1239  *
1240  * @param device a pointer to an MTP device.
1241  * @param object_id Object reference
1242  * @param attribute_id MTP attribute ID
1243  * @param value_default Default value to return on failure
1244  * @return a value
1245  */
LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint16_t const value_default)1246 uint16_t LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1247 				    LIBMTP_property_t const attribute_id, uint16_t const value_default)
1248 {
1249   return get_u16_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1250 }
1251 
1252 /**
1253  * Retrieves an unsigned 8-bit integer from an object attribute
1254  *
1255  * @param device a pointer to an MTP device.
1256  * @param object_id Object reference
1257  * @param attribute_id MTP attribute ID
1258  * @param value_default Default value to return on failure
1259  * @return a value
1260  */
LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint8_t const value_default)1261 uint8_t LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1262 				  LIBMTP_property_t const attribute_id, uint8_t const value_default)
1263 {
1264   return get_u8_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1265 }
1266 
1267 /**
1268  * Sets an object attribute from a string
1269  *
1270  * @param device a pointer to an MTP device.
1271  * @param object_id Object reference
1272  * @param attribute_id MTP attribute ID
1273  * @param string string value to set
1274  * @return 0 on success, any other value means failure
1275  */
LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,char const * const string)1276 int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1277 			     LIBMTP_property_t const attribute_id, char const * const string)
1278 {
1279   return set_object_string(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), string);
1280 }
1281 
1282 
1283 /**
1284  * Sets an object attribute from an unsigned 32-bit integer
1285  *
1286  * @param device a pointer to an MTP device.
1287  * @param object_id Object reference
1288  * @param attribute_id MTP attribute ID
1289  * @param value 32-bit unsigned integer to set
1290  * @return 0 on success, any other value means failure
1291  */
LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint32_t const value)1292 int LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1293 			  LIBMTP_property_t const attribute_id, uint32_t const value)
1294 {
1295   return set_object_u32(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1296 }
1297 
1298 /**
1299  * Sets an object attribute from an unsigned 16-bit integer
1300  *
1301  * @param device a pointer to an MTP device.
1302  * @param object_id Object reference
1303  * @param attribute_id MTP attribute ID
1304  * @param value 16-bit unsigned integer to set
1305  * @return 0 on success, any other value means failure
1306  */
LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint16_t const value)1307 int LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1308 			  LIBMTP_property_t const attribute_id, uint16_t const value)
1309 {
1310   return set_object_u16(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1311 }
1312 
1313 /**
1314  * Sets an object attribute from an unsigned 8-bit integer
1315  *
1316  * @param device a pointer to an MTP device.
1317  * @param object_id Object reference
1318  * @param attribute_id MTP attribute ID
1319  * @param value 8-bit unsigned integer to set
1320  * @return 0 on success, any other value means failure
1321  */
LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint8_t const value)1322 int LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1323 			 LIBMTP_property_t const attribute_id, uint8_t const value)
1324 {
1325   return set_object_u8(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1326 }
1327 
1328 /**
1329  * Retrieves a string from an object
1330  *
1331  * @param device a pointer to an MTP device.
1332  * @param object_id Object reference
1333  * @param attribute_id PTP attribute ID
1334  * @return valid string or NULL on failure. The returned string
1335  *         must bee <code>free()</code>:ed by the caller after
1336  *         use.
1337  */
get_string_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id)1338 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1339 				    uint16_t const attribute_id)
1340 {
1341   PTPPropertyValue propval;
1342   char *retstring = NULL;
1343   PTPParams *params;
1344   uint16_t ret;
1345   MTPProperties *prop;
1346 
1347   if (!device || !object_id)
1348     return NULL;
1349 
1350   params = (PTPParams *) device->params;
1351 
1352   prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1353   if (prop) {
1354     if (prop->propval.str != NULL)
1355       return strdup(prop->propval.str);
1356     else
1357       return NULL;
1358   }
1359 
1360   ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1361   if (ret == PTP_RC_OK) {
1362     if (propval.str != NULL) {
1363       retstring = (char *) strdup(propval.str);
1364       free(propval.str);
1365     }
1366   } else {
1367     add_ptp_error_to_errorstack(device, ret, "get_string_from_object(): could not get object string.");
1368   }
1369 
1370   return retstring;
1371 }
1372 
1373 /**
1374 * Retrieves an unsigned 64-bit integer from an object attribute
1375  *
1376  * @param device a pointer to an MTP device.
1377  * @param object_id Object reference
1378  * @param attribute_id PTP attribute ID
1379  * @param value_default Default value to return on failure
1380  * @return the value
1381  */
get_u64_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint64_t const value_default)1382 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1383                                     uint16_t const attribute_id, uint64_t const value_default)
1384 {
1385   PTPPropertyValue propval;
1386   uint64_t retval = value_default;
1387   PTPParams *params;
1388   uint16_t ret;
1389   MTPProperties *prop;
1390 
1391   if (!device)
1392     return value_default;
1393 
1394   params = (PTPParams *) device->params;
1395 
1396   prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1397   if (prop)
1398     return prop->propval.u64;
1399 
1400   ret = ptp_mtp_getobjectpropvalue(params, object_id,
1401                                    attribute_id,
1402                                    &propval,
1403                                    PTP_DTC_UINT64);
1404   if (ret == PTP_RC_OK) {
1405     retval = propval.u64;
1406   } else {
1407     add_ptp_error_to_errorstack(device, ret, "get_u64_from_object(): could not get unsigned 64bit integer from object.");
1408   }
1409 
1410   return retval;
1411 }
1412 
1413 /**
1414  * Retrieves an unsigned 32-bit integer from an object attribute
1415  *
1416  * @param device a pointer to an MTP device.
1417  * @param object_id Object reference
1418  * @param attribute_id PTP attribute ID
1419  * @param value_default Default value to return on failure
1420  * @return the value
1421  */
get_u32_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint32_t const value_default)1422 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1423 				    uint16_t const attribute_id, uint32_t const value_default)
1424 {
1425   PTPPropertyValue propval;
1426   uint32_t retval = value_default;
1427   PTPParams *params;
1428   uint16_t ret;
1429   MTPProperties *prop;
1430 
1431   if (!device)
1432     return value_default;
1433 
1434   params = (PTPParams *) device->params;
1435 
1436   prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1437   if (prop)
1438     return prop->propval.u32;
1439 
1440   ret = ptp_mtp_getobjectpropvalue(params, object_id,
1441                                    attribute_id,
1442                                    &propval,
1443                                    PTP_DTC_UINT32);
1444   if (ret == PTP_RC_OK) {
1445     retval = propval.u32;
1446   } else {
1447     add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
1448   }
1449   return retval;
1450 }
1451 
1452 /**
1453  * Retrieves an unsigned 16-bit integer from an object attribute
1454  *
1455  * @param device a pointer to an MTP device.
1456  * @param object_id Object reference
1457  * @param attribute_id PTP attribute ID
1458  * @param value_default Default value to return on failure
1459  * @return a value
1460  */
get_u16_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint16_t const value_default)1461 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1462 				    uint16_t const attribute_id, uint16_t const value_default)
1463 {
1464   PTPPropertyValue propval;
1465   uint16_t retval = value_default;
1466   PTPParams *params;
1467   uint16_t ret;
1468   MTPProperties *prop;
1469 
1470   if (!device)
1471     return value_default;
1472 
1473   params = (PTPParams *) device->params;
1474 
1475   // This O(n) search should not be used so often, since code
1476   // using the cached properties don't usually call this function.
1477   prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1478   if (prop)
1479     return prop->propval.u16;
1480 
1481   ret = ptp_mtp_getobjectpropvalue(params, object_id,
1482                                    attribute_id,
1483                                    &propval,
1484                                    PTP_DTC_UINT16);
1485   if (ret == PTP_RC_OK) {
1486     retval = propval.u16;
1487   } else {
1488     add_ptp_error_to_errorstack(device, ret, "get_u16_from_object(): could not get unsigned 16bit integer from object.");
1489   }
1490 
1491   return retval;
1492 }
1493 
1494 /**
1495  * Retrieves an unsigned 8-bit integer from an object attribute
1496  *
1497  * @param device a pointer to an MTP device.
1498  * @param object_id Object reference
1499  * @param attribute_id PTP attribute ID
1500  * @param value_default Default value to return on failure
1501  * @return a value
1502  */
get_u8_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint8_t const value_default)1503 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1504 				  uint16_t const attribute_id, uint8_t const value_default)
1505 {
1506   PTPPropertyValue propval;
1507   uint8_t retval = value_default;
1508   PTPParams *params;
1509   uint16_t ret;
1510   MTPProperties *prop;
1511 
1512   if (!device)
1513     return value_default;
1514 
1515   params = (PTPParams *) device->params;
1516 
1517   // This O(n) search should not be used so often, since code
1518   // using the cached properties don't usually call this function.
1519   prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1520   if (prop)
1521     return prop->propval.u8;
1522 
1523   ret = ptp_mtp_getobjectpropvalue(params, object_id,
1524                                    attribute_id,
1525                                    &propval,
1526                                    PTP_DTC_UINT8);
1527   if (ret == PTP_RC_OK) {
1528     retval = propval.u8;
1529   } else {
1530     add_ptp_error_to_errorstack(device, ret, "get_u8_from_object(): could not get unsigned 8bit integer from object.");
1531   }
1532 
1533   return retval;
1534 }
1535 
1536 /**
1537  * Sets an object attribute from a string
1538  *
1539  * @param device a pointer to an MTP device.
1540  * @param object_id Object reference
1541  * @param attribute_id PTP attribute ID
1542  * @param string string value to set
1543  * @return 0 on success, any other value means failure
1544  */
set_object_string(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,char const * const string)1545 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1546 			     uint16_t const attribute_id, char const * const string)
1547 {
1548   PTPPropertyValue propval;
1549   PTPParams *params;
1550   uint16_t ret;
1551 
1552   if (!device || !string)
1553     return -1;
1554 
1555   params = (PTPParams *) device->params;
1556 
1557   if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1558     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_string(): could not set object string: "
1559 				"PTP_OC_MTP_SetObjectPropValue not supported.");
1560     return -1;
1561   }
1562   propval.str = (char *) string;
1563   ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1564   if (ret != PTP_RC_OK) {
1565     add_ptp_error_to_errorstack(device, ret, "set_object_string(): could not set object string.");
1566     return -1;
1567   }
1568 
1569   return 0;
1570 }
1571 
1572 
1573 /**
1574  * Sets an object attribute from an unsigned 32-bit integer
1575  *
1576  * @param device a pointer to an MTP device.
1577  * @param object_id Object reference
1578  * @param attribute_id PTP attribute ID
1579  * @param value 32-bit unsigned integer to set
1580  * @return 0 on success, any other value means failure
1581  */
set_object_u32(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint32_t const value)1582 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1583 			  uint16_t const attribute_id, uint32_t const value)
1584 {
1585   PTPPropertyValue propval;
1586   PTPParams *params;
1587   uint16_t ret;
1588 
1589   if (!device)
1590     return -1;
1591 
1592   params = (PTPParams *) device->params;
1593 
1594   if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1595     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u32(): could not set unsigned 32bit integer property: "
1596 				"PTP_OC_MTP_SetObjectPropValue not supported.");
1597     return -1;
1598   }
1599 
1600   propval.u32 = value;
1601   ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
1602   if (ret != PTP_RC_OK) {
1603     add_ptp_error_to_errorstack(device, ret, "set_object_u32(): could not set unsigned 32bit integer property.");
1604     return -1;
1605   }
1606 
1607   return 0;
1608 }
1609 
1610 /**
1611  * Sets an object attribute from an unsigned 16-bit integer
1612  *
1613  * @param device a pointer to an MTP device.
1614  * @param object_id Object reference
1615  * @param attribute_id PTP attribute ID
1616  * @param value 16-bit unsigned integer to set
1617  * @return 0 on success, any other value means failure
1618  */
set_object_u16(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint16_t const value)1619 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1620 			  uint16_t const attribute_id, uint16_t const value)
1621 {
1622   PTPPropertyValue propval;
1623   PTPParams *params;
1624   uint16_t ret;
1625 
1626   if (!device)
1627     return 1;
1628 
1629   params = (PTPParams *) device->params;
1630 
1631   if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1632     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u16(): could not set unsigned 16bit integer property: "
1633 				"PTP_OC_MTP_SetObjectPropValue not supported.");
1634     return -1;
1635   }
1636   propval.u16 = value;
1637   ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
1638   if (ret != PTP_RC_OK) {
1639     add_ptp_error_to_errorstack(device, ret, "set_object_u16(): could not set unsigned 16bit integer property.");
1640     return 1;
1641   }
1642 
1643   return 0;
1644 }
1645 
1646 /**
1647  * Sets an object attribute from an unsigned 8-bit integer
1648  *
1649  * @param device a pointer to an MTP device.
1650  * @param object_id Object reference
1651  * @param attribute_id PTP attribute ID
1652  * @param value 8-bit unsigned integer to set
1653  * @return 0 on success, any other value means failure
1654  */
set_object_u8(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint8_t const value)1655 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1656 			 uint16_t const attribute_id, uint8_t const value)
1657 {
1658   PTPPropertyValue propval;
1659   PTPParams *params;
1660   uint16_t ret;
1661 
1662   if (!device)
1663     return 1;
1664 
1665   params = (PTPParams *) device->params;
1666 
1667   if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1668     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u8(): could not set unsigned 8bit integer property: "
1669 			    "PTP_OC_MTP_SetObjectPropValue not supported.");
1670     return -1;
1671   }
1672   propval.u8 = value;
1673   ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
1674   if (ret != PTP_RC_OK) {
1675     add_ptp_error_to_errorstack(device, ret, "set_object_u8(): could not set unsigned 8bit integer property.");
1676     return 1;
1677   }
1678 
1679   return 0;
1680 }
1681 
1682 /**
1683  * Get the first (as in "first in the list of") connected MTP device.
1684  * @return a device pointer.
1685  * @see LIBMTP_Get_Connected_Devices()
1686  */
LIBMTP_Get_First_Device(void)1687 LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
1688 {
1689   LIBMTP_mtpdevice_t *first_device = NULL;
1690   LIBMTP_raw_device_t *devices;
1691   int numdevs;
1692   LIBMTP_error_number_t ret;
1693 
1694   ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
1695   if (ret != LIBMTP_ERROR_NONE) {
1696     return NULL;
1697   }
1698 
1699   if (devices == NULL || numdevs == 0) {
1700     free(devices);
1701     return NULL;
1702   }
1703 
1704   first_device = LIBMTP_Open_Raw_Device(&devices[0]);
1705   free(devices);
1706   return first_device;
1707 }
1708 
1709 /**
1710  * Overriding debug function.
1711  * This way we can disable debug prints.
1712  */
1713 static void
1714 #ifdef __GNUC__
1715 __attribute__((__format__(printf,2,0)))
1716 #endif
LIBMTP_ptp_debug(void * data,const char * format,va_list args)1717 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1718 {
1719   if ((LIBMTP_debug & LIBMTP_DEBUG_PTP) != 0) {
1720     vfprintf (stderr, format, args);
1721     fprintf (stderr, "\n");
1722     fflush (stderr);
1723   }
1724 }
1725 
1726 /**
1727  * Overriding error function.
1728  * This way we can capture all error etc to our errorstack.
1729  */
1730 static void
1731 #ifdef __GNUC__
1732 __attribute__((__format__(printf,2,0)))
1733 #endif
LIBMTP_ptp_error(void * data,const char * format,va_list args)1734 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1735 {
1736   // if (data == NULL) {
1737     vfprintf (stderr, format, args);
1738     fflush (stderr);
1739   /*
1740     FIXME: find out how we shall get the device here.
1741   } else {
1742     PTP_USB *ptp_usb = data;
1743     LIBMTP_mtpdevice_t *device = ...;
1744     char buf[2048];
1745 
1746     vsnprintf (buf, sizeof (buf), format, args);
1747     add_error_to_errorstack(device,
1748 			    LIBMTP_ERROR_PTP_LAYER,
1749 			    buf);
1750   }
1751   */
1752 }
1753 
1754 /**
1755  * Parses the extension descriptor, there may be stuff in
1756  * this that we want to know about.
1757  */
parse_extension_descriptor(LIBMTP_mtpdevice_t * mtpdevice,char * desc)1758 static void parse_extension_descriptor(LIBMTP_mtpdevice_t *mtpdevice,
1759                                        char *desc)
1760 {
1761   int start = 0;
1762   int end = 0;
1763 
1764   /* NULL on Canon A70 */
1765   if (!desc)
1766     return;
1767 
1768   /* descriptors are divided by semicolons */
1769   while (end < strlen(desc)) {
1770     /* Skip past initial whitespace */
1771     while ((end < strlen(desc)) && (desc[start] == ' ' )) {
1772       start++;
1773       end++;
1774     }
1775     /* Detect extension */
1776     while ((end < strlen(desc)) && (desc[end] != ';'))
1777       end++;
1778     if (end < strlen(desc)) {
1779       char *element = strndup(desc + start, end-start);
1780       if (element) {
1781         int i = 0;
1782         // printf("  Element: \"%s\"\n", element);
1783 
1784         /* Parse for an extension */
1785         while ((i < strlen(element)) && (element[i] != ':'))
1786           i++;
1787         if (i < strlen(element)) {
1788           char *name = strndup(element, i);
1789           int major = 0, minor = 0;
1790 
1791 	  /* extension versions have to be MAJOR.MINOR, but Samsung has one
1792 	   * with just 0, so just cope with those cases too */
1793 	  if (	(2 == sscanf(element+i+1,"%d.%d",&major,&minor)) ||
1794 	  	(1 == sscanf(element+i+1,"%d",&major))
1795 	  ) {
1796             LIBMTP_device_extension_t *extension;
1797 
1798             extension = malloc(sizeof(LIBMTP_device_extension_t));
1799             extension->name = name;
1800             extension->major = major;
1801             extension->minor = minor;
1802             extension->next = NULL;
1803             if (mtpdevice->extensions == NULL) {
1804               mtpdevice->extensions = extension;
1805             } else {
1806               LIBMTP_device_extension_t *tmp = mtpdevice->extensions;
1807               while (tmp->next != NULL)
1808                 tmp = tmp->next;
1809               tmp->next = extension;
1810             }
1811           } else {
1812             LIBMTP_ERROR("LIBMTP ERROR: couldnt parse extension %s\n",
1813                          element);
1814           }
1815         }
1816         free(element);
1817       }
1818     }
1819     end++;
1820     start = end;
1821   }
1822 }
1823 
1824 /**
1825  * This function opens a device from a raw device. It is the
1826  * preferred way to access devices in the new interface where
1827  * several devices can come and go as the library is working
1828  * on a certain device.
1829  * @param rawdevice the raw device to open a "real" device for.
1830  * @return an open device.
1831  */
LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t * rawdevice)1832 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevice)
1833 {
1834   LIBMTP_mtpdevice_t *mtp_device;
1835   uint8_t bs = 0;
1836   PTPParams *current_params;
1837   PTP_USB *ptp_usb;
1838   LIBMTP_error_number_t err;
1839   int i;
1840 
1841   /* Allocate dynamic space for our device */
1842   mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1843   /* Check if there was a memory allocation error */
1844   if(mtp_device == NULL) {
1845     /* There has been an memory allocation error. We are going to ignore this
1846        device and attempt to continue */
1847 
1848     /* TODO: This error statement could probably be a bit more robust */
1849     LIBMTP_ERROR("LIBMTP PANIC: connect_usb_devices encountered a memory "
1850 	    "allocation error with device %d on bus %d, trying to continue",
1851 	    rawdevice->devnum, rawdevice->bus_location);
1852 
1853     return NULL;
1854   }
1855   memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1856   // Non-cached by default
1857   mtp_device->cached = 0;
1858 
1859   /* Create PTP params */
1860   current_params = (PTPParams *) malloc(sizeof(PTPParams));
1861   if (current_params == NULL) {
1862     free(mtp_device);
1863     return NULL;
1864   }
1865   memset(current_params, 0, sizeof(PTPParams));
1866   current_params->device_flags = rawdevice->device_entry.device_flags;
1867   current_params->nrofobjects = 0;
1868   current_params->cachetime = 2;
1869   current_params->objects = NULL;
1870   current_params->response_packet_size = 0;
1871   current_params->response_packet = NULL;
1872   /* This will be a pointer to PTP_USB later */
1873   current_params->data = NULL;
1874   /* Set upp local debug and error functions */
1875   current_params->debug_func = LIBMTP_ptp_debug;
1876   current_params->error_func = LIBMTP_ptp_error;
1877   /* TODO: Will this always be little endian? */
1878   current_params->byteorder = PTP_DL_LE;
1879   current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1880   current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
1881 
1882   if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1883      current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1884     LIBMTP_ERROR("LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1885 	    "Too old stdlibc, glibc and libiconv?\n");
1886     free(current_params);
1887     free(mtp_device);
1888     return NULL;
1889   }
1890   mtp_device->params = current_params;
1891 
1892   /* Create usbinfo, this also opens the session */
1893   err = configure_usb_device(rawdevice,
1894 			     current_params,
1895 			     &mtp_device->usbinfo);
1896   if (err != LIBMTP_ERROR_NONE) {
1897     free(current_params);
1898     free(mtp_device);
1899     return NULL;
1900   }
1901   ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1902   /* Set pointer back to params */
1903   ptp_usb->params = current_params;
1904 
1905   /* Cache the device information for later use */
1906   if (ptp_getdeviceinfo(current_params,
1907 			&current_params->deviceinfo) != PTP_RC_OK) {
1908     LIBMTP_ERROR("LIBMTP PANIC: Unable to read device information on device "
1909 	    "%d on bus %d, trying to continue",
1910 	    rawdevice->devnum, rawdevice->bus_location);
1911 
1912     /* Prevent memory leaks for this device */
1913     free(mtp_device->usbinfo);
1914     free(mtp_device->params);
1915     current_params = NULL;
1916     free(mtp_device);
1917     return NULL;
1918   }
1919 
1920   /* Check: if this is a PTP device, is it really tagged as MTP? */
1921   if (current_params->deviceinfo.VendorExtensionID != 0x00000006) {
1922     LIBMTP_ERROR("LIBMTP WARNING: no MTP vendor extension on device "
1923 		 "%d on bus %d",
1924 		 rawdevice->devnum, rawdevice->bus_location);
1925     LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionID: %08x",
1926 		 current_params->deviceinfo.VendorExtensionID);
1927     LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionDesc: %s",
1928 		 current_params->deviceinfo.VendorExtensionDesc);
1929     LIBMTP_ERROR("LIBMTP WARNING: this typically means the device is PTP "
1930 		 "(i.e. a camera) but not an MTP device at all. "
1931 		 "Trying to continue anyway.");
1932   }
1933 
1934   parse_extension_descriptor(mtp_device,
1935                              current_params->deviceinfo.VendorExtensionDesc);
1936 
1937   /*
1938    * Android has a number of bugs, force-assign these bug flags
1939    * if Android is encountered. Same thing for devices we detect
1940    * as SONY NWZ Walkmen. I have no clue what "sony.net/WMFU" means
1941    * I just know only NWZs have it.
1942    */
1943   {
1944     LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
1945     int is_microsoft_com_wpdna = 0;
1946     int is_android = 0;
1947     int is_sony_net_wmfu = 0;
1948     int is_sonyericsson_com_se = 0;
1949 
1950     /* Loop over extensions and set flags */
1951     while (tmpext != NULL) {
1952       if (!strcmp(tmpext->name, "microsoft.com/WPDNA"))
1953 	is_microsoft_com_wpdna = 1;
1954       if (!strcmp(tmpext->name, "android.com"))
1955 	is_android = 1;
1956       if (!strcmp(tmpext->name, "sony.net/WMFU"))
1957 	is_sony_net_wmfu = 1;
1958       if (!strcmp(tmpext->name, "sonyericsson.com/SE"))
1959 	is_sonyericsson_com_se = 1;
1960       tmpext = tmpext->next;
1961     }
1962 
1963     /* Check for specific stacks */
1964     if (is_microsoft_com_wpdna && is_sonyericsson_com_se && !is_android) {
1965       /*
1966        * The Aricent stack seems to be detected by providing WPDNA, the SonyEricsson
1967        * extension and NO Android extension.
1968        */
1969       ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ARICENT_BUGS;
1970       LIBMTP_INFO("Aricent MTP stack device detected, assigning default bug flags\n");
1971     }
1972     else if (is_android) {
1973       /*
1974        * If bugs are fixed in later versions, test on tmpext->major, tmpext->minor
1975        */
1976       ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ANDROID_BUGS;
1977       LIBMTP_INFO("Android device detected, assigning default bug flags\n");
1978     }
1979     else if (is_sony_net_wmfu) {
1980       ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_SONY_NWZ_BUGS;
1981       LIBMTP_INFO("SONY NWZ device detected, assigning default bug flags\n");
1982     }
1983   }
1984 
1985   /*
1986    * If the OGG or FLAC filetypes are flagged as "unknown", check
1987    * if the firmware has been updated to actually support it.
1988    */
1989   if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
1990     for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
1991       if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_OGG) {
1992         /* This is not unknown anymore, unflag it */
1993         ptp_usb->rawdevice.device_entry.device_flags &=
1994           ~DEVICE_FLAG_OGG_IS_UNKNOWN;
1995         break;
1996       }
1997     }
1998   }
1999   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
2000     for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2001       if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_FLAC) {
2002         /* This is not unknown anymore, unflag it */
2003         ptp_usb->rawdevice.device_entry.device_flags &=
2004           ~DEVICE_FLAG_FLAC_IS_UNKNOWN;
2005         break;
2006       }
2007     }
2008   }
2009 
2010   /* Determine if the object size supported is 32 or 64 bit wide */
2011   if (ptp_operation_issupported(current_params,PTP_OC_MTP_GetObjectPropsSupported)) {
2012     for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2013       PTPObjectPropDesc opd;
2014 
2015       if (ptp_mtp_getobjectpropdesc(current_params,
2016                                     PTP_OPC_ObjectSize,
2017                                     current_params->deviceinfo.ImageFormats[i],
2018                                     &opd) != PTP_RC_OK) {
2019         LIBMTP_ERROR("LIBMTP PANIC: "
2020                      "could not inspect object property descriptions!\n");
2021       } else {
2022         if (opd.DataType == PTP_DTC_UINT32) {
2023           if (bs == 0) {
2024             bs = 32;
2025           } else if (bs != 32) {
2026             LIBMTP_ERROR("LIBMTP PANIC: "
2027                          "different objects support different object sizes!\n");
2028             bs = 0;
2029             break;
2030           }
2031         } else if (opd.DataType == PTP_DTC_UINT64) {
2032           if (bs == 0) {
2033             bs = 64;
2034           } else if (bs != 64) {
2035             LIBMTP_ERROR("LIBMTP PANIC: "
2036                          "different objects support different object sizes!\n");
2037             bs = 0;
2038             break;
2039           }
2040         } else {
2041           // Ignore if other size.
2042           LIBMTP_ERROR("LIBMTP PANIC: "
2043                        "awkward object size data type: %04x\n", opd.DataType);
2044           bs = 0;
2045           break;
2046         }
2047       }
2048     }
2049   }
2050   if (bs == 0) {
2051     // Could not detect object bitsize, assume 32 bits
2052     bs = 32;
2053   }
2054   mtp_device->object_bitsize = bs;
2055 
2056   /* No Errors yet for this device */
2057   mtp_device->errorstack = NULL;
2058 
2059   /* Default Max Battery Level, we will adjust this if possible */
2060   mtp_device->maximum_battery_level = 100;
2061 
2062   /* Check if device supports reading maximum battery level */
2063   if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
2064      ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
2065     PTPDevicePropDesc dpd;
2066 
2067     /* Try to read maximum battery level */
2068     if(ptp_getdevicepropdesc(current_params,
2069 			     PTP_DPC_BatteryLevel,
2070 			     &dpd) != PTP_RC_OK) {
2071       add_error_to_errorstack(mtp_device,
2072 			      LIBMTP_ERROR_CONNECTING,
2073 			      "Unable to read Maximum Battery Level for this "
2074 			      "device even though the device supposedly "
2075 			      "supports this functionality");
2076     }
2077 
2078     /* TODO: is this appropriate? */
2079     /* If max battery level is 0 then leave the default, otherwise assign */
2080     if (dpd.FORM.Range.MaximumValue.u8 != 0) {
2081       mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
2082     }
2083 
2084     ptp_free_devicepropdesc(&dpd);
2085   }
2086 
2087   /* Set all default folders to 0xffffffffU (root directory) */
2088   mtp_device->default_music_folder = 0xffffffffU;
2089   mtp_device->default_playlist_folder = 0xffffffffU;
2090   mtp_device->default_picture_folder = 0xffffffffU;
2091   mtp_device->default_video_folder = 0xffffffffU;
2092   mtp_device->default_organizer_folder = 0xffffffffU;
2093   mtp_device->default_zencast_folder = 0xffffffffU;
2094   mtp_device->default_album_folder = 0xffffffffU;
2095   mtp_device->default_text_folder = 0xffffffffU;
2096 
2097   /* Set initial storage information */
2098   mtp_device->storage = NULL;
2099   if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
2100     add_error_to_errorstack(mtp_device,
2101 			    LIBMTP_ERROR_GENERAL,
2102 			    "Get Storage information failed.");
2103     mtp_device->storage = NULL;
2104   }
2105 
2106 
2107   return mtp_device;
2108 }
2109 
LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t * rawdevice)2110 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
2111 {
2112   LIBMTP_mtpdevice_t *mtp_device = LIBMTP_Open_Raw_Device_Uncached(rawdevice);
2113 
2114   if (mtp_device == NULL)
2115     return NULL;
2116 
2117   /* Check for MTPZ devices. */
2118   if (use_mtpz) {
2119     LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
2120 
2121     while (tmpext != NULL) {
2122       if (!strcmp(tmpext->name, "microsoft.com/MTPZ")) {
2123 	LIBMTP_INFO("MTPZ device detected. Authenticating...\n");
2124         if (PTP_RC_OK == ptp_mtpz_handshake(mtp_device->params)) {
2125 	  LIBMTP_INFO ("(MTPZ) Successfully authenticated with device.\n");
2126         } else {
2127           LIBMTP_INFO ("(MTPZ) Failure - could not authenticate with device.\n");
2128         }
2129 	break;
2130       }
2131       tmpext = tmpext->next;
2132     }
2133   }
2134 
2135   // Set up this device as cached
2136   mtp_device->cached = 1;
2137   /*
2138    * Then get the handles and try to locate the default folders.
2139    * This has the desired side effect of caching all handles from
2140    * the device which speeds up later operations.
2141    */
2142   flush_handles(mtp_device);
2143   return mtp_device;
2144 }
2145 
2146 /**
2147  * To read events sent by the device, repeatedly call this function from a secondary
2148  * thread until the return value is < 0.
2149  *
2150  * @param device a pointer to the MTP device to poll for events.
2151  * @param event contains a pointer to be filled in with the event retrieved if the call
2152  * is successful.
2153  * @param out1 contains the param1 value from the raw event.
2154  * @return 0 on success, any other value means the polling loop shall be
2155  * terminated immediately for this session.
2156  */
LIBMTP_Read_Event(LIBMTP_mtpdevice_t * device,LIBMTP_event_t * event,uint32_t * out1)2157 int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *device, LIBMTP_event_t *event, uint32_t *out1)
2158 {
2159   /*
2160    * FIXME: Potential race-condition here, if client deallocs device
2161    * while we're *not* waiting for input. As we'll be waiting for
2162    * input most of the time, it's unlikely but still worth considering
2163    * for improvement. Also we cannot affect the state of the cache etc
2164    * unless we know we are the sole user on the device. A spinlock or
2165    * mutex in the LIBMTP_mtpdevice_t is needed for this to work.
2166    */
2167   PTPParams *params = (PTPParams *) device->params;
2168   PTPContainer ptp_event;
2169   uint16_t ret = ptp_usb_event_wait(params, &ptp_event);
2170 
2171   if (ret != PTP_RC_OK) {
2172     /* Device is closing down or other fatal stuff, exit thread */
2173     return -1;
2174   }
2175   LIBMTP_Handle_Event(&ptp_event, event, out1);
2176   return 0;
2177 }
2178 
LIBMTP_Handle_Event(PTPContainer * ptp_event,LIBMTP_event_t * event,uint32_t * out1)2179 void LIBMTP_Handle_Event(PTPContainer *ptp_event,
2180                          LIBMTP_event_t *event, uint32_t *out1) {
2181   uint16_t code;
2182   uint32_t session_id;
2183   uint32_t param1;
2184 
2185   *event = LIBMTP_EVENT_NONE;
2186 
2187   /* Process the event */
2188   code = ptp_event->Code;
2189   session_id = ptp_event->SessionID;
2190   param1 = ptp_event->Param1;
2191 
2192   switch(code) {
2193     case PTP_EC_Undefined:
2194       LIBMTP_INFO("Received event PTP_EC_Undefined in session %u\n", session_id);
2195       break;
2196     case PTP_EC_CancelTransaction:
2197       LIBMTP_INFO("Received event PTP_EC_CancelTransaction in session %u\n", session_id);
2198       break;
2199     case PTP_EC_ObjectAdded:
2200       LIBMTP_INFO("Received event PTP_EC_ObjectAdded in session %u\n", session_id);
2201       *event = LIBMTP_EVENT_OBJECT_ADDED;
2202       *out1 = param1;
2203       break;
2204     case PTP_EC_ObjectRemoved:
2205       LIBMTP_INFO("Received event PTP_EC_ObjectRemoved in session %u\n", session_id);
2206       *event = LIBMTP_EVENT_OBJECT_REMOVED;
2207       *out1 = param1;
2208       break;
2209     case PTP_EC_StoreAdded:
2210       LIBMTP_INFO("Received event PTP_EC_StoreAdded in session %u\n", session_id);
2211       /* TODO: rescan storages */
2212       *event = LIBMTP_EVENT_STORE_ADDED;
2213       *out1 = param1;
2214       break;
2215     case PTP_EC_StoreRemoved:
2216       LIBMTP_INFO("Received event PTP_EC_StoreRemoved in session %u\n", session_id);
2217       /* TODO: rescan storages */
2218       *event = LIBMTP_EVENT_STORE_REMOVED;
2219       *out1 = param1;
2220       break;
2221     case PTP_EC_DevicePropChanged:
2222       LIBMTP_INFO("Received event PTP_EC_DevicePropChanged in session %u\n", session_id);
2223       /* TODO: update device properties */
2224       break;
2225     case PTP_EC_ObjectInfoChanged:
2226       LIBMTP_INFO("Received event PTP_EC_ObjectInfoChanged in session %u\n", session_id);
2227       /* TODO: rescan object cache or just for this one object */
2228       break;
2229     case PTP_EC_DeviceInfoChanged:
2230       LIBMTP_INFO("Received event PTP_EC_DeviceInfoChanged in session %u\n", session_id);
2231       /* TODO: update device info */
2232       break;
2233     case PTP_EC_RequestObjectTransfer:
2234       LIBMTP_INFO("Received event PTP_EC_RequestObjectTransfer in session %u\n", session_id);
2235       break;
2236     case PTP_EC_StoreFull:
2237       LIBMTP_INFO("Received event PTP_EC_StoreFull in session %u\n", session_id);
2238       break;
2239     case PTP_EC_DeviceReset:
2240       LIBMTP_INFO("Received event PTP_EC_DeviceReset in session %u\n", session_id);
2241       break;
2242     case PTP_EC_StorageInfoChanged :
2243       LIBMTP_INFO( "Received event PTP_EC_StorageInfoChanged in session %u\n", session_id);
2244      /* TODO: update storage info */
2245       break;
2246     case PTP_EC_CaptureComplete :
2247       LIBMTP_INFO( "Received event PTP_EC_CaptureComplete in session %u\n", session_id);
2248       break;
2249     case PTP_EC_UnreportedStatus :
2250       LIBMTP_INFO( "Received event PTP_EC_UnreportedStatus in session %u\n", session_id);
2251       break;
2252     default :
2253       LIBMTP_INFO( "Received unknown event in session %u\n", session_id);
2254       break;
2255   }
2256 }
2257 
LIBMTP_Read_Event_Cb(PTPParams * params,uint16_t ret_code,PTPContainer * ptp_event,void * user_data)2258 static void LIBMTP_Read_Event_Cb(PTPParams *params, uint16_t ret_code,
2259                                  PTPContainer *ptp_event, void *user_data) {
2260   event_cb_data_t *data = user_data;
2261   LIBMTP_event_t event = LIBMTP_EVENT_NONE;
2262   uint32_t param1 = 0;
2263   int handler_ret;
2264 
2265   switch (ret_code) {
2266   case PTP_RC_OK:
2267     handler_ret = LIBMTP_HANDLER_RETURN_OK;
2268     LIBMTP_Handle_Event(ptp_event, &event, &param1);
2269     break;
2270   case PTP_ERROR_CANCEL:
2271     handler_ret = LIBMTP_HANDLER_RETURN_CANCEL;
2272     break;
2273   default:
2274     handler_ret = LIBMTP_HANDLER_RETURN_ERROR;
2275     break;
2276   }
2277 
2278   data->cb(handler_ret, event, param1, data->user_data);
2279   free(data);
2280 }
2281 
2282 /**
2283  * This function reads events sent by the device, in a non-blocking manner.
2284  * The callback function will be called when an event is received, but for the function
2285  * to make progress, polling must take place, using LIBMTP_Handle_Events_Timeout_Completed.
2286  *
2287  * After an event is received, this function should be called again to listen for the next
2288  * event.
2289  *
2290  * For now, this non-blocking mechanism only works with libusb-1.0, and not any of the
2291  * other usb library backends. Attempting to call this method with another backend will
2292  * always return an error.
2293  *
2294  * @param device a pointer to the MTP device to poll for events.
2295  * @param cb a callback to be invoked when an event is received.
2296  * @param user_data arbitrary user data passed to the callback.
2297  * @return 0 on success, any other value means that the callback was not registered and
2298  *         no event notification will take place.
2299  */
LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t * device,LIBMTP_event_cb_fn cb,void * user_data)2300 int LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t *device, LIBMTP_event_cb_fn cb, void *user_data) {
2301   PTPParams *params = (PTPParams *) device->params;
2302   event_cb_data_t *data =  malloc(sizeof(event_cb_data_t));
2303   uint16_t ret;
2304 
2305   data->cb = cb;
2306   data->user_data = user_data;
2307 
2308   ret = ptp_usb_event_async(params, LIBMTP_Read_Event_Cb, data);
2309   return ret == PTP_RC_OK ? 0 : -1;
2310 }
2311 
2312 /**
2313  * Recursive function that adds MTP devices to a linked list
2314  * @param devices a list of raw devices to have real devices created for.
2315  * @return a device pointer to a newly created mtpdevice (used in linked
2316  * list creation).
2317  */
create_usb_mtp_devices(LIBMTP_raw_device_t * devices,int numdevs)2318 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
2319 {
2320   uint8_t i;
2321   LIBMTP_mtpdevice_t *mtp_device_list = NULL;
2322   LIBMTP_mtpdevice_t *current_device = NULL;
2323 
2324   for (i=0; i < numdevs; i++) {
2325     LIBMTP_mtpdevice_t *mtp_device;
2326     mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
2327 
2328     /* On error, try next device */
2329     if (mtp_device == NULL)
2330       continue;
2331 
2332     /* Add the device to the list */
2333     mtp_device->next = NULL;
2334     if (mtp_device_list == NULL) {
2335       mtp_device_list = current_device = mtp_device;
2336     } else {
2337       current_device->next = mtp_device;
2338       current_device = mtp_device;
2339     }
2340   }
2341   return mtp_device_list;
2342 }
2343 
2344 /**
2345  * Get the number of devices that are available in the listed device list
2346  * @param device_list Pointer to a linked list of devices
2347  * @return Number of devices in the device list device_list
2348  * @see LIBMTP_Get_Connected_Devices()
2349  */
LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t * device_list)2350 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
2351 {
2352   uint32_t numdevices = 0;
2353   LIBMTP_mtpdevice_t *iter;
2354   for(iter = device_list; iter != NULL; iter = iter->next)
2355     numdevices++;
2356 
2357   return numdevices;
2358 }
2359 
2360 /**
2361  * Get the first connected MTP device node in the linked list of devices.
2362  * Currently this only provides access to USB devices
2363  * @param device_list A list of devices ready to be used by the caller. You
2364  *        need to know how many there are.
2365  * @return Any error information gathered from device connections
2366  * @see LIBMTP_Number_Devices_In_List()
2367  */
LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t ** device_list)2368 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
2369 {
2370   LIBMTP_raw_device_t *devices;
2371   int numdevs;
2372   LIBMTP_error_number_t ret;
2373 
2374   ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
2375   if (ret != LIBMTP_ERROR_NONE) {
2376     *device_list = NULL;
2377     return ret;
2378   }
2379 
2380   /* Assign linked list of devices */
2381   if (devices == NULL || numdevs == 0) {
2382     *device_list = NULL;
2383     free(devices);
2384     return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2385   }
2386 
2387   *device_list = create_usb_mtp_devices(devices, numdevs);
2388   free(devices);
2389 
2390   /* TODO: Add wifi device access here */
2391 
2392   /* We have found some devices but create failed */
2393   if (*device_list == NULL)
2394     return LIBMTP_ERROR_CONNECTING;
2395 
2396   return LIBMTP_ERROR_NONE;
2397 }
2398 
2399 /**
2400  * This closes and releases an allocated MTP device.
2401  * @param device a pointer to the MTP device to release.
2402  */
LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t * device)2403 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
2404 {
2405   if(device != NULL)
2406   {
2407     if(device->next != NULL)
2408     {
2409       LIBMTP_Release_Device_List(device->next);
2410     }
2411 
2412     LIBMTP_Release_Device(device);
2413   }
2414 }
2415 
2416 /**
2417  * This closes and releases an allocated MTP device.
2418  * @param device a pointer to the MTP device to release.
2419  */
LIBMTP_Release_Device(LIBMTP_mtpdevice_t * device)2420 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
2421 {
2422   PTPParams *params = (PTPParams *) device->params;
2423   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2424 
2425   close_device(ptp_usb, params);
2426   // Clear error stack
2427   LIBMTP_Clear_Errorstack(device);
2428   // Free iconv() converters...
2429   iconv_close(params->cd_locale_to_ucs2);
2430   iconv_close(params->cd_ucs2_to_locale);
2431   free(ptp_usb);
2432   ptp_free_params(params);
2433   free(params);
2434   free_storage_list(device);
2435   // Free extension list...
2436   if (device->extensions != NULL) {
2437     LIBMTP_device_extension_t *tmp = device->extensions;
2438 
2439     while (tmp != NULL) {
2440       LIBMTP_device_extension_t *next = tmp->next;
2441 
2442       if (tmp->name)
2443         free(tmp->name);
2444       free(tmp);
2445       tmp = next;
2446     }
2447   }
2448   free(device);
2449 }
2450 
2451 /**
2452  * This can be used by any libmtp-intrinsic code that
2453  * need to stack up an error on the stack. You are only
2454  * supposed to add errors to the error stack using this
2455  * function, do not create and reference error entries
2456  * directly.
2457  */
add_error_to_errorstack(LIBMTP_mtpdevice_t * device,LIBMTP_error_number_t errornumber,char const * const error_text)2458 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2459 				    LIBMTP_error_number_t errornumber,
2460 				    char const * const error_text)
2461 {
2462   LIBMTP_error_t *newerror;
2463 
2464   if (device == NULL) {
2465     LIBMTP_ERROR("LIBMTP PANIC: Trying to add error to a NULL device!\n");
2466     return;
2467   }
2468   newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2469   newerror->errornumber = errornumber;
2470   newerror->error_text = strdup(error_text);
2471   newerror->next = NULL;
2472   if (device->errorstack == NULL) {
2473     device->errorstack = newerror;
2474   } else {
2475     LIBMTP_error_t *tmp = device->errorstack;
2476 
2477     while (tmp->next != NULL) {
2478       tmp = tmp->next;
2479     }
2480     tmp->next = newerror;
2481   }
2482 }
2483 
2484 /**
2485  * Adds an error from the PTP layer to the error stack.
2486  */
add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t * device,uint16_t ptp_error,char const * const error_text)2487 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2488 					uint16_t ptp_error,
2489 					char const * const error_text)
2490 {
2491   PTPParams      *params = (PTPParams *) device->params;
2492 
2493   if (device == NULL) {
2494     LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2495     return;
2496   } else {
2497     char outstr[256];
2498     snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2499     outstr[sizeof(outstr)-1] = '\0';
2500     add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2501 
2502     snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error, params->deviceinfo.VendorExtensionID));
2503     outstr[sizeof(outstr)-1] = '\0';
2504     add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2505   }
2506 }
2507 
2508 /**
2509  * This returns the error stack for a device in case you
2510  * need to either reference the error numbers (e.g. when
2511  * creating multilingual apps with multiple-language text
2512  * representations for each error number) or when you need
2513  * to build a multi-line error text widget or something like
2514  * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2515  * to clear it when you're finished with it.
2516  * @param device a pointer to the MTP device to get the error
2517  *        stack for.
2518  * @return the error stack or NULL if there are no errors
2519  *         on the stack.
2520  * @see LIBMTP_Clear_Errorstack()
2521  * @see LIBMTP_Dump_Errorstack()
2522  */
LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t * device)2523 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2524 {
2525   if (device == NULL) {
2526     LIBMTP_ERROR("LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2527     return NULL;
2528   }
2529   return device->errorstack;
2530 }
2531 
2532 /**
2533  * This function clears the error stack of a device and frees
2534  * any memory used by it. Call this when you're finished with
2535  * using the errors.
2536  * @param device a pointer to the MTP device to clear the error
2537  *        stack for.
2538  */
LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t * device)2539 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2540 {
2541   if (device == NULL) {
2542     LIBMTP_ERROR("LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2543   } else {
2544     LIBMTP_error_t *tmp = device->errorstack;
2545 
2546     while (tmp != NULL) {
2547       LIBMTP_error_t *tmp2;
2548 
2549       if (tmp->error_text != NULL) {
2550 	free(tmp->error_text);
2551       }
2552       tmp2 = tmp;
2553       tmp = tmp->next;
2554       free(tmp2);
2555     }
2556     device->errorstack = NULL;
2557   }
2558 }
2559 
2560 /**
2561  * This function dumps the error stack to <code>stderr</code>.
2562  * (You still have to clear the stack though.)
2563  * @param device a pointer to the MTP device to dump the error
2564  *        stack for.
2565  */
LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t * device)2566 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2567 {
2568   if (device == NULL) {
2569     LIBMTP_ERROR("LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2570   } else {
2571     LIBMTP_error_t *tmp = device->errorstack;
2572 
2573     while (tmp != NULL) {
2574       if (tmp->error_text != NULL) {
2575 	LIBMTP_ERROR("Error %d: %s\n", tmp->errornumber, tmp->error_text);
2576       } else {
2577 	LIBMTP_ERROR("Error %d: (unknown)\n", tmp->errornumber);
2578       }
2579       tmp = tmp->next;
2580     }
2581   }
2582 }
2583 
LIBMTP_Set_Device_Timeout(LIBMTP_mtpdevice_t * device,int milliseconds)2584 void LIBMTP_Set_Device_Timeout(LIBMTP_mtpdevice_t *device, int milliseconds)
2585 {
2586   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2587   set_usb_device_timeout(ptp_usb, milliseconds);
2588 }
2589 
LIBMTP_Get_Device_Timeout(LIBMTP_mtpdevice_t * device,int * milliseconds)2590 void LIBMTP_Get_Device_Timeout(LIBMTP_mtpdevice_t *device, int *milliseconds)
2591 {
2592   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2593   get_usb_device_timeout(ptp_usb, milliseconds);
2594 }
2595 
2596 /**
2597  * This command gets all handles and stuff by FAST directory retrieveal
2598  * which is available by getting all metadata for object
2599  * <code>0xffffffff</code> which simply means "all metadata for all objects".
2600  * This works on the vast majority of MTP devices (there ARE exceptions!)
2601  * and is quite quick. Check the error stack to see if there were
2602  * problems getting the metadata.
2603  * @return 0 if all was OK, -1 on failure.
2604  */
get_all_metadata_fast(LIBMTP_mtpdevice_t * device)2605 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device)
2606 {
2607   PTPParams      *params = (PTPParams *) device->params;
2608   int		 cnt = 0;
2609   int            i, j, nrofprops;
2610   uint32_t	 lasthandle = 0xffffffff;
2611   MTPProperties  *props = NULL;
2612   MTPProperties  *prop;
2613   uint16_t       ret;
2614   int            oldtimeout;
2615   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2616 
2617   /*
2618    * The follow request causes the device to generate
2619    * a list of every file on the device and return it
2620    * in a single response.
2621    *
2622    * Some slow devices as well as devices with very
2623    * large file systems can easily take longer then
2624    * the standard timeout value before it is able
2625    * to return a response.
2626    *
2627    * Temporarly set timeout to allow working with
2628    * widest range of devices.
2629    */
2630   get_usb_device_timeout(ptp_usb, &oldtimeout);
2631   set_usb_device_timeout(ptp_usb, 60000);
2632 
2633   ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2634   set_usb_device_timeout(ptp_usb, oldtimeout);
2635 
2636   if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2637     // What's the point in the device implementing this command if
2638     // you cannot use it to get all props for AT LEAST one object?
2639     // Well, whatever...
2640     add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2641     "cannot retrieve all metadata for an object on this device.");
2642     return -1;
2643   }
2644   if (ret != PTP_RC_OK) {
2645     add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2646     "could not get proplist of all objects.");
2647     return -1;
2648   }
2649   if (props == NULL && nrofprops != 0) {
2650     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2651 			    "get_all_metadata_fast(): "
2652 			    "call to ptp_mtp_getobjectproplist() returned "
2653 			    "inconsistent results.");
2654     return -1;
2655   }
2656   /*
2657    * We count the number of objects by counting the ObjectHandle
2658    * references, whenever it changes we get a new object, when it's
2659    * the same, it is just different properties of the same object.
2660    */
2661   prop = props;
2662   for (i=0;i<nrofprops;i++) {
2663       if (lasthandle != prop->ObjectHandle) {
2664 	cnt++;
2665 	lasthandle = prop->ObjectHandle;
2666       }
2667       prop++;
2668   }
2669   lasthandle = 0xffffffff;
2670   params->objects = calloc (cnt, sizeof(PTPObject));
2671   prop = props;
2672   i = -1;
2673   for (j=0;j<nrofprops;j++) {
2674     if (lasthandle != prop->ObjectHandle) {
2675       if (i >= 0) {
2676         params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2677 	if (!params->objects[i].oi.Filename) {
2678 	  /* I have one such file on my Creative (Marcus) */
2679 	  params->objects[i].oi.Filename = strdup("<null>");
2680 	}
2681       }
2682       i++;
2683       lasthandle = prop->ObjectHandle;
2684       params->objects[i].oid = prop->ObjectHandle;
2685     }
2686     switch (prop->property) {
2687     case PTP_OPC_ParentObject:
2688       params->objects[i].oi.ParentObject = prop->propval.u32;
2689       params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2690       break;
2691     case PTP_OPC_ObjectFormat:
2692       params->objects[i].oi.ObjectFormat = prop->propval.u16;
2693       break;
2694     case PTP_OPC_ObjectSize:
2695       // We loose precision here, up to 32 bits! However the commands that
2696       // retrieve metadata for files and tracks will make sure that the
2697       // PTP_OPC_ObjectSize is read in and duplicated again.
2698       if (device->object_bitsize == 64) {
2699 	params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2700       } else {
2701 	params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2702       }
2703       break;
2704     case PTP_OPC_StorageID:
2705       params->objects[i].oi.StorageID = prop->propval.u32;
2706       params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2707       break;
2708     case PTP_OPC_ObjectFileName:
2709       if (prop->propval.str != NULL)
2710         params->objects[i].oi.Filename = strdup(prop->propval.str);
2711       break;
2712     default: {
2713       MTPProperties *newprops;
2714 
2715       /* Copy all of the other MTP oprierties into the per-object proplist */
2716       if (params->objects[i].nrofmtpprops) {
2717         newprops = realloc(params->objects[i].mtpprops,
2718 		(params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2719       } else {
2720         newprops = calloc(1,sizeof(MTPProperties));
2721       }
2722       if (!newprops) return 0; /* FIXME: error handling? */
2723       params->objects[i].mtpprops = newprops;
2724       memcpy(&params->objects[i].mtpprops[params->objects[i].nrofmtpprops],
2725 	     &props[j],sizeof(props[j]));
2726       params->objects[i].nrofmtpprops++;
2727       params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2728       break;
2729     }
2730     }
2731     prop++;
2732   }
2733   /* mark last entry also */
2734   if (i >= 0) {
2735     params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2736     params->nrofobjects = i+1;
2737   } else {
2738     params->nrofobjects = 0;
2739   }
2740   free (props);
2741   /* The device might not give the list in linear ascending order */
2742   ptp_objects_sort (params);
2743   return 0;
2744 }
2745 
2746 /**
2747  * This function will recurse through all the directories on the device,
2748  * starting at the root directory, gathering metadata as it moves along.
2749  * It works better on some devices that will only return data for a
2750  * certain directory and does not respect the option to get all metadata
2751  * for all objects.
2752  */
get_handles_recursively(LIBMTP_mtpdevice_t * device,PTPParams * params,uint32_t storageid,uint32_t parent)2753 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
2754 				    PTPParams *params,
2755 				    uint32_t storageid,
2756 				    uint32_t parent)
2757 {
2758   PTPObjectHandles currentHandles;
2759   int i = 0;
2760   uint16_t ret = ptp_getobjecthandles(params,
2761                                       storageid,
2762                                       PTP_GOH_ALL_FORMATS,
2763                                       parent,
2764                                       &currentHandles);
2765 
2766   if (ret != PTP_RC_OK) {
2767     add_ptp_error_to_errorstack(device, ret, "get_handles_recursively(): could not get object handles.");
2768     return;
2769   }
2770 
2771   if (currentHandles.Handler == NULL || currentHandles.n == 0)
2772     return;
2773 
2774   // Now descend into any subdirectories found
2775   for (i = 0; i < currentHandles.n; i++) {
2776     PTPObject *ob;
2777     ret = ptp_object_want(params,currentHandles.Handler[i],
2778 			  PTPOBJECT_OBJECTINFO_LOADED, &ob);
2779     if (ret == PTP_RC_OK) {
2780       if (ob->oi.ObjectFormat == PTP_OFC_Association)
2781         get_handles_recursively(device, params,
2782 				storageid, currentHandles.Handler[i]);
2783     } else {
2784       add_error_to_errorstack(device,
2785 			      LIBMTP_ERROR_CONNECTING,
2786 			      "Found a bad handle, trying to ignore it.");
2787     }
2788   }
2789   free(currentHandles.Handler);
2790 }
2791 
2792 /**
2793  * This function refresh the internal handle list whenever
2794  * the items stored inside the device is altered. On operations
2795  * that do not add or remove objects, this is typically not
2796  * called.
2797  * @param device a pointer to the MTP device to flush handles for.
2798  */
flush_handles(LIBMTP_mtpdevice_t * device)2799 static void flush_handles(LIBMTP_mtpdevice_t *device)
2800 {
2801   PTPParams *params = (PTPParams *) device->params;
2802   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2803   int ret;
2804   uint32_t i;
2805 
2806   if (!device->cached) {
2807     return;
2808   }
2809 
2810   if (load_cache_on_demand) {
2811     return;
2812   }
2813 
2814   if (params->objects != NULL) {
2815     for (i=0;i<params->nrofobjects;i++)
2816       ptp_free_object (&params->objects[i]);
2817     free(params->objects);
2818     params->objects = NULL;
2819     params->nrofobjects = 0;
2820   }
2821 
2822   if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2823       && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2824       && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2825     // Use the fast method. Ignore return value for now.
2826     ret = get_all_metadata_fast(device);
2827   }
2828 
2829   // If the previous failed or returned no objects, use classic
2830   // methods instead.
2831   if (params->nrofobjects == 0) {
2832     // Get all the handles using just standard commands.
2833     if (device->storage == NULL) {
2834       get_handles_recursively(device, params,
2835 			      PTP_GOH_ALL_STORAGE,
2836 			      PTP_GOH_ROOT_PARENT);
2837     } else {
2838       // Get handles for each storage in turn.
2839       LIBMTP_devicestorage_t *storage = device->storage;
2840       while(storage != NULL) {
2841 	get_handles_recursively(device, params,
2842 				storage->id,
2843 				PTP_GOH_ROOT_PARENT);
2844 	storage = storage->next;
2845       }
2846     }
2847   }
2848 
2849   /*
2850    * Loop over the handles, fix up any NULL filenames or
2851    * keywords, then attempt to locate some default folders
2852    * in the root directory of the primary storage.
2853    */
2854   for(i = 0; i < params->nrofobjects; i++) {
2855     PTPObject *ob, *xob;
2856 
2857     ob = &params->objects[i];
2858     ret = ptp_object_want(params,params->objects[i].oid,
2859 			  PTPOBJECT_OBJECTINFO_LOADED, &xob);
2860     if (ret != PTP_RC_OK) {
2861 	LIBMTP_ERROR("broken! %x not found\n", params->objects[i].oid);
2862     }
2863     if (ob->oi.Filename == NULL)
2864       ob->oi.Filename = strdup("<null>");
2865     if (ob->oi.Keywords == NULL)
2866       ob->oi.Keywords = strdup("<null>");
2867 
2868     /* Ignore handles that point to non-folders */
2869     if(ob->oi.ObjectFormat != PTP_OFC_Association)
2870       continue;
2871     /* Only look in the root folder */
2872     if (ob->oi.ParentObject == 0xffffffffU) {
2873       LIBMTP_ERROR("object %x has parent 0xffffffff (-1) continuing anyway\n",
2874 		   ob->oid);
2875     } else if (ob->oi.ParentObject != 0x00000000U)
2876       continue;
2877     /* Only look in the primary storage */
2878     if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2879       continue;
2880 
2881     /* Is this the Music Folder */
2882     if (!strcasecmp(ob->oi.Filename, "My Music") ||
2883 	!strcasecmp(ob->oi.Filename, "My_Music") ||
2884 	!strcasecmp(ob->oi.Filename, "Music")) {
2885       device->default_music_folder = ob->oid;
2886     }
2887     else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2888 	     !strcasecmp(ob->oi.Filename, "My_Playlists") ||
2889 	     !strcasecmp(ob->oi.Filename, "Playlists")) {
2890       device->default_playlist_folder = ob->oid;
2891     }
2892     else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2893 	     !strcasecmp(ob->oi.Filename, "My_Pictures") ||
2894 	     !strcasecmp(ob->oi.Filename, "Pictures")) {
2895       device->default_picture_folder = ob->oid;
2896     }
2897     else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2898 	     !strcasecmp(ob->oi.Filename, "My_Video") ||
2899 	     !strcasecmp(ob->oi.Filename, "Video")) {
2900 	device->default_video_folder = ob->oid;
2901     }
2902     else if (!strcasecmp(ob->oi.Filename, "My Organizer") ||
2903 	     !strcasecmp(ob->oi.Filename, "My_Organizer")) {
2904       device->default_organizer_folder = ob->oid;
2905     }
2906     else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2907 	     !strcasecmp(ob->oi.Filename, "Datacasts")) {
2908       device->default_zencast_folder = ob->oid;
2909     }
2910     else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2911 	     !strcasecmp(ob->oi.Filename, "My_Albums") ||
2912 	     !strcasecmp(ob->oi.Filename, "Albums")) {
2913       device->default_album_folder = ob->oid;
2914     }
2915     else if (!strcasecmp(ob->oi.Filename, "Text") ||
2916 	     !strcasecmp(ob->oi.Filename, "Texts")) {
2917       device->default_text_folder = ob->oid;
2918     }
2919   }
2920 }
2921 
2922 /**
2923  * This function traverses a devices storage list freeing up the
2924  * strings and the structs.
2925  * @param device a pointer to the MTP device to free the storage
2926  * list for.
2927  */
free_storage_list(LIBMTP_mtpdevice_t * device)2928 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2929 {
2930   LIBMTP_devicestorage_t *storage;
2931   LIBMTP_devicestorage_t *tmp;
2932 
2933   storage = device->storage;
2934   while(storage != NULL) {
2935     if (storage->StorageDescription != NULL) {
2936       free(storage->StorageDescription);
2937     }
2938     if (storage->VolumeIdentifier != NULL) {
2939       free(storage->VolumeIdentifier);
2940     }
2941     tmp = storage;
2942     storage = storage->next;
2943     free(tmp);
2944   }
2945   device->storage = NULL;
2946 
2947   return;
2948 }
2949 
2950 /**
2951  * This function traverses a devices storage list freeing up the
2952  * strings and the structs.
2953  * @param device a pointer to the MTP device to free the storage
2954  * list for.
2955  */
sort_storage_by(LIBMTP_mtpdevice_t * device,int const sortby)2956 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2957 {
2958   LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2959 
2960   if (device->storage == NULL)
2961     return -1;
2962   if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2963     return 0;
2964 
2965   oldhead = ptr1 = ptr2 = device->storage;
2966 
2967   newlist = NULL;
2968 
2969   while(oldhead != NULL) {
2970     ptr1 = ptr2 = oldhead;
2971     while(ptr1 != NULL) {
2972 
2973       if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2974         ptr2 = ptr1;
2975       if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2976         ptr2 = ptr1;
2977 
2978       ptr1 = ptr1->next;
2979     }
2980 
2981     // Make our previous entries next point to our next
2982     if(ptr2->prev != NULL) {
2983       ptr1 = ptr2->prev;
2984       ptr1->next = ptr2->next;
2985     } else {
2986       oldhead = ptr2->next;
2987       if(oldhead != NULL)
2988         oldhead->prev = NULL;
2989     }
2990 
2991     // Make our next entries previous point to our previous
2992     ptr1 = ptr2->next;
2993     if(ptr1 != NULL) {
2994       ptr1->prev = ptr2->prev;
2995     } else {
2996       ptr1 = ptr2->prev;
2997       if(ptr1 != NULL)
2998         ptr1->next = NULL;
2999     }
3000 
3001     if(newlist == NULL) {
3002       newlist = ptr2;
3003       newlist->prev = NULL;
3004     } else {
3005       ptr2->prev = newlist;
3006       newlist->next = ptr2;
3007       newlist = newlist->next;
3008     }
3009   }
3010 
3011   if (newlist != NULL) {
3012     newlist->next = NULL;
3013     while(newlist->prev != NULL)
3014       newlist = newlist->prev;
3015     device->storage = newlist;
3016   }
3017 
3018   return 0;
3019 }
3020 
3021 /**
3022  * This function grabs the first writeable storageid from the
3023  * device storage list.
3024  * @param device a pointer to the MTP device to locate writeable
3025  *        storage for.
3026  * @param fitsize a file of this file must fit on the device.
3027  */
get_writeable_storageid(LIBMTP_mtpdevice_t * device,uint64_t fitsize)3028 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
3029 					uint64_t fitsize)
3030 {
3031   LIBMTP_devicestorage_t *storage;
3032   uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
3033   int subcall_ret;
3034 
3035   // See if there is some storage we can fit this file on.
3036   storage = device->storage;
3037   if (storage == NULL) {
3038     // Sometimes the storage just cannot be detected.
3039     store = 0x00000000U;
3040   } else {
3041     while(storage != NULL) {
3042       // These storages cannot be used.
3043       if (storage->StorageType == PTP_ST_FixedROM ||
3044 	  storage->StorageType == PTP_ST_RemovableROM) {
3045 	storage = storage->next;
3046 	continue;
3047       }
3048       // Storage IDs with the lower 16 bits 0x0000 are not supposed
3049       // to be writeable.
3050       if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
3051 	storage = storage->next;
3052 	continue;
3053       }
3054       // Also check the access capability to avoid e.g. deletable only storages
3055       if (storage->AccessCapability == PTP_AC_ReadOnly ||
3056 	  storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
3057 	storage = storage->next;
3058 	continue;
3059       }
3060       // Then see if we can fit the file.
3061       subcall_ret = check_if_file_fits(device, storage, fitsize);
3062       if (subcall_ret != 0) {
3063 	storage = storage->next;
3064       } else {
3065 	// We found a storage that is writable and can fit the file!
3066 	break;
3067       }
3068     }
3069     if (storage == NULL) {
3070       add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL,
3071 			      "get_writeable_storageid(): "
3072 			      "all device storage is full or corrupt.");
3073       return -1;
3074     }
3075     store = storage->id;
3076   }
3077 
3078   return store;
3079 }
3080 
3081 /**
3082  * Tries to suggest a storage_id of a given ID when we have a parent
3083  * @param device a pointer to the device where to search for the storage ID
3084  * @param fitsize a file of this file must fit on the device.
3085  * @param parent_id look for this ID
3086  * @ret storageID
3087  */
get_suggested_storage_id(LIBMTP_mtpdevice_t * device,uint64_t fitsize,uint32_t parent_id)3088 static int get_suggested_storage_id(LIBMTP_mtpdevice_t *device,
3089 				    uint64_t fitsize,
3090 				    uint32_t parent_id)
3091 {
3092   PTPParams *params = (PTPParams *) device->params;
3093   PTPObject *ob;
3094   uint16_t ret;
3095 
3096   ret = ptp_object_want(params, parent_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
3097   if ((ret != PTP_RC_OK) || (ob->oi.StorageID == 0)) {
3098     add_ptp_error_to_errorstack(device, ret, "get_suggested_storage_id(): "
3099 				"could not get storage id from parent id.");
3100     return get_writeable_storageid(device, fitsize);
3101   } else {
3102     /* OK we know the parent storage, then use that */
3103     return ob->oi.StorageID;
3104   }
3105 }
3106 
3107 /**
3108  * This function grabs the freespace from a certain storage in
3109  * device storage list.
3110  * @param device a pointer to the MTP device to free the storage
3111  * list for.
3112  * @param storageid the storage ID for the storage to flush and
3113  * get free space for.
3114  * @param freespace the free space on this storage will be returned
3115  * in this variable.
3116  */
get_storage_freespace(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t * freespace)3117 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
3118 				 LIBMTP_devicestorage_t *storage,
3119 				 uint64_t *freespace)
3120 {
3121   PTPParams *params = (PTPParams *) device->params;
3122 
3123   // Always query the device about this, since some models explicitly
3124   // needs that. We flush all data on queries storage here.
3125   if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3126     PTPStorageInfo storageInfo;
3127     uint16_t ret;
3128 
3129     ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
3130     if (ret != PTP_RC_OK) {
3131       add_ptp_error_to_errorstack(device, ret,
3132 		"get_storage_freespace(): could not get storage info.");
3133       return -1;
3134     }
3135     if (storage->StorageDescription != NULL) {
3136       free(storage->StorageDescription);
3137     }
3138     if (storage->VolumeIdentifier != NULL) {
3139       free(storage->VolumeIdentifier);
3140     }
3141     storage->StorageType = storageInfo.StorageType;
3142     storage->FilesystemType = storageInfo.FilesystemType;
3143     storage->AccessCapability = storageInfo.AccessCapability;
3144     storage->MaxCapacity = storageInfo.MaxCapability;
3145     storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3146     storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3147     storage->StorageDescription = storageInfo.StorageDescription;
3148     storage->VolumeIdentifier = storageInfo.VolumeLabel;
3149   }
3150   if(storage->FreeSpaceInBytes == (uint64_t) -1)
3151     return -1;
3152   *freespace = storage->FreeSpaceInBytes;
3153   return 0;
3154 }
3155 
3156 /**
3157  * This function dumps out a large chunk of textual information
3158  * provided from the PTP protocol and additionally some extra
3159  * MTP-specific information where applicable.
3160  * @param device a pointer to the MTP device to report info from.
3161  */
LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t * device)3162 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
3163 {
3164   int i;
3165   PTPParams *params = (PTPParams *) device->params;
3166   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3167   LIBMTP_devicestorage_t *storage = device->storage;
3168   LIBMTP_device_extension_t *tmpext = device->extensions;
3169 
3170   printf("USB low-level info:\n");
3171   dump_usbinfo(ptp_usb);
3172   /* Print out some verbose information */
3173   printf("Device info:\n");
3174   printf("   Manufacturer: %s\n", params->deviceinfo.Manufacturer);
3175   printf("   Model: %s\n", params->deviceinfo.Model);
3176   printf("   Device version: %s\n", params->deviceinfo.DeviceVersion);
3177   printf("   Serial number: %s\n", params->deviceinfo.SerialNumber);
3178   printf("   Vendor extension ID: 0x%08x\n",
3179 	 params->deviceinfo.VendorExtensionID);
3180   printf("   Vendor extension description: %s\n",
3181 	 params->deviceinfo.VendorExtensionDesc);
3182   printf("   Detected object size: %d bits\n",
3183 	 device->object_bitsize);
3184   printf("   Extensions:\n");
3185   while (tmpext != NULL) {
3186     printf("        %s: %d.%d\n",
3187            tmpext->name,
3188            tmpext->major,
3189            tmpext->minor);
3190     tmpext = tmpext->next;
3191   }
3192   printf("Supported operations:\n");
3193   for (i=0;i<params->deviceinfo.OperationsSupported_len;i++)
3194     printf("   %04x: %s\n", params->deviceinfo.OperationsSupported[i], ptp_get_opcode_name(params, params->deviceinfo.OperationsSupported[i]));
3195   printf("Events supported:\n");
3196   if (params->deviceinfo.EventsSupported_len == 0) {
3197     printf("   None.\n");
3198   } else {
3199     for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
3200       printf("   0x%04x (%s)\n", params->deviceinfo.EventsSupported[i], ptp_strerror(params->deviceinfo.EventsSupported[i], params->deviceinfo.VendorExtensionID));
3201     }
3202   }
3203   printf("Device Properties Supported:\n");
3204   for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
3205     char const *propdesc = ptp_get_property_description(params,
3206 			params->deviceinfo.DevicePropertiesSupported[i]);
3207 
3208     if (propdesc != NULL) {
3209       printf("   0x%04x: %s\n",
3210 	     params->deviceinfo.DevicePropertiesSupported[i], propdesc);
3211     } else {
3212       uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
3213       printf("   0x%04x: Unknown property\n", prop);
3214     }
3215   }
3216 
3217   if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
3218     printf("Playable File (Object) Types and Object Properties Supported:\n");
3219     for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3220       char txt[256];
3221       uint16_t ret;
3222       uint16_t *props = NULL;
3223       uint32_t propcnt = 0;
3224       int j;
3225 
3226       (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i],
3227 			     sizeof(txt), txt);
3228       printf("   %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
3229 
3230       ret = ptp_mtp_getobjectpropssupported (params,
3231 			params->deviceinfo.ImageFormats[i], &propcnt, &props);
3232       if (ret != PTP_RC_OK) {
3233 	add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): "
3234 				    "error on query for object properties.");
3235       } else {
3236 	for (j=0;j<propcnt;j++) {
3237 	  PTPObjectPropDesc opd;
3238 	  int k;
3239 
3240 	  printf("      %04x: %s", props[j],
3241 		 LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
3242 	  // Get a more verbose description
3243 	  ret = ptp_mtp_getobjectpropdesc(params, props[j],
3244 					  params->deviceinfo.ImageFormats[i],
3245 					  &opd);
3246 	  if (ret != PTP_RC_OK) {
3247 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3248 				    "LIBMTP_Dump_Device_Info(): "
3249 				    "could not get property description.");
3250 	    break;
3251 	  }
3252 
3253 	  if (opd.DataType == PTP_DTC_STR) {
3254 	    printf(" STRING data type");
3255 	    switch (opd.FormFlag) {
3256 	    case PTP_OPFF_DateTime:
3257 	      printf(" DATETIME FORM");
3258 	      break;
3259 	    case PTP_OPFF_RegularExpression:
3260 	      printf(" REGULAR EXPRESSION FORM");
3261 	      break;
3262 	    case PTP_OPFF_LongString:
3263 	      printf(" LONG STRING FORM");
3264 	      break;
3265 	    default:
3266 	      break;
3267 	    }
3268 	  } else {
3269 	    if (opd.DataType & PTP_DTC_ARRAY_MASK) {
3270 	      printf(" array of");
3271 	    }
3272 
3273 	    switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
3274 
3275 	    case PTP_DTC_UNDEF:
3276 	      printf(" UNDEFINED data type");
3277 	      break;
3278 	    case PTP_DTC_INT8:
3279 	      printf(" INT8 data type");
3280 	      switch (opd.FormFlag) {
3281 	      case PTP_OPFF_Range:
3282 		printf(" range: MIN %d, MAX %d, STEP %d",
3283 		       opd.FORM.Range.MinimumValue.i8,
3284 		       opd.FORM.Range.MaximumValue.i8,
3285 		       opd.FORM.Range.StepSize.i8);
3286 		break;
3287 	      case PTP_OPFF_Enumeration:
3288 		printf(" enumeration: ");
3289 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3290 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
3291 		}
3292 		break;
3293 	      case PTP_OPFF_ByteArray:
3294 		printf(" byte array: ");
3295 		break;
3296 	      default:
3297 		printf(" ANY 8BIT VALUE form");
3298 		break;
3299 	      }
3300 	      break;
3301 
3302 	    case PTP_DTC_UINT8:
3303 	      printf(" UINT8 data type");
3304 	      switch (opd.FormFlag) {
3305 	      case PTP_OPFF_Range:
3306 		printf(" range: MIN %d, MAX %d, STEP %d",
3307 		       opd.FORM.Range.MinimumValue.u8,
3308 		       opd.FORM.Range.MaximumValue.u8,
3309 		       opd.FORM.Range.StepSize.u8);
3310 		break;
3311 	      case PTP_OPFF_Enumeration:
3312 		printf(" enumeration: ");
3313 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3314 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
3315 		}
3316 		break;
3317 	      case PTP_OPFF_ByteArray:
3318 		printf(" byte array: ");
3319 		break;
3320 	      default:
3321 		printf(" ANY 8BIT VALUE form");
3322 		break;
3323 	      }
3324 	      break;
3325 
3326 	    case PTP_DTC_INT16:
3327 	      printf(" INT16 data type");
3328 	      switch (opd.FormFlag) {
3329 	      case PTP_OPFF_Range:
3330 	      printf(" range: MIN %d, MAX %d, STEP %d",
3331 		     opd.FORM.Range.MinimumValue.i16,
3332 		     opd.FORM.Range.MaximumValue.i16,
3333 		     opd.FORM.Range.StepSize.i16);
3334 	      break;
3335 	      case PTP_OPFF_Enumeration:
3336 		printf(" enumeration: ");
3337 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3338 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3339 		}
3340 		break;
3341 	      default:
3342 		printf(" ANY 16BIT VALUE form");
3343 		break;
3344 	      }
3345 	      break;
3346 
3347 	    case PTP_DTC_UINT16:
3348 	      printf(" UINT16 data type");
3349 	      switch (opd.FormFlag) {
3350 	      case PTP_OPFF_Range:
3351 		printf(" range: MIN %d, MAX %d, STEP %d",
3352 		       opd.FORM.Range.MinimumValue.u16,
3353 		       opd.FORM.Range.MaximumValue.u16,
3354 		       opd.FORM.Range.StepSize.u16);
3355 		break;
3356 	      case PTP_OPFF_Enumeration:
3357 		printf(" enumeration: ");
3358 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3359 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3360 		}
3361 		break;
3362 	      default:
3363 		printf(" ANY 16BIT VALUE form");
3364 		break;
3365 	      }
3366 	      break;
3367 
3368 	    case PTP_DTC_INT32:
3369 	      printf(" INT32 data type");
3370 	      switch (opd.FormFlag) {
3371 	      case PTP_OPFF_Range:
3372 		printf(" range: MIN %d, MAX %d, STEP %d",
3373 		       opd.FORM.Range.MinimumValue.i32,
3374 		       opd.FORM.Range.MaximumValue.i32,
3375 		       opd.FORM.Range.StepSize.i32);
3376 		break;
3377 	      case PTP_OPFF_Enumeration:
3378 		printf(" enumeration: ");
3379 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3380 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3381 		}
3382 		break;
3383 	      default:
3384 		printf(" ANY 32BIT VALUE form");
3385 		break;
3386 	      }
3387 	      break;
3388 
3389 	    case PTP_DTC_UINT32:
3390 	      printf(" UINT32 data type");
3391 	      switch (opd.FormFlag) {
3392 	      case PTP_OPFF_Range:
3393 		printf(" range: MIN %d, MAX %d, STEP %d",
3394 		       opd.FORM.Range.MinimumValue.u32,
3395 		       opd.FORM.Range.MaximumValue.u32,
3396 		       opd.FORM.Range.StepSize.u32);
3397 		break;
3398 	      case PTP_OPFF_Enumeration:
3399 		// Special pretty-print for FOURCC codes
3400 		if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3401 		  printf(" enumeration of u32 casted FOURCC: ");
3402 		  for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3403 		    if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3404 		      printf("ANY, ");
3405 		    } else {
3406 		      char fourcc[6];
3407 		      fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3408 		      fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3409 		      fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3410 		      fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3411 		      fourcc[4] = '\n';
3412 		      fourcc[5] = '\0';
3413 		      printf("\"%s\", ", fourcc);
3414 		    }
3415 		  }
3416 		} else {
3417 		  printf(" enumeration: ");
3418 		  for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3419 		    printf("%d, ", opd.FORM.Enum.SupportedValue[k].u32);
3420 		  }
3421 		}
3422 		break;
3423 	      default:
3424 		printf(" ANY 32BIT VALUE form");
3425 		break;
3426 	      }
3427 	      break;
3428 
3429 	    case PTP_DTC_INT64:
3430 	      printf(" INT64 data type");
3431 	      break;
3432 
3433 	    case PTP_DTC_UINT64:
3434 	      printf(" UINT64 data type");
3435 	      break;
3436 
3437 	    case PTP_DTC_INT128:
3438 	      printf(" INT128 data type");
3439 	      break;
3440 
3441 	    case PTP_DTC_UINT128:
3442 	      printf(" UINT128 data type");
3443 	      break;
3444 
3445 	    default:
3446 	      printf(" UNKNOWN data type");
3447 	      break;
3448 	    }
3449 	  }
3450 	  if (opd.GetSet) {
3451 	    printf(" GET/SET");
3452 	  } else {
3453 	    printf(" READ ONLY");
3454 	  }
3455 	  printf("\n");
3456 	  ptp_free_objectpropdesc(&opd);
3457 	}
3458 	free(props);
3459       }
3460     }
3461   }
3462 
3463   if(storage != NULL &&
3464      ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3465     printf("Storage Devices:\n");
3466     while(storage != NULL) {
3467       printf("   StorageID: 0x%08x\n",storage->id);
3468       printf("      StorageType: 0x%04x ",storage->StorageType);
3469       switch (storage->StorageType) {
3470       case PTP_ST_Undefined:
3471 	printf("(undefined)\n");
3472 	break;
3473       case PTP_ST_FixedROM:
3474 	printf("fixed ROM storage\n");
3475 	break;
3476       case PTP_ST_RemovableROM:
3477 	printf("removable ROM storage\n");
3478 	break;
3479       case PTP_ST_FixedRAM:
3480 	printf("fixed RAM storage\n");
3481 	break;
3482       case PTP_ST_RemovableRAM:
3483 	printf("removable RAM storage\n");
3484 	break;
3485       default:
3486 	printf("UNKNOWN storage\n");
3487 	break;
3488       }
3489       printf("      FilesystemType: 0x%04x ",storage->FilesystemType);
3490       switch(storage->FilesystemType) {
3491       case PTP_FST_Undefined:
3492 	printf("(undefined)\n");
3493 	break;
3494       case PTP_FST_GenericFlat:
3495 	printf("generic flat filesystem\n");
3496 	break;
3497       case PTP_FST_GenericHierarchical:
3498 	printf("generic hierarchical\n");
3499 	break;
3500       case PTP_FST_DCF:
3501 	printf("DCF\n");
3502 	break;
3503       default:
3504 	printf("UNKNONWN filesystem type\n");
3505 	break;
3506       }
3507       printf("      AccessCapability: 0x%04x ",storage->AccessCapability);
3508       switch(storage->AccessCapability) {
3509       case PTP_AC_ReadWrite:
3510 	printf("read/write\n");
3511 	break;
3512       case PTP_AC_ReadOnly:
3513 	printf("read only\n");
3514 	break;
3515       case PTP_AC_ReadOnly_with_Object_Deletion:
3516 	printf("read only + object deletion\n");
3517 	break;
3518       default:
3519 	printf("UNKNOWN access capability\n");
3520 	break;
3521       }
3522       printf("      MaxCapacity: %llu\n",
3523 	     (long long unsigned int) storage->MaxCapacity);
3524       printf("      FreeSpaceInBytes: %llu\n",
3525 	     (long long unsigned int) storage->FreeSpaceInBytes);
3526       printf("      FreeSpaceInObjects: %llu\n",
3527 	     (long long unsigned int) storage->FreeSpaceInObjects);
3528       printf("      StorageDescription: %s\n",storage->StorageDescription);
3529       printf("      VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3530       storage = storage->next;
3531     }
3532   }
3533 
3534   printf("Special directories:\n");
3535   printf("   Default music folder: 0x%08x\n",
3536 	 device->default_music_folder);
3537   printf("   Default playlist folder: 0x%08x\n",
3538 	 device->default_playlist_folder);
3539   printf("   Default picture folder: 0x%08x\n",
3540 	 device->default_picture_folder);
3541   printf("   Default video folder: 0x%08x\n",
3542 	 device->default_video_folder);
3543   printf("   Default organizer folder: 0x%08x\n",
3544 	 device->default_organizer_folder);
3545   printf("   Default zencast folder: 0x%08x\n",
3546 	 device->default_zencast_folder);
3547   printf("   Default album folder: 0x%08x\n",
3548 	 device->default_album_folder);
3549   printf("   Default text folder: 0x%08x\n",
3550 	 device->default_text_folder);
3551 }
3552 
3553 /**
3554  * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3555  * operation code (0x1010).
3556  * @param device a pointer to the device to reset.
3557  * @return 0 on success, any other value means failure.
3558  */
LIBMTP_Reset_Device(LIBMTP_mtpdevice_t * device)3559 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3560 {
3561   PTPParams *params = (PTPParams *) device->params;
3562   uint16_t ret;
3563 
3564   if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3565     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3566 			    "LIBMTP_Reset_Device(): "
3567 			    "device does not support resetting.");
3568     return -1;
3569   }
3570   ret = ptp_resetdevice(params);
3571   if (ret != PTP_RC_OK) {
3572     add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3573     return -1;
3574   }
3575   return 0;
3576 }
3577 
3578 /**
3579  * This retrieves the manufacturer name of an MTP device.
3580  * @param device a pointer to the device to get the manufacturer name for.
3581  * @return a newly allocated UTF-8 string representing the manufacturer name.
3582  *         The string must be freed by the caller after use. If the call
3583  *         was unsuccessful this will contain NULL.
3584  */
LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t * device)3585 char *LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t *device)
3586 {
3587   char *retmanuf = NULL;
3588   PTPParams *params = (PTPParams *) device->params;
3589 
3590   if (params->deviceinfo.Manufacturer != NULL) {
3591     retmanuf = strdup(params->deviceinfo.Manufacturer);
3592   }
3593   return retmanuf;
3594 }
3595 
3596 /**
3597  * This retrieves the model name (often equal to product name)
3598  * of an MTP device.
3599  * @param device a pointer to the device to get the model name for.
3600  * @return a newly allocated UTF-8 string representing the model name.
3601  *         The string must be freed by the caller after use. If the call
3602  *         was unsuccessful this will contain NULL.
3603  */
LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t * device)3604 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3605 {
3606   char *retmodel = NULL;
3607   PTPParams *params = (PTPParams *) device->params;
3608 
3609   if (params->deviceinfo.Model != NULL) {
3610     retmodel = strdup(params->deviceinfo.Model);
3611   }
3612   return retmodel;
3613 }
3614 
3615 /**
3616  * This retrieves the serial number of an MTP device.
3617  * @param device a pointer to the device to get the serial number for.
3618  * @return a newly allocated UTF-8 string representing the serial number.
3619  *         The string must be freed by the caller after use. If the call
3620  *         was unsuccessful this will contain NULL.
3621  */
LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t * device)3622 char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
3623 {
3624   char *retnumber = NULL;
3625   PTPParams *params = (PTPParams *) device->params;
3626 
3627   if (params->deviceinfo.SerialNumber != NULL) {
3628     retnumber = strdup(params->deviceinfo.SerialNumber);
3629   }
3630   return retnumber;
3631 }
3632 
3633 /**
3634  * This retrieves the device version (hardware and firmware version) of an
3635  * MTP device.
3636  * @param device a pointer to the device to get the device version for.
3637  * @return a newly allocated UTF-8 string representing the device version.
3638  *         The string must be freed by the caller after use. If the call
3639  *         was unsuccessful this will contain NULL.
3640  */
LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t * device)3641 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3642 {
3643   char *retversion = NULL;
3644   PTPParams *params = (PTPParams *) device->params;
3645 
3646   if (params->deviceinfo.DeviceVersion != NULL) {
3647     retversion = strdup(params->deviceinfo.DeviceVersion);
3648   }
3649   return retversion;
3650 }
3651 
3652 
3653 /**
3654  * This retrieves the "friendly name" of an MTP device. Usually
3655  * this is simply the name of the owner or something like
3656  * "John Doe's Digital Audio Player". This property should be supported
3657  * by all MTP devices.
3658  * @param device a pointer to the device to get the friendly name for.
3659  * @return a newly allocated UTF-8 string representing the friendly name.
3660  *         The string must be freed by the caller after use.
3661  * @see LIBMTP_Set_Friendlyname()
3662  */
LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t * device)3663 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3664 {
3665   PTPPropertyValue propval;
3666   char *retstring = NULL;
3667   PTPParams *params = (PTPParams *) device->params;
3668   uint16_t ret;
3669 
3670   if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3671     return NULL;
3672   }
3673 
3674   ret = ptp_getdevicepropvalue(params,
3675 			       PTP_DPC_MTP_DeviceFriendlyName,
3676 			       &propval,
3677 			       PTP_DTC_STR);
3678   if (ret != PTP_RC_OK) {
3679     add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3680     return NULL;
3681   }
3682   if (propval.str != NULL) {
3683     retstring = strdup(propval.str);
3684     free(propval.str);
3685   }
3686   return retstring;
3687 }
3688 
3689 /**
3690  * Sets the "friendly name" of an MTP device.
3691  * @param device a pointer to the device to set the friendly name for.
3692  * @param friendlyname the new friendly name for the device.
3693  * @return 0 on success, any other value means failure.
3694  * @see LIBMTP_Get_Friendlyname()
3695  */
LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t * device,char const * const friendlyname)3696 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3697 			 char const * const friendlyname)
3698 {
3699   PTPPropertyValue propval;
3700   PTPParams *params = (PTPParams *) device->params;
3701   uint16_t ret;
3702 
3703   if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3704     return -1;
3705   }
3706   propval.str = (char *) friendlyname;
3707   ret = ptp_setdevicepropvalue(params,
3708 			       PTP_DPC_MTP_DeviceFriendlyName,
3709 			       &propval,
3710 			       PTP_DTC_STR);
3711   if (ret != PTP_RC_OK) {
3712     add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3713     return -1;
3714   }
3715   return 0;
3716 }
3717 
3718 /**
3719  * This retrieves the syncronization partner of an MTP device. This
3720  * property should be supported by all MTP devices.
3721  * @param device a pointer to the device to get the sync partner for.
3722  * @return a newly allocated UTF-8 string representing the synchronization
3723  *         partner. The string must be freed by the caller after use.
3724  * @see LIBMTP_Set_Syncpartner()
3725  */
LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t * device)3726 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3727 {
3728   PTPPropertyValue propval;
3729   char *retstring = NULL;
3730   PTPParams *params = (PTPParams *) device->params;
3731   uint16_t ret;
3732 
3733   if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3734     return NULL;
3735   }
3736 
3737   ret = ptp_getdevicepropvalue(params,
3738 			       PTP_DPC_MTP_SynchronizationPartner,
3739 			       &propval,
3740 			       PTP_DTC_STR);
3741   if (ret != PTP_RC_OK) {
3742     add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3743     return NULL;
3744   }
3745   if (propval.str != NULL) {
3746     retstring = strdup(propval.str);
3747     free(propval.str);
3748   }
3749   return retstring;
3750 }
3751 
3752 
3753 /**
3754  * Sets the synchronization partner of an MTP device. Note that
3755  * we have no idea what the effect of setting this to "foobar"
3756  * may be. But the general idea seems to be to tell which program
3757  * shall synchronize with this device and tell others to leave
3758  * it alone.
3759  * @param device a pointer to the device to set the sync partner for.
3760  * @param syncpartner the new synchronization partner for the device.
3761  * @return 0 on success, any other value means failure.
3762  * @see LIBMTP_Get_Syncpartner()
3763  */
LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t * device,char const * const syncpartner)3764 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3765 			 char const * const syncpartner)
3766 {
3767   PTPPropertyValue propval;
3768   PTPParams *params = (PTPParams *) device->params;
3769   uint16_t ret;
3770 
3771   if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3772     return -1;
3773   }
3774   propval.str = (char *) syncpartner;
3775   ret = ptp_setdevicepropvalue(params,
3776 			       PTP_DPC_MTP_SynchronizationPartner,
3777 			       &propval,
3778 			       PTP_DTC_STR);
3779   if (ret != PTP_RC_OK) {
3780     add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3781     return -1;
3782   }
3783   return 0;
3784 }
3785 
3786 /**
3787  * Checks if the device can stora a file of this size or
3788  * if it's too big.
3789  * @param device a pointer to the device.
3790  * @param filesize the size of the file to check whether it will fit.
3791  * @param storageid the ID of the storage to try to fit the file on.
3792  * @return 0 if the file fits, any other value means failure.
3793  */
check_if_file_fits(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t const filesize)3794 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3795 			      LIBMTP_devicestorage_t *storage,
3796 			      uint64_t const filesize) {
3797   PTPParams *params = (PTPParams *) device->params;
3798   uint64_t freebytes;
3799   int ret;
3800 
3801   // If we cannot check the storage, no big deal.
3802   if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3803     return 0;
3804   }
3805 
3806   ret = get_storage_freespace(device, storage, &freebytes);
3807   if (ret != 0) {
3808     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3809 			    "check_if_file_fits(): error checking free storage.");
3810     return -1;
3811   } else {
3812     // See if it fits.
3813     if (filesize > freebytes) {
3814       return -1;
3815     }
3816   }
3817   return 0;
3818 }
3819 
3820 
3821 /**
3822  * This function retrieves the current battery level on the device.
3823  * @param device a pointer to the device to get the battery level for.
3824  * @param maximum_level a pointer to a variable that will hold the
3825  *        maximum level of the battery if the call was successful.
3826  * @param current_level a pointer to a variable that will hold the
3827  *        current level of the battery if the call was successful.
3828  *        A value of 0 means that the device is on external power.
3829  * @return 0 if the storage info was successfully retrieved, any other
3830  *        means failure. A typical cause of failure is that
3831  *        the device does not support the battery level property.
3832  */
LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t * device,uint8_t * const maximum_level,uint8_t * const current_level)3833 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3834 			    uint8_t * const maximum_level,
3835 			    uint8_t * const current_level)
3836 {
3837   PTPPropertyValue propval;
3838   uint16_t ret;
3839   PTPParams *params = (PTPParams *) device->params;
3840   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3841 
3842   *maximum_level = 0;
3843   *current_level = 0;
3844 
3845   if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3846       !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3847     return -1;
3848   }
3849 
3850   ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel,
3851 			       &propval, PTP_DTC_UINT8);
3852   if (ret != PTP_RC_OK) {
3853     add_ptp_error_to_errorstack(device, ret,
3854 				"LIBMTP_Get_Batterylevel(): "
3855 				"could not get device property value.");
3856     return -1;
3857   }
3858 
3859   *maximum_level = device->maximum_battery_level;
3860   *current_level = propval.u8;
3861 
3862   return 0;
3863 }
3864 
3865 
3866 /**
3867  * Formats device storage (if the device supports the operation).
3868  * WARNING: This WILL delete all data from the device. Make sure you've
3869  * got confirmation from the user BEFORE you call this function.
3870  *
3871  * @param device a pointer to the device containing the storage to format.
3872  * @param storage the actual storage to format.
3873  * @return 0 on success, any other value means failure.
3874  */
LIBMTP_Format_Storage(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage)3875 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device,
3876 			  LIBMTP_devicestorage_t *storage)
3877 {
3878   uint16_t ret;
3879   PTPParams *params = (PTPParams *) device->params;
3880 
3881   if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3882     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3883 			    "LIBMTP_Format_Storage(): "
3884 			    "device does not support formatting storage.");
3885     return -1;
3886   }
3887   ret = ptp_formatstore(params, storage->id);
3888   if (ret != PTP_RC_OK) {
3889     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): "
3890 				"failed to format storage.");
3891     return -1;
3892   }
3893   return 0;
3894 }
3895 
3896 /**
3897  * Helper function to extract a unicode property off a device.
3898  * This is the standard way of retrieveing unicode device
3899  * properties as described by the PTP spec.
3900  * @param device a pointer to the device to get the property from.
3901  * @param unicstring a pointer to a pointer that will hold the
3902  *        property after this call is completed.
3903  * @param property the property to retrieve.
3904  * @return 0 on success, any other value means failure.
3905  */
get_device_unicode_property(LIBMTP_mtpdevice_t * device,char ** unicstring,uint16_t property)3906 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3907 				       char **unicstring, uint16_t property)
3908 {
3909   PTPPropertyValue propval;
3910   PTPParams *params = (PTPParams *) device->params;
3911   uint16_t *tmp;
3912   uint16_t ret;
3913   int i;
3914 
3915   if (!ptp_property_issupported(params, property)) {
3916     return -1;
3917   }
3918 
3919   // Unicode strings are 16bit unsigned integer arrays.
3920   ret = ptp_getdevicepropvalue(params,
3921 			       property,
3922 			       &propval,
3923 			       PTP_DTC_AUINT16);
3924   if (ret != PTP_RC_OK) {
3925     // TODO: add a note on WHICH property that we failed to get.
3926     *unicstring = NULL;
3927     add_ptp_error_to_errorstack(device, ret,
3928 				"get_device_unicode_property(): "
3929 				"failed to get unicode property.");
3930     return -1;
3931   }
3932 
3933   // Extract the actual array.
3934   // printf("Array of %d elements\n", propval.a.count);
3935   tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3936   for (i = 0; i < propval.a.count; i++) {
3937     tmp[i] = propval.a.v[i].u16;
3938     // printf("%04x ", tmp[i]);
3939   }
3940   tmp[propval.a.count] = 0x0000U;
3941   free(propval.a.v);
3942 
3943   *unicstring = utf16_to_utf8(device, tmp);
3944 
3945   free(tmp);
3946 
3947   return 0;
3948 }
3949 
3950 /**
3951  * This function returns the secure time as an XML document string from
3952  * the device.
3953  * @param device a pointer to the device to get the secure time for.
3954  * @param sectime the secure time string as an XML document or NULL if the call
3955  *         failed or the secure time property is not supported. This string
3956  *         must be <code>free()</code>:ed by the caller after use.
3957  * @return 0 on success, any other value means failure.
3958  */
LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t * device,char ** const sectime)3959 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3960 {
3961   return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3962 }
3963 
3964 /**
3965  * This function returns the device (public key) certificate as an
3966  * XML document string from the device.
3967  * @param device a pointer to the device to get the device certificate for.
3968  * @param devcert the device certificate as an XML string or NULL if the call
3969  *        failed or the device certificate property is not supported. This
3970  *        string must be <code>free()</code>:ed by the caller after use.
3971  * @return 0 on success, any other value means failure.
3972  */
LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t * device,char ** const devcert)3973 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3974 {
3975   return get_device_unicode_property(device, devcert,
3976 				     PTP_DPC_MTP_DeviceCertificate);
3977 }
3978 
3979 /**
3980  * This function retrieves a list of supported file types, i.e. the file
3981  * types that this device claims it supports, e.g. audio file types that
3982  * the device can play etc. This list is mitigated to
3983  * inlcude the file types that libmtp can handle, i.e. it will not list
3984  * filetypes that libmtp will handle internally like playlists and folders.
3985  * @param device a pointer to the device to get the filetype capabilities for.
3986  * @param filetypes a pointer to a pointer that will hold the list of
3987  *        supported filetypes if the call was successful. This list must
3988  *        be <code>free()</code>:ed by the caller after use.
3989  * @param length a pointer to a variable that will hold the length of the
3990  *        list of supported filetypes if the call was successful.
3991  * @return 0 on success, any other value means failure.
3992  * @see LIBMTP_Get_Filetype_Description()
3993  */
LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t * device,uint16_t ** const filetypes,uint16_t * const length)3994 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
3995 				  uint16_t * const length)
3996 {
3997   PTPParams *params = (PTPParams *) device->params;
3998   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3999   uint16_t *localtypes;
4000   uint16_t localtypelen;
4001   uint32_t i;
4002 
4003   // This is more memory than needed if there are unknown types, but what the heck.
4004   localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
4005   localtypelen = 0;
4006 
4007   for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
4008     uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
4009     if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
4010       localtypes[localtypelen] = localtype;
4011       localtypelen++;
4012     }
4013   }
4014   // The forgotten Ogg support on YP-10 and others...
4015   if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
4016     localtypes = (uint16_t *) realloc(localtypes,
4017 		(params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4018     localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
4019     localtypelen++;
4020   }
4021   // The forgotten FLAC support on Cowon iAudio S9 and others...
4022   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
4023     localtypes = (uint16_t *) realloc(localtypes,
4024 		(params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4025     localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
4026     localtypelen++;
4027   }
4028 
4029   *filetypes = localtypes;
4030   *length = localtypelen;
4031 
4032   return 0;
4033 }
4034 
4035 /**
4036  * This function checks if the device has some specific capabilities, in
4037  * order to avoid calling APIs that may disturb the device.
4038  *
4039  * @param device a pointer to the device to check the capability on.
4040  * @param cap the capability to check.
4041  * @return 0 if not supported, any other value means the device has the
4042  * requested capability.
4043  */
LIBMTP_Check_Capability(LIBMTP_mtpdevice_t * device,LIBMTP_devicecap_t cap)4044 int LIBMTP_Check_Capability(LIBMTP_mtpdevice_t *device, LIBMTP_devicecap_t cap)
4045 {
4046   switch (cap) {
4047   case LIBMTP_DEVICECAP_GetPartialObject:
4048     return (ptp_operation_issupported(device->params,
4049 				      PTP_OC_GetPartialObject) ||
4050 	    ptp_operation_issupported(device->params,
4051 				      PTP_OC_ANDROID_GetPartialObject64));
4052   case LIBMTP_DEVICECAP_SendPartialObject:
4053     return ptp_operation_issupported(device->params,
4054 				     PTP_OC_ANDROID_SendPartialObject);
4055   case LIBMTP_DEVICECAP_EditObjects:
4056     return (ptp_operation_issupported(device->params,
4057 				      PTP_OC_ANDROID_TruncateObject) &&
4058 	    ptp_operation_issupported(device->params,
4059 				      PTP_OC_ANDROID_BeginEditObject) &&
4060 	    ptp_operation_issupported(device->params,
4061 				      PTP_OC_ANDROID_EndEditObject));
4062   /*
4063    * Handle other capabilities here, this is also a good place to
4064    * blacklist some advanced operations on specific devices if need
4065    * be.
4066    */
4067 
4068   default:
4069     break;
4070   }
4071   return 0;
4072 }
4073 
4074 /**
4075  * This function updates all the storage id's of a device and their
4076  * properties, then creates a linked list and puts the list head into
4077  * the device struct. It also optionally sorts this list. If you want
4078  * to display storage information in your application you should call
4079  * this function, then dereference the device struct
4080  * (<code>device-&gt;storage</code>) to get out information on the storage.
4081  *
4082  * You need to call this everytime you want to update the
4083  * <code>device-&gt;storage</code> list, for example anytime you need
4084  * to check available storage somewhere.
4085  *
4086  * <b>WARNING:</b> since this list is dynamically updated, do not
4087  * reference its fields in external applications by pointer! E.g
4088  * do not put a reference to any <code>char *</code> field. instead
4089  * <code>strncpy()</code> it!
4090  *
4091  * @param device a pointer to the device to get the storage for.
4092  * @param sortby an integer that determines the sorting of the storage list.
4093  *        Valid sort methods are defined in libmtp.h with beginning with
4094  *        LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
4095  *        sort.
4096  * @return 0 on success, 1 success but only with storage id's, storage
4097  *        properities could not be retrieved and -1 means failure.
4098  */
LIBMTP_Get_Storage(LIBMTP_mtpdevice_t * device,int const sortby)4099 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
4100 {
4101   uint32_t i = 0;
4102   PTPStorageInfo storageInfo;
4103   PTPParams *params = (PTPParams *) device->params;
4104   PTPStorageIDs storageIDs;
4105   LIBMTP_devicestorage_t *storage = NULL;
4106   LIBMTP_devicestorage_t *storageprev = NULL;
4107 
4108   if (device->storage != NULL)
4109     free_storage_list(device);
4110 
4111   // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
4112   //   return -1;
4113   if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
4114     return -1;
4115   if (storageIDs.n < 1)
4116     return -1;
4117 
4118   if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
4119     for (i = 0; i < storageIDs.n; i++) {
4120 
4121       storage = (LIBMTP_devicestorage_t *)
4122 	malloc(sizeof(LIBMTP_devicestorage_t));
4123       storage->prev = storageprev;
4124       if (storageprev != NULL)
4125         storageprev->next = storage;
4126       if (device->storage == NULL)
4127         device->storage = storage;
4128 
4129       storage->id = storageIDs.Storage[i];
4130       storage->StorageType = PTP_ST_Undefined;
4131       storage->FilesystemType = PTP_FST_Undefined;
4132       storage->AccessCapability = PTP_AC_ReadWrite;
4133       storage->MaxCapacity = (uint64_t) -1;
4134       storage->FreeSpaceInBytes = (uint64_t) -1;
4135       storage->FreeSpaceInObjects = (uint64_t) -1;
4136       storage->StorageDescription = strdup("Unknown storage");
4137       storage->VolumeIdentifier = strdup("Unknown volume");
4138       storage->next = NULL;
4139 
4140       storageprev = storage;
4141     }
4142     free(storageIDs.Storage);
4143     return 1;
4144   } else {
4145     for (i = 0; i < storageIDs.n; i++) {
4146       uint16_t ret;
4147       ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
4148       if (ret != PTP_RC_OK) {
4149 	add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): "
4150 				    "Could not get storage info.");
4151 	if (device->storage != NULL) {
4152           free_storage_list(device);
4153 	}
4154 	return -1;
4155       }
4156 
4157       storage = (LIBMTP_devicestorage_t *)
4158 	malloc(sizeof(LIBMTP_devicestorage_t));
4159       storage->prev = storageprev;
4160       if (storageprev != NULL)
4161         storageprev->next = storage;
4162       if (device->storage == NULL)
4163         device->storage = storage;
4164 
4165       storage->id = storageIDs.Storage[i];
4166       storage->StorageType = storageInfo.StorageType;
4167       storage->FilesystemType = storageInfo.FilesystemType;
4168       storage->AccessCapability = storageInfo.AccessCapability;
4169       storage->MaxCapacity = storageInfo.MaxCapability;
4170       storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
4171       storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
4172       storage->StorageDescription = storageInfo.StorageDescription;
4173       storage->VolumeIdentifier = storageInfo.VolumeLabel;
4174       storage->next = NULL;
4175 
4176       storageprev = storage;
4177     }
4178 
4179     if (storage != NULL)
4180       storage->next = NULL;
4181 
4182     sort_storage_by(device,sortby);
4183     free(storageIDs.Storage);
4184     return 0;
4185   }
4186 }
4187 
4188 /**
4189  * This creates a new file metadata structure and allocates memory
4190  * for it. Notice that if you add strings to this structure they
4191  * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
4192  * operation later, so be careful of using strdup() when assigning
4193  * strings, e.g.:
4194  *
4195  * <pre>
4196  * LIBMTP_file_t *file = LIBMTP_new_file_t();
4197  * file->filename = strdup(namestr);
4198  * ....
4199  * LIBMTP_destroy_file_t(file);
4200  * </pre>
4201  *
4202  * @return a pointer to the newly allocated metadata structure.
4203  * @see LIBMTP_destroy_file_t()
4204  */
LIBMTP_new_file_t(void)4205 LIBMTP_file_t *LIBMTP_new_file_t(void)
4206 {
4207   LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
4208   if (new == NULL) {
4209     return NULL;
4210   }
4211   new->filename = NULL;
4212   new->item_id = 0;
4213   new->parent_id = 0;
4214   new->storage_id = 0;
4215   new->filesize = 0;
4216   new->modificationdate = 0;
4217   new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4218   new->next = NULL;
4219   return new;
4220 }
4221 
4222 /**
4223  * This destroys a file metadata structure and deallocates the memory
4224  * used by it, including any strings. Never use a file metadata
4225  * structure again after calling this function on it.
4226  * @param file the file metadata to destroy.
4227  * @see LIBMTP_new_file_t()
4228  */
LIBMTP_destroy_file_t(LIBMTP_file_t * file)4229 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
4230 {
4231   if (file == NULL) {
4232     return;
4233   }
4234   if (file->filename != NULL)
4235     free(file->filename);
4236   free(file);
4237   return;
4238 }
4239 
4240 /**
4241  * Helper function that takes one PTP object and creates a
4242  * LIBMTP_file_t metadata entry.
4243  */
obj2file(LIBMTP_mtpdevice_t * device,PTPObject * ob)4244 static LIBMTP_file_t *obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
4245 {
4246   PTPParams *params = (PTPParams *) device->params;
4247   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4248   LIBMTP_file_t *file;
4249   int i;
4250 
4251   // Allocate a new file type
4252   file = LIBMTP_new_file_t();
4253 
4254   file->parent_id = ob->oi.ParentObject;
4255   file->storage_id = ob->oi.StorageID;
4256 
4257   // Set the filetype
4258   file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4259 
4260   /*
4261    * A special quirk for devices that doesn't quite
4262    * remember that some files marked as "unknown" type are
4263    * actually OGG or FLAC files. We look at the filename extension
4264    * and see if it happens that this was atleast named "ogg" or "flac"
4265    * and fall back on this heuristic approach in that case,
4266    * for these bugged devices only.
4267    */
4268   if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
4269     if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4270 	 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4271         has_ogg_extension(file->filename)) {
4272       file->filetype = LIBMTP_FILETYPE_OGG;
4273     }
4274 
4275     if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename)) {
4276         file->filetype = LIBMTP_FILETYPE_FLAC;
4277     }
4278   }
4279 
4280   // Set the modification date
4281   file->modificationdate = ob->oi.ModificationDate;
4282 
4283   // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4284   file->filesize = ob->oi.ObjectCompressedSize;
4285   if (ob->oi.Filename != NULL) {
4286     file->filename = strdup(ob->oi.Filename);
4287   }
4288 
4289   // This is a unique ID so we can keep track of the file.
4290   file->item_id = ob->oid;
4291 
4292   /*
4293    * If we have a cached, large set of metadata, then use it!
4294    */
4295   if (ob->mtpprops) {
4296     MTPProperties *prop = ob->mtpprops;
4297 
4298     for (i=0; i < ob->nrofmtpprops; i++, prop++) {
4299       // Pick ObjectSize here...
4300       if (prop->property == PTP_OPC_ObjectSize) {
4301 	// This may already be set, but this 64bit precision value
4302 	// is better than the PTP 32bit value, so let it override.
4303 	if (device->object_bitsize == 64) {
4304 	  file->filesize = prop->propval.u64;
4305 	} else {
4306 	  file->filesize = prop->propval.u32;
4307 	}
4308 	break;
4309       }
4310     }
4311   } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
4312     uint16_t *props = NULL;
4313     uint32_t propcnt = 0;
4314     int ret;
4315 
4316     // First see which properties can be retrieved for this object format
4317     ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4318     if (ret != PTP_RC_OK) {
4319       add_ptp_error_to_errorstack(device, ret, "obj2file: call to ptp_mtp_getobjectpropssupported() failed.");
4320       // Silently fall through.
4321     } else {
4322       for (i = 0; i < propcnt; i++) {
4323 	switch (props[i]) {
4324 	case PTP_OPC_ObjectSize:
4325 	  if (device->object_bitsize == 64) {
4326 	    file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4327 	  } else {
4328 	    file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4329 	  }
4330 	  break;
4331 	default:
4332 	  break;
4333 	}
4334       }
4335       free(props);
4336     }
4337   }
4338 
4339   return file;
4340 }
4341 
4342 
4343 /**
4344  * This function retrieves the metadata for a single file off
4345  * the device.
4346  *
4347  * Do not call this function repeatedly! The file handles are linearly
4348  * searched O(n) and the call may involve (slow) USB traffic, so use
4349  * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4350  * as an efficient data structure such as a hash list.
4351  *
4352  * Incidentally this function will return metadata for
4353  * a folder (association) as well, but this is not a proper use
4354  * of it, it is intended for file manipulation, not folder manipulation.
4355  *
4356  * @param device a pointer to the device to get the file metadata from.
4357  * @param fileid the object ID of the file that you want the metadata for.
4358  * @return a metadata entry on success or NULL on failure.
4359  * @see LIBMTP_Get_Filelisting()
4360  */
LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t * device,uint32_t const fileid)4361 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4362 {
4363   PTPParams *params = (PTPParams *) device->params;
4364   uint16_t ret;
4365   PTPObject *ob;
4366 
4367   // Get all the handles if we haven't already done that
4368   // (Only on cached devices.)
4369   if (device->cached && params->nrofobjects == 0) {
4370     flush_handles(device);
4371   }
4372 
4373   ret = ptp_object_want(params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4374   if (ret != PTP_RC_OK)
4375     return NULL;
4376 
4377   return obj2file(device, ob);
4378 }
4379 
4380 /**
4381 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4382  * NOT TO USE IT.
4383  * @see LIBMTP_Get_Filelisting_With_Callback()
4384  */
LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t * device)4385 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
4386 {
4387   LIBMTP_INFO("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
4388   LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
4389   return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
4390 }
4391 
4392 /**
4393  * This returns a long list of all files available
4394  * on the current MTP device. Folders will not be returned, but abstract
4395  * entities like playlists and albums will show up as "files". Typical usage:
4396  *
4397  * <pre>
4398  * LIBMTP_file_t *filelist;
4399  *
4400  * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
4401  * while (filelist != NULL) {
4402  *   LIBMTP_file_t *tmp;
4403  *
4404  *   // Do something on each element in the list here...
4405  *   tmp = filelist;
4406  *   filelist = filelist->next;
4407  *   LIBMTP_destroy_file_t(tmp);
4408  * }
4409  * </pre>
4410  *
4411  * If you want to group your file listing by storage (per storage unit) or
4412  * arrange files into folders, you must dereference the <code>storage_id</code>
4413  * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
4414  * struct. To arrange by folders or files you typically have to create the proper
4415  * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4416  * <code>LIBMTP_Get_Folder_List()</code> first.
4417  *
4418  * @param device a pointer to the device to get the file listing for.
4419  * @param callback a function to be called during the tracklisting retrieveal
4420  *        for displaying progress bars etc, or NULL if you don't want
4421  *        any callbacks.
4422  * @param data a user-defined pointer that is passed along to
4423  *        the <code>progress</code> function in order to
4424  *        pass along some user defined data to the progress
4425  *        updates. If not used, set this to NULL.
4426  * @return a list of files that can be followed using the <code>next</code>
4427  *        field of the <code>LIBMTP_file_t</code> data structure.
4428  *        Each of the metadata tags must be freed after use, and may
4429  *        contain only partial metadata information, i.e. one or several
4430  *        fields may be NULL or 0.
4431  * @see LIBMTP_Get_Filemetadata()
4432  */
LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4433 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
4434                                                     LIBMTP_progressfunc_t const callback,
4435                                                     void const * const data)
4436 {
4437   uint32_t i = 0;
4438   LIBMTP_file_t *retfiles = NULL;
4439   LIBMTP_file_t *curfile = NULL;
4440   PTPParams *params = (PTPParams *) device->params;
4441 
4442   // Get all the handles if we haven't already done that
4443   if (params->nrofobjects == 0) {
4444     flush_handles(device);
4445   }
4446 
4447   for (i = 0; i < params->nrofobjects; i++) {
4448     LIBMTP_file_t *file;
4449     PTPObject *ob;
4450 
4451     if (callback != NULL)
4452       callback(i, params->nrofobjects, data);
4453 
4454     ob = &params->objects[i];
4455 
4456     if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4457       // MTP use this object format for folders which means
4458       // these "files" will turn up on a folder listing instead.
4459       continue;
4460     }
4461 
4462     // Look up metadata
4463     file = obj2file(device, ob);
4464     if (file == NULL) {
4465       continue;
4466     }
4467 
4468     // Add track to a list that will be returned afterwards.
4469     if (retfiles == NULL) {
4470       retfiles = file;
4471       curfile = file;
4472     } else {
4473       curfile->next = file;
4474       curfile = file;
4475     }
4476 
4477     // Call listing callback
4478     // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4479 
4480   } // Handle counting loop
4481   return retfiles;
4482 }
4483 
4484 /**
4485  * This function retrieves the contents of a certain folder
4486  * with id parent on a certain storage on a certain device.
4487  * The result contains both files and folders.
4488  * The device used with this operations must have been opened with
4489  * LIBMTP_Open_Raw_Device_Uncached() or it will fail.
4490  *
4491  * NOTE: the request will always perform I/O with the device.
4492  * @param device a pointer to the MTP device to report info from.
4493  * @param storage a storage on the device to report info from. If
4494  *        0 is passed in, the files for the given parent will be
4495  *        searched across all available storages.
4496  * @param parent the parent folder id.
4497  */
LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t * device,uint32_t const storage,uint32_t const parent)4498 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device,
4499 			     uint32_t const storage,
4500 			     uint32_t const parent)
4501 {
4502   PTPParams *params = (PTPParams *) device->params;
4503   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4504   LIBMTP_file_t *retfiles = NULL;
4505   LIBMTP_file_t *curfile = NULL;
4506   PTPObjectHandles currentHandles;
4507   uint32_t storageid;
4508   uint16_t ret;
4509   int i = 0;
4510 
4511   if (device->cached) {
4512     // This function is only supposed to be used by devices
4513     // opened as uncached!
4514     LIBMTP_ERROR("tried to use %s on a cached device!\n",
4515 		 __func__);
4516     return NULL;
4517   }
4518 
4519   if (FLAG_BROKEN_GET_OBJECT_PROPVAL(ptp_usb)) {
4520     // These devices cannot handle the commands needed for
4521     // Uncached access!
4522     LIBMTP_ERROR("tried to use %s on an unsupported device, "
4523 		 "this command does not work on all devices "
4524 		 "due to missing low-level support to read "
4525 		 "information on individual tracks\n",
4526 		 __func__);
4527     return NULL;
4528   }
4529 
4530   if (storage == 0)
4531     storageid = PTP_GOH_ALL_STORAGE;
4532   else
4533     storageid = storage;
4534 
4535   ret = ptp_getobjecthandles(params,
4536 			     storageid,
4537 			     PTP_GOH_ALL_FORMATS,
4538 			     parent,
4539 			     &currentHandles);
4540 
4541   if (ret != PTP_RC_OK) {
4542     add_ptp_error_to_errorstack(device, ret,
4543 		"LIBMTP_Get_Files_And_Folders(): could not get object handles.");
4544     return NULL;
4545   }
4546 
4547   if (currentHandles.Handler == NULL || currentHandles.n == 0)
4548     return NULL;
4549 
4550   for (i = 0; i < currentHandles.n; i++) {
4551     LIBMTP_file_t *file;
4552 
4553     // Get metadata for one file, if it fails, try next file
4554     file = LIBMTP_Get_Filemetadata(device, currentHandles.Handler[i]);
4555     if (file == NULL)
4556       continue;
4557 
4558     // Add track to a list that will be returned afterwards.
4559     if (curfile == NULL) {
4560       curfile = file;
4561       retfiles = file;
4562     } else {
4563       curfile->next = file;
4564       curfile = file;
4565     }
4566   }
4567 
4568   free(currentHandles.Handler);
4569 
4570   // Return a pointer to the original first file
4571   // in the big list.
4572   return retfiles;
4573 }
4574 
LIBMTP_Set_Load_Cache_On_Demand(int flag)4575 void LIBMTP_Set_Load_Cache_On_Demand(int flag)
4576 {
4577   load_cache_on_demand = flag;
4578 }
4579 
4580 /**
4581  * This creates a new track metadata structure and allocates memory
4582  * for it. Notice that if you add strings to this structure they
4583  * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4584  * operation later, so be careful of using strdup() when assigning
4585  * strings, e.g.:
4586  *
4587  * <pre>
4588  * LIBMTP_track_t *track = LIBMTP_new_track_t();
4589  * track->title = strdup(titlestr);
4590  * ....
4591  * LIBMTP_destroy_track_t(track);
4592  * </pre>
4593  *
4594  * @return a pointer to the newly allocated metadata structure.
4595  * @see LIBMTP_destroy_track_t()
4596  */
LIBMTP_new_track_t(void)4597 LIBMTP_track_t *LIBMTP_new_track_t(void)
4598 {
4599   LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4600   if (new == NULL) {
4601     return NULL;
4602   }
4603   new->item_id = 0;
4604   new->parent_id = 0;
4605   new->storage_id = 0;
4606   new->title = NULL;
4607   new->artist = NULL;
4608   new->composer = NULL;
4609   new->album = NULL;
4610   new->genre = NULL;
4611   new->date = NULL;
4612   new->filename = NULL;
4613   new->duration = 0;
4614   new->tracknumber = 0;
4615   new->filesize = 0;
4616   new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4617   new->samplerate = 0;
4618   new->nochannels = 0;
4619   new->wavecodec = 0;
4620   new->bitrate = 0;
4621   new->bitratetype = 0;
4622   new->rating = 0;
4623   new->usecount = 0;
4624   new->modificationdate = 0;
4625   new->next = NULL;
4626   return new;
4627 }
4628 
4629 /**
4630  * This destroys a track metadata structure and deallocates the memory
4631  * used by it, including any strings. Never use a track metadata
4632  * structure again after calling this function on it.
4633  * @param track the track metadata to destroy.
4634  * @see LIBMTP_new_track_t()
4635  */
LIBMTP_destroy_track_t(LIBMTP_track_t * track)4636 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4637 {
4638   if (track == NULL) {
4639     return;
4640   }
4641   if (track->title != NULL)
4642     free(track->title);
4643   if (track->artist != NULL)
4644     free(track->artist);
4645   if (track->composer != NULL)
4646     free(track->composer);
4647   if (track->album != NULL)
4648     free(track->album);
4649   if (track->genre != NULL)
4650     free(track->genre);
4651   if (track->date != NULL)
4652     free(track->date);
4653   if (track->filename != NULL)
4654     free(track->filename);
4655   free(track);
4656   return;
4657 }
4658 
4659 /**
4660  * This function maps and copies a property onto the track metadata if applicable.
4661  */
pick_property_to_track_metadata(LIBMTP_mtpdevice_t * device,MTPProperties * prop,LIBMTP_track_t * track)4662 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4663 {
4664   switch (prop->property) {
4665   case PTP_OPC_Name:
4666     if (prop->propval.str != NULL)
4667       track->title = strdup(prop->propval.str);
4668     else
4669       track->title = NULL;
4670     break;
4671   case PTP_OPC_Artist:
4672     if (prop->propval.str != NULL)
4673       track->artist = strdup(prop->propval.str);
4674     else
4675       track->artist = NULL;
4676     break;
4677   case PTP_OPC_Composer:
4678     if (prop->propval.str != NULL)
4679       track->composer = strdup(prop->propval.str);
4680     else
4681       track->composer = NULL;
4682     break;
4683   case PTP_OPC_Duration:
4684     track->duration = prop->propval.u32;
4685     break;
4686   case PTP_OPC_Track:
4687     track->tracknumber = prop->propval.u16;
4688     break;
4689   case PTP_OPC_Genre:
4690     if (prop->propval.str != NULL)
4691       track->genre = strdup(prop->propval.str);
4692     else
4693       track->genre = NULL;
4694     break;
4695   case PTP_OPC_AlbumName:
4696     if (prop->propval.str != NULL)
4697       track->album = strdup(prop->propval.str);
4698     else
4699       track->album = NULL;
4700     break;
4701   case PTP_OPC_OriginalReleaseDate:
4702     if (prop->propval.str != NULL)
4703       track->date = strdup(prop->propval.str);
4704     else
4705       track->date = NULL;
4706     break;
4707     // These are, well not so important.
4708   case PTP_OPC_SampleRate:
4709     track->samplerate = prop->propval.u32;
4710     break;
4711   case PTP_OPC_NumberOfChannels:
4712     track->nochannels = prop->propval.u16;
4713     break;
4714   case PTP_OPC_AudioWAVECodec:
4715     track->wavecodec = prop->propval.u32;
4716     break;
4717   case PTP_OPC_AudioBitRate:
4718     track->bitrate = prop->propval.u32;
4719     break;
4720   case PTP_OPC_BitRateType:
4721     track->bitratetype = prop->propval.u16;
4722     break;
4723   case PTP_OPC_Rating:
4724     track->rating = prop->propval.u16;
4725     break;
4726   case PTP_OPC_UseCount:
4727     track->usecount = prop->propval.u32;
4728     break;
4729   case PTP_OPC_ObjectSize:
4730     if (device->object_bitsize == 64) {
4731       track->filesize = prop->propval.u64;
4732     } else {
4733       track->filesize = prop->propval.u32;
4734     }
4735     break;
4736   default:
4737     break;
4738   }
4739 }
4740 
4741 /**
4742  * This function retrieves the track metadata for a track
4743  * given by a unique ID.
4744  * @param device a pointer to the device to get the track metadata off.
4745  * @param trackid the unique ID of the track.
4746  * @param objectformat the object format of this track, so we know what it supports.
4747  * @param track a metadata set to fill in.
4748  */
get_track_metadata(LIBMTP_mtpdevice_t * device,uint16_t objectformat,LIBMTP_track_t * track)4749 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4750 			       LIBMTP_track_t *track)
4751 {
4752   uint16_t ret;
4753   PTPParams *params = (PTPParams *) device->params;
4754   uint32_t i;
4755   MTPProperties *prop;
4756   PTPObject *ob;
4757 
4758   /*
4759    * If we have a cached, large set of metadata, then use it!
4760    */
4761   ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4762   if (ob->mtpprops) {
4763     prop = ob->mtpprops;
4764     for (i=0;i<ob->nrofmtpprops;i++,prop++)
4765       pick_property_to_track_metadata(device, prop, track);
4766   } else {
4767     uint16_t *props = NULL;
4768     uint32_t propcnt = 0;
4769 
4770     // First see which properties can be retrieved for this object format
4771     ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4772     if (ret != PTP_RC_OK) {
4773       add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4774       // Just bail out for now, nothing is ever set.
4775       return;
4776     } else {
4777       for (i=0;i<propcnt;i++) {
4778 	switch (props[i]) {
4779 	case PTP_OPC_Name:
4780 	  track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4781 	  break;
4782 	case PTP_OPC_Artist:
4783 	  track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4784 	  break;
4785 	case PTP_OPC_Composer:
4786 	  track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4787 	  break;
4788 	case PTP_OPC_Duration:
4789 	  track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4790 	  break;
4791 	case PTP_OPC_Track:
4792 	  track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4793 	  break;
4794 	case PTP_OPC_Genre:
4795 	  track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4796 	  break;
4797 	case PTP_OPC_AlbumName:
4798 	  track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4799 	  break;
4800 	case PTP_OPC_OriginalReleaseDate:
4801 	  track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4802 	  break;
4803 	  // These are, well not so important.
4804 	case PTP_OPC_SampleRate:
4805 	  track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4806 	  break;
4807 	case PTP_OPC_NumberOfChannels:
4808 	  track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4809 	  break;
4810 	case PTP_OPC_AudioWAVECodec:
4811 	  track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4812 	  break;
4813 	case PTP_OPC_AudioBitRate:
4814 	  track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4815 	  break;
4816 	case PTP_OPC_BitRateType:
4817 	  track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4818 	  break;
4819 	case PTP_OPC_Rating:
4820 	  track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4821 	  break;
4822 	case PTP_OPC_UseCount:
4823 	  track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4824 	  break;
4825 	case PTP_OPC_ObjectSize:
4826 	  if (device->object_bitsize == 64) {
4827 	    track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4828 	  } else {
4829 	    track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4830 	  }
4831 	  break;
4832 	}
4833       }
4834       free(props);
4835     }
4836   }
4837 }
4838 
4839 /**
4840  * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4841  * NOT TO USE IT.
4842  * @see LIBMTP_Get_Tracklisting_With_Callback()
4843  */
LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t * device)4844 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4845 {
4846   LIBMTP_INFO("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4847   LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4848   return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4849 }
4850 
4851 /**
4852  * This returns a long list of all tracks available on the current MTP device.
4853  * Tracks include multimedia objects, both music tracks and video tracks.
4854  * Typical usage:
4855  *
4856  * <pre>
4857  * LIBMTP_track_t *tracklist;
4858  *
4859  * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4860  * while (tracklist != NULL) {
4861  *   LIBMTP_track_t *tmp;
4862  *
4863  *   // Do something on each element in the list here...
4864  *   tmp = tracklist;
4865  *   tracklist = tracklist->next;
4866  *   LIBMTP_destroy_track_t(tmp);
4867  * }
4868  * </pre>
4869  *
4870  * If you want to group your track listing by storage (per storage unit) or
4871  * arrange tracks into folders, you must dereference the <code>storage_id</code>
4872  * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4873  * struct. To arrange by folders or files you typically have to create the proper
4874  * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4875  * <code>LIBMTP_Get_Folder_List()</code> first.
4876  *
4877  * @param device a pointer to the device to get the track listing for.
4878  * @param callback a function to be called during the tracklisting retrieveal
4879  *        for displaying progress bars etc, or NULL if you don't want
4880  *        any callbacks.
4881  * @param data a user-defined pointer that is passed along to
4882  *        the <code>progress</code> function in order to
4883  *        pass along some user defined data to the progress
4884  *        updates. If not used, set this to NULL.
4885  * @return a list of tracks that can be followed using the <code>next</code>
4886  *        field of the <code>LIBMTP_track_t</code> data structure.
4887  *        Each of the metadata tags must be freed after use, and may
4888  *        contain only partial metadata information, i.e. one or several
4889  *        fields may be NULL or 0.
4890  * @see LIBMTP_Get_Trackmetadata()
4891  */
LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4892 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4893                                                       LIBMTP_progressfunc_t const callback,
4894                                                       void const * const data)
4895 {
4896 	return LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, 0, callback, data);
4897 }
4898 
4899 
4900 /**
4901  * This returns a long list of all tracks available on the current MTP device.
4902  * Tracks include multimedia objects, both music tracks and video tracks.
4903  * Typical usage:
4904  *
4905  * <pre>
4906  * LIBMTP_track_t *tracklist;
4907  *
4908  * tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
4909  * while (tracklist != NULL) {
4910  *   LIBMTP_track_t *tmp;
4911  *
4912  *   // Do something on each element in the list here...
4913  *   tmp = tracklist;
4914  *   tracklist = tracklist->next;
4915  *   LIBMTP_destroy_track_t(tmp);
4916  * }
4917  * </pre>
4918  *
4919  * If you want to group your track listing by storage (per storage unit) or
4920  * arrange tracks into folders, you must dereference the <code>storage_id</code>
4921  * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4922  * struct. To arrange by folders or files you typically have to create the proper
4923  * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4924  * <code>LIBMTP_Get_Folder_List()</code> first.
4925  *
4926  * @param device a pointer to the device to get the track listing for.
4927  * @param storage_id ID of device storage (if null, no filter)
4928  * @param callback a function to be called during the tracklisting retrieveal
4929  *        for displaying progress bars etc, or NULL if you don't want
4930  *        any callbacks.
4931  * @param data a user-defined pointer that is passed along to
4932  *        the <code>progress</code> function in order to
4933  *        pass along some user defined data to the progress
4934  *        updates. If not used, set this to NULL.
4935  * @return a list of tracks that can be followed using the <code>next</code>
4936  *        field of the <code>LIBMTP_track_t</code> data structure.
4937  *        Each of the metadata tags must be freed after use, and may
4938  *        contain only partial metadata information, i.e. one or several
4939  *        fields may be NULL or 0.
4940  * @see LIBMTP_Get_Trackmetadata()
4941  */
LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t * device,uint32_t const storage_id,LIBMTP_progressfunc_t const callback,void const * const data)4942 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id,
4943                                                       LIBMTP_progressfunc_t const callback,
4944                                                       void const * const data)
4945 {
4946   uint32_t i = 0;
4947   LIBMTP_track_t *retracks = NULL;
4948   LIBMTP_track_t *curtrack = NULL;
4949   PTPParams *params = (PTPParams *) device->params;
4950   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4951 
4952   // Get all the handles if we haven't already done that
4953   if (params->nrofobjects == 0) {
4954     flush_handles(device);
4955   }
4956 
4957   for (i = 0; i < params->nrofobjects; i++) {
4958     LIBMTP_track_t *track;
4959     PTPObject *ob;
4960     LIBMTP_filetype_t mtptype;
4961 
4962     if (callback != NULL)
4963       callback(i, params->nrofobjects, data);
4964 
4965     ob = &params->objects[i];
4966     mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4967 
4968     // Ignore stuff we don't know how to handle...
4969     // TODO: get this list as an intersection of the sets
4970     // supported by the device and the from the device and
4971     // all known track files?
4972     if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4973 	// This row lets through undefined files for examination since they may be forgotten OGG files.
4974 	(ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4975 	 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4976 	  !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4977 	  !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4978 	) {
4979       //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4980       continue;
4981     }
4982 
4983 	// Ignore stuff that isn't into the storage device
4984 	if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
4985 		continue;
4986 
4987     // Allocate a new track type
4988     track = LIBMTP_new_track_t();
4989 
4990     // This is some sort of unique ID so we can keep track of the track.
4991     track->item_id = ob->oid;
4992     track->parent_id = ob->oi.ParentObject;
4993     track->storage_id = ob->oi.StorageID;
4994     track->modificationdate = ob->oi.ModificationDate;
4995 
4996     track->filetype = mtptype;
4997 
4998     // Original file-specific properties
4999     track->filesize = ob->oi.ObjectCompressedSize;
5000     if (ob->oi.Filename != NULL) {
5001       track->filename = strdup(ob->oi.Filename);
5002     }
5003 
5004     get_track_metadata(device, ob->oi.ObjectFormat, track);
5005 
5006     /*
5007      * A special quirk for iriver devices that doesn't quite
5008      * remember that some files marked as "unknown" type are
5009      * actually OGG or FLAC files. We look at the filename extension
5010      * and see if it happens that this was atleast named "ogg" or "flac"
5011      * and fall back on this heuristic approach in that case,
5012      * for these bugged devices only.
5013      */
5014     if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5015 	track->filename != NULL) {
5016       if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5017 	   FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5018 	  has_ogg_extension(track->filename))
5019 	track->filetype = LIBMTP_FILETYPE_OGG;
5020       else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5021 	       has_flac_extension(track->filename))
5022 	track->filetype = LIBMTP_FILETYPE_FLAC;
5023       else {
5024 	// This was not an OGG/FLAC file so discard it and continue
5025 	LIBMTP_destroy_track_t(track);
5026 	continue;
5027       }
5028     }
5029 
5030     // Add track to a list that will be returned afterwards.
5031     if (retracks == NULL) {
5032       retracks = track;
5033       curtrack = track;
5034     } else {
5035       curtrack->next = track;
5036       curtrack = track;
5037     }
5038 
5039     // Call listing callback
5040     // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
5041 
5042   } // Handle counting loop
5043   return retracks;
5044 }
5045 
5046 /**
5047  * This function retrieves the metadata for a single track off
5048  * the device.
5049  *
5050  * Do not call this function repeatedly! The track handles are linearly
5051  * searched O(n) and the call may involve (slow) USB traffic, so use
5052  * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
5053  * as an efficient data structure such as a hash list.
5054  *
5055  * @param device a pointer to the device to get the track metadata from.
5056  * @param trackid the object ID of the track that you want the metadata for.
5057  * @return a track metadata entry on success or NULL on failure.
5058  * @see LIBMTP_Get_Tracklisting()
5059  */
LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t * device,uint32_t const trackid)5060 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
5061 {
5062   PTPParams *params = (PTPParams *) device->params;
5063   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5064   PTPObject *ob;
5065   LIBMTP_track_t *track;
5066   LIBMTP_filetype_t mtptype;
5067   uint16_t ret;
5068 
5069   // Get all the handles if we haven't already done that
5070   if (params->nrofobjects == 0)
5071     flush_handles(device);
5072 
5073   ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5074   if (ret != PTP_RC_OK)
5075     return NULL;
5076 
5077   mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
5078 
5079   // Ignore stuff we don't know how to handle...
5080   if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
5081       /*
5082        * This row lets through undefined files for examination
5083        * since they may be forgotten OGG or FLAC files.
5084        */
5085       (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
5086        (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
5087 	!FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
5088 	!FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
5089       ) {
5090     //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
5091     return NULL;
5092   }
5093 
5094   // Allocate a new track type
5095   track = LIBMTP_new_track_t();
5096 
5097   // This is some sort of unique ID so we can keep track of the track.
5098   track->item_id = ob->oid;
5099   track->parent_id = ob->oi.ParentObject;
5100   track->storage_id = ob->oi.StorageID;
5101   track->modificationdate = ob->oi.ModificationDate;
5102 
5103   track->filetype = mtptype;
5104 
5105   // Original file-specific properties
5106   track->filesize = ob->oi.ObjectCompressedSize;
5107   if (ob->oi.Filename != NULL) {
5108     track->filename = strdup(ob->oi.Filename);
5109   }
5110 
5111   /*
5112    * A special quirk for devices that doesn't quite
5113    * remember that some files marked as "unknown" type are
5114    * actually OGG or FLAC files. We look at the filename extension
5115    * and see if it happens that this was atleast named "ogg"
5116    * and fall back on this heuristic approach in that case,
5117    * for these bugged devices only.
5118    */
5119   if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5120       track->filename != NULL) {
5121     if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5122 	 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5123 	has_ogg_extension(track->filename))
5124       track->filetype = LIBMTP_FILETYPE_OGG;
5125     else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5126 	     has_flac_extension(track->filename))
5127       track->filetype = LIBMTP_FILETYPE_FLAC;
5128     else {
5129       // This was not an OGG/FLAC file so discard it
5130       LIBMTP_destroy_track_t(track);
5131       return NULL;
5132     }
5133   }
5134   get_track_metadata(device, ob->oi.ObjectFormat, track);
5135   return track;
5136 }
5137 
5138 /**
5139  * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
5140  * to isolate the internal type.
5141  */
get_func_wrapper(PTPParams * params,void * priv,unsigned long wantlen,unsigned char * data,unsigned long * gotlen)5142 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
5143 {
5144   MTPDataHandler *handler = (MTPDataHandler *)priv;
5145   uint16_t ret;
5146   uint32_t local_gotlen = 0;
5147   ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
5148   *gotlen = local_gotlen;
5149   switch (ret)
5150   {
5151     case LIBMTP_HANDLER_RETURN_OK:
5152       return PTP_RC_OK;
5153     case LIBMTP_HANDLER_RETURN_ERROR:
5154       return PTP_ERROR_IO;
5155     case LIBMTP_HANDLER_RETURN_CANCEL:
5156       return PTP_ERROR_CANCEL;
5157     default:
5158       return PTP_ERROR_IO;
5159   }
5160 }
5161 
5162 /**
5163  * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
5164  * to isolate the internal type.
5165  */
put_func_wrapper(PTPParams * params,void * priv,unsigned long sendlen,unsigned char * data)5166 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data)
5167 {
5168   MTPDataHandler *handler = (MTPDataHandler *)priv;
5169   uint16_t ret;
5170   uint32_t local_putlen = 0;
5171 
5172   ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
5173 
5174   switch (ret)
5175   {
5176     case LIBMTP_HANDLER_RETURN_OK:
5177       if (local_putlen != sendlen)
5178 	return PTP_ERROR_IO;
5179       return PTP_RC_OK;
5180     case LIBMTP_HANDLER_RETURN_ERROR:
5181       return PTP_ERROR_IO;
5182     case LIBMTP_HANDLER_RETURN_CANCEL:
5183       return PTP_ERROR_CANCEL;
5184     default:
5185       return PTP_ERROR_IO;
5186   }
5187 }
5188 
5189 /**
5190  * This gets a file off the device to a local file identified
5191  * by a filename.
5192  * @param device a pointer to the device to get the track from.
5193  * @param id the file ID of the file to retrieve.
5194  * @param path a filename to use for the retrieved file.
5195  * @param callback a progress indicator function or NULL to ignore.
5196  * @param data a user-defined pointer that is passed along to
5197  *             the <code>progress</code> function in order to
5198  *             pass along some user defined data to the progress
5199  *             updates. If not used, set this to NULL.
5200  * @return 0 if the transfer was successful, any other value means
5201  *           failure.
5202  * @see LIBMTP_Get_File_To_File_Descriptor()
5203  */
LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t * device,uint32_t const id,char const * const path,LIBMTP_progressfunc_t const callback,void const * const data)5204 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5205 			 char const * const path, LIBMTP_progressfunc_t const callback,
5206 			 void const * const data)
5207 {
5208   int fd = -1;
5209   int ret;
5210 
5211   // Sanity check
5212   if (path == NULL) {
5213     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
5214     return -1;
5215   }
5216 
5217   // Open file
5218 #ifdef __WIN32__
5219 #ifdef USE_WINDOWS_IO_H
5220   if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
5221 #else
5222   if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
5223 #endif
5224 #else
5225   if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
5226 #endif
5227     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
5228     return -1;
5229   }
5230 
5231   ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5232 
5233   // Close file
5234   close(fd);
5235 
5236   // Delete partial file.
5237   if (ret == -1) {
5238     unlink(path);
5239   }
5240 
5241   return ret;
5242 }
5243 
5244 /**
5245  * This gets a file off the device to a file identified
5246  * by a file descriptor.
5247  *
5248  * This function can potentially be used for streaming
5249  * files off the device for playback or broadcast for example,
5250  * by downloading the file into a stream sink e.g. a socket.
5251  *
5252  * @param device a pointer to the device to get the file from.
5253  * @param id the file ID of the file to retrieve.
5254  * @param fd a local file descriptor to write the file to.
5255  * @param callback a progress indicator function or NULL to ignore.
5256  * @param data a user-defined pointer that is passed along to
5257  *             the <code>progress</code> function in order to
5258  *             pass along some user defined data to the progress
5259  *             updates. If not used, set this to NULL.
5260  * @return 0 if the transfer was successful, any other value means
5261  *           failure.
5262  * @see LIBMTP_Get_File_To_File()
5263  */
5264 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5265 					uint32_t const id,
5266 					int const fd,
5267 					LIBMTP_progressfunc_t const callback,
5268 					void const * const data)
5269 {
5270   uint16_t ret;
5271   PTPParams *params = (PTPParams *) device->params;
5272   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5273   PTPObject *ob;
5274 
5275   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5276   if (ret != PTP_RC_OK) {
5277     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5278     return -1;
5279   }
5280   if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5281     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5282     return -1;
5283   }
5284 
5285   // Callbacks
5286   ptp_usb->callback_active = 1;
5287   ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5288     PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5289   ptp_usb->current_transfer_complete = 0;
5290   ptp_usb->current_transfer_callback = callback;
5291   ptp_usb->current_transfer_callback_data = data;
5292 
5293   ret = ptp_getobject_tofd(params, id, fd);
5294 
5295   ptp_usb->callback_active = 0;
5296   ptp_usb->current_transfer_callback = NULL;
5297   ptp_usb->current_transfer_callback_data = NULL;
5298 
5299   if (ret == PTP_ERROR_CANCEL) {
5300     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5301     return -1;
5302   }
5303   if (ret != PTP_RC_OK) {
5304     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5305     return -1;
5306   }
5307 
5308   return 0;
5309 }
5310 
5311 /**
5312  * This gets a file off the device and calls put_func
5313  * with chunks of data
5314  *
5315  * @param device a pointer to the device to get the file from.
5316  * @param id the file ID of the file to retrieve.
5317  * @param put_func the function to call when we have data.
5318  * @param priv the user-defined pointer that is passed to
5319  *             <code>put_func</code>.
5320  * @param callback a progress indicator function or NULL to ignore.
5321  * @param data a user-defined pointer that is passed along to
5322  *             the <code>progress</code> function in order to
5323  *             pass along some user defined data to the progress
5324  *             updates. If not used, set this to NULL.
5325  * @return 0 if the transfer was successful, any other value means
5326  *           failure.
5327  */
5328 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
5329 					uint32_t const id,
5330 					MTPDataPutFunc put_func,
5331           void * priv,
5332 					LIBMTP_progressfunc_t const callback,
5333 					void const * const data)
5334 {
5335   PTPObject *ob;
5336   uint16_t ret;
5337   PTPParams *params = (PTPParams *) device->params;
5338   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5339 
5340   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5341   if (ret != PTP_RC_OK) {
5342     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5343     return -1;
5344   }
5345   if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5346     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5347     return -1;
5348   }
5349 
5350   // Callbacks
5351   ptp_usb->callback_active = 1;
5352   ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5353     PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5354   ptp_usb->current_transfer_complete = 0;
5355   ptp_usb->current_transfer_callback = callback;
5356   ptp_usb->current_transfer_callback_data = data;
5357 
5358   MTPDataHandler mtp_handler;
5359   mtp_handler.getfunc = NULL;
5360   mtp_handler.putfunc = put_func;
5361   mtp_handler.priv = priv;
5362 
5363   PTPDataHandler handler;
5364   handler.getfunc = NULL;
5365   handler.putfunc = put_func_wrapper;
5366   handler.priv = &mtp_handler;
5367 
5368   ret = ptp_getobject_to_handler(params, id, &handler);
5369 
5370   ptp_usb->callback_active = 0;
5371   ptp_usb->current_transfer_callback = NULL;
5372   ptp_usb->current_transfer_callback_data = NULL;
5373 
5374   if (ret == PTP_ERROR_CANCEL) {
5375     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5376     return -1;
5377   }
5378   if (ret != PTP_RC_OK) {
5379     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5380     return -1;
5381   }
5382 
5383   return 0;
5384 }
5385 
5386 
5387 /**
5388  * This gets a track off the device to a file identified
5389  * by a filename. This is actually just a wrapper for the
5390  * \c LIBMTP_Get_Track_To_File() function.
5391  * @param device a pointer to the device to get the track from.
5392  * @param id the track ID of the track to retrieve.
5393  * @param path a filename to use for the retrieved track.
5394  * @param callback a progress indicator function or NULL to ignore.
5395  * @param data a user-defined pointer that is passed along to
5396  *             the <code>progress</code> function in order to
5397  *             pass along some user defined data to the progress
5398  *             updates. If not used, set this to NULL.
5399  * @return 0 if the transfer was successful, any other value means
5400  *           failure.
5401  * @see LIBMTP_Get_Track_To_File_Descriptor()
5402  */
5403 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5404 			 char const * const path, LIBMTP_progressfunc_t const callback,
5405 			 void const * const data)
5406 {
5407   // This is just a wrapper
5408   return LIBMTP_Get_File_To_File(device, id, path, callback, data);
5409 }
5410 
5411 /**
5412  * This gets a track off the device to a file identified
5413  * by a file descriptor. This is actually just a wrapper for
5414  * the \c LIBMTP_Get_File_To_File_Descriptor() function.
5415  * @param device a pointer to the device to get the track from.
5416  * @param id the track ID of the track to retrieve.
5417  * @param fd a file descriptor to write the track to.
5418  * @param callback a progress indicator function or NULL to ignore.
5419  * @param data a user-defined pointer that is passed along to
5420  *             the <code>progress</code> function in order to
5421  *             pass along some user defined data to the progress
5422  *             updates. If not used, set this to NULL.
5423  * @return 0 if the transfer was successful, any other value means
5424  *           failure.
5425  * @see LIBMTP_Get_Track_To_File()
5426  */
5427 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5428 					uint32_t const id,
5429 					int const fd,
5430 					LIBMTP_progressfunc_t const callback,
5431 					void const * const data)
5432 {
5433   // This is just a wrapper
5434   return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5435 }
5436 
5437 /**
5438  * This gets a track off the device to a handler function.
5439  * This is actually just a wrapper for
5440  * the \c LIBMTP_Get_File_To_Handler() function.
5441  * @param device a pointer to the device to get the track from.
5442  * @param id the track ID of the track to retrieve.
5443  * @param put_func the function to call when we have data.
5444  * @param priv the user-defined pointer that is passed to
5445  *             <code>put_func</code>.
5446  * @param callback a progress indicator function or NULL to ignore.
5447  * @param data a user-defined pointer that is passed along to
5448  *             the <code>progress</code> function in order to
5449  *             pass along some user defined data to the progress
5450  *             updates. If not used, set this to NULL.
5451  * @return 0 if the transfer was successful, any other value means
5452  *           failure.
5453  */
5454 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
5455 					uint32_t const id,
5456 					MTPDataPutFunc put_func,
5457           void * priv,
5458 					LIBMTP_progressfunc_t const callback,
5459 					void const * const data)
5460 {
5461   // This is just a wrapper
5462   return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
5463 }
5464 
5465 /**
5466  * This function sends a track from a local file to an
5467  * MTP device. A filename and a set of metadata must be
5468  * given as input.
5469  * @param device a pointer to the device to send the track to.
5470  * @param path the filename of a local file which will be sent.
5471  * @param metadata a track metadata set to be written along with the file.
5472  *        After this call the field <code>metadata-&gt;item_id</code>
5473  *        will contain the new track ID. Other fields such
5474  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
5475  *        or <code>metadata-&gt;storage_id</code> may also change during this
5476  *        operation due to device restrictions, so do not rely on the
5477  *        contents of this struct to be preserved in any way.
5478  *        <ul>
5479  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
5480  *        (e.g. folder) to store this track in. Since some
5481  *        devices are a bit picky about where files
5482  *        are placed, a default folder will be chosen if libmtp
5483  *        has detected one for the current filetype and this
5484  *        parameter is set to 0. If this is 0 and no default folder
5485  *        can be found, the file will be stored in the root folder.
5486  *        <li><code>metadata-&gt;storage_id</code> should be set to the
5487  *        desired storage (e.g. memory card or whatever your device
5488  *        presents) to store this track in. Setting this to 0 will store
5489  *        the track on the primary storage.
5490  *        </ul>
5491  * @param callback a progress indicator function or NULL to ignore.
5492  * @param data a user-defined pointer that is passed along to
5493  *             the <code>progress</code> function in order to
5494  *             pass along some user defined data to the progress
5495  *             updates. If not used, set this to NULL.
5496  * @return 0 if the transfer was successful, any other value means
5497  *           failure.
5498  * @see LIBMTP_Send_Track_From_File_Descriptor()
5499  * @see LIBMTP_Send_File_From_File()
5500  * @see LIBMTP_Delete_Object()
5501  */
5502 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5503 			 char const * const path, LIBMTP_track_t * const metadata,
5504                          LIBMTP_progressfunc_t const callback,
5505 			 void const * const data)
5506 {
5507   int fd;
5508   int ret;
5509 
5510   // Sanity check
5511   if (path == NULL) {
5512     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5513     return -1;
5514   }
5515 
5516   // Open file
5517 #ifdef __WIN32__
5518 #ifdef USE_WINDOWS_IO_H
5519   if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5520 #else
5521   if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5522 #endif
5523 #else
5524   if ( (fd = open(path, O_RDONLY)) == -1) {
5525 #endif
5526     LIBMTP_ERROR("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5527     return -1;
5528   }
5529 
5530   ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5531 
5532   // Close file.
5533 #ifdef USE_WINDOWS_IO_H
5534   _close(fd);
5535 #else
5536   close(fd);
5537 #endif
5538 
5539   return ret;
5540 }
5541 
5542 
5543 
5544 /**
5545  * This helper function checks if a filename already exists on the device
5546  * @param PTPParams*
5547  * @param string representing the filename
5548  * @return 0 if the filename doesn't exist, -1 if it does
5549  */
5550 static int check_filename_exists(PTPParams* params, char const * const filename)
5551 {
5552   int i;
5553 
5554   for (i = 0; i < params->nrofobjects; i++) {
5555     char *fname = params->objects[i].oi.Filename;
5556     if ((fname != NULL) && (strcmp(filename, fname) == 0))
5557     {
5558       return -1;
5559     }
5560   }
5561 
5562   return 0;
5563 }
5564 
5565 /**
5566  * This helper function returns a unique filename, with a random string before the extension
5567  * @param string representing the original filename
5568  * @return a string representing the unique filename
5569  */
5570 static char *generate_unique_filename(PTPParams* params, char const * const filename)
5571 {
5572   int suffix;
5573   char * extension_position;
5574 
5575   if (check_filename_exists(params, filename))
5576   {
5577     extension_position = strrchr(filename,'.');
5578 
5579     char basename[extension_position - filename + 1];
5580     strncpy(basename, filename, extension_position - filename);
5581     basename[extension_position - filename] = '\0';
5582 
5583     suffix = 1;
5584     char newname[ strlen(basename) + 6 + strlen(extension_position)];
5585     sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5586     while ((check_filename_exists(params, newname)) && (suffix < 1000000)) {
5587       suffix++;
5588       sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5589     }
5590   return strdup(newname);
5591   }
5592   else
5593   {
5594     return strdup(filename);
5595   }
5596 }
5597 
5598 /**
5599  * This function sends a track from a file descriptor to an
5600  * MTP device. A filename and a set of metadata must be
5601  * given as input.
5602  * @param device a pointer to the device to send the track to.
5603  * @param fd the filedescriptor for a local file which will be sent.
5604  * @param metadata a track metadata set to be written along with the file.
5605  *        After this call the field <code>metadata-&gt;item_id</code>
5606  *        will contain the new track ID. Other fields such
5607  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
5608  *        or <code>metadata-&gt;storage_id</code> may also change during this
5609  *        operation due to device restrictions, so do not rely on the
5610  *        contents of this struct to be preserved in any way.
5611  *        <ul>
5612  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
5613  *        (e.g. folder) to store this track in. Since some
5614  *        devices are a bit picky about where files
5615  *        are placed, a default folder will be chosen if libmtp
5616  *        has detected one for the current filetype and this
5617  *        parameter is set to 0. If this is 0 and no default folder
5618  *        can be found, the file will be stored in the root folder.
5619  *        <li><code>metadata-&gt;storage_id</code> should be set to the
5620  *        desired storage (e.g. memory card or whatever your device
5621  *        presents) to store this track in. Setting this to 0 will store
5622  *        the track on the primary storage.
5623  *        </ul>
5624  * @param callback a progress indicator function or NULL to ignore.
5625  * @param data a user-defined pointer that is passed along to
5626  *             the <code>progress</code> function in order to
5627  *             pass along some user defined data to the progress
5628  *             updates. If not used, set this to NULL.
5629  * @return 0 if the transfer was successful, any other value means
5630  *           failure.
5631  * @see LIBMTP_Send_Track_From_File()
5632  * @see LIBMTP_Delete_Object()
5633  */
5634 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5635 			 int const fd, LIBMTP_track_t * const metadata,
5636                          LIBMTP_progressfunc_t const callback,
5637 			 void const * const data)
5638 {
5639   int subcall_ret;
5640   LIBMTP_file_t filedata;
5641   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5642   PTPParams *params = (PTPParams *) device->params;
5643 
5644   // Sanity check, is this really a track?
5645   if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5646     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5647 			    "LIBMTP_Send_Track_From_File_Descriptor(): "
5648 			    "I don't think this is actually a track, strange filetype...");
5649   }
5650 
5651   // Wrap around the file transfer function
5652   filedata.item_id = metadata->item_id;
5653   filedata.parent_id = metadata->parent_id;
5654   filedata.storage_id = metadata->storage_id;
5655   if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5656     filedata.filename = generate_unique_filename(params, metadata->filename);
5657   }
5658   else {
5659     filedata.filename = metadata->filename;
5660   }
5661   filedata.filesize = metadata->filesize;
5662   filedata.filetype = metadata->filetype;
5663   filedata.next = NULL;
5664 
5665   subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5666 						      fd,
5667 						      &filedata,
5668 						      callback,
5669 						      data);
5670 
5671   if (subcall_ret != 0) {
5672     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5673 			    "LIBMTP_Send_Track_From_File_Descriptor(): "
5674 			    "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
5675     // We used to delete the file here, but don't... It might be OK after all.
5676     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5677     return -1;
5678   }
5679 
5680   // Pick up new item (and parent, storage) ID
5681   metadata->item_id = filedata.item_id;
5682   metadata->parent_id = filedata.parent_id;
5683   metadata->storage_id = filedata.storage_id;
5684 
5685   // Set track metadata for the new fine track
5686   subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5687   if (subcall_ret != 0) {
5688     // Subcall will add error to errorstack
5689     // We used to delete the file here, but don't... It might be OK after all.
5690     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5691     return -1;
5692   }
5693 
5694   // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5695   // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5696 
5697   return 0;
5698 }
5699 
5700 /**
5701  * This function sends a track from a handler function to an
5702  * MTP device. A filename and a set of metadata must be
5703  * given as input.
5704  * @param device a pointer to the device to send the track to.
5705  * @param get_func the function to call when we have data.
5706  * @param priv the user-defined pointer that is passed to
5707  *             <code>get_func</code>.
5708  * @param metadata a track metadata set to be written along with the file.
5709  *        After this call the field <code>metadata-&gt;item_id</code>
5710  *        will contain the new track ID. Other fields such
5711  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
5712  *        or <code>metadata-&gt;storage_id</code> may also change during this
5713  *        operation due to device restrictions, so do not rely on the
5714  *        contents of this struct to be preserved in any way.
5715  *        <ul>
5716  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
5717  *        (e.g. folder) to store this track in. Since some
5718  *        devices are a bit picky about where files
5719  *        are placed, a default folder will be chosen if libmtp
5720  *        has detected one for the current filetype and this
5721  *        parameter is set to 0. If this is 0 and no default folder
5722  *        can be found, the file will be stored in the root folder.
5723  *        <li><code>metadata-&gt;storage_id</code> should be set to the
5724  *        desired storage (e.g. memory card or whatever your device
5725  *        presents) to store this track in. Setting this to 0 will store
5726  *        the track on the primary storage.
5727  *        </ul>
5728  * @param callback a progress indicator function or NULL to ignore.
5729  * @param data a user-defined pointer that is passed along to
5730  *             the <code>progress</code> function in order to
5731  *             pass along some user defined data to the progress
5732  *             updates. If not used, set this to NULL.
5733  * @return 0 if the transfer was successful, any other value means
5734  *           failure.
5735  * @see LIBMTP_Send_Track_From_File()
5736  * @see LIBMTP_Delete_Object()
5737  */
5738 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5739 			 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5740                          LIBMTP_progressfunc_t const callback,
5741 			 void const * const data)
5742 {
5743   int subcall_ret;
5744   LIBMTP_file_t filedata;
5745   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5746   PTPParams *params = (PTPParams *) device->params;
5747 
5748   // Sanity check, is this really a track?
5749   if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5750     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5751 			    "LIBMTP_Send_Track_From_Handler(): "
5752 			    "I don't think this is actually a track, strange filetype...");
5753   }
5754 
5755   // Wrap around the file transfer function
5756   filedata.item_id = metadata->item_id;
5757   filedata.parent_id = metadata->parent_id;
5758   filedata.storage_id = metadata->storage_id;
5759   if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5760     filedata.filename = generate_unique_filename(params, metadata->filename);
5761   }
5762   else {
5763     filedata.filename = metadata->filename;
5764   }
5765   filedata.filesize = metadata->filesize;
5766   filedata.filetype = metadata->filetype;
5767   filedata.next = NULL;
5768 
5769   subcall_ret = LIBMTP_Send_File_From_Handler(device,
5770 					      get_func,
5771 					      priv,
5772 					      &filedata,
5773 					      callback,
5774 					      data);
5775 
5776   if (subcall_ret != 0) {
5777     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5778 			    "LIBMTP_Send_Track_From_Handler(): "
5779 			    "subcall to LIBMTP_Send_File_From_Handler failed.");
5780     // We used to delete the file here, but don't... It might be OK after all.
5781     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5782     return -1;
5783   }
5784 
5785   // Pick up new item (and parent, storage) ID
5786   metadata->item_id = filedata.item_id;
5787   metadata->parent_id = filedata.parent_id;
5788   metadata->storage_id = filedata.storage_id;
5789 
5790   // Set track metadata for the new fine track
5791   subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5792   if (subcall_ret != 0) {
5793     // Subcall will add error to errorstack
5794     // We used to delete the file here, but don't... It might be OK after all.
5795     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5796     return -1;
5797   }
5798 
5799   // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5800   // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5801 
5802   return 0;
5803 }
5804 
5805 /**
5806  * This function sends a local file to an MTP device.
5807  * A filename and a set of metadata must be
5808  * given as input.
5809  * @param device a pointer to the device to send the track to.
5810  * @param path the filename of a local file which will be sent.
5811  * @param filedata a file metadata set to be written along with the file.
5812  *        After this call the field <code>filedata-&gt;item_id</code>
5813  *        will contain the new file ID. Other fields such
5814  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
5815  *        or <code>filedata-&gt;storage_id</code> may also change during this
5816  *        operation due to device restrictions, so do not rely on the
5817  *        contents of this struct to be preserved in any way.
5818  *        <ul>
5819  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
5820  *        (e.g. folder) to store this file in. If this is 0,
5821  *        the file will be stored in the root folder.
5822  *        <li><code>filedata-&gt;storage_id</code> should be set to the
5823  *        desired storage (e.g. memory card or whatever your device
5824  *        presents) to store this file in. Setting this to 0 will store
5825  *        the file on the primary storage.
5826  *        </ul>
5827  * @param callback a progress indicator function or NULL to ignore.
5828  * @param data a user-defined pointer that is passed along to
5829  *             the <code>progress</code> function in order to
5830  *             pass along some user defined data to the progress
5831  *             updates. If not used, set this to NULL.
5832  * @return 0 if the transfer was successful, any other value means
5833  *           failure.
5834  * @see LIBMTP_Send_File_From_File_Descriptor()
5835  * @see LIBMTP_Delete_Object()
5836  */
5837 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5838 			       char const * const path, LIBMTP_file_t * const filedata,
5839 			       LIBMTP_progressfunc_t const callback,
5840 			       void const * const data)
5841 {
5842   int fd;
5843   int ret;
5844 
5845   // Sanity check
5846   if (path == NULL) {
5847     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5848     return -1;
5849   }
5850 
5851   // Open file
5852 #ifdef __WIN32__
5853 #ifdef USE_WINDOWS_IO_H
5854   if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5855 #else
5856   if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5857 #endif
5858 #else
5859   if ( (fd = open(path, O_RDONLY)) == -1) {
5860 #endif
5861     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5862     return -1;
5863   }
5864 
5865   ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5866 
5867   // Close file.
5868 #ifdef USE_WINDOWS_IO_H
5869   _close(fd);
5870 #else
5871   close(fd);
5872 #endif
5873 
5874   return ret;
5875 }
5876 
5877 /**
5878  * This function sends a generic file from a file descriptor to an
5879  * MTP device. A filename and a set of metadata must be
5880  * given as input.
5881  *
5882  * This can potentially be used for sending in a stream of unknown
5883  * length. Send music files with
5884  * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5885  *
5886  * @param device a pointer to the device to send the file to.
5887  * @param fd the filedescriptor for a local file which will be sent.
5888  * @param filedata a file metadata set to be written along with the file.
5889  *        After this call the field <code>filedata-&gt;item_id</code>
5890  *        will contain the new file ID. Other fields such
5891  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
5892  *        or <code>filedata-&gt;storage_id</code> may also change during this
5893  *        operation due to device restrictions, so do not rely on the
5894  *        contents of this struct to be preserved in any way.
5895  *        <ul>
5896  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
5897  *        (e.g. folder) to store this file in. If this is 0,
5898  *        the file will be stored in the root folder.
5899  *        <li><code>filedata-&gt;storage_id</code> should be set to the
5900  *        desired storage (e.g. memory card or whatever your device
5901  *        presents) to store this file in. Setting this to 0 will store
5902  *        the file on the primary storage.
5903  *        </ul>
5904  * @param callback a progress indicator function or NULL to ignore.
5905  * @param data a user-defined pointer that is passed along to
5906  *             the <code>progress</code> function in order to
5907  *             pass along some user defined data to the progress
5908  *             updates. If not used, set this to NULL.
5909  * @return 0 if the transfer was successful, any other value means
5910  *           failure.
5911  * @see LIBMTP_Send_File_From_File()
5912  * @see LIBMTP_Send_Track_From_File_Descriptor()
5913  * @see LIBMTP_Delete_Object()
5914  */
5915 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5916 			 int const fd, LIBMTP_file_t * const filedata,
5917                          LIBMTP_progressfunc_t const callback,
5918 			 void const * const data)
5919 {
5920   uint16_t ret;
5921   PTPParams *params = (PTPParams *) device->params;
5922   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5923   LIBMTP_file_t *newfilemeta;
5924   int oldtimeout;
5925   int timeout;
5926 
5927   if (send_file_object_info(device, filedata))
5928   {
5929     // no need to output an error since send_file_object_info will already have done so
5930     return -1;
5931   }
5932 
5933   // Callbacks
5934   ptp_usb->callback_active = 1;
5935   // The callback will deactivate itself after this amount of data has been sent
5936   // One BULK header for the request, one for the data phase. No parameters to the request.
5937   ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5938   ptp_usb->current_transfer_complete = 0;
5939   ptp_usb->current_transfer_callback = callback;
5940   ptp_usb->current_transfer_callback_data = data;
5941 
5942   /*
5943    * We might need to increase the timeout here, files can be pretty
5944    * large. Take the default timeout and add the calculated time for
5945    * this transfer
5946    */
5947   get_usb_device_timeout(ptp_usb, &oldtimeout);
5948   timeout = oldtimeout +
5949     (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
5950   set_usb_device_timeout(ptp_usb, timeout);
5951 
5952   ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5953 
5954   ptp_usb->callback_active = 0;
5955   ptp_usb->current_transfer_callback = NULL;
5956   ptp_usb->current_transfer_callback_data = NULL;
5957   set_usb_device_timeout(ptp_usb, oldtimeout);
5958 
5959   if (ret == PTP_ERROR_CANCEL) {
5960     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5961     return -1;
5962   }
5963   if (ret != PTP_RC_OK) {
5964     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5965 				"Could not send object.");
5966     return -1;
5967   }
5968 
5969   add_object_to_cache(device, filedata->item_id);
5970 
5971   /*
5972    * Get the device-assigned parent_id from the cache.
5973    * The operation that adds it to the cache will
5974    * look it up from the device, so we get the new
5975    * parent_id from the cache.
5976    */
5977   newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5978   if (newfilemeta != NULL) {
5979     filedata->parent_id = newfilemeta->parent_id;
5980     filedata->storage_id = newfilemeta->storage_id;
5981     LIBMTP_destroy_file_t(newfilemeta);
5982   } else {
5983     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5984 			    "LIBMTP_Send_File_From_File_Descriptor(): "
5985 			    "Could not retrieve updated metadata.");
5986     return -1;
5987   }
5988 
5989   return 0;
5990 }
5991 
5992 /**
5993  * This function sends a generic file from a handler function to an
5994  * MTP device. A filename and a set of metadata must be
5995  * given as input.
5996  *
5997  * This can potentially be used for sending in a stream of unknown
5998  * length. Send music files with
5999  * <code>LIBMTP_Send_Track_From_Handler()</code>
6000  *
6001  * @param device a pointer to the device to send the file to.
6002  * @param get_func the function to call to get data to write
6003  * @param priv a user-defined pointer that is passed along to
6004  *        <code>get_func</code>. If not used, this is set to NULL.
6005  * @param filedata a file metadata set to be written along with the file.
6006  *        After this call the field <code>filedata-&gt;item_id</code>
6007  *        will contain the new file ID. Other fields such
6008  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
6009  *        or <code>filedata-&gt;storage_id</code> may also change during this
6010  *        operation due to device restrictions, so do not rely on the
6011  *        contents of this struct to be preserved in any way.
6012  *        <ul>
6013  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
6014  *        (e.g. folder) to store this file in. If this is 0,
6015  *        the file will be stored in the root folder.
6016  *        <li><code>filedata-&gt;storage_id</code> should be set to the
6017  *        desired storage (e.g. memory card or whatever your device
6018  *        presents) to store this file in. Setting this to 0 will store
6019  *        the file on the primary storage.
6020  *        </ul>
6021  * @param callback a progress indicator function or NULL to ignore.
6022  * @param data a user-defined pointer that is passed along to
6023  *             the <code>progress</code> function in order to
6024  *             pass along some user defined data to the progress
6025  *             updates. If not used, set this to NULL.
6026  * @return 0 if the transfer was successful, any other value means
6027  *           failure.
6028  * @see LIBMTP_Send_File_From_File()
6029  * @see LIBMTP_Send_Track_From_File_Descriptor()
6030  * @see LIBMTP_Delete_Object()
6031  */
6032 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
6033 			 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
6034        LIBMTP_progressfunc_t const callback, void const * const data)
6035 {
6036   uint16_t ret;
6037   PTPParams *params = (PTPParams *) device->params;
6038   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6039   LIBMTP_file_t *newfilemeta;
6040 
6041   if (send_file_object_info(device, filedata))
6042   {
6043     // no need to output an error since send_file_object_info will already have done so
6044     return -1;
6045   }
6046 
6047   // Callbacks
6048   ptp_usb->callback_active = 1;
6049   // The callback will deactivate itself after this amount of data has been sent
6050   // One BULK header for the request, one for the data phase. No parameters to the request.
6051   ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
6052   ptp_usb->current_transfer_complete = 0;
6053   ptp_usb->current_transfer_callback = callback;
6054   ptp_usb->current_transfer_callback_data = data;
6055 
6056   MTPDataHandler mtp_handler;
6057   mtp_handler.getfunc = get_func;
6058   mtp_handler.putfunc = NULL;
6059   mtp_handler.priv = priv;
6060 
6061   PTPDataHandler handler;
6062   handler.getfunc = get_func_wrapper;
6063   handler.putfunc = NULL;
6064   handler.priv = &mtp_handler;
6065 
6066   ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
6067 
6068   ptp_usb->callback_active = 0;
6069   ptp_usb->current_transfer_callback = NULL;
6070   ptp_usb->current_transfer_callback_data = NULL;
6071 
6072   if (ret == PTP_ERROR_CANCEL) {
6073     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
6074     return -1;
6075   }
6076   if (ret != PTP_RC_OK) {
6077     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
6078 				"Could not send object.");
6079     return -1;
6080   }
6081 
6082   add_object_to_cache(device, filedata->item_id);
6083 
6084   /*
6085    * Get the device-assined parent_id from the cache.
6086    * The operation that adds it to the cache will
6087    * look it up from the device, so we get the new
6088    * parent_id from the cache.
6089    */
6090   newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
6091   if (newfilemeta != NULL) {
6092     filedata->parent_id = newfilemeta->parent_id;
6093     filedata->storage_id = newfilemeta->storage_id;
6094     LIBMTP_destroy_file_t(newfilemeta);
6095   } else {
6096     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
6097 			    "LIBMTP_Send_File_From_Handler(): "
6098 			    "Could not retrieve updated metadata.");
6099     return -1;
6100   }
6101 
6102   return 0;
6103 }
6104 
6105 /**
6106  * This function sends the file object info, ready for sendobject
6107  * @param device a pointer to the device to send the file to.
6108  * @param filedata a file metadata set to be written along with the file.
6109  * @return 0 if the transfer was successful, any other value means
6110  *           failure.
6111  */
6112 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
6113 {
6114   PTPParams *params = (PTPParams *) device->params;
6115   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6116   uint32_t store;
6117   int use_primary_storage = 1;
6118   uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
6119   LIBMTP_devicestorage_t *storage;
6120   uint32_t localph = filedata->parent_id;
6121   uint16_t ret;
6122   int i;
6123 
6124 #if 0
6125   // Sanity check: no zerolength files on some devices?
6126   // If the zerolength files cause problems on some devices,
6127   // then add a bug flag for this.
6128   if (filedata->filesize == 0) {
6129     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
6130 			    "File of zero size.");
6131     return -1;
6132   }
6133 #endif
6134   if (filedata->storage_id != 0) {
6135     store = filedata->storage_id;
6136   } else {
6137     store = get_suggested_storage_id(device, filedata->filesize, localph);
6138   }
6139 
6140   // Detect if something non-primary is in use.
6141   storage = device->storage;
6142   if (storage != NULL && store != storage->id) {
6143     use_primary_storage = 0;
6144   }
6145 
6146   /*
6147    * If no destination folder was given, look up a default
6148    * folder if possible. Perhaps there is some way of retrieveing
6149    * the default folder for different forms of content, what
6150    * do I know, we use a fixed list in lack of any better method.
6151    * Some devices obviously need to have their files in certain
6152    * folders in order to find/display them at all (hello Creative),
6153    * so we have to have a method for this. We only do this if the
6154    * primary storage is in use.
6155    */
6156 
6157   if (localph == 0 && use_primary_storage) {
6158     if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
6159       localph = device->default_music_folder;
6160     } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
6161       localph = device->default_video_folder;
6162     } else if (of == PTP_OFC_EXIF_JPEG ||
6163 	       of == PTP_OFC_JP2 ||
6164 	       of == PTP_OFC_JPX ||
6165 	       of == PTP_OFC_JFIF ||
6166 	       of == PTP_OFC_TIFF ||
6167 	       of == PTP_OFC_TIFF_IT ||
6168 	       of == PTP_OFC_BMP ||
6169 	       of == PTP_OFC_GIF ||
6170 	       of == PTP_OFC_PICT ||
6171 	       of == PTP_OFC_PNG ||
6172 	       of == PTP_OFC_MTP_WindowsImageFormat) {
6173       localph = device->default_picture_folder;
6174     } else if (of == PTP_OFC_MTP_vCalendar1 ||
6175 	       of == PTP_OFC_MTP_vCalendar2 ||
6176 	       of == PTP_OFC_MTP_UndefinedContact ||
6177 	       of == PTP_OFC_MTP_vCard2 ||
6178 	       of == PTP_OFC_MTP_vCard3 ||
6179 	       of == PTP_OFC_MTP_UndefinedCalendarItem) {
6180       localph = device->default_organizer_folder;
6181     } else if (of == PTP_OFC_Text) {
6182       localph = device->default_text_folder;
6183     }
6184   }
6185 
6186   // Here we wire the type to unknown on bugged, but
6187   // Ogg or FLAC-supportive devices.
6188   if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
6189     of = PTP_OFC_Undefined;
6190   }
6191   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
6192     of = PTP_OFC_Undefined;
6193   }
6194 
6195   if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
6196       !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
6197     /*
6198      * MTP enhanched does it this way (from a sniff):
6199      * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6200      *    20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
6201      *    FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
6202      *    Length: 0x00000020
6203      *    Type:   0x0001 PTP_USB_CONTAINER_COMMAND
6204      *    Code:   0x9808
6205      *    Transaction ID: 0x0000001B
6206      *    Param1: 0x00010001 <- store
6207      *    Param2: 0xffffffff <- parent handle (-1 ?)
6208      *    Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
6209      *    Param4: 0x00000000 <- file length MSB (-0x0c header len)
6210      *    Param5: 0x00005e12 <- file length LSB (-0x0c header len)
6211      *
6212      * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6213      *    46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
6214      *    00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
6215      *    00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
6216      *    00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
6217      *    00 4F DC 02 00 01                               - dc4f = non consumable
6218      *    Length: 0x00000046
6219      *    Type:   0x0002 PTP_USB_CONTAINER_DATA
6220      *    Code:   0x9808
6221      *    Transaction ID: 0x0000001B
6222      *    Metadata....
6223      *    0x00000003 <- Number of metadata items
6224      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6225      *    0xdc07     <- metadata type: file name
6226      *    0xffff     <- metadata type: string
6227      *    0x0d       <- number of (uint16_t) characters
6228      *    4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
6229      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6230      *    0xdc03     <- metadata type: protection status
6231      *    0x0004     <- metadata type: uint16_t
6232      *    0x0000     <- not protected
6233      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6234      *    0xdc4f     <- non consumable
6235      *    0x0002     <- metadata type: uint8_t
6236      *    0x01       <- non-consumable (this device cannot display PDF)
6237      *
6238      * <- Read 0x18 bytes back
6239      *    18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
6240      *    00 00 00 00 01 40 00 00
6241      *    Length: 0x000000018
6242      *    Type:   0x0003 PTP_USB_CONTAINER_RESPONSE
6243      *    Code:   0x2001 PTP_OK
6244      *    Transaction ID: 0x0000001B
6245      *    Param1: 0x00010001 <- store
6246      *    Param2: 0x00000000 <- parent handle
6247      *    Param3: 0x00004001 <- new file/object ID
6248      *
6249      * -> PTP_OC_SendObject (0x100d)
6250      *    0C 00 00 00 01 00 0D 10 1C 00 00 00
6251      * -> ... all the bytes ...
6252      * <- Read 0x0c bytes back
6253      *    0C 00 00 00 03 00 01 20 1C 00 00 00
6254      *    ... Then update metadata one-by one, actually (instead of sending it first!) ...
6255      */
6256     MTPProperties *props = NULL;
6257     int nrofprops = 0;
6258     MTPProperties *prop = NULL;
6259     uint16_t *properties = NULL;
6260     uint32_t propcnt = 0;
6261 
6262     // default parent handle
6263     if (localph == 0)
6264       localph = 0xFFFFFFFFU; // Set to -1
6265 
6266     // Must be 0x00000000U for new objects
6267     filedata->item_id = 0x00000000U;
6268 
6269     ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
6270 
6271     for (i=0;i<propcnt;i++) {
6272       PTPObjectPropDesc opd;
6273 
6274       ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
6275       if (ret != PTP_RC_OK) {
6276 	add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6277 				"could not get property description.");
6278       } else if (opd.GetSet) {
6279 	switch (properties[i]) {
6280 	case PTP_OPC_ObjectFileName:
6281 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6282 	  prop->ObjectHandle = filedata->item_id;
6283 	  prop->property = PTP_OPC_ObjectFileName;
6284 	  prop->datatype = PTP_DTC_STR;
6285 	  if (filedata->filename != NULL) {
6286 	    prop->propval.str = strdup(filedata->filename);
6287 	    if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6288 	      strip_7bit_from_utf8(prop->propval.str);
6289 	    }
6290 	  }
6291 	  break;
6292 	case PTP_OPC_ProtectionStatus:
6293 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6294 	  prop->ObjectHandle = filedata->item_id;
6295 	  prop->property = PTP_OPC_ProtectionStatus;
6296 	  prop->datatype = PTP_DTC_UINT16;
6297 	  prop->propval.u16 = 0x0000U; /* Not protected */
6298 	  break;
6299 	case PTP_OPC_NonConsumable:
6300 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6301 	  prop->ObjectHandle = filedata->item_id;
6302 	  prop->property = PTP_OPC_NonConsumable;
6303 	  prop->datatype = PTP_DTC_UINT8;
6304 	  prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
6305 	  break;
6306 	case PTP_OPC_Name:
6307 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6308 	  prop->ObjectHandle = filedata->item_id;
6309 	  prop->property = PTP_OPC_Name;
6310 	  prop->datatype = PTP_DTC_STR;
6311 	  if (filedata->filename != NULL)
6312 	    prop->propval.str = strdup(filedata->filename);
6313 	  break;
6314 	case PTP_OPC_DateModified:
6315 	  // Tag with current time if that is supported
6316 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6317 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6318 	    prop->ObjectHandle = filedata->item_id;
6319 	    prop->property = PTP_OPC_DateModified;
6320 	    prop->datatype = PTP_DTC_STR;
6321 	    prop->propval.str = get_iso8601_stamp();
6322 	    filedata->modificationdate = time(NULL);
6323 	  }
6324 	  break;
6325 	}
6326       }
6327       ptp_free_objectpropdesc(&opd);
6328     }
6329     free(properties);
6330 
6331     ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
6332 				     of, filedata->filesize, props, nrofprops);
6333 
6334     /* Free property list */
6335     ptp_destroy_object_prop_list(props, nrofprops);
6336 
6337     if (ret != PTP_RC_OK) {
6338       add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
6339 				  "Could not send object property list.");
6340       if (ret == PTP_RC_AccessDenied) {
6341 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6342       }
6343       return -1;
6344     }
6345   } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
6346     PTPObjectInfo new_file;
6347 
6348     memset(&new_file, 0, sizeof(PTPObjectInfo));
6349 
6350     new_file.Filename = filedata->filename;
6351     if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6352       strip_7bit_from_utf8(new_file.Filename);
6353     }
6354     if (filedata->filesize > 0xFFFFFFFFL) {
6355       // This is a kludge in the MTP standard for large files.
6356       new_file.ObjectCompressedSize = (uint32_t) 0xFFFFFFFF;
6357     } else {
6358       new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
6359     }
6360     new_file.ObjectFormat = of;
6361     new_file.StorageID = store;
6362     new_file.ParentObject = localph;
6363     new_file.ModificationDate = time(NULL);
6364 
6365     // Create the object
6366     ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
6367 
6368     if (ret != PTP_RC_OK) {
6369       add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6370 				  "Could not send object info.");
6371       if (ret == PTP_RC_AccessDenied) {
6372 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6373       }
6374       return -1;
6375     }
6376     // NOTE: the char* pointers inside new_file are not copies so don't
6377     // try to destroy this objectinfo!
6378   }
6379 
6380   // Now there IS an object with this parent handle.
6381   filedata->parent_id = localph;
6382 
6383   return 0;
6384 }
6385 
6386 /**
6387  * This function updates the MTP track object metadata on a
6388  * single file identified by an object ID.
6389  * @param device a pointer to the device to update the track
6390  *        metadata on.
6391  * @param metadata a track metadata set to be written to the file.
6392  *        notice that the <code>track_id</code> field of the
6393  *        metadata structure must be correct so that the
6394  *        function can update the right file. If some properties
6395  *        of this metadata are set to NULL (strings) or 0
6396  *        (numerical values) they will be discarded and the
6397  *        track will not be tagged with these blank values.
6398  * @return 0 on success, any other value means failure. If some
6399  *        or all of the properties fail to update we will still
6400  *        return success. On some devices (notably iRiver T30)
6401  *        properties that exist cannot be updated.
6402  */
6403 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
6404 				 LIBMTP_track_t const * const metadata)
6405 {
6406   uint16_t ret;
6407   PTPParams *params = (PTPParams *) device->params;
6408   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6409   uint32_t i;
6410   uint16_t *properties = NULL;
6411   uint32_t propcnt = 0;
6412 
6413   // First see which properties can be set on this file format and apply accordingly
6414   // i.e only try to update this metadata for object tags that exist on the current player.
6415   ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
6416   if (ret != PTP_RC_OK) {
6417     // Just bail out for now, nothing is ever set.
6418     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6419 			    "could not retrieve supported object properties.");
6420     return -1;
6421   }
6422   if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6423       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6424     MTPProperties *props = NULL;
6425     MTPProperties *prop = NULL;
6426     int nrofprops = 0;
6427 
6428     for (i=0;i<propcnt;i++) {
6429       PTPObjectPropDesc opd;
6430 
6431       ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6432       if (ret != PTP_RC_OK) {
6433 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6434 				"could not get property description.");
6435       } else if (opd.GetSet) {
6436 	switch (properties[i]) {
6437 	case PTP_OPC_Name:
6438 	  if (metadata->title == NULL)
6439 	    break;
6440 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6441 	  prop->ObjectHandle = metadata->item_id;
6442 	  prop->property = PTP_OPC_Name;
6443 	  prop->datatype = PTP_DTC_STR;
6444 	  prop->propval.str = strdup(metadata->title);
6445 	  break;
6446 	case PTP_OPC_AlbumName:
6447 	  if (metadata->album == NULL)
6448 	    break;
6449 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6450 	  prop->ObjectHandle = metadata->item_id;
6451 	  prop->property = PTP_OPC_AlbumName;
6452 	  prop->datatype = PTP_DTC_STR;
6453 	  prop->propval.str = strdup(metadata->album);
6454 	  break;
6455 	case PTP_OPC_Artist:
6456 	  if (metadata->artist == NULL)
6457 	    break;
6458 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6459 	  prop->ObjectHandle = metadata->item_id;
6460 	  prop->property = PTP_OPC_Artist;
6461 	  prop->datatype = PTP_DTC_STR;
6462 	  prop->propval.str = strdup(metadata->artist);
6463 	  break;
6464 	case PTP_OPC_Composer:
6465 	  if (metadata->composer == NULL)
6466 	    break;
6467 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6468 	  prop->ObjectHandle = metadata->item_id;
6469 	  prop->property = PTP_OPC_Composer;
6470 	  prop->datatype = PTP_DTC_STR;
6471 	  prop->propval.str = strdup(metadata->composer);
6472 	  break;
6473 	case PTP_OPC_Genre:
6474 	  if (metadata->genre == NULL)
6475 	    break;
6476 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6477 	  prop->ObjectHandle = metadata->item_id;
6478 	  prop->property = PTP_OPC_Genre;
6479 	  prop->datatype = PTP_DTC_STR;
6480 	  prop->propval.str = strdup(metadata->genre);
6481 	  break;
6482 	case PTP_OPC_Duration:
6483 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6484 	  prop->ObjectHandle = metadata->item_id;
6485 	  prop->property = PTP_OPC_Duration;
6486 	  prop->datatype = PTP_DTC_UINT32;
6487 	  prop->propval.u32 = adjust_u32(metadata->duration, &opd);
6488 	  break;
6489 	case PTP_OPC_Track:
6490 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6491 	  prop->ObjectHandle = metadata->item_id;
6492 	  prop->property = PTP_OPC_Track;
6493 	  prop->datatype = PTP_DTC_UINT16;
6494 	  prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
6495 	  break;
6496 	case PTP_OPC_OriginalReleaseDate:
6497 	  if (metadata->date == NULL)
6498 	    break;
6499 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6500 	  prop->ObjectHandle = metadata->item_id;
6501 	  prop->property = PTP_OPC_OriginalReleaseDate;
6502 	  prop->datatype = PTP_DTC_STR;
6503 	  prop->propval.str = strdup(metadata->date);
6504 	  break;
6505 	case PTP_OPC_SampleRate:
6506 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6507 	  prop->ObjectHandle = metadata->item_id;
6508 	  prop->property = PTP_OPC_SampleRate;
6509 	  prop->datatype = PTP_DTC_UINT32;
6510 	  prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
6511 	  break;
6512 	case PTP_OPC_NumberOfChannels:
6513 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6514 	  prop->ObjectHandle = metadata->item_id;
6515 	  prop->property = PTP_OPC_NumberOfChannels;
6516 	  prop->datatype = PTP_DTC_UINT16;
6517 	  prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
6518 	  break;
6519 	case PTP_OPC_AudioWAVECodec:
6520 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6521 	  prop->ObjectHandle = metadata->item_id;
6522 	  prop->property = PTP_OPC_AudioWAVECodec;
6523 	  prop->datatype = PTP_DTC_UINT32;
6524 	  prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
6525 	  break;
6526 	case PTP_OPC_AudioBitRate:
6527 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6528 	  prop->ObjectHandle = metadata->item_id;
6529 	  prop->property = PTP_OPC_AudioBitRate;
6530 	  prop->datatype = PTP_DTC_UINT32;
6531 	  prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
6532 	  break;
6533 	case PTP_OPC_BitRateType:
6534 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6535 	  prop->ObjectHandle = metadata->item_id;
6536 	  prop->property = PTP_OPC_BitRateType;
6537 	  prop->datatype = PTP_DTC_UINT16;
6538 	  prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
6539 	  break;
6540 	case PTP_OPC_Rating:
6541 	  // TODO: shall this be set for rating 0?
6542 	  if (metadata->rating == 0)
6543 	    break;
6544 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6545 	  prop->ObjectHandle = metadata->item_id;
6546 	  prop->property = PTP_OPC_Rating;
6547 	  prop->datatype = PTP_DTC_UINT16;
6548 	  prop->propval.u16 = adjust_u16(metadata->rating, &opd);
6549 	  break;
6550 	case PTP_OPC_UseCount:
6551 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6552 	  prop->ObjectHandle = metadata->item_id;
6553 	  prop->property = PTP_OPC_UseCount;
6554 	  prop->datatype = PTP_DTC_UINT32;
6555 	  prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
6556 	  break;
6557 	case PTP_OPC_DateModified:
6558 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6559 	    // Tag with current time if that is supported
6560 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6561 	    prop->ObjectHandle = metadata->item_id;
6562 	    prop->property = PTP_OPC_DateModified;
6563 	    prop->datatype = PTP_DTC_STR;
6564 	    prop->propval.str = get_iso8601_stamp();
6565 	  }
6566 	  break;
6567 	default:
6568 	  break;
6569 	}
6570       }
6571       ptp_free_objectpropdesc(&opd);
6572     }
6573 
6574     // NOTE: File size is not updated, this should not change anyway.
6575     // neither will we change the filename.
6576 
6577     ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6578 
6579     ptp_destroy_object_prop_list(props, nrofprops);
6580 
6581     if (ret != PTP_RC_OK) {
6582       // TODO: return error of which property we couldn't set
6583       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6584 			      "could not set object property list.");
6585       free(properties);
6586       return -1;
6587     }
6588 
6589   } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6590     for (i=0;i<propcnt;i++) {
6591       PTPObjectPropDesc opd;
6592 
6593       ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6594       if (ret != PTP_RC_OK) {
6595 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6596 				"could not get property description.");
6597       } else if (opd.GetSet) {
6598 	switch (properties[i]) {
6599 	case PTP_OPC_Name:
6600 	  // Update title
6601 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6602 	  if (ret != 0) {
6603 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6604 				    "could not set track title.");
6605 	  }
6606 	  break;
6607 	case PTP_OPC_AlbumName:
6608 	  // Update album
6609 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6610 	  if (ret != 0) {
6611 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6612 				    "could not set track album name.");
6613 	  }
6614 	  break;
6615 	case PTP_OPC_Artist:
6616 	  // Update artist
6617 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6618 	  if (ret != 0) {
6619 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6620 				    "could not set track artist name.");
6621 	  }
6622 	  break;
6623 	case PTP_OPC_Composer:
6624 	  // Update composer
6625 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6626 	  if (ret != 0) {
6627 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6628 				    "could not set track composer name.");
6629 	  }
6630 	  break;
6631 	case PTP_OPC_Genre:
6632 	  // Update genre (but only if valid)
6633 	  if (metadata->genre) {
6634 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6635 	    if (ret != 0) {
6636 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6637 				      "could not set genre.");
6638 	    }
6639 	  }
6640 	  break;
6641 	case PTP_OPC_Duration:
6642 	  // Update duration
6643 	  if (metadata->duration != 0) {
6644 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6645 	    if (ret != 0) {
6646 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6647 				      "could not set track duration.");
6648 	    }
6649 	  }
6650 	  break;
6651 	case PTP_OPC_Track:
6652 	  // Update track number.
6653 	  if (metadata->tracknumber != 0) {
6654 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6655 	    if (ret != 0) {
6656 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6657 				      "could not set track tracknumber.");
6658 	    }
6659 	  }
6660 	  break;
6661 	case PTP_OPC_OriginalReleaseDate:
6662 	  // Update creation datetime
6663 	  // The date can be zero, but some devices do not support setting zero
6664 	  // dates (and it seems that a zero date should never be set anyway)
6665 	  if (metadata->date) {
6666 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6667 	    if (ret != 0) {
6668 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6669 				      "could not set track release date.");
6670 	    }
6671 	  }
6672 	  break;
6673 	  // These are, well not so important.
6674 	case PTP_OPC_SampleRate:
6675 	  // Update sample rate
6676 	  if (metadata->samplerate != 0) {
6677 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6678 	    if (ret != 0) {
6679 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6680 				      "could not set samplerate.");
6681 	    }
6682 	  }
6683 	  break;
6684 	case PTP_OPC_NumberOfChannels:
6685 	  // Update number of channels
6686 	  if (metadata->nochannels != 0) {
6687 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6688 	  if (ret != 0) {
6689 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6690 				    "could not set number of channels.");
6691 	  }
6692 	}
6693 	  break;
6694 	case PTP_OPC_AudioWAVECodec:
6695 	  // Update WAVE codec
6696 	  if (metadata->wavecodec != 0) {
6697 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6698 	    if (ret != 0) {
6699 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6700 				      "could not set WAVE codec.");
6701 	    }
6702 	  }
6703 	  break;
6704 	case PTP_OPC_AudioBitRate:
6705 	  // Update bitrate
6706 	  if (metadata->bitrate != 0) {
6707 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6708 	    if (ret != 0) {
6709 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6710 				      "could not set bitrate.");
6711 	  }
6712 	  }
6713 	  break;
6714 	case PTP_OPC_BitRateType:
6715 	  // Update bitrate type
6716 	  if (metadata->bitratetype != 0) {
6717 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6718 	    if (ret != 0) {
6719 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6720 				      "could not set bitratetype.");
6721 	    }
6722 	  }
6723 	  break;
6724 	case PTP_OPC_Rating:
6725 	  // Update user rating
6726 	  // TODO: shall this be set for rating 0?
6727 	  if (metadata->rating != 0) {
6728 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6729 	    if (ret != 0) {
6730 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6731 				      "could not set user rating.");
6732 	    }
6733 	  }
6734 	  break;
6735 	case PTP_OPC_UseCount:
6736 	  // Update use count, set even to zero if desired.
6737 	  ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6738 	  if (ret != 0) {
6739 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6740 				  "could not set use count.");
6741 	  }
6742 	  break;
6743 	case PTP_OPC_DateModified:
6744 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6745 	    // Update modification time if supported
6746 	    char *tmpstamp = get_iso8601_stamp();
6747 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6748 	    if (ret != 0) {
6749 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6750 				      "could not set modification date.");
6751 	    }
6752 	    free(tmpstamp);
6753 	  }
6754 	  break;
6755 
6756 	  // NOTE: File size is not updated, this should not change anyway.
6757 	  // neither will we change the filename.
6758 	default:
6759 	  break;
6760 	}
6761       }
6762       ptp_free_objectpropdesc(&opd);
6763     }
6764   } else {
6765     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6766                             "Your device doesn't seem to support any known way of setting metadata.");
6767     free(properties);
6768     return -1;
6769   }
6770 
6771   // update cached object properties if metadata cache exists
6772   update_metadata_cache(device, metadata->item_id);
6773 
6774   free(properties);
6775 
6776   return 0;
6777 }
6778 
6779 /**
6780  * This function deletes a single file, track, playlist, folder or
6781  * any other object off the MTP device, identified by the object ID.
6782  *
6783  * If you delete a folder, there is no guarantee that the device will
6784  * really delete all the files that were in that folder, rather it is
6785  * expected that they will not be deleted, and will turn up in object
6786  * listings with parent set to a non-existant object ID. The safe way
6787  * to do this is to recursively delete all files (and folders) contained
6788  * in the folder, then the folder itself.
6789  *
6790  * @param device a pointer to the device to delete the object from.
6791  * @param object_id the object to delete.
6792  * @return 0 on success, any other value means failure.
6793  */
6794 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6795 			 uint32_t object_id)
6796 {
6797   uint16_t ret;
6798   PTPParams *params = (PTPParams *) device->params;
6799 
6800   ret = ptp_deleteobject(params, object_id, 0);
6801   if (ret != PTP_RC_OK) {
6802     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6803     return -1;
6804   }
6805 
6806   return 0;
6807 }
6808 
6809 /**
6810  * Internal function to update an object filename property.
6811  */
6812 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6813 			       uint32_t object_id, uint16_t ptp_type,
6814 			       const char **newname_ptr)
6815 {
6816   PTPParams             *params = (PTPParams *) device->params;
6817   PTP_USB               *ptp_usb = (PTP_USB*) device->usbinfo;
6818   PTPObjectPropDesc     opd;
6819   uint16_t              ret;
6820   char                  *newname;
6821 
6822   // See if we can modify the filename on this kind of files.
6823   ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6824   if (ret != PTP_RC_OK) {
6825     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6826 			    "could not get property description.");
6827     return -1;
6828   }
6829 
6830   if (!opd.GetSet) {
6831     ptp_free_objectpropdesc(&opd);
6832     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6833             " property is not settable.");
6834     // TODO: we COULD actually upload/download the object here, if we feel
6835     //       like wasting time for the user.
6836     return -1;
6837   }
6838 
6839   newname = strdup(*newname_ptr);
6840 
6841   if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6842     strip_7bit_from_utf8(newname);
6843   }
6844 
6845   if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6846       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6847     MTPProperties *props = NULL;
6848     MTPProperties *prop = NULL;
6849     int nrofprops = 0;
6850 
6851     prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6852     prop->ObjectHandle = object_id;
6853     prop->property = PTP_OPC_ObjectFileName;
6854     prop->datatype = PTP_DTC_STR;
6855     prop->propval.str = newname;
6856 
6857     ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6858 
6859     ptp_destroy_object_prop_list(props, nrofprops);
6860 
6861     if (ret != PTP_RC_OK) {
6862         add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6863               " could not set object property list.");
6864         ptp_free_objectpropdesc(&opd);
6865         return -1;
6866     }
6867   } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6868     ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6869     if (ret != 0) {
6870       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6871               " could not set object filename.");
6872       ptp_free_objectpropdesc(&opd);
6873       return -1;
6874     }
6875   } else {
6876     free(newname);
6877     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6878               " your device doesn't seem to support any known way of setting metadata.");
6879     ptp_free_objectpropdesc(&opd);
6880     return -1;
6881   }
6882 
6883   ptp_free_objectpropdesc(&opd);
6884 
6885   // update cached object properties if metadata cache exists
6886   update_metadata_cache(device, object_id);
6887 
6888   return 0;
6889 }
6890 
6891 /**
6892  * This function renames a single file.
6893  * This simply means that the PTP_OPC_ObjectFileName property
6894  * is updated, if this is supported by the device.
6895  *
6896  * @param device a pointer to the device that contains the file.
6897  * @param file the file metadata of the file to rename.
6898  *        On success, the filename member is updated. Be aware, that
6899  *        this name can be different than newname depending of device restrictions.
6900  * @param newname the new filename for this object.
6901  * @return 0 on success, any other value means failure.
6902  */
6903 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6904                    LIBMTP_file_t *file, const char *newname)
6905 {
6906   int         ret;
6907 
6908   ret = set_object_filename(device, file->item_id,
6909 			    map_libmtp_type_to_ptp_type(file->filetype),
6910 			    &newname);
6911 
6912   if (ret != 0) {
6913     return ret;
6914   }
6915 
6916   free(file->filename);
6917   file->filename = strdup(newname);
6918   return ret;
6919 }
6920 
6921 /**
6922  * This function renames a single folder.
6923  * This simply means that the PTP_OPC_ObjectFileName property
6924  * is updated, if this is supported by the device.
6925  *
6926  * @param device a pointer to the device that contains the file.
6927  * @param folder the folder metadata of the folder to rename.
6928  *        On success, the name member is updated. Be aware, that
6929  *        this name can be different than newname depending of device restrictions.
6930  * @param newname the new name for this object.
6931  * @return 0 on success, any other value means failure.
6932  */
6933 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
6934                    LIBMTP_folder_t *folder, const char* newname)
6935 {
6936   int ret;
6937 
6938   ret = set_object_filename(device, folder->folder_id,
6939 			    PTP_OFC_Association,
6940 			    &newname);
6941 
6942   if (ret != 0) {
6943     return ret;
6944     }
6945 
6946   free(folder->name);
6947   folder->name = strdup(newname);
6948   return ret;
6949 }
6950 
6951 /**
6952  * This function renames a single track.
6953  * This simply means that the PTP_OPC_ObjectFileName property
6954  * is updated, if this is supported by the device.
6955  *
6956  * @param device a pointer to the device that contains the file.
6957  * @param track the track metadata of the track to rename.
6958  *        On success, the filename member is updated. Be aware, that
6959  *        this name can be different than newname depending of device restrictions.
6960  * @param newname the new filename for this object.
6961  * @return 0 on success, any other value means failure.
6962  */
6963 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
6964                    LIBMTP_track_t *track, const char* newname)
6965 {
6966   int         ret;
6967 
6968   ret = set_object_filename(device, track->item_id,
6969 			    map_libmtp_type_to_ptp_type(track->filetype),
6970 			    &newname);
6971 
6972   if (ret != 0) {
6973     return ret;
6974   }
6975 
6976   free(track->filename);
6977   track->filename = strdup(newname);
6978   return ret;
6979 }
6980 
6981 /**
6982  * This function renames a single playlist object file holder.
6983  * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6984  * property is updated, if this is supported by the device.
6985  * The playlist filename should nominally end with an extension
6986  * like ".pla".
6987  *
6988  * NOTE: if you want to change the metadata the device display
6989  * about a playlist you must <i>not</i> use this function,
6990  * use <code>LIBMTP_Update_Playlist()</code> instead!
6991  *
6992  * @param device a pointer to the device that contains the file.
6993  * @param playlist the playlist metadata of the playlist to rename.
6994  *        On success, the name member is updated. Be aware, that
6995  *        this name can be different than newname depending of device restrictions.
6996  * @param newname the new name for this object.
6997  * @return 0 on success, any other value means failure.
6998  * @see LIBMTP_Update_Playlist()
6999  */
7000 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
7001                    LIBMTP_playlist_t *playlist, const char* newname)
7002 {
7003   int ret;
7004 
7005   ret = set_object_filename(device, playlist->playlist_id,
7006 			    PTP_OFC_MTP_AbstractAudioVideoPlaylist,
7007 			    &newname);
7008 
7009   if (ret != 0) {
7010     return ret;
7011   }
7012 
7013   free(playlist->name);
7014   playlist->name = strdup(newname);
7015   return ret;
7016 }
7017 
7018 /**
7019  * This function renames a single album.
7020  * This simply means that the <code>PTP_OPC_ObjectFileName</code>
7021  * property is updated, if this is supported by the device.
7022  * The album filename should nominally end with an extension
7023  * like ".alb".
7024  *
7025  * NOTE: if you want to change the metadata the device display
7026  * about a playlist you must <i>not</i> use this function,
7027  * use <code>LIBMTP_Update_Album()</code> instead!
7028  *
7029  * @param device a pointer to the device that contains the file.
7030  * @param album the album metadata of the album to rename.
7031  *        On success, the name member is updated. Be aware, that
7032  *        this name can be different than newname depending of device restrictions.
7033  * @param newname the new name for this object.
7034  * @return 0 on success, any other value means failure.
7035  * @see LIBMTP_Update_Album()
7036  */
7037 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
7038                    LIBMTP_album_t *album, const char* newname)
7039 {
7040   int ret;
7041 
7042   ret = set_object_filename(device, album->album_id,
7043 			    PTP_OFC_MTP_AbstractAudioAlbum,
7044 			    &newname);
7045 
7046   if (ret != 0) {
7047     return ret;
7048   }
7049 
7050   free(album->name);
7051   album->name = strdup(newname);
7052   return ret;
7053 }
7054 
7055 /**
7056  * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
7057  * NOT TO USE IT.
7058  *
7059  * @see LIBMTP_Set_File_Name()
7060  * @see LIBMTP_Set_Track_Name()
7061  * @see LIBMTP_Set_Folder_Name()
7062  * @see LIBMTP_Set_Playlist_Name()
7063  * @see LIBMTP_Set_Album_Name()
7064  */
7065 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
7066                    uint32_t object_id, char* newname)
7067 {
7068   int             ret;
7069   LIBMTP_file_t   *file;
7070 
7071   file = LIBMTP_Get_Filemetadata(device, object_id);
7072 
7073   if (file == NULL) {
7074     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
7075 			    "could not get file metadata for target object.");
7076     return -1;
7077   }
7078 
7079   ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
7080 
7081   free(file);
7082 
7083   return ret;
7084 }
7085 
7086 /**
7087  * Helper function. This indicates if a track exists on the device
7088  * @param device a pointer to the device to get the track from.
7089  * @param id the track ID of the track to retrieve.
7090  * @return TRUE (!=0) if the track exists, FALSE (0) if not
7091  */
7092 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
7093            uint32_t const id)
7094 {
7095   PTPParams *params = (PTPParams *) device->params;
7096   uint16_t ret;
7097   PTPObject *ob;
7098 
7099   ret = ptp_object_want (params, id, 0, &ob);
7100   if (ret == PTP_RC_OK)
7101       return -1;
7102   return 0;
7103 }
7104 
7105 /**
7106  * This creates a new folder structure and allocates memory
7107  * for it. Notice that if you add strings to this structure they
7108  * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
7109  * operation later, so be careful of using strdup() when assigning
7110  * strings, e.g.:
7111  *
7112  * @return a pointer to the newly allocated folder structure.
7113  * @see LIBMTP_destroy_folder_t()
7114  */
7115 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
7116 {
7117   LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
7118   if (new == NULL) {
7119     return NULL;
7120   }
7121   new->folder_id = 0;
7122   new->parent_id = 0;
7123   new->storage_id = 0;
7124   new->name = NULL;
7125   new->sibling = NULL;
7126   new->child = NULL;
7127   return new;
7128 }
7129 
7130 /**
7131  * This recursively deletes the memory for a folder structure.
7132  * This shall typically be called on a top-level folder list to
7133  * detsroy the entire folder tree.
7134  *
7135  * @param folder folder structure to destroy
7136  * @see LIBMTP_new_folder_t()
7137  */
7138 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
7139 {
7140 
7141   if(folder == NULL) {
7142      return;
7143   }
7144 
7145   //Destroy from the bottom up
7146   if(folder->child != NULL) {
7147      LIBMTP_destroy_folder_t(folder->child);
7148   }
7149 
7150   if(folder->sibling != NULL) {
7151     LIBMTP_destroy_folder_t(folder->sibling);
7152   }
7153 
7154   if(folder->name != NULL) {
7155     free(folder->name);
7156   }
7157 
7158   free(folder);
7159 }
7160 
7161 /**
7162  * Helper function. Returns a folder structure for a
7163  * specified id.
7164  *
7165  * @param folderlist list of folders to search
7166  * @id id of folder to look for
7167  * @return a folder or NULL if not found
7168  */
7169 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
7170 {
7171   LIBMTP_folder_t *ret = NULL;
7172 
7173   if(folderlist == NULL) {
7174     return NULL;
7175   }
7176 
7177   if(folderlist->folder_id == id) {
7178     return folderlist;
7179   }
7180 
7181   if(folderlist->sibling) {
7182     ret = LIBMTP_Find_Folder(folderlist->sibling, id);
7183   }
7184 
7185   if(folderlist->child && ret == NULL) {
7186     ret = LIBMTP_Find_Folder(folderlist->child, id);
7187   }
7188 
7189   return ret;
7190 }
7191 
7192 /**
7193  * Function used to recursively get subfolders from params.
7194  */
7195 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
7196 {
7197   LIBMTP_folder_t *retfolders = NULL;
7198   LIBMTP_folder_t *children, *iter, *curr;
7199 
7200   iter = list->sibling;
7201   while(iter != list) {
7202     if (iter->parent_id != parent) {
7203       iter = iter->sibling;
7204       continue;
7205     }
7206 
7207     /* We know that iter is a child of 'parent', therefore we can safely
7208      * hold on to 'iter' locally since no one else will steal it
7209      * from the 'list' as we recurse. */
7210     children = get_subfolders_for_folder(list, iter->folder_id);
7211 
7212     curr = iter;
7213     iter = iter->sibling;
7214 
7215     // Remove curr from the list.
7216     curr->child->sibling = curr->sibling;
7217     curr->sibling->child = curr->child;
7218 
7219     // Attach the children to curr.
7220     curr->child = children;
7221 
7222     // Put this folder into the list of siblings.
7223     curr->sibling = retfolders;
7224     retfolders = curr;
7225   }
7226 
7227   return retfolders;
7228 }
7229 
7230 /**
7231  * This returns a list of all folders available
7232  * on the current MTP device.
7233  *
7234  * @param device a pointer to the device to get the folder listing for.
7235  * @param storage a storage ID to get the folder list from
7236  * @return a list of folders
7237  */
7238  LIBMTP_folder_t *LIBMTP_Get_Folder_List_For_Storage(LIBMTP_mtpdevice_t *device,
7239 						    uint32_t const storage)
7240 {
7241   PTPParams *params = (PTPParams *) device->params;
7242   LIBMTP_folder_t head, *rv;
7243   int i;
7244 
7245   // Get all the handles if we haven't already done that
7246   if (params->nrofobjects == 0) {
7247     flush_handles(device);
7248   }
7249 
7250   /*
7251    * This creates a temporary list of the folders, this is in a
7252    * reverse order and uses the Folder pointers that are already
7253    * in the Folder structure. From this we can then build up the
7254    * folder hierarchy with only looking at this temporary list,
7255    * and removing the folders from this temporary list as we go.
7256    * This significantly reduces the number of operations that we
7257    * have to do in building the folder hierarchy. Also since the
7258    * temp list is in reverse order, when we prepend to the sibling
7259    * list things are in the same order as they were originally
7260    * in the handle list.
7261    */
7262   head.sibling = &head;
7263   head.child = &head;
7264   for (i = 0; i < params->nrofobjects; i++) {
7265     LIBMTP_folder_t *folder;
7266     PTPObject *ob;
7267 
7268     ob = &params->objects[i];
7269     if (ob->oi.ObjectFormat != PTP_OFC_Association) {
7270       continue;
7271     }
7272 
7273     if (storage != PTP_GOH_ALL_STORAGE && storage != ob->oi.StorageID) {
7274       continue;
7275     }
7276 
7277     /*
7278      * Do we know how to handle these? They are part
7279      * of the MTP 1.0 specification paragraph 3.6.4.
7280      * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
7281      * should be called on these to get the contained objects, but
7282      * we basically don't care. Hopefully parent_id is maintained for all
7283      * children, because we rely on that instead.
7284      */
7285     if (ob->oi.AssociationDesc != 0x00000000U) {
7286       LIBMTP_INFO("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
7287     }
7288 
7289     // Create a folder struct...
7290     folder = LIBMTP_new_folder_t();
7291     if (folder == NULL) {
7292       // malloc failure or so.
7293       return NULL;
7294     }
7295     folder->folder_id = ob->oid;
7296     folder->parent_id = ob->oi.ParentObject;
7297     folder->storage_id = ob->oi.StorageID;
7298     folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
7299 
7300     // pretend sibling says next, and child says prev.
7301     folder->sibling = head.sibling;
7302     folder->child = &head;
7303     head.sibling->child = folder;
7304     head.sibling = folder;
7305   }
7306 
7307   // We begin at the given root folder and get them all recursively
7308   rv = get_subfolders_for_folder(&head, 0x00000000U);
7309 
7310   // Some buggy devices may have some files in the "root folder"
7311   // 0xffffffff so if 0x00000000 didn't return any folders,
7312   // look for children of the root 0xffffffffU
7313   if (rv == NULL) {
7314     rv = get_subfolders_for_folder(&head, 0xffffffffU);
7315     if (rv != NULL)
7316       LIBMTP_ERROR("Device have files in \"root folder\" 0xffffffffU - "
7317 		   "this is a firmware bug (but continuing)\n");
7318   }
7319 
7320   // The temp list should be empty. Clean up any orphans just in case.
7321   while(head.sibling != &head) {
7322     LIBMTP_folder_t *curr = head.sibling;
7323 
7324     LIBMTP_INFO("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
7325 	   curr->folder_id,
7326 	   curr->name);
7327     curr->sibling->child = curr->child;
7328     curr->child->sibling = curr->sibling;
7329     curr->child = NULL;
7330     curr->sibling = NULL;
7331     LIBMTP_destroy_folder_t(curr);
7332   }
7333 
7334   return rv;
7335 }
7336 
7337 /**
7338  * This returns a list of all folders available
7339  * on the current MTP device.
7340  *
7341  * @param device a pointer to the device to get the folder listing for.
7342  * @return a list of folders
7343  */
7344 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
7345 {
7346   return LIBMTP_Get_Folder_List_For_Storage(device, PTP_GOH_ALL_STORAGE);
7347 }
7348 
7349 /**
7350  * This create a folder on the current MTP device. The PTP name
7351  * for a folder is "association". The PTP/MTP devices does not
7352  * have an internal "folder" concept really, it contains a flat
7353  * list of all files and some file are "associations" that other
7354  * files and folders may refer to as its "parent".
7355  *
7356  * @param device a pointer to the device to create the folder on.
7357  * @param name the name of the new folder. Note this can be modified
7358  *        if the device does not support all the characters in the
7359  *        name.
7360  * @param parent_id id of parent folder to add the new folder to,
7361  *        or 0xFFFFFFFF to put it in the root directory.
7362  * @param storage_id id of the storage to add this new folder to.
7363  *        notice that you cannot mismatch storage id and parent id:
7364  *        they must both be on the same storage! Pass in 0 if you
7365  *        want to create this folder on the default storage.
7366  * @return id to new folder or 0 if an error occured
7367  */
7368 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
7369 			      uint32_t parent_id, uint32_t storage_id)
7370 {
7371   PTPParams *params = (PTPParams *) device->params;
7372   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7373   uint32_t parenthandle = 0;
7374   uint32_t store;
7375   PTPObjectInfo new_folder;
7376   uint16_t ret;
7377   uint32_t new_id = 0;
7378 
7379   if (storage_id == 0) {
7380     // I'm just guessing that a folder may require 512 bytes
7381     store = get_suggested_storage_id(device, 512, parent_id);
7382   } else {
7383     store = storage_id;
7384   }
7385   parenthandle = parent_id;
7386 
7387   memset(&new_folder, 0, sizeof(new_folder));
7388   new_folder.Filename = name;
7389   if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7390     strip_7bit_from_utf8(new_folder.Filename);
7391   }
7392   new_folder.ObjectCompressedSize = 0;
7393   new_folder.ObjectFormat = PTP_OFC_Association;
7394   new_folder.ProtectionStatus = PTP_PS_NoProtection;
7395   new_folder.AssociationType = PTP_AT_GenericFolder;
7396   new_folder.ParentObject = parent_id;
7397   new_folder.StorageID = store;
7398 
7399   // Create the object
7400   if (!(params->device_flags & DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST) &&
7401 	ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
7402 	MTPProperties *props = (MTPProperties*)calloc(2,sizeof(MTPProperties));
7403 
7404 	props[0].property = PTP_OPC_ObjectFileName;
7405 	props[0].datatype = PTP_DTC_STR;
7406 	props[0].propval.str = name;
7407 
7408 	props[1].property = PTP_OPC_Name;
7409 	props[1].datatype = PTP_DTC_STR;
7410 	props[1].propval.str = name;
7411 
7412 	ret = ptp_mtp_sendobjectproplist(params, &store, &parenthandle, &new_id, PTP_OFC_Association,
7413 			0, props, 1);
7414 	free(props);
7415   } else {
7416 	ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
7417   }
7418 
7419   if (ret != PTP_RC_OK) {
7420     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
7421     if (ret == PTP_RC_AccessDenied) {
7422       add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7423     }
7424     return 0;
7425   }
7426   // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
7427   // several strings.
7428 
7429   add_object_to_cache(device, new_id);
7430 
7431   return new_id;
7432 }
7433 
7434 /**
7435  * This creates a new playlist metadata structure and allocates memory
7436  * for it. Notice that if you add strings to this structure they
7437  * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
7438  * operation later, so be careful of using strdup() when assigning
7439  * strings, e.g.:
7440  *
7441  * <pre>
7442  * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
7443  * pl->name = strdup(str);
7444  * ....
7445  * LIBMTP_destroy_playlist_t(pl);
7446  * </pre>
7447  *
7448  * @return a pointer to the newly allocated metadata structure.
7449  * @see LIBMTP_destroy_playlist_t()
7450  */
7451 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
7452 {
7453   LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
7454   if (new == NULL) {
7455     return NULL;
7456   }
7457   new->playlist_id = 0;
7458   new->parent_id = 0;
7459   new->storage_id = 0;
7460   new->name = NULL;
7461   new->tracks = NULL;
7462   new->no_tracks = 0;
7463   new->next = NULL;
7464   return new;
7465 }
7466 
7467 /**
7468  * This destroys a playlist metadata structure and deallocates the memory
7469  * used by it, including any strings. Never use a track metadata
7470  * structure again after calling this function on it.
7471  * @param playlist the playlist metadata to destroy.
7472  * @see LIBMTP_new_playlist_t()
7473  */
7474 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
7475 {
7476   if (playlist == NULL) {
7477     return;
7478   }
7479   if (playlist->name != NULL)
7480     free(playlist->name);
7481   if (playlist->tracks != NULL)
7482     free(playlist->tracks);
7483   free(playlist);
7484   return;
7485 }
7486 
7487 /**
7488  * This function returns a list of the playlists available on the
7489  * device. Typical usage:
7490  *
7491  * <pre>
7492  * </pre>
7493  *
7494  * @param device a pointer to the device to get the playlist listing from.
7495  * @return a playlist list on success, else NULL. If there are no playlists
7496  *         on the device, NULL will be returned as well.
7497  * @see LIBMTP_Get_Playlist()
7498  */
7499 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
7500 {
7501   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7502   const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7503   PTPParams *params = (PTPParams *) device->params;
7504   LIBMTP_playlist_t *retlists = NULL;
7505   LIBMTP_playlist_t *curlist = NULL;
7506   uint32_t i;
7507 
7508   // Get all the handles if we haven't already done that
7509   if (params->nrofobjects == 0) {
7510     flush_handles(device);
7511   }
7512 
7513   for (i = 0; i < params->nrofobjects; i++) {
7514     LIBMTP_playlist_t *pl;
7515     PTPObject *ob;
7516     uint16_t ret;
7517 
7518     ob = &params->objects[i];
7519 
7520     // Ignore stuff that isn't playlists
7521 
7522     // For Samsung players we must look for the .spl extension explicitly since
7523     // playlists are not stored as playlist objects.
7524     if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7525       // Allocate a new playlist type
7526       pl = LIBMTP_new_playlist_t();
7527       spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7528     }
7529     else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7530       continue;
7531     }
7532     else {
7533       // Allocate a new playlist type
7534       pl = LIBMTP_new_playlist_t();
7535 
7536       // Try to look up proper name, else use the oi->Filename field.
7537       pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7538       if (pl->name == NULL) {
7539 	pl->name = strdup(ob->oi.Filename);
7540       }
7541       pl->playlist_id = ob->oid;
7542       pl->parent_id = ob->oi.ParentObject;
7543       pl->storage_id = ob->oi.StorageID;
7544 
7545       // Then get the track listing for this playlist
7546       ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7547       if (ret != PTP_RC_OK) {
7548         add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
7549 				    "could not get object references.");
7550         pl->tracks = NULL;
7551         pl->no_tracks = 0;
7552       }
7553     }
7554 
7555     // Add playlist to a list that will be returned afterwards.
7556     if (retlists == NULL) {
7557       retlists = pl;
7558       curlist = pl;
7559     } else {
7560       curlist->next = pl;
7561       curlist = pl;
7562     }
7563 
7564     // Call callback here if we decide to add that possibility...
7565   }
7566   return retlists;
7567 }
7568 
7569 
7570 /**
7571  * This function retrieves an individual playlist from the device.
7572  * @param device a pointer to the device to get the playlist from.
7573  * @param plid the unique ID of the playlist to retrieve.
7574  * @return a valid playlist metadata post or NULL on failure.
7575  * @see LIBMTP_Get_Playlist_List()
7576  */
7577 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
7578 {
7579   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7580   const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7581   PTPParams *params = (PTPParams *) device->params;
7582   PTPObject *ob;
7583   LIBMTP_playlist_t *pl;
7584   uint16_t ret;
7585 
7586   // Get all the handles if we haven't already done that
7587   if (params->nrofobjects == 0) {
7588     flush_handles(device);
7589   }
7590 
7591   ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7592   if (ret != PTP_RC_OK)
7593     return NULL;
7594 
7595   // For Samsung players we must look for the .spl extension explicitly since
7596   // playlists are not stored as playlist objects.
7597   if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7598     // Allocate a new playlist type
7599     pl = LIBMTP_new_playlist_t();
7600     spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7601     return pl;
7602   }
7603 
7604   // Ignore stuff that isn't playlists
7605   else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7606     return NULL;
7607   }
7608 
7609   // Allocate a new playlist type
7610   pl = LIBMTP_new_playlist_t();
7611 
7612   pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7613   if (pl->name == NULL) {
7614     pl->name = strdup(ob->oi.Filename);
7615   }
7616   pl->playlist_id = ob->oid;
7617   pl->parent_id = ob->oi.ParentObject;
7618   pl->storage_id = ob->oi.StorageID;
7619 
7620   // Then get the track listing for this playlist
7621   ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7622   if (ret != PTP_RC_OK) {
7623     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7624     pl->tracks = NULL;
7625     pl->no_tracks = 0;
7626   }
7627 
7628   return pl;
7629 }
7630 
7631 /**
7632  * This function creates a new abstract list such as a playlist
7633  * or an album.
7634  *
7635  * @param device a pointer to the device to create the new abstract list
7636  *        on.
7637  * @param name the name of the new abstract list.
7638  * @param artist the artist of the new abstract list or NULL.
7639  * @param genre the genre of the new abstract list or NULL.
7640  * @param parenthandle the handle of the parent or 0 for no parent
7641  *        i.e. the root folder.
7642  * @param objectformat the abstract list type to create.
7643  * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7644  *        "file" created by this operation.
7645  * @param newid a pointer to a variable that will hold the new object
7646  *        ID if this call is successful.
7647  * @param tracks an array of tracks to associate with this list.
7648  * @param no_tracks the number of tracks in the list.
7649  * @return 0 on success, any other value means failure.
7650  */
7651 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7652 				    char const * const name,
7653 				    char const * const artist,
7654 				    char const * const composer,
7655 				    char const * const genre,
7656 				    uint32_t const parenthandle,
7657 				    uint32_t const storageid,
7658 				    uint16_t const objectformat,
7659 				    char const * const suffix,
7660 				    uint32_t * const newid,
7661 				    uint32_t const * const tracks,
7662 				    uint32_t const no_tracks)
7663 
7664 {
7665   int i;
7666   int supported = 0;
7667   uint16_t ret;
7668   uint16_t *properties = NULL;
7669   uint32_t propcnt = 0;
7670   uint32_t store;
7671   uint32_t localph = parenthandle;
7672   uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7673   PTPParams *params = (PTPParams *) device->params;
7674   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7675   char fname[256];
7676   //uint8_t data[2];
7677 
7678   // NULL check
7679   if (!name) {
7680     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): list name was NULL, using default name \"Unknown\"");
7681     return -1;
7682   }
7683 
7684   if (storageid == 0) {
7685     // I'm just guessing that an abstract list may require 512 bytes
7686     store = get_suggested_storage_id(device, 512, localph);
7687   } else {
7688     store = storageid;
7689   }
7690 
7691   // Check if we can create an object of this type
7692   for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7693     if (params->deviceinfo.ImageFormats[i] == objectformat) {
7694       supported = 1;
7695       break;
7696     }
7697   }
7698   if (!supported) {
7699     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type");
7700     LIBMTP_ERROR("Unsupported abstract list type: %04x\n", objectformat);
7701     return -1;
7702   }
7703 
7704   // add the new suffix if it isn't there
7705   fname[0] = '\0';
7706   if (strlen(name) > strlen(suffix)) {
7707     char const * const suff = &name[strlen(name)-strlen(suffix)];
7708     if (!strcmp(suff, suffix)) {
7709       // Home free.
7710       strncpy(fname, name, sizeof(fname));
7711     }
7712   }
7713   // If it didn't end with "<suffix>" then add that here.
7714   if (fname[0] == '\0') {
7715     strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7716     strcat(fname, suffix);
7717     fname[sizeof(fname)-1] = '\0';
7718   }
7719 
7720   if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7721       !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7722     MTPProperties *props = NULL;
7723     MTPProperties *prop = NULL;
7724     int nrofprops = 0;
7725 
7726     *newid = 0x00000000U;
7727 
7728     ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7729 
7730     for (i=0;i<propcnt;i++) {
7731       PTPObjectPropDesc opd;
7732 
7733       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7734       if (ret != PTP_RC_OK) {
7735 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7736 				"could not get property description.");
7737       } else if (opd.GetSet) {
7738 	switch (properties[i]) {
7739 	case PTP_OPC_ObjectFileName:
7740 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7741 	  prop->ObjectHandle = *newid;
7742 	  prop->property = PTP_OPC_ObjectFileName;
7743 	  prop->datatype = PTP_DTC_STR;
7744 	  prop->propval.str = strdup(fname);
7745 	  if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7746 	    strip_7bit_from_utf8(prop->propval.str);
7747 	  }
7748 	  break;
7749 	case PTP_OPC_ProtectionStatus:
7750 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7751 	  prop->ObjectHandle = *newid;
7752 	  prop->property = PTP_OPC_ProtectionStatus;
7753 	  prop->datatype = PTP_DTC_UINT16;
7754 	  prop->propval.u16 = 0x0000U; /* Not protected */
7755 	  break;
7756 	case PTP_OPC_NonConsumable:
7757 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7758 	  prop->ObjectHandle = *newid;
7759 	  prop->property = PTP_OPC_NonConsumable;
7760 	  prop->datatype = PTP_DTC_UINT8;
7761 	  prop->propval.u8 = nonconsumable;
7762 	  break;
7763 	case PTP_OPC_Name:
7764 	  if (name != NULL) {
7765 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7766 	    prop->ObjectHandle = *newid;
7767 	    prop->property = PTP_OPC_Name;
7768 	    prop->datatype = PTP_DTC_STR;
7769 	    prop->propval.str = strdup(name);
7770 	  }
7771 	  break;
7772 	case PTP_OPC_AlbumArtist:
7773 	  if (artist != NULL) {
7774 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7775 	    prop->ObjectHandle = *newid;
7776 	    prop->property = PTP_OPC_AlbumArtist;
7777 	    prop->datatype = PTP_DTC_STR;
7778 	    prop->propval.str = strdup(artist);
7779 	  }
7780 	  break;
7781 	case PTP_OPC_Artist:
7782 	  if (artist != NULL) {
7783 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7784 	    prop->ObjectHandle = *newid;
7785 	    prop->property = PTP_OPC_Artist;
7786 	    prop->datatype = PTP_DTC_STR;
7787 	    prop->propval.str = strdup(artist);
7788 	  }
7789 	  break;
7790 	case PTP_OPC_Composer:
7791 	  if (composer != NULL) {
7792 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7793 	    prop->ObjectHandle = *newid;
7794 	    prop->property = PTP_OPC_Composer;
7795 	    prop->datatype = PTP_DTC_STR;
7796 	    prop->propval.str = strdup(composer);
7797 	  }
7798 	  break;
7799 	case PTP_OPC_Genre:
7800 	  if (genre != NULL) {
7801 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7802 	    prop->ObjectHandle = *newid;
7803 	    prop->property = PTP_OPC_Genre;
7804 	    prop->datatype = PTP_DTC_STR;
7805 	    prop->propval.str = strdup(genre);
7806 	  }
7807 	  break;
7808  	case PTP_OPC_DateModified:
7809 	  // Tag with current time if that is supported
7810 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7811 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7812 	    prop->ObjectHandle = *newid;
7813 	    prop->property = PTP_OPC_DateModified;
7814 	    prop->datatype = PTP_DTC_STR;
7815 	    prop->propval.str = get_iso8601_stamp();
7816 	  }
7817 	  break;
7818 	}
7819       }
7820       ptp_free_objectpropdesc(&opd);
7821     }
7822     free(properties);
7823 
7824     ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7825 				     objectformat, 0, props, nrofprops);
7826 
7827     /* Free property list */
7828     ptp_destroy_object_prop_list(props, nrofprops);
7829 
7830     if (ret != PTP_RC_OK) {
7831       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7832       if (ret == PTP_RC_AccessDenied) {
7833 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7834       }
7835       return -1;
7836     }
7837 
7838     // now send the blank object
7839     ret = ptp_sendobject(params, NULL, 0);
7840     if (ret != PTP_RC_OK) {
7841       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7842       return -1;
7843     }
7844 
7845   } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7846     PTPObjectInfo new_object;
7847 
7848     new_object.Filename = fname;
7849     if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7850       strip_7bit_from_utf8(new_object.Filename);
7851     }
7852     // At one point this had to be one
7853     new_object.ObjectCompressedSize = 0;
7854     new_object.ObjectFormat = objectformat;
7855 
7856     // Create the object
7857     ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7858     if (ret != PTP_RC_OK) {
7859       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7860       if (ret == PTP_RC_AccessDenied) {
7861 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7862       }
7863       return -1;
7864     }
7865     // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7866     // not copies.
7867 
7868 #if 0
7869     /*
7870      * At one time we had to send this one blank data byte.
7871      * If we didn't, the handle will not be created and thus there is
7872      * no playlist. Possibly this was masking some bug, so removing it
7873      * now.
7874      */
7875     data[0] = '\0';
7876     data[1] = '\0';
7877     ret = ptp_sendobject(params, data, 1);
7878     if (ret != PTP_RC_OK) {
7879       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7880       return -1;
7881     }
7882 #endif
7883 
7884     // set the properties one by one
7885     ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7886 
7887     for (i=0;i<propcnt;i++) {
7888       PTPObjectPropDesc opd;
7889 
7890       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7891       if (ret != PTP_RC_OK) {
7892 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7893 				"could not get property description.");
7894       } else if (opd.GetSet) {
7895 	switch (properties[i]) {
7896 	case PTP_OPC_Name:
7897 	  if (name != NULL) {
7898 	    ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7899 	    if (ret != 0) {
7900 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7901 	      return -1;
7902 	    }
7903 	  }
7904 	  break;
7905 	case PTP_OPC_AlbumArtist:
7906 	  if (artist != NULL) {
7907 	    ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7908 	    if (ret != 0) {
7909 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7910 	      return -1;
7911 	    }
7912 	  }
7913 	  break;
7914 	case PTP_OPC_Artist:
7915 	  if (artist != NULL) {
7916 	    ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
7917 	    if (ret != 0) {
7918 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
7919 	      return -1;
7920 	    }
7921 	  }
7922 	  break;
7923 	case PTP_OPC_Composer:
7924 	  if (composer != NULL) {
7925 	    ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
7926 	    if (ret != 0) {
7927 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
7928 	      return -1;
7929 	    }
7930 	  }
7931 	  break;
7932 	case PTP_OPC_Genre:
7933 	  if (genre != NULL) {
7934 	    ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
7935 	    if (ret != 0) {
7936 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
7937 	      return -1;
7938 	    }
7939 	  }
7940 	  break;
7941  	case PTP_OPC_DateModified:
7942 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7943 	    ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
7944 	    if (ret != 0) {
7945 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
7946 	      return -1;
7947 	    }
7948 	  }
7949 	  break;
7950 	}
7951       }
7952       ptp_free_objectpropdesc(&opd);
7953     }
7954     free(properties);
7955   }
7956 
7957   if (no_tracks > 0) {
7958     // Add tracks to the list as object references.
7959     ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
7960     if (ret != PTP_RC_OK) {
7961       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
7962       return -1;
7963     }
7964   }
7965 
7966   add_object_to_cache(device, *newid);
7967 
7968   return 0;
7969 }
7970 
7971 /**
7972  * This updates the metadata and track listing
7973  * for an abstract list.
7974  * @param device a pointer to the device that the abstract list
7975  *        resides on.
7976  * @param name the name of the abstract list.
7977  * @param artist the artist of the abstract list or NULL.
7978  * @param genre the genre of the abstract list or NULL.
7979  * @param objecthandle the object to be updated.
7980  * @param objectformat the abstract list type to update.
7981  * @param tracks an array of tracks to associate with this list.
7982  * @param no_tracks the number of tracks in the list.
7983  * @return 0 on success, any other value means failure.
7984  */
7985 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
7986 				char const * const name,
7987 				char const * const artist,
7988 				char const * const composer,
7989 				char const * const genre,
7990 				uint32_t const objecthandle,
7991 				uint16_t const objectformat,
7992 				uint32_t const * const tracks,
7993 				uint32_t const no_tracks)
7994 {
7995   uint16_t ret;
7996   PTPParams *params = (PTPParams *) device->params;
7997   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7998   uint16_t *properties = NULL;
7999   uint32_t propcnt = 0;
8000   int i;
8001 
8002   // First see which properties can be set
8003   // i.e only try to update this metadata for object tags that exist on the current player.
8004   ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
8005   if (ret != PTP_RC_OK) {
8006     // Just bail out for now, nothing is ever set.
8007     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8008 			    "could not retrieve supported object properties.");
8009     return -1;
8010   }
8011   if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
8012       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
8013     MTPProperties *props = NULL;
8014     MTPProperties *prop = NULL;
8015     int nrofprops = 0;
8016 
8017     for (i=0;i<propcnt;i++) {
8018       PTPObjectPropDesc opd;
8019 
8020       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
8021       if (ret != PTP_RC_OK) {
8022 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8023 				"could not get property description.");
8024       } else if (opd.GetSet) {
8025 	switch (properties[i]) {
8026 	case PTP_OPC_Name:
8027 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8028 	  prop->ObjectHandle = objecthandle;
8029 	  prop->property = PTP_OPC_Name;
8030 	  prop->datatype = PTP_DTC_STR;
8031 	  if (name != NULL)
8032 	    prop->propval.str = strdup(name);
8033 	  break;
8034 	case PTP_OPC_AlbumArtist:
8035 	  if (artist != NULL) {
8036 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8037 	    prop->ObjectHandle = objecthandle;
8038 	    prop->property = PTP_OPC_AlbumArtist;
8039 	    prop->datatype = PTP_DTC_STR;
8040 	    prop->propval.str = strdup(artist);
8041 	  }
8042 	  break;
8043 	case PTP_OPC_Artist:
8044 	  if (artist != NULL) {
8045 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8046 	    prop->ObjectHandle = objecthandle;
8047 	    prop->property = PTP_OPC_Artist;
8048 	    prop->datatype = PTP_DTC_STR;
8049 	    prop->propval.str = strdup(artist);
8050 	  }
8051 	  break;
8052 	case PTP_OPC_Composer:
8053 	  if (composer != NULL) {
8054 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8055 	    prop->ObjectHandle = objecthandle;
8056 	    prop->property = PTP_OPC_Composer;
8057 	    prop->datatype = PTP_DTC_STR;
8058 	    prop->propval.str = strdup(composer);
8059 	  }
8060 	  break;
8061 	case PTP_OPC_Genre:
8062 	  if (genre != NULL) {
8063 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8064 	    prop->ObjectHandle = objecthandle;
8065 	    prop->property = PTP_OPC_Genre;
8066 	    prop->datatype = PTP_DTC_STR;
8067 	    prop->propval.str = strdup(genre);
8068 	  }
8069 	  break;
8070  	case PTP_OPC_DateModified:
8071 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8072 	    // Tag with current time if that is supported
8073 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8074 	    prop->ObjectHandle = objecthandle;
8075 	    prop->property = PTP_OPC_DateModified;
8076 	    prop->datatype = PTP_DTC_STR;
8077 	    prop->propval.str = get_iso8601_stamp();
8078 	  }
8079 	  break;
8080 	default:
8081 	  break;
8082 	}
8083       }
8084       ptp_free_objectpropdesc(&opd);
8085     }
8086 
8087     // proplist could be NULL if we can't write any properties
8088     if (props != NULL) {
8089       ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
8090 
8091       ptp_destroy_object_prop_list(props, nrofprops);
8092 
8093       if (ret != PTP_RC_OK) {
8094         // TODO: return error of which property we couldn't set
8095         add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8096                                 "could not set object property list.");
8097         free(properties);
8098         return -1;
8099       }
8100     }
8101 
8102   } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
8103     for (i=0;i<propcnt;i++) {
8104       switch (properties[i]) {
8105       case PTP_OPC_Name:
8106 	// Update title
8107 	ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
8108 	if (ret != 0) {
8109 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8110 				  "could not set title.");
8111 	}
8112 	break;
8113       case PTP_OPC_AlbumArtist:
8114 	// Update album artist
8115 	ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
8116 	if (ret != 0) {
8117 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8118 				  "could not set album artist name.");
8119 	}
8120 	break;
8121       case PTP_OPC_Artist:
8122 	// Update artist
8123 	ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
8124 	if (ret != 0) {
8125 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8126 				  "could not set artist name.");
8127 	}
8128 	break;
8129       case PTP_OPC_Composer:
8130 	// Update composer
8131 	ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
8132 	if (ret != 0) {
8133 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8134 				  "could not set composer name.");
8135 	}
8136 	break;
8137       case PTP_OPC_Genre:
8138 	// Update genre (but only if valid)
8139 	if(genre) {
8140 	  ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
8141 	  if (ret != 0) {
8142 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8143 				    "could not set genre.");
8144 	  }
8145         }
8146 	break;
8147       case PTP_OPC_DateModified:
8148 	// Update date modified
8149 	if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8150 	  char *tmpdate = get_iso8601_stamp();
8151 	  ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
8152 	  if (ret != 0) {
8153 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8154 				    "could not set modification date.");
8155 	  }
8156 	  free(tmpdate);
8157 	}
8158 	break;
8159       default:
8160 	break;
8161       }
8162     }
8163   } else {
8164     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8165                             "Your device doesn't seem to support any known way of setting metadata.");
8166     free(properties);
8167     return -1;
8168   }
8169 
8170   // Then the object references...
8171   ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
8172   if (ret != PTP_RC_OK) {
8173     add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
8174     free(properties);
8175     return -1;
8176   }
8177 
8178   free(properties);
8179 
8180   update_metadata_cache(device, objecthandle);
8181 
8182   return 0;
8183 }
8184 
8185 
8186 /**
8187  * This routine creates a new playlist based on the metadata
8188  * supplied. If the <code>tracks</code> field of the metadata
8189  * contains a track listing, these tracks will be added to the
8190  * playlist.
8191  * @param device a pointer to the device to create the new playlist on.
8192  * @param metadata the metadata for the new playlist. If the function
8193  *        exits with success, the <code>playlist_id</code> field of this
8194  *        struct will contain the new playlist ID of the playlist.
8195  *        <ul>
8196  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
8197  *        (e.g. folder) to store this track in. Since some
8198  *        devices are a bit picky about where files
8199  *        are placed, a default folder will be chosen if libmtp
8200  *        has detected one for the current filetype and this
8201  *        parameter is set to 0. If this is 0 and no default folder
8202  *        can be found, the file will be stored in the root folder.
8203  *        <li><code>metadata-&gt;storage_id</code> should be set to the
8204  *        desired storage (e.g. memory card or whatever your device
8205  *        presents) to store this track in. Setting this to 0 will store
8206  *        the track on the primary storage.
8207  *        </ul>
8208  * @return 0 on success, any other value means failure.
8209  * @see LIBMTP_Update_Playlist()
8210  * @see LIBMTP_Delete_Object()
8211  */
8212 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
8213 			       LIBMTP_playlist_t * const metadata)
8214 {
8215   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8216   uint32_t localph = metadata->parent_id;
8217 
8218   // Use a default folder if none given
8219   if (localph == 0) {
8220     if (device->default_playlist_folder != 0)
8221       localph = device->default_playlist_folder;
8222     else
8223       localph = device->default_music_folder;
8224   }
8225   metadata->parent_id = localph;
8226 
8227   // Samsung needs its own special type of playlists
8228   if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8229     return playlist_t_to_spl(device, metadata);
8230   }
8231 
8232   // Just create a new abstract audio/video playlist...
8233   return create_new_abstract_list(device,
8234 				  metadata->name,
8235 				  NULL,
8236 				  NULL,
8237 				  NULL,
8238 				  localph,
8239 				  metadata->storage_id,
8240 				  PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8241 				  get_playlist_extension(ptp_usb),
8242 				  &metadata->playlist_id,
8243 				  metadata->tracks,
8244 				  metadata->no_tracks);
8245 }
8246 
8247 /**
8248  * This routine updates a playlist based on the metadata
8249  * supplied. If the <code>tracks</code> field of the metadata
8250  * contains a track listing, these tracks will be added to the
8251  * playlist in place of those already present, i.e. the
8252  * previous track listing will be deleted. For Samsung devices the
8253  * playlist id (metadata->playlist_id) is likely to change.
8254  * @param device a pointer to the device to create the new playlist on.
8255  * @param metadata the metadata for the playlist to be updated.
8256  *                 notice that the field <code>playlist_id</code>
8257  *                 must contain the apropriate playlist ID. Playlist ID
8258  *                 be modified to a new playlist ID by the time the
8259  *                 function returns since edit-in-place is not always possible.
8260  * @return 0 on success, any other value means failure.
8261  * @see LIBMTP_Create_New_Playlist()
8262  * @see LIBMTP_Delete_Object()
8263  */
8264 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
8265 			   LIBMTP_playlist_t * const metadata)
8266 {
8267 
8268   // Samsung needs its own special type of playlists
8269   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8270   if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8271     return update_spl_playlist(device, metadata);
8272   }
8273 
8274   return update_abstract_list(device,
8275 			      metadata->name,
8276 			      NULL,
8277 			      NULL,
8278 			      NULL,
8279 			      metadata->playlist_id,
8280 			      PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8281 			      metadata->tracks,
8282 			      metadata->no_tracks);
8283 }
8284 
8285 /**
8286  * This creates a new album metadata structure and allocates memory
8287  * for it. Notice that if you add strings to this structure they
8288  * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
8289  * operation later, so be careful of using strdup() when assigning
8290  * strings.
8291  *
8292  * @return a pointer to the newly allocated metadata structure.
8293  * @see LIBMTP_destroy_album_t()
8294  */
8295 LIBMTP_album_t *LIBMTP_new_album_t(void)
8296 {
8297   LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
8298   if (new == NULL) {
8299     return NULL;
8300   }
8301   new->album_id = 0;
8302   new->parent_id = 0;
8303   new->storage_id = 0;
8304   new->name = NULL;
8305   new->artist = NULL;
8306   new->composer = NULL;
8307   new->genre = NULL;
8308   new->tracks = NULL;
8309   new->no_tracks = 0;
8310   new->next = NULL;
8311   return new;
8312 }
8313 
8314 /**
8315  * This recursively deletes the memory for an album structure
8316  *
8317  * @param album structure to destroy
8318  * @see LIBMTP_new_album_t()
8319  */
8320 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
8321 {
8322   if (album == NULL) {
8323     return;
8324   }
8325   if (album->name != NULL)
8326     free(album->name);
8327   if (album->artist != NULL)
8328     free(album->artist);
8329   if (album->composer != NULL)
8330     free(album->composer);
8331   if (album->genre != NULL)
8332     free(album->genre);
8333   if (album->tracks != NULL)
8334     free(album->tracks);
8335   free(album);
8336   return;
8337 }
8338 
8339 /**
8340  * This function maps and copies a property onto the album metadata if applicable.
8341  */
8342 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
8343 					    MTPProperties *prop, LIBMTP_album_t *alb)
8344 {
8345   switch (prop->property) {
8346   case PTP_OPC_Name:
8347     if (prop->propval.str != NULL)
8348       alb->name = strdup(prop->propval.str);
8349     else
8350       alb->name = NULL;
8351     break;
8352   case PTP_OPC_AlbumArtist:
8353     if (prop->propval.str != NULL) {
8354       // This should take precedence over plain "Artist"
8355       if (alb->artist != NULL)
8356 	free(alb->artist);
8357       alb->artist = strdup(prop->propval.str);
8358     } else
8359       alb->artist = NULL;
8360     break;
8361   case PTP_OPC_Artist:
8362     if (prop->propval.str != NULL) {
8363       // Only use of AlbumArtist is not set
8364       if (alb->artist == NULL)
8365 	alb->artist = strdup(prop->propval.str);
8366     } else
8367       alb->artist = NULL;
8368     break;
8369   case PTP_OPC_Composer:
8370     if (prop->propval.str != NULL)
8371       alb->composer = strdup(prop->propval.str);
8372     else
8373       alb->composer = NULL;
8374     break;
8375   case PTP_OPC_Genre:
8376     if (prop->propval.str != NULL)
8377       alb->genre = strdup(prop->propval.str);
8378     else
8379       alb->genre = NULL;
8380     break;
8381   }
8382 }
8383 
8384 /**
8385  * This function retrieves the album metadata for an album
8386  * given by a unique ID.
8387  * @param device a pointer to the device to get the track metadata off.
8388  * @param alb an album metadata metadata set to fill in.
8389  */
8390 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
8391 			       LIBMTP_album_t *alb)
8392 {
8393   uint16_t ret;
8394   PTPParams *params = (PTPParams *) device->params;
8395   uint32_t i;
8396   MTPProperties *prop;
8397   PTPObject *ob;
8398 
8399   /*
8400    * If we have a cached, large set of metadata, then use it!
8401    */
8402   ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
8403   if (ob->mtpprops) {
8404     prop = ob->mtpprops;
8405     for (i=0;i<ob->nrofmtpprops;i++,prop++)
8406       pick_property_to_album_metadata(device, prop, alb);
8407   } else {
8408     uint16_t *props = NULL;
8409     uint32_t propcnt = 0;
8410 
8411     // First see which properties can be retrieved for albums
8412     ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
8413     if (ret != PTP_RC_OK) {
8414       add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
8415       // Just bail out for now, nothing is ever set.
8416       return;
8417     } else {
8418       for (i=0;i<propcnt;i++) {
8419 	switch (props[i]) {
8420 	case PTP_OPC_Name:
8421 	  alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
8422 	  break;
8423 	case PTP_OPC_AlbumArtist:
8424 	  if (alb->artist != NULL)
8425 	    free(alb->artist);
8426 	  alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
8427 	  break;
8428 	case PTP_OPC_Artist:
8429 	  if (alb->artist == NULL)
8430 	    alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
8431 	  break;
8432 	case PTP_OPC_Composer:
8433 	  alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
8434 	  break;
8435 	case PTP_OPC_Genre:
8436 	  alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
8437 	  break;
8438 	default:
8439 	  break;
8440 	}
8441       }
8442       free(props);
8443     }
8444   }
8445 }
8446 
8447 
8448 /**
8449  * This function returns a list of the albums available on the
8450  * device.
8451  *
8452  * @param device a pointer to the device to get the album listing from.
8453  * @return an album list on success, else NULL. If there are no albums
8454  *         on the device, NULL will be returned as well.
8455  * @see LIBMTP_Get_Album()
8456  */
8457 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
8458 {
8459 	// Read all storage devices
8460 	return LIBMTP_Get_Album_List_For_Storage(device, 0);
8461 }
8462 
8463 
8464 /**
8465  * This function returns a list of the albums available on the
8466  * device. You can filter on the storage ID.
8467  *
8468  * @param device a pointer to the device to get the album listing from.
8469  * @param storage_id ID of device storage (if null, all storages)
8470  *
8471  * @return an album list on success, else NULL. If there are no albums
8472  *         on the device, NULL will be returned as well.
8473  * @see LIBMTP_Get_Album()
8474  */
8475 LIBMTP_album_t *LIBMTP_Get_Album_List_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id)
8476 {
8477   PTPParams *params = (PTPParams *) device->params;
8478   LIBMTP_album_t *retalbums = NULL;
8479   LIBMTP_album_t *curalbum = NULL;
8480   uint32_t i;
8481 
8482   // Get all the handles if we haven't already done that
8483   if (params->nrofobjects == 0)
8484     flush_handles(device);
8485 
8486   for (i = 0; i < params->nrofobjects; i++) {
8487     LIBMTP_album_t *alb;
8488     PTPObject *ob;
8489     uint16_t ret;
8490 
8491     ob = &params->objects[i];
8492 
8493     // Ignore stuff that isn't an album
8494     if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
8495       continue;
8496 
8497 	// Ignore stuff that isn't into the storage device
8498 	if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
8499 		continue;
8500 
8501     // Allocate a new album type
8502     alb = LIBMTP_new_album_t();
8503     alb->album_id = ob->oid;
8504     alb->parent_id = ob->oi.ParentObject;
8505     alb->storage_id = ob->oi.StorageID;
8506 
8507     // Fetch supported metadata
8508     get_album_metadata(device, alb);
8509 
8510     // Then get the track listing for this album
8511     ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8512     if (ret != PTP_RC_OK) {
8513       add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
8514       alb->tracks = NULL;
8515       alb->no_tracks = 0;
8516     }
8517 
8518     // Add album to a list that will be returned afterwards.
8519     if (retalbums == NULL) {
8520       retalbums = alb;
8521       curalbum = alb;
8522     } else {
8523       curalbum->next = alb;
8524       curalbum = alb;
8525     }
8526 
8527   }
8528   return retalbums;
8529 }
8530 
8531 /**
8532  * This function retrieves an individual album from the device.
8533  * @param device a pointer to the device to get the album from.
8534  * @param albid the unique ID of the album to retrieve.
8535  * @return a valid album metadata or NULL on failure.
8536  * @see LIBMTP_Get_Album_List()
8537  */
8538 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
8539 {
8540   PTPParams *params = (PTPParams *) device->params;
8541   uint16_t ret;
8542   PTPObject *ob;
8543   LIBMTP_album_t *alb;
8544 
8545   // Get all the handles if we haven't already done that
8546   if (params->nrofobjects == 0)
8547     flush_handles(device);
8548 
8549   ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8550   if (ret != PTP_RC_OK)
8551     return NULL;
8552 
8553   // Ignore stuff that isn't an album
8554   if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
8555     return NULL;
8556 
8557   // Allocate a new album type
8558   alb = LIBMTP_new_album_t();
8559   alb->album_id = ob->oid;
8560   alb->parent_id = ob->oi.ParentObject;
8561   alb->storage_id = ob->oi.StorageID;
8562 
8563   // Fetch supported metadata
8564   get_album_metadata(device, alb);
8565 
8566   // Then get the track listing for this album
8567   ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8568   if (ret != PTP_RC_OK) {
8569     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
8570     alb->tracks = NULL;
8571     alb->no_tracks = 0;
8572   }
8573 
8574   return alb;
8575 }
8576 
8577 /**
8578  * This routine creates a new album based on the metadata
8579  * supplied. If the <code>tracks</code> field of the metadata
8580  * contains a track listing, these tracks will be added to the
8581  * album.
8582  * @param device a pointer to the device to create the new album on.
8583  * @param metadata the metadata for the new album. If the function
8584  *        exits with success, the <code>album_id</code> field of this
8585  *        struct will contain the new ID of the album.
8586  *        <ul>
8587  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
8588  *        (e.g. folder) to store this track in. Since some
8589  *        devices are a bit picky about where files
8590  *        are placed, a default folder will be chosen if libmtp
8591  *        has detected one for the current filetype and this
8592  *        parameter is set to 0. If this is 0 and no default folder
8593  *        can be found, the file will be stored in the root folder.
8594  *        <li><code>metadata-&gt;storage_id</code> should be set to the
8595  *        desired storage (e.g. memory card or whatever your device
8596  *        presents) to store this track in. Setting this to 0 will store
8597  *        the track on the primary storage.
8598  *        </ul>
8599  * @return 0 on success, any other value means failure.
8600  * @see LIBMTP_Update_Album()
8601  * @see LIBMTP_Delete_Object()
8602  */
8603 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
8604 			    LIBMTP_album_t * const metadata)
8605 {
8606   uint32_t localph = metadata->parent_id;
8607 
8608   // Use a default folder if none given
8609   if (localph == 0) {
8610     if (device->default_album_folder != 0)
8611       localph = device->default_album_folder;
8612     else
8613       localph = device->default_music_folder;
8614   }
8615   metadata->parent_id = localph;
8616 
8617   // Just create a new abstract album...
8618   return create_new_abstract_list(device,
8619 				  metadata->name,
8620 				  metadata->artist,
8621 				  metadata->composer,
8622 				  metadata->genre,
8623 				  localph,
8624 				  metadata->storage_id,
8625 				  PTP_OFC_MTP_AbstractAudioAlbum,
8626 				  ".alb",
8627 				  &metadata->album_id,
8628 				  metadata->tracks,
8629 				  metadata->no_tracks);
8630 }
8631 
8632 /**
8633  * This creates a new sample data metadata structure and allocates memory
8634  * for it. Notice that if you add strings to this structure they
8635  * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
8636  * operation later, so be careful of using strdup() when assigning
8637  * strings.
8638  *
8639  * @return a pointer to the newly allocated metadata structure.
8640  * @see LIBMTP_destroy_sampledata_t()
8641  */
8642 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
8643 {
8644   LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
8645   if (new == NULL) {
8646     return NULL;
8647   }
8648   new->height=0;
8649   new->width = 0;
8650   new->data = NULL;
8651   new->duration = 0;
8652   new->size = 0;
8653   return new;
8654 }
8655 
8656 /**
8657  * This destroys a file sample metadata type.
8658  * @param sample the file sample metadata to be destroyed.
8659  */
8660 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8661 {
8662   if (sample == NULL) {
8663     return;
8664   }
8665   if (sample->data != NULL) {
8666     free(sample->data);
8667   }
8668   free(sample);
8669 }
8670 
8671 /**
8672  * This routine figures out whether a certain filetype supports
8673  * representative samples (small thumbnail images) or not. This
8674  * typically applies to JPEG files, MP3 files and Album abstract
8675  * playlists, but in theory any filetype could support representative
8676  * samples.
8677  * @param device a pointer to the device which is to be examined.
8678  * @param filetype the fileype to examine, and return the representative sample
8679  *        properties for.
8680  * @param sample this will contain a new sample type with the fields
8681  *        filled in with suitable default values. For example, the
8682  *        supported sample type will be set, the supported height and
8683  *        width will be set to max values if it is an image sample,
8684  *        and duration will also be given some suitable default value
8685  *        which should not be exceeded on audio samples. If the
8686  *        device does not support samples for this filetype, this
8687  *        pointer will be NULL. If it is not NULL, the user must
8688  *        destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8689  *        after use.
8690  * @return 0 on success, any other value means failure.
8691  * @see LIBMTP_Send_Representative_Sample()
8692  * @see LIBMTP_Create_New_Album()
8693  */
8694 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8695 					    LIBMTP_filetype_t const filetype,
8696 					    LIBMTP_filesampledata_t ** sample)
8697 {
8698   uint16_t ret;
8699   PTPParams *params = (PTPParams *) device->params;
8700   uint16_t *props = NULL;
8701   uint32_t propcnt = 0;
8702   int i;
8703   // TODO: Get rid of these when we can properly query the device.
8704   int support_data = 0;
8705   int support_format = 0;
8706   int support_height = 0;
8707   int support_width = 0;
8708   int support_duration = 0;
8709   int support_size = 0;
8710 
8711   PTPObjectPropDesc opd_height;
8712   PTPObjectPropDesc opd_width;
8713   PTPObjectPropDesc opd_format;
8714   PTPObjectPropDesc opd_duration;
8715   PTPObjectPropDesc opd_size;
8716 
8717   // Default to no type supported.
8718   *sample = NULL;
8719 
8720   ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8721   if (ret != PTP_RC_OK) {
8722     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8723     return -1;
8724   }
8725   /*
8726    * TODO: when walking through these object properties, make calls to
8727    * a new function in ptp.h/ptp.c that can send the command
8728    * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8729    * supported.
8730    */
8731   for (i = 0; i < propcnt; i++) {
8732     switch(props[i]) {
8733     case PTP_OPC_RepresentativeSampleData:
8734       support_data = 1;
8735       break;
8736     case PTP_OPC_RepresentativeSampleFormat:
8737       support_format = 1;
8738       break;
8739     case PTP_OPC_RepresentativeSampleSize:
8740       support_size = 1;
8741       break;
8742     case PTP_OPC_RepresentativeSampleHeight:
8743       support_height = 1;
8744       break;
8745     case PTP_OPC_RepresentativeSampleWidth:
8746       support_width = 1;
8747       break;
8748     case PTP_OPC_RepresentativeSampleDuration:
8749       support_duration = 1;
8750       break;
8751     default:
8752       break;
8753     }
8754   }
8755   free(props);
8756 
8757   if (support_data && support_format && support_height && support_width && !support_duration) {
8758     // Something that supports height and width and not duration is likely to be JPEG
8759     LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8760     /*
8761      * Populate the sample format with the first supported format
8762      *
8763      * TODO: figure out how to pass back more than one format if more are
8764      * supported by the device.
8765      */
8766     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8767     retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8768     ptp_free_objectpropdesc(&opd_format);
8769     /* Populate the maximum image height */
8770     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8771     retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8772     ptp_free_objectpropdesc(&opd_width);
8773     /* Populate the maximum image width */
8774     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8775     retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8776     ptp_free_objectpropdesc(&opd_height);
8777     /* Populate the maximum size */
8778     if (support_size) {
8779       ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8780       retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8781       ptp_free_objectpropdesc(&opd_size);
8782     }
8783     *sample = retsam;
8784   } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8785     // Another qualified guess
8786     LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8787     /*
8788      * Populate the sample format with the first supported format
8789      *
8790      * TODO: figure out how to pass back more than one format if more are
8791      * supported by the device.
8792      */
8793     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8794     retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8795     ptp_free_objectpropdesc(&opd_format);
8796     /* Populate the maximum duration */
8797     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8798     retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8799     ptp_free_objectpropdesc(&opd_duration);
8800     /* Populate the maximum size */
8801     if (support_size) {
8802       ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8803       retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8804       ptp_free_objectpropdesc(&opd_size);
8805     }
8806     *sample = retsam;
8807   }
8808   return 0;
8809 }
8810 
8811 /**
8812  * This routine sends representative sample data for an object.
8813  * This uses the RepresentativeSampleData property of the album,
8814  * if the device supports it. The data should be of a format acceptable
8815  * to the player (for iRiver and Creative, this seems to be JPEG) and
8816  * must not be too large. (for a Creative, max seems to be about 20KB.)
8817  * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8818  * maximum size, dimensions, etc..
8819  * @param device a pointer to the device which the object is on.
8820  * @param id unique id of the object to set artwork for.
8821  * @param pointer to LIBMTP_filesampledata_t struct containing data
8822  * @return 0 on success, any other value means failure.
8823  * @see LIBMTP_Get_Representative_Sample()
8824  * @see LIBMTP_Get_Representative_Sample_Format()
8825  * @see LIBMTP_Create_New_Album()
8826  */
8827 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8828                           uint32_t const id,
8829                           LIBMTP_filesampledata_t *sampledata)
8830 {
8831   uint16_t ret;
8832   PTPParams *params = (PTPParams *) device->params;
8833   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8834   PTPPropertyValue propval;
8835   PTPObject *ob;
8836   uint32_t i;
8837   uint16_t *props = NULL;
8838   uint32_t propcnt = 0;
8839   int supported = 0;
8840 
8841   // get the file format for the object we're going to send representative data for
8842   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8843   if (ret != PTP_RC_OK) {
8844     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8845     return -1;
8846   }
8847 
8848   // check that we can send representative sample data for this object format
8849   ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8850   if (ret != PTP_RC_OK) {
8851     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8852     return -1;
8853   }
8854 
8855   for (i = 0; i < propcnt; i++) {
8856     if (props[i] == PTP_OPC_RepresentativeSampleData) {
8857       supported = 1;
8858       break;
8859     }
8860   }
8861   if (!supported) {
8862     free(props);
8863     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8864     return -1;
8865   }
8866   free(props);
8867 
8868   // Go ahead and send the data
8869   propval.a.count = sampledata->size;
8870   propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8871   for (i = 0; i < sampledata->size; i++) {
8872     propval.a.v[i].u8 = sampledata->data[i];
8873   }
8874 
8875   ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8876 				   &propval,PTP_DTC_AUINT8);
8877   if (ret != PTP_RC_OK) {
8878     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8879     free(propval.a.v);
8880     return -1;
8881   }
8882   free(propval.a.v);
8883 
8884   /* Set the height and width if the sample is an image, otherwise just
8885    * set the duration and size */
8886   switch(sampledata->filetype) {
8887   case LIBMTP_FILETYPE_JPEG:
8888   case LIBMTP_FILETYPE_JFIF:
8889   case LIBMTP_FILETYPE_TIFF:
8890   case LIBMTP_FILETYPE_BMP:
8891   case LIBMTP_FILETYPE_GIF:
8892   case LIBMTP_FILETYPE_PICT:
8893   case LIBMTP_FILETYPE_PNG:
8894     if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8895       // For images, set the height and width
8896       set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8897       set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8898     }
8899     break;
8900   default:
8901     // For anything not an image, set the duration and size
8902     set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8903     set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8904     break;
8905   }
8906 
8907   return 0;
8908 }
8909 
8910 /**
8911  * This routine gets representative sample data for an object.
8912  * This uses the RepresentativeSampleData property of the album,
8913  * if the device supports it.
8914  * @param device a pointer to the device which the object is on.
8915  * @param id unique id of the object to get data for.
8916  * @param pointer to LIBMTP_filesampledata_t struct to receive data
8917  * @return 0 on success, any other value means failure.
8918  * @see LIBMTP_Send_Representative_Sample()
8919  * @see LIBMTP_Get_Representative_Sample_Format()
8920  * @see LIBMTP_Create_New_Album()
8921  */
8922 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
8923                           uint32_t const id,
8924                           LIBMTP_filesampledata_t *sampledata)
8925 {
8926   uint16_t ret;
8927   PTPParams *params = (PTPParams *) device->params;
8928   PTPPropertyValue propval;
8929   PTPObject *ob;
8930   uint32_t i;
8931   uint16_t *props = NULL;
8932   uint32_t propcnt = 0;
8933   int supported = 0;
8934 
8935   // get the file format for the object we're going to send representative data for
8936   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8937   if (ret != PTP_RC_OK) {
8938     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
8939     return -1;
8940   }
8941 
8942   // check that we can store representative sample data for this object format
8943   ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8944   if (ret != PTP_RC_OK) {
8945     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
8946     return -1;
8947   }
8948 
8949   for (i = 0; i < propcnt; i++) {
8950     if (props[i] == PTP_OPC_RepresentativeSampleData) {
8951       supported = 1;
8952       break;
8953     }
8954   }
8955   if (!supported) {
8956     free(props);
8957     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8958     return -1;
8959   }
8960   free(props);
8961 
8962   // Get the data
8963   ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8964 				   &propval,PTP_DTC_AUINT8);
8965   if (ret != PTP_RC_OK) {
8966     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
8967     return -1;
8968   }
8969 
8970   // Store it
8971   sampledata->size = propval.a.count;
8972   sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
8973   for (i = 0; i < propval.a.count; i++) {
8974     sampledata->data[i] = propval.a.v[i].u8;
8975   }
8976   free(propval.a.v);
8977 
8978   // Get the other properties
8979   sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
8980   sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
8981   sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
8982   sampledata->filetype = map_ptp_type_to_libmtp_type(
8983         get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
8984 
8985   return 0;
8986 }
8987 
8988 /**
8989  * Retrieve the thumbnail for a file.
8990  * @param device a pointer to the device to get the thumbnail from.
8991  * @param id the object ID of the file to retrieve the thumbnail for.
8992  * @return 0 on success, any other value means failure.
8993  */
8994 int LIBMTP_Get_Thumbnail(LIBMTP_mtpdevice_t *device, uint32_t const id,
8995                          unsigned char **data, unsigned int *size)
8996 {
8997   PTPParams *params = (PTPParams *) device->params;
8998   uint16_t ret;
8999 
9000   ret = ptp_getthumb(params, id, data, size);
9001   if (ret == PTP_RC_OK)
9002       return 0;
9003   return -1;
9004 }
9005 
9006 
9007 int LIBMTP_GetPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9008                             uint64_t offset, uint32_t maxbytes,
9009                             unsigned char **data, unsigned int *size)
9010 {
9011   PTPParams *params = (PTPParams *) device->params;
9012   uint16_t ret;
9013 
9014   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_GetPartialObject64)) {
9015     if  (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
9016       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9017         "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject not supported");
9018       return -1;
9019     }
9020 
9021     if (offset >> 32 != 0) {
9022       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9023         "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject only supports 32bit offsets");
9024       return -1;
9025     }
9026 
9027     ret = ptp_getpartialobject(params, id, (uint32_t)offset, maxbytes, data, size);
9028   } else {
9029     ret = ptp_android_getpartialobject64(params, id, offset, maxbytes, data, size);
9030   }
9031   if (ret == PTP_RC_OK)
9032       return 0;
9033   return -1;
9034 }
9035 
9036 
9037 int LIBMTP_SendPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9038                              uint64_t offset, unsigned char *data, unsigned int size)
9039 {
9040   PTPParams *params = (PTPParams *) device->params;
9041   uint16_t ret;
9042 
9043   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_SendPartialObject)) {
9044     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9045       "LIBMTP_SendPartialObject: PTP_OC_ANDROID_SendPartialObject not supported");
9046     return -1;
9047   }
9048 
9049   ret = ptp_android_sendpartialobject(params, id, offset, data, size);
9050   if (ret == PTP_RC_OK)
9051       return 0;
9052   return -1;
9053 }
9054 
9055 
9056 int LIBMTP_BeginEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9057 {
9058   PTPParams *params = (PTPParams *) device->params;
9059   uint16_t ret;
9060 
9061   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_BeginEditObject)) {
9062     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9063       "LIBMTP_BeginEditObject: PTP_OC_ANDROID_BeginEditObject not supported");
9064     return -1;
9065   }
9066 
9067   ret = ptp_android_begineditobject(params, id);
9068   if (ret == PTP_RC_OK)
9069       return 0;
9070   return -1;
9071 }
9072 
9073 
9074 int LIBMTP_EndEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9075 {
9076   PTPParams *params = (PTPParams *) device->params;
9077   uint16_t ret;
9078 
9079   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_EndEditObject)) {
9080     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9081       "LIBMTP_EndEditObject: PTP_OC_ANDROID_EndEditObject not supported");
9082     return -1;
9083   }
9084 
9085   ret = ptp_android_endeditobject(params, id);
9086   if (ret == PTP_RC_OK) {
9087       // update cached object properties if metadata cache exists
9088       update_metadata_cache(device, id);
9089       return 0;
9090   }
9091   return -1;
9092 }
9093 
9094 
9095 int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9096                           uint64_t offset)
9097 {
9098   PTPParams *params = (PTPParams *) device->params;
9099   uint16_t ret;
9100 
9101   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_TruncateObject)) {
9102     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9103       "LIBMTP_TruncateObject: PTP_OC_ANDROID_TruncateObject not supported");
9104     return -1;
9105   }
9106 
9107   ret = ptp_android_truncate(params, id, offset);
9108   if (ret == PTP_RC_OK)
9109       return 0;
9110   return -1;
9111 }
9112 
9113 
9114 /**
9115  * This routine updates an album based on the metadata
9116  * supplied. If the <code>tracks</code> field of the metadata
9117  * contains a track listing, these tracks will be added to the
9118  * album in place of those already present, i.e. the
9119  * previous track listing will be deleted.
9120  * @param device a pointer to the device to create the new album on.
9121  * @param metadata the metadata for the album to be updated.
9122  *                 notice that the field <code>album_id</code>
9123  *                 must contain the apropriate album ID.
9124  * @return 0 on success, any other value means failure.
9125  * @see LIBMTP_Create_New_Album()
9126  * @see LIBMTP_Delete_Object()
9127  */
9128 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
9129 			   LIBMTP_album_t const * const metadata)
9130 {
9131   return update_abstract_list(device,
9132 			      metadata->name,
9133 			      metadata->artist,
9134 			      metadata->composer,
9135 			      metadata->genre,
9136 			      metadata->album_id,
9137 			      PTP_OFC_MTP_AbstractAudioAlbum,
9138 			      metadata->tracks,
9139 			      metadata->no_tracks);
9140 }
9141 
9142 /**
9143  * Dummy function needed to interface to upstream
9144  * ptp.c/ptp.h files.
9145  */
9146 void ptp_nikon_getptpipguid (unsigned char* guid) {
9147   return;
9148 }
9149 
9150 /**
9151  * Add an object to cache.
9152  * @param device the device which may have a cache to which the object should be added.
9153  * @param object_id the object to add to the cache.
9154  */
9155 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9156 {
9157   PTPParams *params = (PTPParams *)device->params;
9158   uint16_t ret;
9159 
9160   ret = ptp_add_object_to_cache(params, object_id);
9161   if (ret != PTP_RC_OK) {
9162     add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
9163   }
9164 }
9165 
9166 
9167 /**
9168  * Update cache after object has been modified
9169  * @param device the device which may have a cache to which the object should be updated.
9170  * @param object_id the object to update.
9171  */
9172 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9173 {
9174   PTPParams *params = (PTPParams *)device->params;
9175 
9176   ptp_remove_object_from_cache(params, object_id);
9177   add_object_to_cache(device, object_id);
9178 }
9179 
9180 
9181 /**
9182  * Issue custom (e.g. vendor specific) operation (without data phase)
9183  * @param device a pointer to the device to send custom operation to.
9184  * @param code operation code to send.
9185  * @param n_param number of parameters passed.
9186  * @param ... uint32_t operation specific parameters.
9187  */
9188 int LIBMTP_Custom_Operation(LIBMTP_mtpdevice_t *device, uint16_t code, int n_param, ...)
9189 {
9190   PTPParams *params = (PTPParams *) device->params;
9191   PTPContainer ptp;
9192   va_list args;
9193   uint16_t ret;
9194   int i;
9195 
9196   ptp.Code = code;
9197   ptp.Nparam = n_param;
9198   va_start(args, n_param);
9199   for (i = 0; i < n_param; i++)
9200     (&ptp.Param1)[i] = va_arg(args, uint32_t);
9201   va_end(args);
9202 
9203   ret = ptp_transaction_new(params, &ptp, PTP_DP_NODATA, 0, NULL);
9204 
9205   if (ret != PTP_RC_OK) {
9206     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Custom_Operation(): failed to execute operation.");
9207     return -1;
9208   }
9209 
9210   return 0;
9211 }
9212