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 int use_mtpz;
48 
49 #include <stdarg.h>
50 #include <stdlib.h>
51 #include <limits.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 #include <time.h>
58 #include <errno.h>
59 #ifdef _MSC_VER // For MSVC++
60 #define USE_WINDOWS_IO_H
61 #include <io.h>
62 #endif
63 
64 
65 /**
66  * Global debug level
67  * We use a flag system to enable a part of logs.
68  *
69  * The LIBMTP_DEBUG environment variable sets the debug flags for any binary
70  * that uses libmtp and calls LIBMTP_Init. The value can be given in decimal
71  * (must not start with "0" or it will be interpreted in octal), or in
72  * hexadecimal (must start with "0x").
73  *
74  * The value "-1" enables all debug flags.
75  *
76  * Some of the utilities in examples/ also take a command-line flag "-d" that
77  * enables LIBMTP_DEBUG_PTP and LIBMTP_DEBUG_DATA (same as setting
78  * LIBMTP_DEBUG=9).
79  *
80  * Flags (combine by adding the hex values):
81  *  0x00 [0000 0000] : LIBMTP_DEBUG_NONE  : no debug (default)
82  *  0x01 [0000 0001] : LIBMTP_DEBUG_PTP   : PTP debug
83  *  0x02 [0000 0010] : LIBMTP_DEBUG_PLST  : Playlist debug
84  *  0x04 [0000 0100] : LIBMTP_DEBUG_USB   : USB debug
85  *  0x08 [0000 1000] : LIBMTP_DEBUG_DATA  : USB data debug
86  *
87  * (Please keep this list in sync with libmtp.h.)
88  */
89 int LIBMTP_debug = LIBMTP_DEBUG_NONE;
90 
91 
92 /*
93  * This is a mapping between libmtp internal MTP filetypes and
94  * the libgphoto2/PTP equivalent defines. We need this because
95  * otherwise the libmtp.h device has to be dependent on ptp.h
96  * to be installed too, and we don't want that.
97  */
98 //typedef struct filemap_struct filemap_t;
99 typedef struct filemap_struct {
100   char *description; /**< Text description for the file type */
101   LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
102   uint16_t ptp_id; /**< PTP ID for the filetype */
103   struct filemap_struct *next;
104 } filemap_t;
105 
106 /*
107  * This is a mapping between libmtp internal MTP properties and
108  * the libgphoto2/PTP equivalent defines. We need this because
109  * otherwise the libmtp.h device has to be dependent on ptp.h
110  * to be installed too, and we don't want that.
111  */
112 typedef struct propertymap_struct {
113   char *description; /**< Text description for the property */
114   LIBMTP_property_t id; /**< LIBMTP internal type for the property */
115   uint16_t ptp_id; /**< PTP ID for the property */
116   struct propertymap_struct *next;
117 } propertymap_t;
118 
119 /*
120  * This is a simple container for holding our callback and user_data
121  * for parsing onwards to the usb_event_async function.
122  */
123 typedef struct event_cb_data_struct {
124   LIBMTP_event_cb_fn cb;
125   void *user_data;
126 } event_cb_data_t;
127 
128 // Global variables
129 // This holds the global filetype mapping table
130 static filemap_t *g_filemap = NULL;
131 // This holds the global property mapping table
132 static propertymap_t *g_propertymap = NULL;
133 
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 uint16_t 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 connected MTP device by list position.
1684  * @return a device pointer.
1685  * @see LIBMTP_Get_Connected_Devices()
1686  */
LIBMTP_Get_Device(int device_nr)1687 LIBMTP_mtpdevice_t *LIBMTP_Get_Device(int device_nr)
1688 {
1689   LIBMTP_mtpdevice_t *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   if (device_nr < 0 || device_nr >= numdevs) {
1705     free(devices);
1706     return NULL;
1707   }
1708 
1709   device = LIBMTP_Open_Raw_Device(&devices[device_nr]);
1710   free(devices);
1711   return device;
1712 }
1713 
1714 /**
1715  * Get the first (as in "first in the list of") connected MTP device.
1716  * @return a device pointer.
1717  * @see LIBMTP_Get_Connected_Devices()
1718  */
LIBMTP_Get_First_Device(void)1719 LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
1720 {
1721   return LIBMTP_Get_Device(0);
1722 }
1723 
1724 /**
1725  * Overriding debug function.
1726  * This way we can disable debug prints.
1727  */
1728 static void
1729 #ifdef __GNUC__
1730 __attribute__((__format__(printf,2,0)))
1731 #endif
LIBMTP_ptp_debug(void * data,const char * format,va_list args)1732 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1733 {
1734   if ((LIBMTP_debug & LIBMTP_DEBUG_PTP) != 0) {
1735     vfprintf (stderr, format, args);
1736     fprintf (stderr, "\n");
1737     fflush (stderr);
1738   }
1739 }
1740 
1741 /**
1742  * Overriding error function.
1743  * This way we can capture all error etc to our errorstack.
1744  */
1745 static void
1746 #ifdef __GNUC__
1747 __attribute__((__format__(printf,2,0)))
1748 #endif
LIBMTP_ptp_error(void * data,const char * format,va_list args)1749 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1750 {
1751   // if (data == NULL) {
1752     vfprintf (stderr, format, args);
1753     fflush (stderr);
1754   /*
1755     FIXME: find out how we shall get the device here.
1756   } else {
1757     PTP_USB *ptp_usb = data;
1758     LIBMTP_mtpdevice_t *device = ...;
1759     char buf[2048];
1760 
1761     vsnprintf (buf, sizeof (buf), format, args);
1762     add_error_to_errorstack(device,
1763 			    LIBMTP_ERROR_PTP_LAYER,
1764 			    buf);
1765   }
1766   */
1767 }
1768 
1769 /**
1770  * Parses the extension descriptor, there may be stuff in
1771  * this that we want to know about.
1772  */
parse_extension_descriptor(LIBMTP_mtpdevice_t * mtpdevice,char * desc)1773 static void parse_extension_descriptor(LIBMTP_mtpdevice_t *mtpdevice,
1774                                        char *desc)
1775 {
1776   int start = 0;
1777   int end = 0;
1778 
1779   /* NULL on Canon A70 */
1780   if (!desc)
1781     return;
1782 
1783   /* descriptors are divided by semicolons */
1784   while (end < strlen(desc)) {
1785     /* Skip past initial whitespace */
1786     while ((end < strlen(desc)) && (desc[start] == ' ' )) {
1787       start++;
1788       end++;
1789     }
1790     /* Detect extension */
1791     while ((end < strlen(desc)) && (desc[end] != ';'))
1792       end++;
1793     if (end < strlen(desc)) {
1794       char *element = strndup(desc + start, end-start);
1795       if (element) {
1796         int i = 0;
1797         // printf("  Element: \"%s\"\n", element);
1798 
1799         /* Parse for an extension */
1800         while ((i < strlen(element)) && (element[i] != ':'))
1801           i++;
1802         if (i < strlen(element)) {
1803           char *name = strndup(element, i);
1804           int major = 0, minor = 0;
1805 
1806 	  /* extension versions have to be MAJOR.MINOR, but Samsung has one
1807 	   * with just 0, so just cope with those cases too */
1808 	  if (	(2 == sscanf(element+i+1,"%d.%d",&major,&minor)) ||
1809 	  	(1 == sscanf(element+i+1,"%d",&major))
1810 	  ) {
1811             LIBMTP_device_extension_t *extension;
1812 
1813             extension = malloc(sizeof(LIBMTP_device_extension_t));
1814             extension->name = name;
1815             extension->major = major;
1816             extension->minor = minor;
1817             extension->next = NULL;
1818             if (mtpdevice->extensions == NULL) {
1819               mtpdevice->extensions = extension;
1820             } else {
1821               LIBMTP_device_extension_t *tmp = mtpdevice->extensions;
1822               while (tmp->next != NULL)
1823                 tmp = tmp->next;
1824               tmp->next = extension;
1825             }
1826           } else {
1827             LIBMTP_ERROR("LIBMTP ERROR: couldnt parse extension %s\n",
1828                          element);
1829           }
1830         }
1831         free(element);
1832       }
1833     }
1834     end++;
1835     start = end;
1836   }
1837 }
1838 
1839 /**
1840  * This function opens a device from a raw device. It is the
1841  * preferred way to access devices in the new interface where
1842  * several devices can come and go as the library is working
1843  * on a certain device.
1844  * @param rawdevice the raw device to open a "real" device for.
1845  * @return an open device.
1846  */
LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t * rawdevice)1847 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevice)
1848 {
1849   LIBMTP_mtpdevice_t *mtp_device;
1850   uint8_t bs = 0;
1851   PTPParams *current_params;
1852   PTP_USB *ptp_usb;
1853   LIBMTP_error_number_t err;
1854   int i;
1855 
1856   /* Allocate dynamic space for our device */
1857   mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1858   /* Check if there was a memory allocation error */
1859   if(mtp_device == NULL) {
1860     /* There has been an memory allocation error. We are going to ignore this
1861        device and attempt to continue */
1862 
1863     /* TODO: This error statement could probably be a bit more robust */
1864     LIBMTP_ERROR("LIBMTP PANIC: connect_usb_devices encountered a memory "
1865 	    "allocation error with device %d on bus %d, trying to continue",
1866 	    rawdevice->devnum, rawdevice->bus_location);
1867 
1868     return NULL;
1869   }
1870   memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1871   // Non-cached by default
1872   mtp_device->cached = 0;
1873 
1874   /* Create PTP params */
1875   current_params = (PTPParams *) malloc(sizeof(PTPParams));
1876   if (current_params == NULL) {
1877     free(mtp_device);
1878     return NULL;
1879   }
1880   memset(current_params, 0, sizeof(PTPParams));
1881   current_params->device_flags = rawdevice->device_entry.device_flags;
1882   current_params->nrofobjects = 0;
1883   current_params->cachetime = 2;
1884   current_params->objects = NULL;
1885   current_params->response_packet_size = 0;
1886   current_params->response_packet = NULL;
1887   /* This will be a pointer to PTP_USB later */
1888   current_params->data = NULL;
1889   /* Set upp local debug and error functions */
1890   current_params->debug_func = LIBMTP_ptp_debug;
1891   current_params->error_func = LIBMTP_ptp_error;
1892   /* TODO: Will this always be little endian? */
1893   current_params->byteorder = PTP_DL_LE;
1894 #if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
1895   current_params->cd_locale_to_ucs2 = iconv_open("UTF-16LE", "UTF-8");
1896   current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UTF-16LE");
1897 
1898   if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1899      current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1900     LIBMTP_ERROR("LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1901 	    "Too old stdlibc, glibc and libiconv?\n");
1902     free(current_params);
1903     free(mtp_device);
1904     return NULL;
1905   }
1906 #endif
1907   mtp_device->params = current_params;
1908 
1909   /* Create usbinfo, this also opens the session */
1910   err = configure_usb_device(rawdevice,
1911 			     current_params,
1912 			     &mtp_device->usbinfo);
1913   if (err != LIBMTP_ERROR_NONE) {
1914     free(current_params);
1915     free(mtp_device);
1916     return NULL;
1917   }
1918   ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1919   /* Set pointer back to params */
1920   ptp_usb->params = current_params;
1921 
1922   /* Cache the device information for later use */
1923   if (ptp_getdeviceinfo(current_params,
1924 			&current_params->deviceinfo) != PTP_RC_OK) {
1925     LIBMTP_ERROR("LIBMTP PANIC: Unable to read device information on device "
1926 	    "%d on bus %d, trying to continue",
1927 	    rawdevice->devnum, rawdevice->bus_location);
1928 
1929     /* Prevent memory leaks for this device */
1930     free(mtp_device->usbinfo);
1931     free(mtp_device->params);
1932     current_params = NULL;
1933     free(mtp_device);
1934     return NULL;
1935   }
1936 
1937   /* Check: if this is a PTP device, is it really tagged as MTP? */
1938   if (current_params->deviceinfo.VendorExtensionID != 0x00000006) {
1939     LIBMTP_ERROR("LIBMTP WARNING: no MTP vendor extension on device "
1940 		 "%d on bus %d",
1941 		 rawdevice->devnum, rawdevice->bus_location);
1942     LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionID: %08x",
1943 		 current_params->deviceinfo.VendorExtensionID);
1944     LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionDesc: %s",
1945 		 current_params->deviceinfo.VendorExtensionDesc);
1946     LIBMTP_ERROR("LIBMTP WARNING: this typically means the device is PTP "
1947 		 "(i.e. a camera) but not an MTP device at all. "
1948 		 "Trying to continue anyway.");
1949   }
1950 
1951   parse_extension_descriptor(mtp_device,
1952                              current_params->deviceinfo.VendorExtensionDesc);
1953 
1954   /*
1955    * Android has a number of bugs, force-assign these bug flags
1956    * if Android is encountered. Same thing for devices we detect
1957    * as SONY NWZ Walkmen. I have no clue what "sony.net/WMFU" means
1958    * I just know only NWZs have it.
1959    */
1960   {
1961     LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
1962     int is_microsoft_com_wpdna = 0;
1963     int is_android = 0;
1964     int is_sony_net_wmfu = 0;
1965     int is_sonyericsson_com_se = 0;
1966 
1967     /* Loop over extensions and set flags */
1968     while (tmpext != NULL) {
1969       if (!strcmp(tmpext->name, "microsoft.com/WPDNA"))
1970 	is_microsoft_com_wpdna = 1;
1971       if (!strcmp(tmpext->name, "android.com"))
1972 	is_android = 1;
1973       if (!strcmp(tmpext->name, "sony.net/WMFU"))
1974 	is_sony_net_wmfu = 1;
1975       if (!strcmp(tmpext->name, "sonyericsson.com/SE"))
1976 	is_sonyericsson_com_se = 1;
1977       tmpext = tmpext->next;
1978     }
1979 
1980     /* Check for specific stacks */
1981     if (is_microsoft_com_wpdna && is_sonyericsson_com_se && !is_android) {
1982       /*
1983        * The Aricent stack seems to be detected by providing WPDNA, the SonyEricsson
1984        * extension and NO Android extension.
1985        */
1986       ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ARICENT_BUGS;
1987       LIBMTP_INFO("Aricent MTP stack device detected, assigning default bug flags\n");
1988     }
1989     else if (is_android) {
1990       /*
1991        * If bugs are fixed in later versions, test on tmpext->major, tmpext->minor
1992        */
1993       ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ANDROID_BUGS;
1994       LIBMTP_INFO("Android device detected, assigning default bug flags\n");
1995     }
1996     else if (is_sony_net_wmfu) {
1997       ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_SONY_NWZ_BUGS;
1998       LIBMTP_INFO("SONY NWZ device detected, assigning default bug flags\n");
1999     }
2000   }
2001 
2002   /*
2003    * If the OGG or FLAC filetypes are flagged as "unknown", check
2004    * if the firmware has been updated to actually support it.
2005    */
2006   if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
2007     for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2008       if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_OGG) {
2009         /* This is not unknown anymore, unflag it */
2010         ptp_usb->rawdevice.device_entry.device_flags &=
2011           ~DEVICE_FLAG_OGG_IS_UNKNOWN;
2012         break;
2013       }
2014     }
2015   }
2016   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
2017     for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2018       if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_FLAC) {
2019         /* This is not unknown anymore, unflag it */
2020         ptp_usb->rawdevice.device_entry.device_flags &=
2021           ~DEVICE_FLAG_FLAC_IS_UNKNOWN;
2022         break;
2023       }
2024     }
2025   }
2026 
2027   /* Determine if the object size supported is 32 or 64 bit wide */
2028   if (ptp_operation_issupported(current_params,PTP_OC_MTP_GetObjectPropsSupported)) {
2029     for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2030       PTPObjectPropDesc opd;
2031 
2032       if (ptp_mtp_getobjectpropdesc(current_params,
2033                                     PTP_OPC_ObjectSize,
2034                                     current_params->deviceinfo.ImageFormats[i],
2035                                     &opd) != PTP_RC_OK) {
2036         LIBMTP_ERROR("LIBMTP PANIC: "
2037                      "could not inspect object property description 0x%04x!\n", current_params->deviceinfo.ImageFormats[i]);
2038       } else {
2039         if (opd.DataType == PTP_DTC_UINT32) {
2040           if (bs == 0) {
2041             bs = 32;
2042           } else if (bs != 32) {
2043             LIBMTP_ERROR("LIBMTP PANIC: "
2044                          "different objects support different object sizes!\n");
2045             bs = 0;
2046             break;
2047           }
2048         } else if (opd.DataType == PTP_DTC_UINT64) {
2049           if (bs == 0) {
2050             bs = 64;
2051           } else if (bs != 64) {
2052             LIBMTP_ERROR("LIBMTP PANIC: "
2053                          "different objects support different object sizes!\n");
2054             bs = 0;
2055             break;
2056           }
2057         } else {
2058           // Ignore if other size.
2059           LIBMTP_ERROR("LIBMTP PANIC: "
2060                        "awkward object size data type: %04x\n", opd.DataType);
2061           bs = 0;
2062           break;
2063         }
2064       }
2065     }
2066   }
2067   if (bs == 0) {
2068     // Could not detect object bitsize, assume 32 bits
2069     bs = 32;
2070   }
2071   mtp_device->object_bitsize = bs;
2072 
2073   /* No Errors yet for this device */
2074   mtp_device->errorstack = NULL;
2075 
2076   /* Default Max Battery Level, we will adjust this if possible */
2077   mtp_device->maximum_battery_level = 100;
2078 
2079   /* Check if device supports reading maximum battery level */
2080   if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
2081      ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
2082     PTPDevicePropDesc dpd;
2083 
2084     /* Try to read maximum battery level */
2085     if(ptp_getdevicepropdesc(current_params,
2086 			     PTP_DPC_BatteryLevel,
2087 			     &dpd) != PTP_RC_OK) {
2088       add_error_to_errorstack(mtp_device,
2089 			      LIBMTP_ERROR_CONNECTING,
2090 			      "Unable to read Maximum Battery Level for this "
2091 			      "device even though the device supposedly "
2092 			      "supports this functionality");
2093     }
2094 
2095     /* TODO: is this appropriate? */
2096     /* If max battery level is 0 then leave the default, otherwise assign */
2097     if (dpd.FORM.Range.MaximumValue.u8 != 0) {
2098       mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
2099     }
2100 
2101     ptp_free_devicepropdesc(&dpd);
2102   }
2103 
2104   /* Set all default folders to 0xffffffffU (root directory) */
2105   mtp_device->default_music_folder = 0xffffffffU;
2106   mtp_device->default_playlist_folder = 0xffffffffU;
2107   mtp_device->default_picture_folder = 0xffffffffU;
2108   mtp_device->default_video_folder = 0xffffffffU;
2109   mtp_device->default_organizer_folder = 0xffffffffU;
2110   mtp_device->default_zencast_folder = 0xffffffffU;
2111   mtp_device->default_album_folder = 0xffffffffU;
2112   mtp_device->default_text_folder = 0xffffffffU;
2113 
2114   /* Set initial storage information */
2115   mtp_device->storage = NULL;
2116   if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
2117     add_error_to_errorstack(mtp_device,
2118 			    LIBMTP_ERROR_GENERAL,
2119 			    "Get Storage information failed.");
2120     mtp_device->storage = NULL;
2121   }
2122 
2123 
2124   return mtp_device;
2125 }
2126 
LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t * rawdevice)2127 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
2128 {
2129   LIBMTP_mtpdevice_t *mtp_device = LIBMTP_Open_Raw_Device_Uncached(rawdevice);
2130 
2131   if (mtp_device == NULL)
2132     return NULL;
2133 
2134   /* Check for MTPZ devices. */
2135   if (use_mtpz) {
2136     LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
2137 
2138     while (tmpext != NULL) {
2139       if (!strcmp(tmpext->name, "microsoft.com/MTPZ")) {
2140 	LIBMTP_INFO("MTPZ device detected. Authenticating...\n");
2141         if (PTP_RC_OK == ptp_mtpz_handshake(mtp_device->params)) {
2142 	  LIBMTP_INFO ("(MTPZ) Successfully authenticated with device.\n");
2143         } else {
2144           LIBMTP_INFO ("(MTPZ) Failure - could not authenticate with device.\n");
2145         }
2146 	break;
2147       }
2148       tmpext = tmpext->next;
2149     }
2150   }
2151 
2152   // Set up this device as cached
2153   mtp_device->cached = 1;
2154   /*
2155    * Then get the handles and try to locate the default folders.
2156    * This has the desired side effect of caching all handles from
2157    * the device which speeds up later operations.
2158    */
2159   flush_handles(mtp_device);
2160   return mtp_device;
2161 }
2162 
2163 /**
2164  * To read events sent by the device, repeatedly call this function from a secondary
2165  * thread until the return value is < 0.
2166  *
2167  * @param device a pointer to the MTP device to poll for events.
2168  * @param event contains a pointer to be filled in with the event retrieved if the call
2169  * is successful.
2170  * @param out1 contains the param1 value from the raw event.
2171  * @return 0 on success, any other value means the polling loop shall be
2172  * terminated immediately for this session.
2173  */
LIBMTP_Read_Event(LIBMTP_mtpdevice_t * device,LIBMTP_event_t * event,uint32_t * out1)2174 int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *device, LIBMTP_event_t *event, uint32_t *out1)
2175 {
2176   /*
2177    * FIXME: Potential race-condition here, if client deallocs device
2178    * while we're *not* waiting for input. As we'll be waiting for
2179    * input most of the time, it's unlikely but still worth considering
2180    * for improvement. Also we cannot affect the state of the cache etc
2181    * unless we know we are the sole user on the device. A spinlock or
2182    * mutex in the LIBMTP_mtpdevice_t is needed for this to work.
2183    */
2184   PTPParams *params = (PTPParams *) device->params;
2185   PTPContainer ptp_event;
2186   uint16_t ret = ptp_usb_event_wait(params, &ptp_event);
2187 
2188   if (ret != PTP_RC_OK) {
2189     /* Device is closing down or other fatal stuff, exit thread */
2190     return -1;
2191   }
2192   LIBMTP_Handle_Event(&ptp_event, event, out1);
2193   return 0;
2194 }
2195 
LIBMTP_Handle_Event(PTPContainer * ptp_event,LIBMTP_event_t * event,uint32_t * out1)2196 void LIBMTP_Handle_Event(PTPContainer *ptp_event,
2197                          LIBMTP_event_t *event, uint32_t *out1) {
2198   uint16_t code;
2199   uint32_t session_id;
2200   uint32_t param1;
2201 
2202   *event = LIBMTP_EVENT_NONE;
2203 
2204   /* Process the event */
2205   code = ptp_event->Code;
2206   session_id = ptp_event->SessionID;
2207   param1 = ptp_event->Param1;
2208 
2209   switch(code) {
2210     case PTP_EC_Undefined:
2211       LIBMTP_INFO("Received event PTP_EC_Undefined in session %u\n", session_id);
2212       break;
2213     case PTP_EC_CancelTransaction:
2214       LIBMTP_INFO("Received event PTP_EC_CancelTransaction in session %u\n", session_id);
2215       break;
2216     case PTP_EC_ObjectAdded:
2217       LIBMTP_INFO("Received event PTP_EC_ObjectAdded in session %u\n", session_id);
2218       *event = LIBMTP_EVENT_OBJECT_ADDED;
2219       *out1 = param1;
2220       break;
2221     case PTP_EC_ObjectRemoved:
2222       LIBMTP_INFO("Received event PTP_EC_ObjectRemoved in session %u\n", session_id);
2223       *event = LIBMTP_EVENT_OBJECT_REMOVED;
2224       *out1 = param1;
2225       break;
2226     case PTP_EC_StoreAdded:
2227       LIBMTP_INFO("Received event PTP_EC_StoreAdded in session %u\n", session_id);
2228       /* TODO: rescan storages */
2229       *event = LIBMTP_EVENT_STORE_ADDED;
2230       *out1 = param1;
2231       break;
2232     case PTP_EC_StoreRemoved:
2233       LIBMTP_INFO("Received event PTP_EC_StoreRemoved in session %u\n", session_id);
2234       /* TODO: rescan storages */
2235       *event = LIBMTP_EVENT_STORE_REMOVED;
2236       *out1 = param1;
2237       break;
2238     case PTP_EC_DevicePropChanged:
2239       LIBMTP_INFO("Received event PTP_EC_DevicePropChanged in session %u\n", session_id);
2240       /* TODO: update device properties */
2241       *event = LIBMTP_EVENT_DEVICE_PROPERTY_CHANGED;
2242       *out1 = param1;
2243       break;
2244     case PTP_EC_ObjectInfoChanged:
2245       LIBMTP_INFO("Received event PTP_EC_ObjectInfoChanged in session %u\n", session_id);
2246       /* TODO: rescan object cache or just for this one object */
2247       break;
2248     case PTP_EC_DeviceInfoChanged:
2249       LIBMTP_INFO("Received event PTP_EC_DeviceInfoChanged in session %u\n", session_id);
2250       /* TODO: update device info */
2251       break;
2252     case PTP_EC_RequestObjectTransfer:
2253       LIBMTP_INFO("Received event PTP_EC_RequestObjectTransfer in session %u\n", session_id);
2254       break;
2255     case PTP_EC_StoreFull:
2256       LIBMTP_INFO("Received event PTP_EC_StoreFull in session %u\n", session_id);
2257       break;
2258     case PTP_EC_DeviceReset:
2259       LIBMTP_INFO("Received event PTP_EC_DeviceReset in session %u\n", session_id);
2260       break;
2261     case PTP_EC_StorageInfoChanged :
2262       LIBMTP_INFO( "Received event PTP_EC_StorageInfoChanged in session %u\n", session_id);
2263      /* TODO: update storage info */
2264       break;
2265     case PTP_EC_CaptureComplete :
2266       LIBMTP_INFO( "Received event PTP_EC_CaptureComplete in session %u\n", session_id);
2267       break;
2268     case PTP_EC_UnreportedStatus :
2269       LIBMTP_INFO( "Received event PTP_EC_UnreportedStatus in session %u\n", session_id);
2270       break;
2271     default :
2272       LIBMTP_INFO( "Received unknown event in session %u\n", session_id);
2273       break;
2274   }
2275 }
2276 
LIBMTP_Read_Event_Cb(PTPParams * params,uint16_t ret_code,PTPContainer * ptp_event,void * user_data)2277 static void LIBMTP_Read_Event_Cb(PTPParams *params, uint16_t ret_code,
2278                                  PTPContainer *ptp_event, void *user_data) {
2279   event_cb_data_t *data = user_data;
2280   LIBMTP_event_t event = LIBMTP_EVENT_NONE;
2281   uint32_t param1 = 0;
2282   int handler_ret;
2283 
2284   switch (ret_code) {
2285   case PTP_RC_OK:
2286     handler_ret = LIBMTP_HANDLER_RETURN_OK;
2287     LIBMTP_Handle_Event(ptp_event, &event, &param1);
2288     break;
2289   case PTP_ERROR_CANCEL:
2290     handler_ret = LIBMTP_HANDLER_RETURN_CANCEL;
2291     break;
2292   default:
2293     handler_ret = LIBMTP_HANDLER_RETURN_ERROR;
2294     break;
2295   }
2296 
2297   data->cb(handler_ret, event, param1, data->user_data);
2298   free(data);
2299 }
2300 
2301 /**
2302  * This function reads events sent by the device, in a non-blocking manner.
2303  * The callback function will be called when an event is received, but for the function
2304  * to make progress, polling must take place, using LIBMTP_Handle_Events_Timeout_Completed.
2305  *
2306  * After an event is received, this function should be called again to listen for the next
2307  * event.
2308  *
2309  * For now, this non-blocking mechanism only works with libusb-1.0, and not any of the
2310  * other usb library backends. Attempting to call this method with another backend will
2311  * always return an error.
2312  *
2313  * @param device a pointer to the MTP device to poll for events.
2314  * @param cb a callback to be invoked when an event is received.
2315  * @param user_data arbitrary user data passed to the callback.
2316  * @return 0 on success, any other value means that the callback was not registered and
2317  *         no event notification will take place.
2318  */
LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t * device,LIBMTP_event_cb_fn cb,void * user_data)2319 int LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t *device, LIBMTP_event_cb_fn cb, void *user_data) {
2320   PTPParams *params = (PTPParams *) device->params;
2321   event_cb_data_t *data =  malloc(sizeof(event_cb_data_t));
2322   uint16_t ret;
2323 
2324   data->cb = cb;
2325   data->user_data = user_data;
2326 
2327   ret = ptp_usb_event_async(params, LIBMTP_Read_Event_Cb, data);
2328   return ret == PTP_RC_OK ? 0 : -1;
2329 }
2330 
2331 /**
2332  * Recursive function that adds MTP devices to a linked list
2333  * @param devices a list of raw devices to have real devices created for.
2334  * @return a device pointer to a newly created mtpdevice (used in linked
2335  * list creation).
2336  */
create_usb_mtp_devices(LIBMTP_raw_device_t * devices,int numdevs)2337 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
2338 {
2339   uint8_t i;
2340   LIBMTP_mtpdevice_t *mtp_device_list = NULL;
2341   LIBMTP_mtpdevice_t *current_device = NULL;
2342 
2343   for (i=0; i < numdevs; i++) {
2344     LIBMTP_mtpdevice_t *mtp_device;
2345     mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
2346 
2347     /* On error, try next device */
2348     if (mtp_device == NULL)
2349       continue;
2350 
2351     /* Add the device to the list */
2352     mtp_device->next = NULL;
2353     if (mtp_device_list == NULL) {
2354       mtp_device_list = current_device = mtp_device;
2355     } else {
2356       current_device->next = mtp_device;
2357       current_device = mtp_device;
2358     }
2359   }
2360   return mtp_device_list;
2361 }
2362 
2363 /**
2364  * Get the number of devices that are available in the listed device list
2365  * @param device_list Pointer to a linked list of devices
2366  * @return Number of devices in the device list device_list
2367  * @see LIBMTP_Get_Connected_Devices()
2368  */
LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t * device_list)2369 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
2370 {
2371   uint32_t numdevices = 0;
2372   LIBMTP_mtpdevice_t *iter;
2373   for(iter = device_list; iter != NULL; iter = iter->next)
2374     numdevices++;
2375 
2376   return numdevices;
2377 }
2378 
2379 /**
2380  * Get the first connected MTP device node in the linked list of devices.
2381  * Currently this only provides access to USB devices
2382  * @param device_list A list of devices ready to be used by the caller. You
2383  *        need to know how many there are.
2384  * @return Any error information gathered from device connections
2385  * @see LIBMTP_Number_Devices_In_List()
2386  */
LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t ** device_list)2387 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
2388 {
2389   LIBMTP_raw_device_t *devices;
2390   int numdevs;
2391   LIBMTP_error_number_t ret;
2392 
2393   ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
2394   if (ret != LIBMTP_ERROR_NONE) {
2395     *device_list = NULL;
2396     return ret;
2397   }
2398 
2399   /* Assign linked list of devices */
2400   if (devices == NULL || numdevs == 0) {
2401     *device_list = NULL;
2402     free(devices);
2403     return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2404   }
2405 
2406   *device_list = create_usb_mtp_devices(devices, numdevs);
2407   free(devices);
2408 
2409   /* TODO: Add wifi device access here */
2410 
2411   /* We have found some devices but create failed */
2412   if (*device_list == NULL)
2413     return LIBMTP_ERROR_CONNECTING;
2414 
2415   return LIBMTP_ERROR_NONE;
2416 }
2417 
2418 /**
2419  * This closes and releases an allocated MTP device.
2420  * @param device a pointer to the MTP device to release.
2421  */
LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t * device)2422 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
2423 {
2424   if(device != NULL)
2425   {
2426     if(device->next != NULL)
2427     {
2428       LIBMTP_Release_Device_List(device->next);
2429     }
2430 
2431     LIBMTP_Release_Device(device);
2432   }
2433 }
2434 
2435 /**
2436  * This closes and releases an allocated MTP device.
2437  * @param device a pointer to the MTP device to release.
2438  */
LIBMTP_Release_Device(LIBMTP_mtpdevice_t * device)2439 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
2440 {
2441   PTPParams *params = (PTPParams *) device->params;
2442   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2443 
2444   close_device(ptp_usb, params);
2445   // Clear error stack
2446   LIBMTP_Clear_Errorstack(device);
2447 #if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
2448   iconv_close(params->cd_locale_to_ucs2);
2449   iconv_close(params->cd_ucs2_to_locale);
2450 #endif
2451   free(ptp_usb);
2452   ptp_free_params(params);
2453   free(params);
2454   free_storage_list(device);
2455   // Free extension list...
2456   if (device->extensions != NULL) {
2457     LIBMTP_device_extension_t *tmp = device->extensions;
2458 
2459     while (tmp != NULL) {
2460       LIBMTP_device_extension_t *next = tmp->next;
2461 
2462       if (tmp->name)
2463         free(tmp->name);
2464       free(tmp);
2465       tmp = next;
2466     }
2467   }
2468   free(device);
2469 }
2470 
2471 /**
2472  * This can be used by any libmtp-intrinsic code that
2473  * need to stack up an error on the stack. You are only
2474  * supposed to add errors to the error stack using this
2475  * function, do not create and reference error entries
2476  * directly.
2477  */
add_error_to_errorstack(LIBMTP_mtpdevice_t * device,LIBMTP_error_number_t errornumber,char const * const error_text)2478 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2479 				    LIBMTP_error_number_t errornumber,
2480 				    char const * const error_text)
2481 {
2482   LIBMTP_error_t *newerror;
2483 
2484   if (device == NULL) {
2485     LIBMTP_ERROR("LIBMTP PANIC: Trying to add error to a NULL device!\n");
2486     return;
2487   }
2488   newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2489   newerror->errornumber = errornumber;
2490   newerror->error_text = strdup(error_text);
2491   newerror->next = NULL;
2492   if (device->errorstack == NULL) {
2493     device->errorstack = newerror;
2494   } else {
2495     LIBMTP_error_t *tmp = device->errorstack;
2496 
2497     while (tmp->next != NULL) {
2498       tmp = tmp->next;
2499     }
2500     tmp->next = newerror;
2501   }
2502 }
2503 
2504 /**
2505  * Adds an error from the PTP layer to the error stack.
2506  */
add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t * device,uint16_t ptp_error,char const * const error_text)2507 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2508 					uint16_t ptp_error,
2509 					char const * const error_text)
2510 {
2511   PTPParams      *params = (PTPParams *) device->params;
2512 
2513   if (device == NULL) {
2514     LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2515     return;
2516   } else {
2517     char outstr[256];
2518     snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2519     outstr[sizeof(outstr)-1] = '\0';
2520     add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2521 
2522     snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error, params->deviceinfo.VendorExtensionID));
2523     outstr[sizeof(outstr)-1] = '\0';
2524     add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2525   }
2526 }
2527 
2528 /**
2529  * This returns the error stack for a device in case you
2530  * need to either reference the error numbers (e.g. when
2531  * creating multilingual apps with multiple-language text
2532  * representations for each error number) or when you need
2533  * to build a multi-line error text widget or something like
2534  * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2535  * to clear it when you're finished with it.
2536  * @param device a pointer to the MTP device to get the error
2537  *        stack for.
2538  * @return the error stack or NULL if there are no errors
2539  *         on the stack.
2540  * @see LIBMTP_Clear_Errorstack()
2541  * @see LIBMTP_Dump_Errorstack()
2542  */
LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t * device)2543 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2544 {
2545   if (device == NULL) {
2546     LIBMTP_ERROR("LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2547     return NULL;
2548   }
2549   return device->errorstack;
2550 }
2551 
2552 /**
2553  * This function clears the error stack of a device and frees
2554  * any memory used by it. Call this when you're finished with
2555  * using the errors.
2556  * @param device a pointer to the MTP device to clear the error
2557  *        stack for.
2558  */
LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t * device)2559 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2560 {
2561   if (device == NULL) {
2562     LIBMTP_ERROR("LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2563   } else {
2564     LIBMTP_error_t *tmp = device->errorstack;
2565 
2566     while (tmp != NULL) {
2567       LIBMTP_error_t *tmp2;
2568 
2569       if (tmp->error_text != NULL) {
2570 	free(tmp->error_text);
2571       }
2572       tmp2 = tmp;
2573       tmp = tmp->next;
2574       free(tmp2);
2575     }
2576     device->errorstack = NULL;
2577   }
2578 }
2579 
2580 /**
2581  * This function dumps the error stack to <code>stderr</code>.
2582  * (You still have to clear the stack though.)
2583  * @param device a pointer to the MTP device to dump the error
2584  *        stack for.
2585  */
LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t * device)2586 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2587 {
2588   if (device == NULL) {
2589     LIBMTP_ERROR("LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2590   } else {
2591     LIBMTP_error_t *tmp = device->errorstack;
2592 
2593     while (tmp != NULL) {
2594       if (tmp->error_text != NULL) {
2595 	LIBMTP_ERROR("Error %d: %s\n", tmp->errornumber, tmp->error_text);
2596       } else {
2597 	LIBMTP_ERROR("Error %d: (unknown)\n", tmp->errornumber);
2598       }
2599       tmp = tmp->next;
2600     }
2601   }
2602 }
2603 
2604 /**
2605  * This command gets all handles and stuff by FAST directory retrieveal
2606  * which is available by getting all metadata for object
2607  * <code>0xffffffff</code> which simply means "all metadata for all objects".
2608  * This works on the vast majority of MTP devices (there ARE exceptions!)
2609  * and is quite quick. Check the error stack to see if there were
2610  * problems getting the metadata.
2611  * @return 0 if all was OK, -1 on failure.
2612  */
get_all_metadata_fast(LIBMTP_mtpdevice_t * device)2613 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device)
2614 {
2615   PTPParams      *params = (PTPParams *) device->params;
2616   int		 cnt = 0;
2617   int            i, j, nrofprops;
2618   uint32_t	 lasthandle = 0xffffffff;
2619   MTPProperties  *props = NULL;
2620   MTPProperties  *prop;
2621   uint16_t       ret;
2622   int            oldtimeout;
2623   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2624 
2625   /*
2626    * The follow request causes the device to generate
2627    * a list of every file on the device and return it
2628    * in a single response.
2629    *
2630    * Some slow devices as well as devices with very
2631    * large file systems can easily take longer then
2632    * the standard timeout value before it is able
2633    * to return a response.
2634    *
2635    * Temporarly set timeout to allow working with
2636    * widest range of devices.
2637    */
2638   get_usb_device_timeout(ptp_usb, &oldtimeout);
2639   set_usb_device_timeout(ptp_usb, 60000);
2640 
2641   ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2642   set_usb_device_timeout(ptp_usb, oldtimeout);
2643 
2644   if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2645     // What's the point in the device implementing this command if
2646     // you cannot use it to get all props for AT LEAST one object?
2647     // Well, whatever...
2648     add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2649     "cannot retrieve all metadata for an object on this device.");
2650     return -1;
2651   }
2652   if (ret != PTP_RC_OK) {
2653     add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2654     "could not get proplist of all objects.");
2655     return -1;
2656   }
2657   if (props == NULL && nrofprops != 0) {
2658     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2659 			    "get_all_metadata_fast(): "
2660 			    "call to ptp_mtp_getobjectproplist() returned "
2661 			    "inconsistent results.");
2662     return -1;
2663   }
2664   /*
2665    * We count the number of objects by counting the ObjectHandle
2666    * references, whenever it changes we get a new object, when it's
2667    * the same, it is just different properties of the same object.
2668    */
2669   prop = props;
2670   for (i=0;i<nrofprops;i++) {
2671       if (lasthandle != prop->ObjectHandle) {
2672 	cnt++;
2673 	lasthandle = prop->ObjectHandle;
2674       }
2675       prop++;
2676   }
2677   lasthandle = 0xffffffff;
2678   params->objects = calloc (cnt, sizeof(PTPObject));
2679   prop = props;
2680   i = -1;
2681   for (j=0;j<nrofprops;j++) {
2682     if (lasthandle != prop->ObjectHandle) {
2683       if (i >= 0) {
2684         params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2685 	if (!params->objects[i].oi.Filename) {
2686 	  /* I have one such file on my Creative (Marcus) */
2687 	  params->objects[i].oi.Filename = strdup("<null>");
2688 	}
2689       }
2690       i++;
2691       lasthandle = prop->ObjectHandle;
2692       params->objects[i].oid = prop->ObjectHandle;
2693     }
2694     switch (prop->property) {
2695     case PTP_OPC_ParentObject:
2696       params->objects[i].oi.ParentObject = prop->propval.u32;
2697       params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2698       break;
2699     case PTP_OPC_ObjectFormat:
2700       params->objects[i].oi.ObjectFormat = prop->propval.u16;
2701       break;
2702     case PTP_OPC_ObjectSize:
2703       // We loose precision here, up to 32 bits! However the commands that
2704       // retrieve metadata for files and tracks will make sure that the
2705       // PTP_OPC_ObjectSize is read in and duplicated again.
2706       if (device->object_bitsize == 64) {
2707 	params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2708       } else {
2709 	params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2710       }
2711       break;
2712     case PTP_OPC_StorageID:
2713       params->objects[i].oi.StorageID = prop->propval.u32;
2714       params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2715       break;
2716     case PTP_OPC_ObjectFileName:
2717       if (prop->propval.str != NULL)
2718         params->objects[i].oi.Filename = strdup(prop->propval.str);
2719       break;
2720     default: {
2721       MTPProperties *newprops;
2722 
2723       /* Copy all of the other MTP oprierties into the per-object proplist */
2724       if (params->objects[i].nrofmtpprops) {
2725         newprops = realloc(params->objects[i].mtpprops,
2726 		(params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2727       } else {
2728         newprops = calloc(1,sizeof(MTPProperties));
2729       }
2730       if (!newprops) return 0; /* FIXME: error handling? */
2731       params->objects[i].mtpprops = newprops;
2732       memcpy(&params->objects[i].mtpprops[params->objects[i].nrofmtpprops],
2733 	     &props[j],sizeof(props[j]));
2734       params->objects[i].nrofmtpprops++;
2735       params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2736       break;
2737     }
2738     }
2739     prop++;
2740   }
2741   /* mark last entry also */
2742   if (i >= 0) {
2743     params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2744     params->nrofobjects = i+1;
2745   } else {
2746     params->nrofobjects = 0;
2747   }
2748   free (props);
2749   /* The device might not give the list in linear ascending order */
2750   ptp_objects_sort (params);
2751   return 0;
2752 }
2753 
2754 /**
2755  * This function will recurse through all the directories on the device,
2756  * starting at the root directory, gathering metadata as it moves along.
2757  * It works better on some devices that will only return data for a
2758  * certain directory and does not respect the option to get all metadata
2759  * for all objects.
2760  */
get_handles_recursively(LIBMTP_mtpdevice_t * device,PTPParams * params,uint32_t storageid,uint32_t parent)2761 static uint16_t get_handles_recursively(LIBMTP_mtpdevice_t *device,
2762 				    PTPParams *params,
2763 				    uint32_t storageid,
2764 				    uint32_t parent)
2765 {
2766   PTPObjectHandles currentHandles;
2767   int i = 0;
2768   uint16_t ret = ptp_getobjecthandles(params,
2769                                       storageid,
2770                                       PTP_GOH_ALL_FORMATS,
2771                                       parent,
2772                                       &currentHandles);
2773 
2774   if (ret != PTP_RC_OK) {
2775     char buf[80];
2776     sprintf(buf,"get_handles_recursively(): could not get object handles of %08x", parent);
2777     add_ptp_error_to_errorstack(device, ret, buf);
2778     return ret;
2779   }
2780 
2781   if (currentHandles.Handler == NULL || currentHandles.n == 0)
2782     return PTP_RC_OK;
2783 
2784   // Now descend into any subdirectories found
2785   for (i = 0; i < currentHandles.n; i++) {
2786     PTPObject *ob;
2787     ret = ptp_object_want(params,currentHandles.Handler[i],
2788 			  PTPOBJECT_OBJECTINFO_LOADED, &ob);
2789     if (ret == PTP_RC_OK) {
2790       if (ob->oi.ObjectFormat == PTP_OFC_Association)
2791         get_handles_recursively(device, params,
2792 				storageid, currentHandles.Handler[i]);
2793     } else {
2794       add_error_to_errorstack(device,
2795 			      LIBMTP_ERROR_CONNECTING,
2796 			      "Found a bad handle, trying to ignore it.");
2797       return ret;
2798     }
2799   }
2800   free(currentHandles.Handler);
2801   return PTP_RC_OK;
2802 }
2803 
2804 /**
2805  * This function refresh the internal handle list whenever
2806  * the items stored inside the device is altered. On operations
2807  * that do not add or remove objects, this is typically not
2808  * called.
2809  * @param device a pointer to the MTP device to flush handles for.
2810  */
flush_handles(LIBMTP_mtpdevice_t * device)2811 static void flush_handles(LIBMTP_mtpdevice_t *device)
2812 {
2813   PTPParams *params = (PTPParams *) device->params;
2814   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2815   int ret;
2816   uint32_t i;
2817 
2818   if (!device->cached) {
2819     return;
2820   }
2821 
2822   if (params->objects != NULL) {
2823     for (i=0;i<params->nrofobjects;i++)
2824       ptp_free_object (&params->objects[i]);
2825     free(params->objects);
2826     params->objects = NULL;
2827     params->nrofobjects = 0;
2828   }
2829 
2830   if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2831       && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2832       && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2833     // Use the fast method. Ignore return value for now.
2834     ret = get_all_metadata_fast(device);
2835   }
2836 
2837   // If the previous failed or returned no objects, use classic
2838   // methods instead.
2839   if (params->nrofobjects == 0) {
2840     // Get all the handles using just standard commands.
2841     if (device->storage == NULL) {
2842       get_handles_recursively(device, params,
2843 			      PTP_GOH_ALL_STORAGE,
2844 			      PTP_GOH_ROOT_PARENT);
2845     } else {
2846       // Get handles for each storage in turn.
2847       LIBMTP_devicestorage_t *storage = device->storage;
2848       while(storage != NULL) {
2849 	get_handles_recursively(device, params,
2850 				storage->id,
2851 				PTP_GOH_ROOT_PARENT);
2852 	storage = storage->next;
2853       }
2854     }
2855   }
2856 
2857   /*
2858    * Loop over the handles, fix up any NULL filenames or
2859    * keywords, then attempt to locate some default folders
2860    * in the root directory of the primary storage.
2861    */
2862   for(i = 0; i < params->nrofobjects; i++) {
2863     PTPObject *ob, *xob;
2864 
2865     ob = &params->objects[i];
2866     ret = ptp_object_want(params,params->objects[i].oid,
2867 			  PTPOBJECT_OBJECTINFO_LOADED, &xob);
2868     if (ret != PTP_RC_OK) {
2869 	LIBMTP_ERROR("broken! %x not found\n", params->objects[i].oid);
2870     }
2871     if (ob->oi.Filename == NULL)
2872       ob->oi.Filename = strdup("<null>");
2873     if (ob->oi.Keywords == NULL)
2874       ob->oi.Keywords = strdup("<null>");
2875 
2876     /* Ignore handles that point to non-folders */
2877     if(ob->oi.ObjectFormat != PTP_OFC_Association)
2878       continue;
2879     /* Only look in the root folder */
2880     if (ob->oi.ParentObject == 0xffffffffU) {
2881       LIBMTP_ERROR("object %x has parent 0xffffffff (-1) continuing anyway\n",
2882 		   ob->oid);
2883     } else if (ob->oi.ParentObject != 0x00000000U)
2884       continue;
2885     /* Only look in the primary storage */
2886     if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2887       continue;
2888 
2889     /* Is this the Music Folder */
2890     if (!strcasecmp(ob->oi.Filename, "My Music") ||
2891 	!strcasecmp(ob->oi.Filename, "My_Music") ||
2892 	!strcasecmp(ob->oi.Filename, "Music")) {
2893       device->default_music_folder = ob->oid;
2894     }
2895     else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2896 	     !strcasecmp(ob->oi.Filename, "My_Playlists") ||
2897 	     !strcasecmp(ob->oi.Filename, "Playlists")) {
2898       device->default_playlist_folder = ob->oid;
2899     }
2900     else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2901 	     !strcasecmp(ob->oi.Filename, "My_Pictures") ||
2902 	     !strcasecmp(ob->oi.Filename, "Pictures")) {
2903       device->default_picture_folder = ob->oid;
2904     }
2905     else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2906 	     !strcasecmp(ob->oi.Filename, "My_Video") ||
2907 	     !strcasecmp(ob->oi.Filename, "Video")) {
2908 	device->default_video_folder = ob->oid;
2909     }
2910     else if (!strcasecmp(ob->oi.Filename, "My Organizer") ||
2911 	     !strcasecmp(ob->oi.Filename, "My_Organizer")) {
2912       device->default_organizer_folder = ob->oid;
2913     }
2914     else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2915 	     !strcasecmp(ob->oi.Filename, "Datacasts")) {
2916       device->default_zencast_folder = ob->oid;
2917     }
2918     else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2919 	     !strcasecmp(ob->oi.Filename, "My_Albums") ||
2920 	     !strcasecmp(ob->oi.Filename, "Albums")) {
2921       device->default_album_folder = ob->oid;
2922     }
2923     else if (!strcasecmp(ob->oi.Filename, "Text") ||
2924 	     !strcasecmp(ob->oi.Filename, "Texts")) {
2925       device->default_text_folder = ob->oid;
2926     }
2927   }
2928 }
2929 
2930 /**
2931  * This function traverses a devices storage list freeing up the
2932  * strings and the structs.
2933  * @param device a pointer to the MTP device to free the storage
2934  * list for.
2935  */
free_storage_list(LIBMTP_mtpdevice_t * device)2936 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2937 {
2938   LIBMTP_devicestorage_t *storage;
2939   LIBMTP_devicestorage_t *tmp;
2940 
2941   storage = device->storage;
2942   while(storage != NULL) {
2943     if (storage->StorageDescription != NULL) {
2944       free(storage->StorageDescription);
2945     }
2946     if (storage->VolumeIdentifier != NULL) {
2947       free(storage->VolumeIdentifier);
2948     }
2949     tmp = storage;
2950     storage = storage->next;
2951     free(tmp);
2952   }
2953   device->storage = NULL;
2954 
2955   return;
2956 }
2957 
2958 /**
2959  * This function traverses a devices storage list freeing up the
2960  * strings and the structs.
2961  * @param device a pointer to the MTP device to free the storage
2962  * list for.
2963  */
sort_storage_by(LIBMTP_mtpdevice_t * device,int const sortby)2964 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2965 {
2966   LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2967 
2968   if (device->storage == NULL)
2969     return -1;
2970   if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2971     return 0;
2972 
2973   oldhead = ptr1 = ptr2 = device->storage;
2974 
2975   newlist = NULL;
2976 
2977   while(oldhead != NULL) {
2978     ptr1 = ptr2 = oldhead;
2979     while(ptr1 != NULL) {
2980 
2981       if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2982         ptr2 = ptr1;
2983       if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2984         ptr2 = ptr1;
2985 
2986       ptr1 = ptr1->next;
2987     }
2988 
2989     // Make our previous entries next point to our next
2990     if(ptr2->prev != NULL) {
2991       ptr1 = ptr2->prev;
2992       ptr1->next = ptr2->next;
2993     } else {
2994       oldhead = ptr2->next;
2995       if(oldhead != NULL)
2996         oldhead->prev = NULL;
2997     }
2998 
2999     // Make our next entries previous point to our previous
3000     ptr1 = ptr2->next;
3001     if(ptr1 != NULL) {
3002       ptr1->prev = ptr2->prev;
3003     } else {
3004       ptr1 = ptr2->prev;
3005       if(ptr1 != NULL)
3006         ptr1->next = NULL;
3007     }
3008 
3009     if(newlist == NULL) {
3010       newlist = ptr2;
3011       newlist->prev = NULL;
3012     } else {
3013       ptr2->prev = newlist;
3014       newlist->next = ptr2;
3015       newlist = newlist->next;
3016     }
3017   }
3018 
3019   if (newlist != NULL) {
3020     newlist->next = NULL;
3021     while(newlist->prev != NULL)
3022       newlist = newlist->prev;
3023     device->storage = newlist;
3024   }
3025 
3026   return 0;
3027 }
3028 
3029 /**
3030  * This function grabs the first writeable storageid from the
3031  * device storage list.
3032  * @param device a pointer to the MTP device to locate writeable
3033  *        storage for.
3034  * @param fitsize a file of this file must fit on the device.
3035  */
get_writeable_storageid(LIBMTP_mtpdevice_t * device,uint64_t fitsize)3036 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
3037 					uint64_t fitsize)
3038 {
3039   LIBMTP_devicestorage_t *storage;
3040   uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
3041   int subcall_ret;
3042 
3043   // See if there is some storage we can fit this file on.
3044   storage = device->storage;
3045   if (storage == NULL) {
3046     // Sometimes the storage just cannot be detected.
3047     store = 0x00000000U;
3048   } else {
3049     while(storage != NULL) {
3050       // These storages cannot be used.
3051       if (storage->StorageType == PTP_ST_FixedROM ||
3052 	  storage->StorageType == PTP_ST_RemovableROM) {
3053 	storage = storage->next;
3054 	continue;
3055       }
3056       // Storage IDs with the lower 16 bits 0x0000 are not supposed
3057       // to be writeable.
3058       if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
3059 	storage = storage->next;
3060 	continue;
3061       }
3062       // Also check the access capability to avoid e.g. deletable only storages
3063       if (storage->AccessCapability == PTP_AC_ReadOnly ||
3064 	  storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
3065 	storage = storage->next;
3066 	continue;
3067       }
3068       // Then see if we can fit the file.
3069       subcall_ret = check_if_file_fits(device, storage, fitsize);
3070       if (subcall_ret != 0) {
3071 	storage = storage->next;
3072       } else {
3073 	// We found a storage that is writable and can fit the file!
3074 	break;
3075       }
3076     }
3077     if (storage == NULL) {
3078       add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL,
3079 			      "get_writeable_storageid(): "
3080 			      "all device storage is full or corrupt.");
3081       return -1;
3082     }
3083     store = storage->id;
3084   }
3085 
3086   return store;
3087 }
3088 
3089 /**
3090  * Tries to suggest a storage_id of a given ID when we have a parent
3091  * @param device a pointer to the device where to search for the storage ID
3092  * @param fitsize a file of this file must fit on the device.
3093  * @param parent_id look for this ID
3094  * @ret storageID
3095  */
get_suggested_storage_id(LIBMTP_mtpdevice_t * device,uint64_t fitsize,uint32_t parent_id)3096 static int get_suggested_storage_id(LIBMTP_mtpdevice_t *device,
3097 				    uint64_t fitsize,
3098 				    uint32_t parent_id)
3099 {
3100   PTPParams *params = (PTPParams *) device->params;
3101   PTPObject *ob;
3102   uint16_t ret;
3103 
3104   ret = ptp_object_want(params, parent_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
3105   if ((ret != PTP_RC_OK) || (ob->oi.StorageID == 0)) {
3106     add_ptp_error_to_errorstack(device, ret, "get_suggested_storage_id(): "
3107 				"could not get storage id from parent id.");
3108     return get_writeable_storageid(device, fitsize);
3109   } else {
3110     /* OK we know the parent storage, then use that */
3111     return ob->oi.StorageID;
3112   }
3113 }
3114 
3115 /**
3116  * This function grabs the freespace from a certain storage in
3117  * device storage list.
3118  * @param device a pointer to the MTP device to free the storage
3119  * list for.
3120  * @param storageid the storage ID for the storage to flush and
3121  * get free space for.
3122  * @param freespace the free space on this storage will be returned
3123  * in this variable.
3124  */
get_storage_freespace(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t * freespace)3125 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
3126 				 LIBMTP_devicestorage_t *storage,
3127 				 uint64_t *freespace)
3128 {
3129   PTPParams *params = (PTPParams *) device->params;
3130 
3131   // Always query the device about this, since some models explicitly
3132   // needs that. We flush all data on queries storage here.
3133   if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3134     PTPStorageInfo storageInfo;
3135     uint16_t ret;
3136 
3137     ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
3138     if (ret != PTP_RC_OK) {
3139       add_ptp_error_to_errorstack(device, ret,
3140 		"get_storage_freespace(): could not get storage info.");
3141       return -1;
3142     }
3143     if (storage->StorageDescription != NULL) {
3144       free(storage->StorageDescription);
3145     }
3146     if (storage->VolumeIdentifier != NULL) {
3147       free(storage->VolumeIdentifier);
3148     }
3149     storage->StorageType = storageInfo.StorageType;
3150     storage->FilesystemType = storageInfo.FilesystemType;
3151     storage->AccessCapability = storageInfo.AccessCapability;
3152     storage->MaxCapacity = storageInfo.MaxCapability;
3153     storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3154     storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3155     storage->StorageDescription = storageInfo.StorageDescription;
3156     storage->VolumeIdentifier = storageInfo.VolumeLabel;
3157   }
3158   if(storage->FreeSpaceInBytes == (uint64_t) -1)
3159     return -1;
3160   *freespace = storage->FreeSpaceInBytes;
3161   return 0;
3162 }
3163 
3164 /**
3165  * This function dumps out a large chunk of textual information
3166  * provided from the PTP protocol and additionally some extra
3167  * MTP-specific information where applicable.
3168  * @param device a pointer to the MTP device to report info from.
3169  */
LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t * device)3170 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
3171 {
3172   int i;
3173   PTPParams *params = (PTPParams *) device->params;
3174   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3175   LIBMTP_devicestorage_t *storage = device->storage;
3176   LIBMTP_device_extension_t *tmpext = device->extensions;
3177 
3178   printf("USB low-level info:\n");
3179   dump_usbinfo(ptp_usb);
3180   /* Print out some verbose information */
3181   printf("Device info:\n");
3182   printf("   Manufacturer: %s\n", params->deviceinfo.Manufacturer);
3183   printf("   Model: %s\n", params->deviceinfo.Model);
3184   printf("   Device version: %s\n", params->deviceinfo.DeviceVersion);
3185   printf("   Serial number: %s\n", params->deviceinfo.SerialNumber);
3186   printf("   Vendor extension ID: 0x%08x\n",
3187 	 params->deviceinfo.VendorExtensionID);
3188   printf("   Vendor extension description: %s\n",
3189 	 params->deviceinfo.VendorExtensionDesc);
3190   printf("   Detected object size: %d bits\n",
3191 	 device->object_bitsize);
3192   printf("   Extensions:\n");
3193   while (tmpext != NULL) {
3194     printf("        %s: %d.%d\n",
3195            tmpext->name,
3196            tmpext->major,
3197            tmpext->minor);
3198     tmpext = tmpext->next;
3199   }
3200   printf("Supported operations:\n");
3201   for (i=0;i<params->deviceinfo.OperationsSupported_len;i++)
3202     printf("   %04x: %s\n", params->deviceinfo.OperationsSupported[i], ptp_get_opcode_name(params, params->deviceinfo.OperationsSupported[i]));
3203   printf("Events supported:\n");
3204   if (params->deviceinfo.EventsSupported_len == 0) {
3205     printf("   None.\n");
3206   } else {
3207     for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
3208       printf("   0x%04x: %s\n", params->deviceinfo.EventsSupported[i], ptp_get_event_code_name(params, params->deviceinfo.EventsSupported[i]));
3209     }
3210   }
3211   printf("Device Properties Supported:\n");
3212   for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
3213     char const *propdesc = ptp_get_property_description(params,
3214 			params->deviceinfo.DevicePropertiesSupported[i]);
3215 
3216     if (propdesc != NULL) {
3217       printf("   0x%04x: %s\n",
3218 	     params->deviceinfo.DevicePropertiesSupported[i], propdesc);
3219     } else {
3220       uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
3221       printf("   0x%04x: Unknown property\n", prop);
3222     }
3223   }
3224 
3225   if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
3226     printf("Playable File (Object) Types and Object Properties Supported:\n");
3227     for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3228       char txt[256];
3229       uint16_t ret;
3230       uint16_t *props = NULL;
3231       uint32_t propcnt = 0;
3232       int j;
3233 
3234       (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i],
3235 			     sizeof(txt), txt);
3236       printf("   %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
3237 
3238       ret = ptp_mtp_getobjectpropssupported (params,
3239 			params->deviceinfo.ImageFormats[i], &propcnt, &props);
3240       if (ret != PTP_RC_OK) {
3241 	add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): "
3242 				    "error on query for object properties.");
3243       } else {
3244 	for (j=0;j<propcnt;j++) {
3245 	  PTPObjectPropDesc opd;
3246 	  int k;
3247 
3248 	  printf("      %04x: %s", props[j],
3249 		 LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
3250 	  // Get a more verbose description
3251 	  ret = ptp_mtp_getobjectpropdesc(params, props[j],
3252 					  params->deviceinfo.ImageFormats[i],
3253 					  &opd);
3254 	  if (ret != PTP_RC_OK) {
3255 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3256 				    "LIBMTP_Dump_Device_Info(): "
3257 				    "could not get property description.");
3258 	    break;
3259 	  }
3260 
3261 	  if (opd.DataType == PTP_DTC_STR) {
3262 	    printf(" STRING data type");
3263 	    switch (opd.FormFlag) {
3264 	    case PTP_OPFF_DateTime:
3265 	      printf(" DATETIME FORM");
3266 	      break;
3267 	    case PTP_OPFF_RegularExpression:
3268 	      printf(" REGULAR EXPRESSION FORM");
3269 	      break;
3270 	    case PTP_OPFF_LongString:
3271 	      printf(" LONG STRING FORM");
3272 	      break;
3273 	    default:
3274 	      break;
3275 	    }
3276 	  } else {
3277 	    if (opd.DataType & PTP_DTC_ARRAY_MASK) {
3278 	      printf(" array of");
3279 	    }
3280 
3281 	    switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
3282 
3283 	    case PTP_DTC_UNDEF:
3284 	      printf(" UNDEFINED data type");
3285 	      break;
3286 	    case PTP_DTC_INT8:
3287 	      printf(" INT8 data type");
3288 	      switch (opd.FormFlag) {
3289 	      case PTP_OPFF_Range:
3290 		printf(" range: MIN %d, MAX %d, STEP %d",
3291 		       opd.FORM.Range.MinimumValue.i8,
3292 		       opd.FORM.Range.MaximumValue.i8,
3293 		       opd.FORM.Range.StepSize.i8);
3294 		break;
3295 	      case PTP_OPFF_Enumeration:
3296 		printf(" enumeration: ");
3297 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3298 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
3299 		}
3300 		break;
3301 	      case PTP_OPFF_ByteArray:
3302 		printf(" byte array: ");
3303 		break;
3304 	      default:
3305 		printf(" ANY 8BIT VALUE form");
3306 		break;
3307 	      }
3308 	      break;
3309 
3310 	    case PTP_DTC_UINT8:
3311 	      printf(" UINT8 data type");
3312 	      switch (opd.FormFlag) {
3313 	      case PTP_OPFF_Range:
3314 		printf(" range: MIN %d, MAX %d, STEP %d",
3315 		       opd.FORM.Range.MinimumValue.u8,
3316 		       opd.FORM.Range.MaximumValue.u8,
3317 		       opd.FORM.Range.StepSize.u8);
3318 		break;
3319 	      case PTP_OPFF_Enumeration:
3320 		printf(" enumeration: ");
3321 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3322 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
3323 		}
3324 		break;
3325 	      case PTP_OPFF_ByteArray:
3326 		printf(" byte array: ");
3327 		break;
3328 	      default:
3329 		printf(" ANY 8BIT VALUE form");
3330 		break;
3331 	      }
3332 	      break;
3333 
3334 	    case PTP_DTC_INT16:
3335 	      printf(" INT16 data type");
3336 	      switch (opd.FormFlag) {
3337 	      case PTP_OPFF_Range:
3338 	      printf(" range: MIN %d, MAX %d, STEP %d",
3339 		     opd.FORM.Range.MinimumValue.i16,
3340 		     opd.FORM.Range.MaximumValue.i16,
3341 		     opd.FORM.Range.StepSize.i16);
3342 	      break;
3343 	      case PTP_OPFF_Enumeration:
3344 		printf(" enumeration: ");
3345 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3346 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3347 		}
3348 		break;
3349 	      default:
3350 		printf(" ANY 16BIT VALUE form");
3351 		break;
3352 	      }
3353 	      break;
3354 
3355 	    case PTP_DTC_UINT16:
3356 	      printf(" UINT16 data type");
3357 	      switch (opd.FormFlag) {
3358 	      case PTP_OPFF_Range:
3359 		printf(" range: MIN %d, MAX %d, STEP %d",
3360 		       opd.FORM.Range.MinimumValue.u16,
3361 		       opd.FORM.Range.MaximumValue.u16,
3362 		       opd.FORM.Range.StepSize.u16);
3363 		break;
3364 	      case PTP_OPFF_Enumeration:
3365 		printf(" enumeration: ");
3366 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3367 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3368 		}
3369 		break;
3370 	      default:
3371 		printf(" ANY 16BIT VALUE form");
3372 		break;
3373 	      }
3374 	      break;
3375 
3376 	    case PTP_DTC_INT32:
3377 	      printf(" INT32 data type");
3378 	      switch (opd.FormFlag) {
3379 	      case PTP_OPFF_Range:
3380 		printf(" range: MIN %d, MAX %d, STEP %d",
3381 		       opd.FORM.Range.MinimumValue.i32,
3382 		       opd.FORM.Range.MaximumValue.i32,
3383 		       opd.FORM.Range.StepSize.i32);
3384 		break;
3385 	      case PTP_OPFF_Enumeration:
3386 		printf(" enumeration: ");
3387 		for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3388 		  printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3389 		}
3390 		break;
3391 	      default:
3392 		printf(" ANY 32BIT VALUE form");
3393 		break;
3394 	      }
3395 	      break;
3396 
3397 	    case PTP_DTC_UINT32:
3398 	      printf(" UINT32 data type");
3399 	      switch (opd.FormFlag) {
3400 	      case PTP_OPFF_Range:
3401 		printf(" range: MIN %u, MAX %u, STEP %u",
3402 		       opd.FORM.Range.MinimumValue.u32,
3403 		       opd.FORM.Range.MaximumValue.u32,
3404 		       opd.FORM.Range.StepSize.u32);
3405 		break;
3406 	      case PTP_OPFF_Enumeration:
3407 		// Special pretty-print for FOURCC codes
3408 		if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3409 		  printf(" enumeration of u32 casted FOURCC: ");
3410 		  for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3411 		    if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3412 		      printf("ANY, ");
3413 		    } else {
3414 		      char fourcc[6];
3415 		      fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3416 		      fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3417 		      fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3418 		      fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3419 		      fourcc[4] = '\n';
3420 		      fourcc[5] = '\0';
3421 		      printf("\"%s\", ", fourcc);
3422 		    }
3423 		  }
3424 		} else {
3425 		  printf(" enumeration: ");
3426 		  for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3427 		    printf("%u, ", opd.FORM.Enum.SupportedValue[k].u32);
3428 		  }
3429 		}
3430 		break;
3431 	      default:
3432 		printf(" ANY 32BIT VALUE form");
3433 		break;
3434 	      }
3435 	      break;
3436 
3437 	    case PTP_DTC_INT64:
3438 	      printf(" INT64 data type");
3439 	      break;
3440 
3441 	    case PTP_DTC_UINT64:
3442 	      printf(" UINT64 data type");
3443 	      break;
3444 
3445 	    case PTP_DTC_INT128:
3446 	      printf(" INT128 data type");
3447 	      break;
3448 
3449 	    case PTP_DTC_UINT128:
3450 	      printf(" UINT128 data type");
3451 	      break;
3452 
3453 	    default:
3454 	      printf(" UNKNOWN data type");
3455 	      break;
3456 	    }
3457 	  }
3458 	  if (opd.GetSet) {
3459 	    printf(" GET/SET");
3460 	  } else {
3461 	    printf(" READ ONLY");
3462 	  }
3463 	  printf(" GROUP 0x%x", opd.GroupCode);
3464 
3465 	  printf("\n");
3466 	  ptp_free_objectpropdesc(&opd);
3467 	}
3468 	free(props);
3469       }
3470     }
3471   }
3472 
3473   if(storage != NULL &&
3474      ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3475     printf("Storage Devices:\n");
3476     while(storage != NULL) {
3477       printf("   StorageID: 0x%08x\n",storage->id);
3478       printf("      StorageType: 0x%04x ",storage->StorageType);
3479       switch (storage->StorageType) {
3480       case PTP_ST_Undefined:
3481 	printf("(undefined)\n");
3482 	break;
3483       case PTP_ST_FixedROM:
3484 	printf("fixed ROM storage\n");
3485 	break;
3486       case PTP_ST_RemovableROM:
3487 	printf("removable ROM storage\n");
3488 	break;
3489       case PTP_ST_FixedRAM:
3490 	printf("fixed RAM storage\n");
3491 	break;
3492       case PTP_ST_RemovableRAM:
3493 	printf("removable RAM storage\n");
3494 	break;
3495       default:
3496 	printf("UNKNOWN storage\n");
3497 	break;
3498       }
3499       printf("      FilesystemType: 0x%04x ",storage->FilesystemType);
3500       switch(storage->FilesystemType) {
3501       case PTP_FST_Undefined:
3502 	printf("(undefined)\n");
3503 	break;
3504       case PTP_FST_GenericFlat:
3505 	printf("generic flat filesystem\n");
3506 	break;
3507       case PTP_FST_GenericHierarchical:
3508 	printf("generic hierarchical\n");
3509 	break;
3510       case PTP_FST_DCF:
3511 	printf("DCF\n");
3512 	break;
3513       default:
3514 	printf("UNKNONWN filesystem type\n");
3515 	break;
3516       }
3517       printf("      AccessCapability: 0x%04x ",storage->AccessCapability);
3518       switch(storage->AccessCapability) {
3519       case PTP_AC_ReadWrite:
3520 	printf("read/write\n");
3521 	break;
3522       case PTP_AC_ReadOnly:
3523 	printf("read only\n");
3524 	break;
3525       case PTP_AC_ReadOnly_with_Object_Deletion:
3526 	printf("read only + object deletion\n");
3527 	break;
3528       default:
3529 	printf("UNKNOWN access capability\n");
3530 	break;
3531       }
3532       printf("      MaxCapacity: %llu\n",
3533 	     (long long unsigned int) storage->MaxCapacity);
3534       printf("      FreeSpaceInBytes: %llu\n",
3535 	     (long long unsigned int) storage->FreeSpaceInBytes);
3536       printf("      FreeSpaceInObjects: %llu\n",
3537 	     (long long unsigned int) storage->FreeSpaceInObjects);
3538       printf("      StorageDescription: %s\n",storage->StorageDescription);
3539       printf("      VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3540       storage = storage->next;
3541     }
3542   }
3543 
3544   printf("Special directories:\n");
3545   printf("   Default music folder: 0x%08x\n",
3546 	 device->default_music_folder);
3547   printf("   Default playlist folder: 0x%08x\n",
3548 	 device->default_playlist_folder);
3549   printf("   Default picture folder: 0x%08x\n",
3550 	 device->default_picture_folder);
3551   printf("   Default video folder: 0x%08x\n",
3552 	 device->default_video_folder);
3553   printf("   Default organizer folder: 0x%08x\n",
3554 	 device->default_organizer_folder);
3555   printf("   Default zencast folder: 0x%08x\n",
3556 	 device->default_zencast_folder);
3557   printf("   Default album folder: 0x%08x\n",
3558 	 device->default_album_folder);
3559   printf("   Default text folder: 0x%08x\n",
3560 	 device->default_text_folder);
3561 }
3562 
3563 /**
3564  * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3565  * operation code (0x1010).
3566  * @param device a pointer to the device to reset.
3567  * @return 0 on success, any other value means failure.
3568  */
LIBMTP_Reset_Device(LIBMTP_mtpdevice_t * device)3569 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3570 {
3571   PTPParams *params = (PTPParams *) device->params;
3572   uint16_t ret;
3573 
3574   if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3575     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3576 			    "LIBMTP_Reset_Device(): "
3577 			    "device does not support resetting.");
3578     return -1;
3579   }
3580   ret = ptp_resetdevice(params);
3581   if (ret != PTP_RC_OK) {
3582     add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3583     return -1;
3584   }
3585   return 0;
3586 }
3587 
3588 /**
3589  * This retrieves the manufacturer name of an MTP device.
3590  * @param device a pointer to the device to get the manufacturer name for.
3591  * @return a newly allocated UTF-8 string representing the manufacturer name.
3592  *         The string must be freed by the caller after use. If the call
3593  *         was unsuccessful this will contain NULL.
3594  */
LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t * device)3595 char *LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t *device)
3596 {
3597   char *retmanuf = NULL;
3598   PTPParams *params = (PTPParams *) device->params;
3599 
3600   if (params->deviceinfo.Manufacturer != NULL) {
3601     retmanuf = strdup(params->deviceinfo.Manufacturer);
3602   }
3603   return retmanuf;
3604 }
3605 
3606 /**
3607  * This retrieves the model name (often equal to product name)
3608  * of an MTP device.
3609  * @param device a pointer to the device to get the model name for.
3610  * @return a newly allocated UTF-8 string representing the model name.
3611  *         The string must be freed by the caller after use. If the call
3612  *         was unsuccessful this will contain NULL.
3613  */
LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t * device)3614 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3615 {
3616   char *retmodel = NULL;
3617   PTPParams *params = (PTPParams *) device->params;
3618 
3619   if (params->deviceinfo.Model != NULL) {
3620     retmodel = strdup(params->deviceinfo.Model);
3621   }
3622   return retmodel;
3623 }
3624 
3625 /**
3626  * This retrieves the serial number of an MTP device.
3627  * @param device a pointer to the device to get the serial number for.
3628  * @return a newly allocated UTF-8 string representing the serial number.
3629  *         The string must be freed by the caller after use. If the call
3630  *         was unsuccessful this will contain NULL.
3631  */
LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t * device)3632 char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
3633 {
3634   char *retnumber = NULL;
3635   PTPParams *params = (PTPParams *) device->params;
3636 
3637   if (params->deviceinfo.SerialNumber != NULL) {
3638     retnumber = strdup(params->deviceinfo.SerialNumber);
3639   }
3640   return retnumber;
3641 }
3642 
3643 /**
3644  * This retrieves the device version (hardware and firmware version) of an
3645  * MTP device.
3646  * @param device a pointer to the device to get the device version for.
3647  * @return a newly allocated UTF-8 string representing the device version.
3648  *         The string must be freed by the caller after use. If the call
3649  *         was unsuccessful this will contain NULL.
3650  */
LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t * device)3651 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3652 {
3653   char *retversion = NULL;
3654   PTPParams *params = (PTPParams *) device->params;
3655 
3656   if (params->deviceinfo.DeviceVersion != NULL) {
3657     retversion = strdup(params->deviceinfo.DeviceVersion);
3658   }
3659   return retversion;
3660 }
3661 
3662 
3663 /**
3664  * This retrieves the "friendly name" of an MTP device. Usually
3665  * this is simply the name of the owner or something like
3666  * "John Doe's Digital Audio Player". This property should be supported
3667  * by all MTP devices.
3668  * @param device a pointer to the device to get the friendly name for.
3669  * @return a newly allocated UTF-8 string representing the friendly name.
3670  *         The string must be freed by the caller after use.
3671  * @see LIBMTP_Set_Friendlyname()
3672  */
LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t * device)3673 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3674 {
3675   PTPPropertyValue propval;
3676   char *retstring = NULL;
3677   PTPParams *params = (PTPParams *) device->params;
3678   uint16_t ret;
3679 
3680   if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3681     return NULL;
3682   }
3683 
3684   ret = ptp_getdevicepropvalue(params,
3685 			       PTP_DPC_MTP_DeviceFriendlyName,
3686 			       &propval,
3687 			       PTP_DTC_STR);
3688   if (ret != PTP_RC_OK) {
3689     add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3690     return NULL;
3691   }
3692   if (propval.str != NULL) {
3693     retstring = strdup(propval.str);
3694     free(propval.str);
3695   }
3696   return retstring;
3697 }
3698 
3699 /**
3700  * Sets the "friendly name" of an MTP device.
3701  * @param device a pointer to the device to set the friendly name for.
3702  * @param friendlyname the new friendly name for the device.
3703  * @return 0 on success, any other value means failure.
3704  * @see LIBMTP_Get_Friendlyname()
3705  */
LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t * device,char const * const friendlyname)3706 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3707 			 char const * const friendlyname)
3708 {
3709   PTPPropertyValue propval;
3710   PTPParams *params = (PTPParams *) device->params;
3711   uint16_t ret;
3712 
3713   if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3714     return -1;
3715   }
3716   propval.str = (char *) friendlyname;
3717   ret = ptp_setdevicepropvalue(params,
3718 			       PTP_DPC_MTP_DeviceFriendlyName,
3719 			       &propval,
3720 			       PTP_DTC_STR);
3721   if (ret != PTP_RC_OK) {
3722     add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3723     return -1;
3724   }
3725   return 0;
3726 }
3727 
3728 /**
3729  * This retrieves the synchronization partner of an MTP device. This
3730  * property should be supported by all MTP devices.
3731  * @param device a pointer to the device to get the sync partner for.
3732  * @return a newly allocated UTF-8 string representing the synchronization
3733  *         partner. The string must be freed by the caller after use.
3734  * @see LIBMTP_Set_Syncpartner()
3735  */
LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t * device)3736 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3737 {
3738   PTPPropertyValue propval;
3739   char *retstring = NULL;
3740   PTPParams *params = (PTPParams *) device->params;
3741   uint16_t ret;
3742 
3743   if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3744     return NULL;
3745   }
3746 
3747   ret = ptp_getdevicepropvalue(params,
3748 			       PTP_DPC_MTP_SynchronizationPartner,
3749 			       &propval,
3750 			       PTP_DTC_STR);
3751   if (ret != PTP_RC_OK) {
3752     add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3753     return NULL;
3754   }
3755   if (propval.str != NULL) {
3756     retstring = strdup(propval.str);
3757     free(propval.str);
3758   }
3759   return retstring;
3760 }
3761 
3762 
3763 /**
3764  * Sets the synchronization partner of an MTP device. Note that
3765  * we have no idea what the effect of setting this to "foobar"
3766  * may be. But the general idea seems to be to tell which program
3767  * shall synchronize with this device and tell others to leave
3768  * it alone.
3769  * @param device a pointer to the device to set the sync partner for.
3770  * @param syncpartner the new synchronization partner for the device.
3771  * @return 0 on success, any other value means failure.
3772  * @see LIBMTP_Get_Syncpartner()
3773  */
LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t * device,char const * const syncpartner)3774 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3775 			 char const * const syncpartner)
3776 {
3777   PTPPropertyValue propval;
3778   PTPParams *params = (PTPParams *) device->params;
3779   uint16_t ret;
3780 
3781   if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3782     return -1;
3783   }
3784   propval.str = (char *) syncpartner;
3785   ret = ptp_setdevicepropvalue(params,
3786 			       PTP_DPC_MTP_SynchronizationPartner,
3787 			       &propval,
3788 			       PTP_DTC_STR);
3789   if (ret != PTP_RC_OK) {
3790     add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3791     return -1;
3792   }
3793   return 0;
3794 }
3795 
3796 /**
3797  * Checks if the device can stora a file of this size or
3798  * if it's too big.
3799  * @param device a pointer to the device.
3800  * @param filesize the size of the file to check whether it will fit.
3801  * @param storageid the ID of the storage to try to fit the file on.
3802  * @return 0 if the file fits, any other value means failure.
3803  */
check_if_file_fits(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t const filesize)3804 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3805 			      LIBMTP_devicestorage_t *storage,
3806 			      uint64_t const filesize) {
3807   PTPParams *params = (PTPParams *) device->params;
3808   uint64_t freebytes;
3809   int ret;
3810 
3811   // If we cannot check the storage, no big deal.
3812   if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3813     return 0;
3814   }
3815 
3816   ret = get_storage_freespace(device, storage, &freebytes);
3817   if (ret != 0) {
3818     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3819 			    "check_if_file_fits(): error checking free storage.");
3820     return -1;
3821   } else {
3822     // See if it fits.
3823     if (filesize > freebytes) {
3824       return -1;
3825     }
3826   }
3827   return 0;
3828 }
3829 
3830 
3831 /**
3832  * This function retrieves the current battery level on the device.
3833  * @param device a pointer to the device to get the battery level for.
3834  * @param maximum_level a pointer to a variable that will hold the
3835  *        maximum level of the battery if the call was successful.
3836  * @param current_level a pointer to a variable that will hold the
3837  *        current level of the battery if the call was successful.
3838  *        A value of 0 means that the device is on external power.
3839  * @return 0 if the storage info was successfully retrieved, any other
3840  *        means failure. A typical cause of failure is that
3841  *        the device does not support the battery level property.
3842  */
LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t * device,uint8_t * const maximum_level,uint8_t * const current_level)3843 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3844 			    uint8_t * const maximum_level,
3845 			    uint8_t * const current_level)
3846 {
3847   PTPPropertyValue propval;
3848   uint16_t ret;
3849   PTPParams *params = (PTPParams *) device->params;
3850   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3851 
3852   *maximum_level = 0;
3853   *current_level = 0;
3854 
3855   if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3856       !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3857     return -1;
3858   }
3859 
3860   ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel,
3861 			       &propval, PTP_DTC_UINT8);
3862   if (ret != PTP_RC_OK) {
3863     add_ptp_error_to_errorstack(device, ret,
3864 				"LIBMTP_Get_Batterylevel(): "
3865 				"could not get device property value.");
3866     return -1;
3867   }
3868 
3869   *maximum_level = device->maximum_battery_level;
3870   *current_level = propval.u8;
3871 
3872   return 0;
3873 }
3874 
3875 
3876 /**
3877  * Formats device storage (if the device supports the operation).
3878  * WARNING: This WILL delete all data from the device. Make sure you've
3879  * got confirmation from the user BEFORE you call this function.
3880  *
3881  * @param device a pointer to the device containing the storage to format.
3882  * @param storage the actual storage to format.
3883  * @return 0 on success, any other value means failure.
3884  */
LIBMTP_Format_Storage(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage)3885 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device,
3886 			  LIBMTP_devicestorage_t *storage)
3887 {
3888   uint16_t ret;
3889   PTPParams *params = (PTPParams *) device->params;
3890 
3891   if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3892     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3893 			    "LIBMTP_Format_Storage(): "
3894 			    "device does not support formatting storage.");
3895     return -1;
3896   }
3897   ret = ptp_formatstore(params, storage->id);
3898   if (ret != PTP_RC_OK) {
3899     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): "
3900 				"failed to format storage.");
3901     return -1;
3902   }
3903   return 0;
3904 }
3905 
3906 /**
3907  * Helper function to extract a unicode property off a device.
3908  * This is the standard way of retrieveing unicode device
3909  * properties as described by the PTP spec.
3910  * @param device a pointer to the device to get the property from.
3911  * @param unicstring a pointer to a pointer that will hold the
3912  *        property after this call is completed.
3913  * @param property the property to retrieve.
3914  * @return 0 on success, any other value means failure.
3915  */
get_device_unicode_property(LIBMTP_mtpdevice_t * device,char ** unicstring,uint16_t property)3916 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3917 				       char **unicstring, uint16_t property)
3918 {
3919   PTPPropertyValue propval;
3920   PTPParams *params = (PTPParams *) device->params;
3921   uint16_t *tmp;
3922   uint16_t ret;
3923   int i;
3924 
3925   if (!ptp_property_issupported(params, property)) {
3926     return -1;
3927   }
3928 
3929   // Unicode strings are 16bit unsigned integer arrays.
3930   ret = ptp_getdevicepropvalue(params,
3931 			       property,
3932 			       &propval,
3933 			       PTP_DTC_AUINT16);
3934   if (ret != PTP_RC_OK) {
3935     // TODO: add a note on WHICH property that we failed to get.
3936     *unicstring = NULL;
3937     add_ptp_error_to_errorstack(device, ret,
3938 				"get_device_unicode_property(): "
3939 				"failed to get unicode property.");
3940     return -1;
3941   }
3942 
3943   // Extract the actual array.
3944   // printf("Array of %d elements\n", propval.a.count);
3945   tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3946   for (i = 0; i < propval.a.count; i++) {
3947     tmp[i] = propval.a.v[i].u16;
3948     // printf("%04x ", tmp[i]);
3949   }
3950   tmp[propval.a.count] = 0x0000U;
3951   free(propval.a.v);
3952 
3953   *unicstring = utf16_to_utf8(device, tmp);
3954 
3955   free(tmp);
3956 
3957   return 0;
3958 }
3959 
3960 /**
3961  * This function returns the secure time as an XML document string from
3962  * the device.
3963  * @param device a pointer to the device to get the secure time for.
3964  * @param sectime the secure time string as an XML document or NULL if the call
3965  *         failed or the secure time property is not supported. This string
3966  *         must be <code>free()</code>:ed by the caller after use.
3967  * @return 0 on success, any other value means failure.
3968  */
LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t * device,char ** const sectime)3969 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3970 {
3971   return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3972 }
3973 
3974 /**
3975  * This function returns the device (public key) certificate as an
3976  * XML document string from the device.
3977  * @param device a pointer to the device to get the device certificate for.
3978  * @param devcert the device certificate as an XML string or NULL if the call
3979  *        failed or the device certificate property is not supported. This
3980  *        string must be <code>free()</code>:ed by the caller after use.
3981  * @return 0 on success, any other value means failure.
3982  */
LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t * device,char ** const devcert)3983 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3984 {
3985   return get_device_unicode_property(device, devcert,
3986 				     PTP_DPC_MTP_DeviceCertificate);
3987 }
3988 
3989 /**
3990  * This function retrieves a list of supported file types, i.e. the file
3991  * types that this device claims it supports, e.g. audio file types that
3992  * the device can play etc. This list is mitigated to
3993  * include the file types that libmtp can handle, i.e. it will not list
3994  * filetypes that libmtp will handle internally like playlists and folders.
3995  * @param device a pointer to the device to get the filetype capabilities for.
3996  * @param filetypes a pointer to a pointer that will hold the list of
3997  *        supported filetypes if the call was successful. This list must
3998  *        be <code>free()</code>:ed by the caller after use.
3999  * @param length a pointer to a variable that will hold the length of the
4000  *        list of supported filetypes if the call was successful.
4001  * @return 0 on success, any other value means failure.
4002  * @see LIBMTP_Get_Filetype_Description()
4003  */
LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t * device,uint16_t ** const filetypes,uint16_t * const length)4004 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
4005 				  uint16_t * const length)
4006 {
4007   PTPParams *params = (PTPParams *) device->params;
4008   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4009   uint16_t *localtypes;
4010   uint16_t localtypelen;
4011   uint32_t i;
4012 
4013   // This is more memory than needed if there are unknown types, but what the heck.
4014   localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
4015   localtypelen = 0;
4016 
4017   for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
4018     uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
4019     if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
4020       localtypes[localtypelen] = localtype;
4021       localtypelen++;
4022     }
4023   }
4024   // The forgotten Ogg support on YP-10 and others...
4025   if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
4026     uint16_t *tmp = (uint16_t *) realloc(
4027         localtypes, (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4028     if (tmp == NULL)
4029       return -ENOMEM;
4030     localtypes = tmp;
4031     localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
4032     localtypelen++;
4033   }
4034   // The forgotten FLAC support on Cowon iAudio S9 and others...
4035   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
4036     uint16_t *tmp = (uint16_t *) realloc(
4037         localtypes, (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4038     if (tmp == NULL)
4039       return -ENOMEM;
4040     localtypes = tmp;
4041     localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
4042     localtypelen++;
4043   }
4044 
4045   *filetypes = localtypes;
4046   *length = localtypelen;
4047 
4048   return 0;
4049 }
4050 
4051 /**
4052  * This function checks if the device has some specific capabilities, in
4053  * order to avoid calling APIs that may disturb the device.
4054  *
4055  * @param device a pointer to the device to check the capability on.
4056  * @param cap the capability to check.
4057  * @return 0 if not supported, any other value means the device has the
4058  * requested capability.
4059  */
LIBMTP_Check_Capability(LIBMTP_mtpdevice_t * device,LIBMTP_devicecap_t cap)4060 int LIBMTP_Check_Capability(LIBMTP_mtpdevice_t *device, LIBMTP_devicecap_t cap)
4061 {
4062   switch (cap) {
4063   case LIBMTP_DEVICECAP_GetPartialObject:
4064     return (ptp_operation_issupported(device->params,
4065 				      PTP_OC_GetPartialObject) ||
4066 	    ptp_operation_issupported(device->params,
4067 				      PTP_OC_ANDROID_GetPartialObject64));
4068   case LIBMTP_DEVICECAP_SendPartialObject:
4069     return ptp_operation_issupported(device->params,
4070 				     PTP_OC_ANDROID_SendPartialObject);
4071   case LIBMTP_DEVICECAP_EditObjects:
4072     return (ptp_operation_issupported(device->params,
4073 				      PTP_OC_ANDROID_TruncateObject) &&
4074 	    ptp_operation_issupported(device->params,
4075 				      PTP_OC_ANDROID_BeginEditObject) &&
4076 	    ptp_operation_issupported(device->params,
4077 				      PTP_OC_ANDROID_EndEditObject));
4078   case LIBMTP_DEVICECAP_MoveObject:
4079     return ptp_operation_issupported(device->params,
4080 				     PTP_OC_MoveObject);
4081   case LIBMTP_DEVICECAP_CopyObject:
4082     return ptp_operation_issupported(device->params,
4083 				     PTP_OC_CopyObject);
4084   /*
4085    * Handle other capabilities here, this is also a good place to
4086    * blacklist some advanced operations on specific devices if need
4087    * be.
4088    */
4089 
4090   default:
4091     break;
4092   }
4093   return 0;
4094 }
4095 
4096 /**
4097  * This function updates all the storage id's of a device and their
4098  * properties, then creates a linked list and puts the list head into
4099  * the device struct. It also optionally sorts this list. If you want
4100  * to display storage information in your application you should call
4101  * this function, then dereference the device struct
4102  * (<code>device-&gt;storage</code>) to get out information on the storage.
4103  *
4104  * You need to call this every time you want to update the
4105  * <code>device-&gt;storage</code> list, for example anytime you need
4106  * to check available storage somewhere.
4107  *
4108  * <b>WARNING:</b> since this list is dynamically updated, do not
4109  * reference its fields in external applications by pointer! E.g
4110  * do not put a reference to any <code>char *</code> field. instead
4111  * <code>strncpy()</code> it!
4112  *
4113  * @param device a pointer to the device to get the storage for.
4114  * @param sortby an integer that determines the sorting of the storage list.
4115  *        Valid sort methods are defined in libmtp.h with beginning with
4116  *        LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
4117  *        sort.
4118  * @return 0 on success, 1 success but only with storage id's, storage
4119  *        properities could not be retrieved and -1 means failure.
4120  */
LIBMTP_Get_Storage(LIBMTP_mtpdevice_t * device,int const sortby)4121 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
4122 {
4123   uint32_t i = 0;
4124   PTPStorageInfo storageInfo;
4125   PTPParams *params = (PTPParams *) device->params;
4126   PTPStorageIDs storageIDs;
4127   LIBMTP_devicestorage_t *storage = NULL;
4128   LIBMTP_devicestorage_t *storageprev = NULL;
4129 
4130   if (device->storage != NULL)
4131     free_storage_list(device);
4132 
4133   // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
4134   //   return -1;
4135   if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
4136     return -1;
4137   if (storageIDs.n < 1)
4138     return -1;
4139 
4140   if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
4141     for (i = 0; i < storageIDs.n; i++) {
4142 
4143       storage = (LIBMTP_devicestorage_t *)
4144 	malloc(sizeof(LIBMTP_devicestorage_t));
4145       storage->prev = storageprev;
4146       if (storageprev != NULL)
4147         storageprev->next = storage;
4148       if (device->storage == NULL)
4149         device->storage = storage;
4150 
4151       storage->id = storageIDs.Storage[i];
4152       storage->StorageType = PTP_ST_Undefined;
4153       storage->FilesystemType = PTP_FST_Undefined;
4154       storage->AccessCapability = PTP_AC_ReadWrite;
4155       storage->MaxCapacity = (uint64_t) -1;
4156       storage->FreeSpaceInBytes = (uint64_t) -1;
4157       storage->FreeSpaceInObjects = (uint64_t) -1;
4158       storage->StorageDescription = strdup("Unknown storage");
4159       storage->VolumeIdentifier = strdup("Unknown volume");
4160       storage->next = NULL;
4161 
4162       storageprev = storage;
4163     }
4164     free(storageIDs.Storage);
4165     return 1;
4166   } else {
4167     for (i = 0; i < storageIDs.n; i++) {
4168       uint16_t ret;
4169       ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
4170       if (ret != PTP_RC_OK) {
4171 	add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): "
4172 				    "Could not get storage info.");
4173 	if (device->storage != NULL) {
4174           free_storage_list(device);
4175 	}
4176 	return -1;
4177       }
4178 
4179       storage = (LIBMTP_devicestorage_t *)
4180 	malloc(sizeof(LIBMTP_devicestorage_t));
4181       storage->prev = storageprev;
4182       if (storageprev != NULL)
4183         storageprev->next = storage;
4184       if (device->storage == NULL)
4185         device->storage = storage;
4186 
4187       storage->id = storageIDs.Storage[i];
4188       storage->StorageType = storageInfo.StorageType;
4189       storage->FilesystemType = storageInfo.FilesystemType;
4190       storage->AccessCapability = storageInfo.AccessCapability;
4191       storage->MaxCapacity = storageInfo.MaxCapability;
4192       storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
4193       storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
4194       storage->StorageDescription = storageInfo.StorageDescription;
4195       storage->VolumeIdentifier = storageInfo.VolumeLabel;
4196       storage->next = NULL;
4197 
4198       storageprev = storage;
4199     }
4200 
4201     if (storage != NULL)
4202       storage->next = NULL;
4203 
4204     sort_storage_by(device,sortby);
4205     free(storageIDs.Storage);
4206     return 0;
4207   }
4208 }
4209 
4210 /**
4211  * This creates a new file metadata structure and allocates memory
4212  * for it. Notice that if you add strings to this structure they
4213  * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
4214  * operation later, so be careful of using strdup() when assigning
4215  * strings, e.g.:
4216  *
4217  * <pre>
4218  * LIBMTP_file_t *file = LIBMTP_new_file_t();
4219  * file->filename = strdup(namestr);
4220  * ....
4221  * LIBMTP_destroy_file_t(file);
4222  * </pre>
4223  *
4224  * @return a pointer to the newly allocated metadata structure.
4225  * @see LIBMTP_destroy_file_t()
4226  */
LIBMTP_new_file_t(void)4227 LIBMTP_file_t *LIBMTP_new_file_t(void)
4228 {
4229   LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
4230   if (new == NULL) {
4231     return NULL;
4232   }
4233   new->filename = NULL;
4234   new->item_id = 0;
4235   new->parent_id = 0;
4236   new->storage_id = 0;
4237   new->filesize = 0;
4238   new->modificationdate = 0;
4239   new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4240   new->next = NULL;
4241   return new;
4242 }
4243 
4244 /**
4245  * This destroys a file metadata structure and deallocates the memory
4246  * used by it, including any strings. Never use a file metadata
4247  * structure again after calling this function on it.
4248  * @param file the file metadata to destroy.
4249  * @see LIBMTP_new_file_t()
4250  */
LIBMTP_destroy_file_t(LIBMTP_file_t * file)4251 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
4252 {
4253   if (file == NULL) {
4254     return;
4255   }
4256   if (file->filename != NULL)
4257     free(file->filename);
4258   free(file);
4259   return;
4260 }
4261 
4262 /**
4263  * Helper function that takes one PTP object and creates a
4264  * LIBMTP_file_t metadata entry.
4265  */
obj2file(LIBMTP_mtpdevice_t * device,PTPObject * ob)4266 static LIBMTP_file_t *obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
4267 {
4268   PTPParams *params = (PTPParams *) device->params;
4269   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4270   LIBMTP_file_t *file;
4271   int i;
4272 
4273   // Allocate a new file type
4274   file = LIBMTP_new_file_t();
4275 
4276   file->parent_id = ob->oi.ParentObject;
4277   file->storage_id = ob->oi.StorageID;
4278 
4279   if (ob->oi.Filename != NULL) {
4280     file->filename = strdup(ob->oi.Filename);
4281   }
4282 
4283   // Set the filetype
4284   file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4285 
4286   /*
4287    * A special quirk for devices that doesn't quite
4288    * remember that some files marked as "unknown" type are
4289    * actually OGG or FLAC files. We look at the filename extension
4290    * and see if it happens that this was atleast named "ogg" or "flac"
4291    * and fall back on this heuristic approach in that case,
4292    * for these bugged devices only.
4293    */
4294   if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
4295     if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4296         FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4297         has_ogg_extension(file->filename)) {
4298       file->filetype = LIBMTP_FILETYPE_OGG;
4299     }
4300 
4301     if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename)) {
4302         file->filetype = LIBMTP_FILETYPE_FLAC;
4303     }
4304   }
4305 
4306   // Set the modification date
4307   file->modificationdate = ob->oi.ModificationDate;
4308 
4309   // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4310   file->filesize = ob->oi.ObjectCompressedSize;
4311 
4312   // This is a unique ID so we can keep track of the file.
4313   file->item_id = ob->oid;
4314 
4315   /*
4316    * If we have a cached, large set of metadata, then use it!
4317    */
4318   if (ob->mtpprops) {
4319     MTPProperties *prop = ob->mtpprops;
4320 
4321     for (i=0; i < ob->nrofmtpprops; i++, prop++) {
4322       // Pick ObjectSize here...
4323       if (prop->property == PTP_OPC_ObjectSize) {
4324 	// This may already be set, but this 64bit precision value
4325 	// is better than the PTP 32bit value, so let it override.
4326 	if (device->object_bitsize == 64) {
4327 	  file->filesize = prop->propval.u64;
4328 	} else {
4329 	  file->filesize = prop->propval.u32;
4330 	}
4331 	break;
4332       }
4333     }
4334   } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
4335     uint16_t *props = NULL;
4336     uint32_t propcnt = 0;
4337     int ret;
4338 
4339     // First see which properties can be retrieved for this object format
4340     ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4341     if (ret != PTP_RC_OK) {
4342       add_ptp_error_to_errorstack(device, ret, "obj2file: call to ptp_mtp_getobjectpropssupported() failed.");
4343       // Silently fall through.
4344     } else {
4345       for (i = 0; i < propcnt; i++) {
4346 	switch (props[i]) {
4347 	case PTP_OPC_ObjectSize:
4348 	  if (device->object_bitsize == 64) {
4349 	    file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4350 	  } else {
4351 	    file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4352 	  }
4353 	  break;
4354 	default:
4355 	  break;
4356 	}
4357       }
4358       free(props);
4359     }
4360   }
4361 
4362   return file;
4363 }
4364 
4365 
4366 /**
4367  * This function retrieves the metadata for a single file off
4368  * the device.
4369  *
4370  * Do not call this function repeatedly! The file handles are linearly
4371  * searched O(n) and the call may involve (slow) USB traffic, so use
4372  * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4373  * as an efficient data structure such as a hash list.
4374  *
4375  * Incidentally this function will return metadata for
4376  * a folder (association) as well, but this is not a proper use
4377  * of it, it is intended for file manipulation, not folder manipulation.
4378  *
4379  * @param device a pointer to the device to get the file metadata from.
4380  * @param fileid the object ID of the file that you want the metadata for.
4381  * @return a metadata entry on success or NULL on failure.
4382  * @see LIBMTP_Get_Filelisting()
4383  */
LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t * device,uint32_t const fileid)4384 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4385 {
4386   PTPParams *params = (PTPParams *) device->params;
4387   uint16_t ret;
4388   PTPObject *ob;
4389 
4390   // Get all the handles if we haven't already done that
4391   // (Only on cached devices.)
4392   if (device->cached && params->nrofobjects == 0) {
4393     flush_handles(device);
4394   }
4395 
4396   ret = ptp_object_want(params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4397   if (ret != PTP_RC_OK)
4398     return NULL;
4399 
4400   return obj2file(device, ob);
4401 }
4402 
4403 /**
4404 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4405  * NOT TO USE IT.
4406  * @see LIBMTP_Get_Filelisting_With_Callback()
4407  */
LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t * device)4408 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
4409 {
4410   LIBMTP_INFO("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
4411   LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
4412   return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
4413 }
4414 
4415 /**
4416  * This returns a long list of all files available
4417  * on the current MTP device. Folders will not be returned, but abstract
4418  * entities like playlists and albums will show up as "files". Typical usage:
4419  *
4420  * <pre>
4421  * LIBMTP_file_t *filelist;
4422  *
4423  * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
4424  * while (filelist != NULL) {
4425  *   LIBMTP_file_t *tmp;
4426  *
4427  *   // Do something on each element in the list here...
4428  *   tmp = filelist;
4429  *   filelist = filelist->next;
4430  *   LIBMTP_destroy_file_t(tmp);
4431  * }
4432  * </pre>
4433  *
4434  * If you want to group your file listing by storage (per storage unit) or
4435  * arrange files into folders, you must dereference the <code>storage_id</code>
4436  * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
4437  * struct. To arrange by folders or files you typically have to create the proper
4438  * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4439  * <code>LIBMTP_Get_Folder_List()</code> first.
4440  *
4441  * @param device a pointer to the device to get the file listing for.
4442  * @param callback a function to be called during the tracklisting retrieveal
4443  *        for displaying progress bars etc, or NULL if you don't want
4444  *        any callbacks.
4445  * @param data a user-defined pointer that is passed along to
4446  *        the <code>progress</code> function in order to
4447  *        pass along some user defined data to the progress
4448  *        updates. If not used, set this to NULL.
4449  * @return a list of files that can be followed using the <code>next</code>
4450  *        field of the <code>LIBMTP_file_t</code> data structure.
4451  *        Each of the metadata tags must be freed after use, and may
4452  *        contain only partial metadata information, i.e. one or several
4453  *        fields may be NULL or 0.
4454  * @see LIBMTP_Get_Filemetadata()
4455  */
LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4456 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
4457                                                     LIBMTP_progressfunc_t const callback,
4458                                                     void const * const data)
4459 {
4460   uint32_t i = 0;
4461   LIBMTP_file_t *retfiles = NULL;
4462   LIBMTP_file_t *curfile = NULL;
4463   PTPParams *params = (PTPParams *) device->params;
4464 
4465   // Get all the handles if we haven't already done that
4466   if (params->nrofobjects == 0) {
4467     flush_handles(device);
4468   }
4469 
4470   for (i = 0; i < params->nrofobjects; i++) {
4471     LIBMTP_file_t *file;
4472     PTPObject *ob;
4473 
4474     if (callback != NULL)
4475       callback(i, params->nrofobjects, data);
4476 
4477     ob = &params->objects[i];
4478 
4479     if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4480       // MTP use this object format for folders which means
4481       // these "files" will turn up on a folder listing instead.
4482       continue;
4483     }
4484 
4485     // Look up metadata
4486     file = obj2file(device, ob);
4487     if (file == NULL) {
4488       continue;
4489     }
4490 
4491     // Add track to a list that will be returned afterwards.
4492     if (retfiles == NULL) {
4493       retfiles = file;
4494       curfile = file;
4495     } else {
4496       curfile->next = file;
4497       curfile = file;
4498     }
4499 
4500     // Call listing callback
4501     // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4502 
4503   } // Handle counting loop
4504   return retfiles;
4505 }
4506 
4507 /**
4508  * This function retrieves the contents of a certain folder
4509  * with id parent on a certain storage on a certain device.
4510  * The result contains both files and folders.
4511  * The device used with this operations must have been opened with
4512  * LIBMTP_Open_Raw_Device_Uncached() or it will fail.
4513  *
4514  * NOTE: the request will always perform I/O with the device.
4515  * @param device a pointer to the MTP device to report info from.
4516  * @param storage a storage on the device to report info from. If
4517  *        0 is passed in, the files for the given parent will be
4518  *        searched across all available storages.
4519  * @param parent the parent folder id.
4520  */
LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t * device,uint32_t const storage,uint32_t const parent)4521 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device,
4522 			     uint32_t const storage,
4523 			     uint32_t const parent)
4524 {
4525   PTPParams *params = (PTPParams *) device->params;
4526   LIBMTP_file_t *retfiles = NULL;
4527   LIBMTP_file_t *curfile = NULL;
4528   PTPObjectHandles currentHandles;
4529   uint32_t storageid;
4530   uint16_t ret;
4531   int i = 0;
4532 
4533   if (device->cached) {
4534     // This function is only supposed to be used by devices
4535     // opened as uncached!
4536     LIBMTP_ERROR("tried to use %s on a cached device!\n",
4537 		 __func__);
4538     return NULL;
4539   }
4540 
4541   if (storage == 0)
4542     storageid = PTP_GOH_ALL_STORAGE;
4543   else
4544     storageid = storage;
4545 
4546   ret = ptp_getobjecthandles(params,
4547 			     storageid,
4548 			     PTP_GOH_ALL_FORMATS,
4549 			     parent,
4550 			     &currentHandles);
4551 
4552   if (ret != PTP_RC_OK) {
4553     char buf[80];
4554     sprintf(buf,"LIBMTP_Get_Files_And_Folders(): could not get object handles of %08x.", parent);
4555     add_ptp_error_to_errorstack(device, ret, buf);
4556     return NULL;
4557   }
4558 
4559   if (currentHandles.Handler == NULL || currentHandles.n == 0)
4560     return NULL;
4561 
4562   for (i = 0; i < currentHandles.n; i++) {
4563     LIBMTP_file_t *file;
4564 
4565     // Get metadata for one file, if it fails, try next file
4566     file = LIBMTP_Get_Filemetadata(device, currentHandles.Handler[i]);
4567     if (file == NULL)
4568       continue;
4569 
4570     // Add track to a list that will be returned afterwards.
4571     if (curfile == NULL) {
4572       curfile = file;
4573       retfiles = file;
4574     } else {
4575       curfile->next = file;
4576       curfile = file;
4577     }
4578   }
4579 
4580   free(currentHandles.Handler);
4581 
4582   // Return a pointer to the original first file
4583   // in the big list.
4584   return retfiles;
4585 }
4586 
4587 
4588 /**
4589  * This creates a new track metadata structure and allocates memory
4590  * for it. Notice that if you add strings to this structure they
4591  * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4592  * operation later, so be careful of using strdup() when assigning
4593  * strings, e.g.:
4594  *
4595  * <pre>
4596  * LIBMTP_track_t *track = LIBMTP_new_track_t();
4597  * track->title = strdup(titlestr);
4598  * ....
4599  * LIBMTP_destroy_track_t(track);
4600  * </pre>
4601  *
4602  * @return a pointer to the newly allocated metadata structure.
4603  * @see LIBMTP_destroy_track_t()
4604  */
LIBMTP_new_track_t(void)4605 LIBMTP_track_t *LIBMTP_new_track_t(void)
4606 {
4607   LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4608   if (new == NULL) {
4609     return NULL;
4610   }
4611   new->item_id = 0;
4612   new->parent_id = 0;
4613   new->storage_id = 0;
4614   new->title = NULL;
4615   new->artist = NULL;
4616   new->composer = NULL;
4617   new->album = NULL;
4618   new->genre = NULL;
4619   new->date = NULL;
4620   new->filename = NULL;
4621   new->duration = 0;
4622   new->tracknumber = 0;
4623   new->filesize = 0;
4624   new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4625   new->samplerate = 0;
4626   new->nochannels = 0;
4627   new->wavecodec = 0;
4628   new->bitrate = 0;
4629   new->bitratetype = 0;
4630   new->rating = 0;
4631   new->usecount = 0;
4632   new->modificationdate = 0;
4633   new->next = NULL;
4634   return new;
4635 }
4636 
4637 /**
4638  * This destroys a track metadata structure and deallocates the memory
4639  * used by it, including any strings. Never use a track metadata
4640  * structure again after calling this function on it.
4641  * @param track the track metadata to destroy.
4642  * @see LIBMTP_new_track_t()
4643  */
LIBMTP_destroy_track_t(LIBMTP_track_t * track)4644 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4645 {
4646   if (track == NULL) {
4647     return;
4648   }
4649   if (track->title != NULL)
4650     free(track->title);
4651   if (track->artist != NULL)
4652     free(track->artist);
4653   if (track->composer != NULL)
4654     free(track->composer);
4655   if (track->album != NULL)
4656     free(track->album);
4657   if (track->genre != NULL)
4658     free(track->genre);
4659   if (track->date != NULL)
4660     free(track->date);
4661   if (track->filename != NULL)
4662     free(track->filename);
4663   free(track);
4664   return;
4665 }
4666 
4667 /**
4668  * This function maps and copies a property onto the track metadata if applicable.
4669  */
pick_property_to_track_metadata(LIBMTP_mtpdevice_t * device,MTPProperties * prop,LIBMTP_track_t * track)4670 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4671 {
4672   switch (prop->property) {
4673   case PTP_OPC_Name:
4674     if (prop->propval.str != NULL)
4675       track->title = strdup(prop->propval.str);
4676     else
4677       track->title = NULL;
4678     break;
4679   case PTP_OPC_Artist:
4680     if (prop->propval.str != NULL)
4681       track->artist = strdup(prop->propval.str);
4682     else
4683       track->artist = NULL;
4684     break;
4685   case PTP_OPC_Composer:
4686     if (prop->propval.str != NULL)
4687       track->composer = strdup(prop->propval.str);
4688     else
4689       track->composer = NULL;
4690     break;
4691   case PTP_OPC_Duration:
4692     track->duration = prop->propval.u32;
4693     break;
4694   case PTP_OPC_Track:
4695     track->tracknumber = prop->propval.u16;
4696     break;
4697   case PTP_OPC_Genre:
4698     if (prop->propval.str != NULL)
4699       track->genre = strdup(prop->propval.str);
4700     else
4701       track->genre = NULL;
4702     break;
4703   case PTP_OPC_AlbumName:
4704     if (prop->propval.str != NULL)
4705       track->album = strdup(prop->propval.str);
4706     else
4707       track->album = NULL;
4708     break;
4709   case PTP_OPC_OriginalReleaseDate:
4710     if (prop->propval.str != NULL)
4711       track->date = strdup(prop->propval.str);
4712     else
4713       track->date = NULL;
4714     break;
4715     // These are, well not so important.
4716   case PTP_OPC_SampleRate:
4717     track->samplerate = prop->propval.u32;
4718     break;
4719   case PTP_OPC_NumberOfChannels:
4720     track->nochannels = prop->propval.u16;
4721     break;
4722   case PTP_OPC_AudioWAVECodec:
4723     track->wavecodec = prop->propval.u32;
4724     break;
4725   case PTP_OPC_AudioBitRate:
4726     track->bitrate = prop->propval.u32;
4727     break;
4728   case PTP_OPC_BitRateType:
4729     track->bitratetype = prop->propval.u16;
4730     break;
4731   case PTP_OPC_Rating:
4732     track->rating = prop->propval.u16;
4733     break;
4734   case PTP_OPC_UseCount:
4735     track->usecount = prop->propval.u32;
4736     break;
4737   case PTP_OPC_ObjectSize:
4738     if (device->object_bitsize == 64) {
4739       track->filesize = prop->propval.u64;
4740     } else {
4741       track->filesize = prop->propval.u32;
4742     }
4743     break;
4744   default:
4745     break;
4746   }
4747 }
4748 
4749 /**
4750  * This function retrieves the track metadata for a track
4751  * given by a unique ID.
4752  * @param device a pointer to the device to get the track metadata off.
4753  * @param trackid the unique ID of the track.
4754  * @param objectformat the object format of this track, so we know what it supports.
4755  * @param track a metadata set to fill in.
4756  */
get_track_metadata(LIBMTP_mtpdevice_t * device,uint16_t objectformat,LIBMTP_track_t * track)4757 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4758 			       LIBMTP_track_t *track)
4759 {
4760   uint16_t ret;
4761   PTPParams *params = (PTPParams *) device->params;
4762   uint32_t i;
4763   MTPProperties *prop;
4764   PTPObject *ob;
4765 
4766   /*
4767    * If we have a cached, large set of metadata, then use it!
4768    */
4769   ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4770   if (ob->mtpprops) {
4771     prop = ob->mtpprops;
4772     for (i=0;i<ob->nrofmtpprops;i++,prop++)
4773       pick_property_to_track_metadata(device, prop, track);
4774   } else {
4775     uint16_t *props = NULL;
4776     uint32_t propcnt = 0;
4777 
4778     // First see which properties can be retrieved for this object format
4779     ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4780     if (ret != PTP_RC_OK) {
4781       add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4782       // Just bail out for now, nothing is ever set.
4783       return;
4784     } else {
4785       for (i=0;i<propcnt;i++) {
4786 	switch (props[i]) {
4787 	case PTP_OPC_Name:
4788 	  track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4789 	  break;
4790 	case PTP_OPC_Artist:
4791 	  track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4792 	  break;
4793 	case PTP_OPC_Composer:
4794 	  track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4795 	  break;
4796 	case PTP_OPC_Duration:
4797 	  track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4798 	  break;
4799 	case PTP_OPC_Track:
4800 	  track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4801 	  break;
4802 	case PTP_OPC_Genre:
4803 	  track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4804 	  break;
4805 	case PTP_OPC_AlbumName:
4806 	  track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4807 	  break;
4808 	case PTP_OPC_OriginalReleaseDate:
4809 	  track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4810 	  break;
4811 	  // These are, well not so important.
4812 	case PTP_OPC_SampleRate:
4813 	  track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4814 	  break;
4815 	case PTP_OPC_NumberOfChannels:
4816 	  track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4817 	  break;
4818 	case PTP_OPC_AudioWAVECodec:
4819 	  track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4820 	  break;
4821 	case PTP_OPC_AudioBitRate:
4822 	  track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4823 	  break;
4824 	case PTP_OPC_BitRateType:
4825 	  track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4826 	  break;
4827 	case PTP_OPC_Rating:
4828 	  track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4829 	  break;
4830 	case PTP_OPC_UseCount:
4831 	  track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4832 	  break;
4833 	case PTP_OPC_ObjectSize:
4834 	  if (device->object_bitsize == 64) {
4835 	    track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4836 	  } else {
4837 	    track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4838 	  }
4839 	  break;
4840 	}
4841       }
4842       free(props);
4843     }
4844   }
4845 }
4846 
4847 /**
4848  * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4849  * NOT TO USE IT.
4850  * @see LIBMTP_Get_Tracklisting_With_Callback()
4851  */
LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t * device)4852 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4853 {
4854   LIBMTP_INFO("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4855   LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4856   return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4857 }
4858 
4859 /**
4860  * This returns a long list of all tracks available on the current MTP device.
4861  * Tracks include multimedia objects, both music tracks and video tracks.
4862  * Typical usage:
4863  *
4864  * <pre>
4865  * LIBMTP_track_t *tracklist;
4866  *
4867  * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4868  * while (tracklist != NULL) {
4869  *   LIBMTP_track_t *tmp;
4870  *
4871  *   // Do something on each element in the list here...
4872  *   tmp = tracklist;
4873  *   tracklist = tracklist->next;
4874  *   LIBMTP_destroy_track_t(tmp);
4875  * }
4876  * </pre>
4877  *
4878  * If you want to group your track listing by storage (per storage unit) or
4879  * arrange tracks into folders, you must dereference the <code>storage_id</code>
4880  * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4881  * struct. To arrange by folders or files you typically have to create the proper
4882  * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4883  * <code>LIBMTP_Get_Folder_List()</code> first.
4884  *
4885  * @param device a pointer to the device to get the track listing for.
4886  * @param callback a function to be called during the tracklisting retrieveal
4887  *        for displaying progress bars etc, or NULL if you don't want
4888  *        any callbacks.
4889  * @param data a user-defined pointer that is passed along to
4890  *        the <code>progress</code> function in order to
4891  *        pass along some user defined data to the progress
4892  *        updates. If not used, set this to NULL.
4893  * @return a list of tracks that can be followed using the <code>next</code>
4894  *        field of the <code>LIBMTP_track_t</code> data structure.
4895  *        Each of the metadata tags must be freed after use, and may
4896  *        contain only partial metadata information, i.e. one or several
4897  *        fields may be NULL or 0.
4898  * @see LIBMTP_Get_Trackmetadata()
4899  */
LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4900 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4901                                                       LIBMTP_progressfunc_t const callback,
4902                                                       void const * const data)
4903 {
4904 	return LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, 0, callback, data);
4905 }
4906 
4907 
4908 /**
4909  * This returns a long list of all tracks available on the current MTP device.
4910  * Tracks include multimedia objects, both music tracks and video tracks.
4911  * Typical usage:
4912  *
4913  * <pre>
4914  * LIBMTP_track_t *tracklist;
4915  *
4916  * tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
4917  * while (tracklist != NULL) {
4918  *   LIBMTP_track_t *tmp;
4919  *
4920  *   // Do something on each element in the list here...
4921  *   tmp = tracklist;
4922  *   tracklist = tracklist->next;
4923  *   LIBMTP_destroy_track_t(tmp);
4924  * }
4925  * </pre>
4926  *
4927  * If you want to group your track listing by storage (per storage unit) or
4928  * arrange tracks into folders, you must dereference the <code>storage_id</code>
4929  * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4930  * struct. To arrange by folders or files you typically have to create the proper
4931  * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4932  * <code>LIBMTP_Get_Folder_List()</code> first.
4933  *
4934  * @param device a pointer to the device to get the track listing for.
4935  * @param storage_id ID of device storage (if null, no filter)
4936  * @param callback a function to be called during the tracklisting retrieveal
4937  *        for displaying progress bars etc, or NULL if you don't want
4938  *        any callbacks.
4939  * @param data a user-defined pointer that is passed along to
4940  *        the <code>progress</code> function in order to
4941  *        pass along some user defined data to the progress
4942  *        updates. If not used, set this to NULL.
4943  * @return a list of tracks that can be followed using the <code>next</code>
4944  *        field of the <code>LIBMTP_track_t</code> data structure.
4945  *        Each of the metadata tags must be freed after use, and may
4946  *        contain only partial metadata information, i.e. one or several
4947  *        fields may be NULL or 0.
4948  * @see LIBMTP_Get_Trackmetadata()
4949  */
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)4950 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id,
4951                                                       LIBMTP_progressfunc_t const callback,
4952                                                       void const * const data)
4953 {
4954   uint32_t i = 0;
4955   LIBMTP_track_t *retracks = NULL;
4956   LIBMTP_track_t *curtrack = NULL;
4957   PTPParams *params = (PTPParams *) device->params;
4958   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4959 
4960   // Get all the handles if we haven't already done that
4961   if (params->nrofobjects == 0) {
4962     flush_handles(device);
4963   }
4964 
4965   for (i = 0; i < params->nrofobjects; i++) {
4966     LIBMTP_track_t *track;
4967     PTPObject *ob;
4968     LIBMTP_filetype_t mtptype;
4969 
4970     if (callback != NULL)
4971       callback(i, params->nrofobjects, data);
4972 
4973     ob = &params->objects[i];
4974     mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4975 
4976     // Ignore stuff we don't know how to handle...
4977     // TODO: get this list as an intersection of the sets
4978     // supported by the device and the from the device and
4979     // all known track files?
4980     if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4981 	// This row lets through undefined files for examination since they may be forgotten OGG files.
4982 	(ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4983 	 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4984 	  !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4985 	  !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4986 	) {
4987       //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4988       continue;
4989     }
4990 
4991 	// Ignore stuff that isn't into the storage device
4992 	if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
4993 		continue;
4994 
4995     // Allocate a new track type
4996     track = LIBMTP_new_track_t();
4997 
4998     // This is some sort of unique ID so we can keep track of the track.
4999     track->item_id = ob->oid;
5000     track->parent_id = ob->oi.ParentObject;
5001     track->storage_id = ob->oi.StorageID;
5002     track->modificationdate = ob->oi.ModificationDate;
5003 
5004     track->filetype = mtptype;
5005 
5006     // Original file-specific properties
5007     track->filesize = ob->oi.ObjectCompressedSize;
5008     if (ob->oi.Filename != NULL) {
5009       track->filename = strdup(ob->oi.Filename);
5010     }
5011 
5012     get_track_metadata(device, ob->oi.ObjectFormat, track);
5013 
5014     /*
5015      * A special quirk for iriver devices that doesn't quite
5016      * remember that some files marked as "unknown" type are
5017      * actually OGG or FLAC files. We look at the filename extension
5018      * and see if it happens that this was atleast named "ogg" or "flac"
5019      * and fall back on this heuristic approach in that case,
5020      * for these bugged devices only.
5021      */
5022     if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5023 	track->filename != NULL) {
5024       if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5025 	   FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5026 	  has_ogg_extension(track->filename))
5027 	track->filetype = LIBMTP_FILETYPE_OGG;
5028       else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5029 	       has_flac_extension(track->filename))
5030 	track->filetype = LIBMTP_FILETYPE_FLAC;
5031       else {
5032 	// This was not an OGG/FLAC file so discard it and continue
5033 	LIBMTP_destroy_track_t(track);
5034 	continue;
5035       }
5036     }
5037 
5038     // Add track to a list that will be returned afterwards.
5039     if (retracks == NULL) {
5040       retracks = track;
5041       curtrack = track;
5042     } else {
5043       curtrack->next = track;
5044       curtrack = track;
5045     }
5046 
5047     // Call listing callback
5048     // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
5049 
5050   } // Handle counting loop
5051   return retracks;
5052 }
5053 
5054 /**
5055  * This function retrieves the metadata for a single track off
5056  * the device.
5057  *
5058  * Do not call this function repeatedly! The track handles are linearly
5059  * searched O(n) and the call may involve (slow) USB traffic, so use
5060  * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
5061  * as an efficient data structure such as a hash list.
5062  *
5063  * @param device a pointer to the device to get the track metadata from.
5064  * @param trackid the object ID of the track that you want the metadata for.
5065  * @return a track metadata entry on success or NULL on failure.
5066  * @see LIBMTP_Get_Tracklisting()
5067  */
LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t * device,uint32_t const trackid)5068 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
5069 {
5070   PTPParams *params = (PTPParams *) device->params;
5071   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5072   PTPObject *ob;
5073   LIBMTP_track_t *track;
5074   LIBMTP_filetype_t mtptype;
5075   uint16_t ret;
5076 
5077   // Get all the handles if we haven't already done that
5078   if (params->nrofobjects == 0)
5079     flush_handles(device);
5080 
5081   ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5082   if (ret != PTP_RC_OK)
5083     return NULL;
5084 
5085   mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
5086 
5087   // Ignore stuff we don't know how to handle...
5088   if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
5089       /*
5090        * This row lets through undefined files for examination
5091        * since they may be forgotten OGG or FLAC files.
5092        */
5093       (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
5094        (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
5095 	!FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
5096 	!FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
5097       ) {
5098     //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
5099     return NULL;
5100   }
5101 
5102   // Allocate a new track type
5103   track = LIBMTP_new_track_t();
5104 
5105   // This is some sort of unique ID so we can keep track of the track.
5106   track->item_id = ob->oid;
5107   track->parent_id = ob->oi.ParentObject;
5108   track->storage_id = ob->oi.StorageID;
5109   track->modificationdate = ob->oi.ModificationDate;
5110 
5111   track->filetype = mtptype;
5112 
5113   // Original file-specific properties
5114   track->filesize = ob->oi.ObjectCompressedSize;
5115   if (ob->oi.Filename != NULL) {
5116     track->filename = strdup(ob->oi.Filename);
5117   }
5118 
5119   /*
5120    * A special quirk for devices that doesn't quite
5121    * remember that some files marked as "unknown" type are
5122    * actually OGG or FLAC files. We look at the filename extension
5123    * and see if it happens that this was atleast named "ogg"
5124    * and fall back on this heuristic approach in that case,
5125    * for these bugged devices only.
5126    */
5127   if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5128       track->filename != NULL) {
5129     if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5130 	 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5131 	has_ogg_extension(track->filename))
5132       track->filetype = LIBMTP_FILETYPE_OGG;
5133     else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5134 	     has_flac_extension(track->filename))
5135       track->filetype = LIBMTP_FILETYPE_FLAC;
5136     else {
5137       // This was not an OGG/FLAC file so discard it
5138       LIBMTP_destroy_track_t(track);
5139       return NULL;
5140     }
5141   }
5142   get_track_metadata(device, ob->oi.ObjectFormat, track);
5143   return track;
5144 }
5145 
5146 /**
5147  * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
5148  * to isolate the internal type.
5149  */
get_func_wrapper(PTPParams * params,void * priv,unsigned long wantlen,unsigned char * data,unsigned long * gotlen)5150 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
5151 {
5152   MTPDataHandler *handler = (MTPDataHandler *)priv;
5153   uint16_t ret;
5154   uint32_t local_gotlen = 0;
5155   ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
5156   *gotlen = local_gotlen;
5157   switch (ret)
5158   {
5159     case LIBMTP_HANDLER_RETURN_OK:
5160       return PTP_RC_OK;
5161     case LIBMTP_HANDLER_RETURN_ERROR:
5162       return PTP_ERROR_IO;
5163     case LIBMTP_HANDLER_RETURN_CANCEL:
5164       return PTP_ERROR_CANCEL;
5165     default:
5166       return PTP_ERROR_IO;
5167   }
5168 }
5169 
5170 /**
5171  * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
5172  * to isolate the internal type.
5173  */
put_func_wrapper(PTPParams * params,void * priv,unsigned long sendlen,unsigned char * data)5174 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data)
5175 {
5176   MTPDataHandler *handler = (MTPDataHandler *)priv;
5177   uint16_t ret;
5178   uint32_t local_putlen = 0;
5179 
5180   ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
5181 
5182   switch (ret)
5183   {
5184     case LIBMTP_HANDLER_RETURN_OK:
5185       if (local_putlen != sendlen)
5186 	return PTP_ERROR_IO;
5187       return PTP_RC_OK;
5188     case LIBMTP_HANDLER_RETURN_ERROR:
5189       return PTP_ERROR_IO;
5190     case LIBMTP_HANDLER_RETURN_CANCEL:
5191       return PTP_ERROR_CANCEL;
5192     default:
5193       return PTP_ERROR_IO;
5194   }
5195 }
5196 
5197 /**
5198  * This gets a file off the device to a local file identified
5199  * by a filename.
5200  * @param device a pointer to the device to get the track from.
5201  * @param id the file ID of the file to retrieve.
5202  * @param path a filename to use for the retrieved file.
5203  * @param callback a progress indicator function or NULL to ignore.
5204  * @param data a user-defined pointer that is passed along to
5205  *             the <code>progress</code> function in order to
5206  *             pass along some user defined data to the progress
5207  *             updates. If not used, set this to NULL.
5208  * @return 0 if the transfer was successful, any other value means
5209  *           failure.
5210  * @see LIBMTP_Get_File_To_File_Descriptor()
5211  */
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)5212 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5213 			 char const * const path, LIBMTP_progressfunc_t const callback,
5214 			 void const * const data)
5215 {
5216   int fd = -1;
5217   int ret;
5218 
5219   // Sanity check
5220   if (path == NULL) {
5221     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
5222     return -1;
5223   }
5224 
5225   // Open file
5226 #ifdef __WIN32__
5227 #ifdef USE_WINDOWS_IO_H
5228   if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
5229 #else
5230   if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
5231 #endif
5232 #else
5233   if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
5234 #endif
5235     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
5236     return -1;
5237   }
5238 
5239   ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5240 
5241   // Close file
5242   close(fd);
5243 
5244   // Delete partial file.
5245   if (ret == -1) {
5246     unlink(path);
5247   }
5248 
5249   return ret;
5250 }
5251 
5252 /**
5253  * This gets a file off the device to a file identified
5254  * by a file descriptor.
5255  *
5256  * This function can potentially be used for streaming
5257  * files off the device for playback or broadcast for example,
5258  * by downloading the file into a stream sink e.g. a socket.
5259  *
5260  * @param device a pointer to the device to get the file from.
5261  * @param id the file ID of the file to retrieve.
5262  * @param fd a local file descriptor to write the file to.
5263  * @param callback a progress indicator function or NULL to ignore.
5264  * @param data a user-defined pointer that is passed along to
5265  *             the <code>progress</code> function in order to
5266  *             pass along some user defined data to the progress
5267  *             updates. If not used, set this to NULL.
5268  * @return 0 if the transfer was successful, any other value means
5269  *           failure.
5270  * @see LIBMTP_Get_File_To_File()
5271  */
5272 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5273 					uint32_t const id,
5274 					int const fd,
5275 					LIBMTP_progressfunc_t const callback,
5276 					void const * const data)
5277 {
5278   uint16_t ret;
5279   PTPParams *params = (PTPParams *) device->params;
5280   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5281 
5282   LIBMTP_file_t *mtpfile = LIBMTP_Get_Filemetadata(device, id);
5283   if (mtpfile == NULL) {
5284     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5285     return -1;
5286   }
5287   if (mtpfile->filetype == LIBMTP_FILETYPE_FOLDER) {
5288     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5289     LIBMTP_destroy_file_t (mtpfile);
5290     return -1;
5291   }
5292 
5293   // Callbacks
5294   ptp_usb->callback_active = 1;
5295   ptp_usb->current_transfer_total = mtpfile->filesize +
5296     PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5297   ptp_usb->current_transfer_complete = 0;
5298   ptp_usb->current_transfer_callback = callback;
5299   ptp_usb->current_transfer_callback_data = data;
5300 
5301   // Don't need mtpfile anymore
5302   LIBMTP_destroy_file_t(mtpfile);
5303 
5304   ret = ptp_getobject_tofd(params, id, fd);
5305 
5306   ptp_usb->callback_active = 0;
5307   ptp_usb->current_transfer_callback = NULL;
5308   ptp_usb->current_transfer_callback_data = NULL;
5309 
5310   if (ret == PTP_ERROR_CANCEL) {
5311     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5312     return -1;
5313   }
5314   if (ret != PTP_RC_OK) {
5315     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5316     return -1;
5317   }
5318 
5319   return 0;
5320 }
5321 
5322 /**
5323  * This gets a file off the device and calls put_func
5324  * with chunks of data
5325  *
5326  * @param device a pointer to the device to get the file from.
5327  * @param id the file ID of the file to retrieve.
5328  * @param put_func the function to call when we have data.
5329  * @param priv the user-defined pointer that is passed to
5330  *             <code>put_func</code>.
5331  * @param callback a progress indicator function or NULL to ignore.
5332  * @param data a user-defined pointer that is passed along to
5333  *             the <code>progress</code> function in order to
5334  *             pass along some user defined data to the progress
5335  *             updates. If not used, set this to NULL.
5336  * @return 0 if the transfer was successful, any other value means
5337  *           failure.
5338  */
5339 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
5340 					uint32_t const id,
5341 					MTPDataPutFunc put_func,
5342           void * priv,
5343 					LIBMTP_progressfunc_t const callback,
5344 					void const * const data)
5345 {
5346   uint16_t ret;
5347   PTPParams *params = (PTPParams *) device->params;
5348   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5349 
5350   LIBMTP_file_t *mtpfile = LIBMTP_Get_Filemetadata(device, id);
5351   if (mtpfile == NULL) {
5352     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5353     return -1;
5354   }
5355   if (mtpfile->filetype == LIBMTP_FILETYPE_FOLDER) {
5356     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5357     LIBMTP_destroy_file_t (mtpfile);
5358     return -1;
5359   }
5360 
5361   // Callbacks
5362   ptp_usb->callback_active = 1;
5363   ptp_usb->current_transfer_total = mtpfile->filesize +
5364     PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5365   ptp_usb->current_transfer_complete = 0;
5366   ptp_usb->current_transfer_callback = callback;
5367   ptp_usb->current_transfer_callback_data = data;
5368 
5369   // Don't need mtpfile anymore
5370   LIBMTP_destroy_file_t(mtpfile);
5371 
5372   MTPDataHandler mtp_handler;
5373   mtp_handler.getfunc = NULL;
5374   mtp_handler.putfunc = put_func;
5375   mtp_handler.priv = priv;
5376 
5377   PTPDataHandler handler;
5378   handler.getfunc = NULL;
5379   handler.putfunc = put_func_wrapper;
5380   handler.priv = &mtp_handler;
5381 
5382   ret = ptp_getobject_to_handler(params, id, &handler);
5383 
5384   ptp_usb->callback_active = 0;
5385   ptp_usb->current_transfer_callback = NULL;
5386   ptp_usb->current_transfer_callback_data = NULL;
5387 
5388   if (ret == PTP_ERROR_CANCEL) {
5389     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5390     return -1;
5391   }
5392   if (ret != PTP_RC_OK) {
5393     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5394     return -1;
5395   }
5396 
5397   return 0;
5398 }
5399 
5400 
5401 /**
5402  * This gets a track off the device to a file identified
5403  * by a filename. This is actually just a wrapper for the
5404  * \c LIBMTP_Get_Track_To_File() function.
5405  * @param device a pointer to the device to get the track from.
5406  * @param id the track ID of the track to retrieve.
5407  * @param path a filename to use for the retrieved track.
5408  * @param callback a progress indicator function or NULL to ignore.
5409  * @param data a user-defined pointer that is passed along to
5410  *             the <code>progress</code> function in order to
5411  *             pass along some user defined data to the progress
5412  *             updates. If not used, set this to NULL.
5413  * @return 0 if the transfer was successful, any other value means
5414  *           failure.
5415  * @see LIBMTP_Get_Track_To_File_Descriptor()
5416  */
5417 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5418 			 char const * const path, LIBMTP_progressfunc_t const callback,
5419 			 void const * const data)
5420 {
5421   // This is just a wrapper
5422   return LIBMTP_Get_File_To_File(device, id, path, callback, data);
5423 }
5424 
5425 /**
5426  * This gets a track off the device to a file identified
5427  * by a file descriptor. This is actually just a wrapper for
5428  * the \c LIBMTP_Get_File_To_File_Descriptor() function.
5429  * @param device a pointer to the device to get the track from.
5430  * @param id the track ID of the track to retrieve.
5431  * @param fd a file descriptor to write the track to.
5432  * @param callback a progress indicator function or NULL to ignore.
5433  * @param data a user-defined pointer that is passed along to
5434  *             the <code>progress</code> function in order to
5435  *             pass along some user defined data to the progress
5436  *             updates. If not used, set this to NULL.
5437  * @return 0 if the transfer was successful, any other value means
5438  *           failure.
5439  * @see LIBMTP_Get_Track_To_File()
5440  */
5441 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5442 					uint32_t const id,
5443 					int const fd,
5444 					LIBMTP_progressfunc_t const callback,
5445 					void const * const data)
5446 {
5447   // This is just a wrapper
5448   return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5449 }
5450 
5451 /**
5452  * This gets a track off the device to a handler function.
5453  * This is actually just a wrapper for
5454  * the \c LIBMTP_Get_File_To_Handler() function.
5455  * @param device a pointer to the device to get the track from.
5456  * @param id the track ID of the track to retrieve.
5457  * @param put_func the function to call when we have data.
5458  * @param priv the user-defined pointer that is passed to
5459  *             <code>put_func</code>.
5460  * @param callback a progress indicator function or NULL to ignore.
5461  * @param data a user-defined pointer that is passed along to
5462  *             the <code>progress</code> function in order to
5463  *             pass along some user defined data to the progress
5464  *             updates. If not used, set this to NULL.
5465  * @return 0 if the transfer was successful, any other value means
5466  *           failure.
5467  */
5468 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
5469 					uint32_t const id,
5470 					MTPDataPutFunc put_func,
5471           void * priv,
5472 					LIBMTP_progressfunc_t const callback,
5473 					void const * const data)
5474 {
5475   // This is just a wrapper
5476   return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
5477 }
5478 
5479 /**
5480  * This function sends a track from a local file to an
5481  * MTP device. A filename and a set of metadata must be
5482  * given as input.
5483  * @param device a pointer to the device to send the track to.
5484  * @param path the filename of a local file which will be sent.
5485  * @param metadata a track metadata set to be written along with the file.
5486  *        After this call the field <code>metadata-&gt;item_id</code>
5487  *        will contain the new track ID. Other fields such
5488  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
5489  *        or <code>metadata-&gt;storage_id</code> may also change during this
5490  *        operation due to device restrictions, so do not rely on the
5491  *        contents of this struct to be preserved in any way.
5492  *        <ul>
5493  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
5494  *        (e.g. folder) to store this track in. Since some
5495  *        devices are a bit picky about where files
5496  *        are placed, a default folder will be chosen if libmtp
5497  *        has detected one for the current filetype and this
5498  *        parameter is set to 0. If this is 0 and no default folder
5499  *        can be found, the file will be stored in the root folder.
5500  *        <li><code>metadata-&gt;storage_id</code> should be set to the
5501  *        desired storage (e.g. memory card or whatever your device
5502  *        presents) to store this track in. Setting this to 0 will store
5503  *        the track on the primary storage.
5504  *        </ul>
5505  * @param callback a progress indicator function or NULL to ignore.
5506  * @param data a user-defined pointer that is passed along to
5507  *             the <code>progress</code> function in order to
5508  *             pass along some user defined data to the progress
5509  *             updates. If not used, set this to NULL.
5510  * @return 0 if the transfer was successful, any other value means
5511  *           failure.
5512  * @see LIBMTP_Send_Track_From_File_Descriptor()
5513  * @see LIBMTP_Send_File_From_File()
5514  * @see LIBMTP_Delete_Object()
5515  */
5516 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5517 			 char const * const path, LIBMTP_track_t * const metadata,
5518                          LIBMTP_progressfunc_t const callback,
5519 			 void const * const data)
5520 {
5521   int fd;
5522   int ret;
5523 
5524   // Sanity check
5525   if (path == NULL) {
5526     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5527     return -1;
5528   }
5529 
5530   // Open file
5531 #ifdef __WIN32__
5532 #ifdef USE_WINDOWS_IO_H
5533   if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5534 #else
5535   if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5536 #endif
5537 #else
5538   if ( (fd = open(path, O_RDONLY)) == -1) {
5539 #endif
5540     LIBMTP_ERROR("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5541     return -1;
5542   }
5543 
5544   ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5545 
5546   // Close file.
5547 #ifdef USE_WINDOWS_IO_H
5548   _close(fd);
5549 #else
5550   close(fd);
5551 #endif
5552 
5553   return ret;
5554 }
5555 
5556 
5557 
5558 /**
5559  * This helper function checks if a filename already exists on the device
5560  * @param PTPParams*
5561  * @param string representing the filename
5562  * @return 0 if the filename doesn't exist, -1 if it does
5563  */
5564 static int check_filename_exists(PTPParams* params, char const * const filename)
5565 {
5566   int i;
5567 
5568   for (i = 0; i < params->nrofobjects; i++) {
5569     char *fname = params->objects[i].oi.Filename;
5570     if ((fname != NULL) && (strcmp(filename, fname) == 0))
5571     {
5572       return -1;
5573     }
5574   }
5575 
5576   return 0;
5577 }
5578 
5579 /**
5580  * This helper function returns a unique filename, with a random string before the extension
5581  * @param string representing the original filename
5582  * @return a string representing the unique filename
5583  */
5584 static char *generate_unique_filename(PTPParams* params, char const * const filename)
5585 {
5586   int suffix;
5587   char * extension_position;
5588 
5589   if (check_filename_exists(params, filename))
5590   {
5591     extension_position = strrchr(filename,'.');
5592 
5593     char basename[extension_position - filename + 1];
5594     strncpy(basename, filename, extension_position - filename);
5595     basename[extension_position - filename] = '\0';
5596 
5597     suffix = 1;
5598     char newname[ strlen(basename) + 6 + strlen(extension_position)];
5599     sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5600     while ((check_filename_exists(params, newname)) && (suffix < 1000000)) {
5601       suffix++;
5602       sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5603     }
5604   return strdup(newname);
5605   }
5606   else
5607   {
5608     return strdup(filename);
5609   }
5610 }
5611 
5612 /**
5613  * This function sends a track from a file descriptor to an
5614  * MTP device. A filename and a set of metadata must be
5615  * given as input.
5616  * @param device a pointer to the device to send the track to.
5617  * @param fd the filedescriptor for a local file which will be sent.
5618  * @param metadata a track metadata set to be written along with the file.
5619  *        After this call the field <code>metadata-&gt;item_id</code>
5620  *        will contain the new track ID. Other fields such
5621  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
5622  *        or <code>metadata-&gt;storage_id</code> may also change during this
5623  *        operation due to device restrictions, so do not rely on the
5624  *        contents of this struct to be preserved in any way.
5625  *        <ul>
5626  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
5627  *        (e.g. folder) to store this track in. Since some
5628  *        devices are a bit picky about where files
5629  *        are placed, a default folder will be chosen if libmtp
5630  *        has detected one for the current filetype and this
5631  *        parameter is set to 0. If this is 0 and no default folder
5632  *        can be found, the file will be stored in the root folder.
5633  *        <li><code>metadata-&gt;storage_id</code> should be set to the
5634  *        desired storage (e.g. memory card or whatever your device
5635  *        presents) to store this track in. Setting this to 0 will store
5636  *        the track on the primary storage.
5637  *        </ul>
5638  * @param callback a progress indicator function or NULL to ignore.
5639  * @param data a user-defined pointer that is passed along to
5640  *             the <code>progress</code> function in order to
5641  *             pass along some user defined data to the progress
5642  *             updates. If not used, set this to NULL.
5643  * @return 0 if the transfer was successful, any other value means
5644  *           failure.
5645  * @see LIBMTP_Send_Track_From_File()
5646  * @see LIBMTP_Delete_Object()
5647  */
5648 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5649 			 int const fd, LIBMTP_track_t * const metadata,
5650                          LIBMTP_progressfunc_t const callback,
5651 			 void const * const data)
5652 {
5653   int subcall_ret;
5654   LIBMTP_file_t filedata;
5655   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5656   PTPParams *params = (PTPParams *) device->params;
5657 
5658   // Sanity check, is this really a track?
5659   if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5660     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5661 			    "LIBMTP_Send_Track_From_File_Descriptor(): "
5662 			    "I don't think this is actually a track, strange filetype...");
5663   }
5664 
5665   // Wrap around the file transfer function
5666   filedata.item_id = metadata->item_id;
5667   filedata.parent_id = metadata->parent_id;
5668   filedata.storage_id = metadata->storage_id;
5669   if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5670     filedata.filename = generate_unique_filename(params, metadata->filename);
5671   }
5672   else {
5673     filedata.filename = metadata->filename;
5674   }
5675   filedata.filesize = metadata->filesize;
5676   filedata.filetype = metadata->filetype;
5677   filedata.next = NULL;
5678 
5679   subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5680 						      fd,
5681 						      &filedata,
5682 						      callback,
5683 						      data);
5684 
5685   if (subcall_ret != 0) {
5686     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5687 			    "LIBMTP_Send_Track_From_File_Descriptor(): "
5688 			    "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
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   // Pick up new item (and parent, storage) ID
5695   metadata->item_id = filedata.item_id;
5696   metadata->parent_id = filedata.parent_id;
5697   metadata->storage_id = filedata.storage_id;
5698 
5699   // Set track metadata for the new fine track
5700   subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5701   if (subcall_ret != 0) {
5702     // Subcall will add error to errorstack
5703     // We used to delete the file here, but don't... It might be OK after all.
5704     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5705     return -1;
5706   }
5707 
5708   // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5709   // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5710 
5711   return 0;
5712 }
5713 
5714 /**
5715  * This function sends a track from a handler function to an
5716  * MTP device. A filename and a set of metadata must be
5717  * given as input.
5718  * @param device a pointer to the device to send the track to.
5719  * @param get_func the function to call when we have data.
5720  * @param priv the user-defined pointer that is passed to
5721  *             <code>get_func</code>.
5722  * @param metadata a track metadata set to be written along with the file.
5723  *        After this call the field <code>metadata-&gt;item_id</code>
5724  *        will contain the new track ID. Other fields such
5725  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
5726  *        or <code>metadata-&gt;storage_id</code> may also change during this
5727  *        operation due to device restrictions, so do not rely on the
5728  *        contents of this struct to be preserved in any way.
5729  *        <ul>
5730  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
5731  *        (e.g. folder) to store this track in. Since some
5732  *        devices are a bit picky about where files
5733  *        are placed, a default folder will be chosen if libmtp
5734  *        has detected one for the current filetype and this
5735  *        parameter is set to 0. If this is 0 and no default folder
5736  *        can be found, the file will be stored in the root folder.
5737  *        <li><code>metadata-&gt;storage_id</code> should be set to the
5738  *        desired storage (e.g. memory card or whatever your device
5739  *        presents) to store this track in. Setting this to 0 will store
5740  *        the track on the primary storage.
5741  *        </ul>
5742  * @param callback a progress indicator function or NULL to ignore.
5743  * @param data a user-defined pointer that is passed along to
5744  *             the <code>progress</code> function in order to
5745  *             pass along some user defined data to the progress
5746  *             updates. If not used, set this to NULL.
5747  * @return 0 if the transfer was successful, any other value means
5748  *           failure.
5749  * @see LIBMTP_Send_Track_From_File()
5750  * @see LIBMTP_Delete_Object()
5751  */
5752 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5753 			 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5754                          LIBMTP_progressfunc_t const callback,
5755 			 void const * const data)
5756 {
5757   int subcall_ret;
5758   LIBMTP_file_t filedata;
5759   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5760   PTPParams *params = (PTPParams *) device->params;
5761 
5762   // Sanity check, is this really a track?
5763   if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5764     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5765 			    "LIBMTP_Send_Track_From_Handler(): "
5766 			    "I don't think this is actually a track, strange filetype...");
5767   }
5768 
5769   // Wrap around the file transfer function
5770   filedata.item_id = metadata->item_id;
5771   filedata.parent_id = metadata->parent_id;
5772   filedata.storage_id = metadata->storage_id;
5773   if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5774     filedata.filename = generate_unique_filename(params, metadata->filename);
5775   }
5776   else {
5777     filedata.filename = metadata->filename;
5778   }
5779   filedata.filesize = metadata->filesize;
5780   filedata.filetype = metadata->filetype;
5781   filedata.next = NULL;
5782 
5783   subcall_ret = LIBMTP_Send_File_From_Handler(device,
5784 					      get_func,
5785 					      priv,
5786 					      &filedata,
5787 					      callback,
5788 					      data);
5789 
5790   if (subcall_ret != 0) {
5791     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5792 			    "LIBMTP_Send_Track_From_Handler(): "
5793 			    "subcall to LIBMTP_Send_File_From_Handler failed.");
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   // Pick up new item (and parent, storage) ID
5800   metadata->item_id = filedata.item_id;
5801   metadata->parent_id = filedata.parent_id;
5802   metadata->storage_id = filedata.storage_id;
5803 
5804   // Set track metadata for the new fine track
5805   subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5806   if (subcall_ret != 0) {
5807     // Subcall will add error to errorstack
5808     // We used to delete the file here, but don't... It might be OK after all.
5809     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5810     return -1;
5811   }
5812 
5813   // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5814   // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5815 
5816   return 0;
5817 }
5818 
5819 /**
5820  * This function sends a local file to an MTP device.
5821  * A filename and a set of metadata must be
5822  * given as input.
5823  * @param device a pointer to the device to send the track to.
5824  * @param path the filename of a local file which will be sent.
5825  * @param filedata a file metadata set to be written along with the file.
5826  *        After this call the field <code>filedata-&gt;item_id</code>
5827  *        will contain the new file ID. Other fields such
5828  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
5829  *        or <code>filedata-&gt;storage_id</code> may also change during this
5830  *        operation due to device restrictions, so do not rely on the
5831  *        contents of this struct to be preserved in any way.
5832  *        <ul>
5833  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
5834  *        (e.g. folder) to store this file in. If this is 0,
5835  *        the file will be stored in the root folder.
5836  *        <li><code>filedata-&gt;storage_id</code> should be set to the
5837  *        desired storage (e.g. memory card or whatever your device
5838  *        presents) to store this file in. Setting this to 0 will store
5839  *        the file on the primary storage.
5840  *        </ul>
5841  * @param callback a progress indicator function or NULL to ignore.
5842  * @param data a user-defined pointer that is passed along to
5843  *             the <code>progress</code> function in order to
5844  *             pass along some user defined data to the progress
5845  *             updates. If not used, set this to NULL.
5846  * @return 0 if the transfer was successful, any other value means
5847  *           failure.
5848  * @see LIBMTP_Send_File_From_File_Descriptor()
5849  * @see LIBMTP_Delete_Object()
5850  */
5851 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5852 			       char const * const path, LIBMTP_file_t * const filedata,
5853 			       LIBMTP_progressfunc_t const callback,
5854 			       void const * const data)
5855 {
5856   int fd;
5857   int ret;
5858 
5859   // Sanity check
5860   if (path == NULL) {
5861     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5862     return -1;
5863   }
5864 
5865   // Open file
5866 #ifdef __WIN32__
5867 #ifdef USE_WINDOWS_IO_H
5868   if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5869 #else
5870   if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5871 #endif
5872 #else
5873   if ( (fd = open(path, O_RDONLY)) == -1) {
5874 #endif
5875     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5876     return -1;
5877   }
5878 
5879   ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5880 
5881   // Close file.
5882 #ifdef USE_WINDOWS_IO_H
5883   _close(fd);
5884 #else
5885   close(fd);
5886 #endif
5887 
5888   return ret;
5889 }
5890 
5891 /**
5892  * This function sends a generic file from a file descriptor to an
5893  * MTP device. A filename and a set of metadata must be
5894  * given as input.
5895  *
5896  * This can potentially be used for sending in a stream of unknown
5897  * length. Send music files with
5898  * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5899  *
5900  * @param device a pointer to the device to send the file to.
5901  * @param fd the filedescriptor for a local file which will be sent.
5902  * @param filedata a file metadata set to be written along with the file.
5903  *        After this call the field <code>filedata-&gt;item_id</code>
5904  *        will contain the new file ID. Other fields such
5905  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
5906  *        or <code>filedata-&gt;storage_id</code> may also change during this
5907  *        operation due to device restrictions, so do not rely on the
5908  *        contents of this struct to be preserved in any way.
5909  *        <ul>
5910  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
5911  *        (e.g. folder) to store this file in. If this is 0,
5912  *        the file will be stored in the root folder.
5913  *        <li><code>filedata-&gt;storage_id</code> should be set to the
5914  *        desired storage (e.g. memory card or whatever your device
5915  *        presents) to store this file in. Setting this to 0 will store
5916  *        the file on the primary storage.
5917  *        </ul>
5918  * @param callback a progress indicator function or NULL to ignore.
5919  * @param data a user-defined pointer that is passed along to
5920  *             the <code>progress</code> function in order to
5921  *             pass along some user defined data to the progress
5922  *             updates. If not used, set this to NULL.
5923  * @return 0 if the transfer was successful, any other value means
5924  *           failure.
5925  * @see LIBMTP_Send_File_From_File()
5926  * @see LIBMTP_Send_Track_From_File_Descriptor()
5927  * @see LIBMTP_Delete_Object()
5928  */
5929 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5930 			 int const fd, LIBMTP_file_t * const filedata,
5931                          LIBMTP_progressfunc_t const callback,
5932 			 void const * const data)
5933 {
5934   uint16_t ret;
5935   PTPParams *params = (PTPParams *) device->params;
5936   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5937   LIBMTP_file_t *newfilemeta;
5938   int oldtimeout;
5939   int timeout;
5940 
5941   if (send_file_object_info(device, filedata))
5942   {
5943     // no need to output an error since send_file_object_info will already have done so
5944     return -1;
5945   }
5946 
5947   // Callbacks
5948   ptp_usb->callback_active = 1;
5949   // The callback will deactivate itself after this amount of data has been sent
5950   // One BULK header for the request, one for the data phase. No parameters to the request.
5951   ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5952   ptp_usb->current_transfer_complete = 0;
5953   ptp_usb->current_transfer_callback = callback;
5954   ptp_usb->current_transfer_callback_data = data;
5955 
5956   /*
5957    * We might need to increase the timeout here, files can be pretty
5958    * large. Take the default timeout and add the calculated time for
5959    * this transfer
5960    */
5961   get_usb_device_timeout(ptp_usb, &oldtimeout);
5962   timeout = oldtimeout +
5963     (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
5964   set_usb_device_timeout(ptp_usb, timeout);
5965 
5966   ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5967 
5968   ptp_usb->callback_active = 0;
5969   ptp_usb->current_transfer_callback = NULL;
5970   ptp_usb->current_transfer_callback_data = NULL;
5971   set_usb_device_timeout(ptp_usb, oldtimeout);
5972 
5973   if (ret == PTP_ERROR_CANCEL) {
5974     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5975     return -1;
5976   }
5977   if (ret != PTP_RC_OK) {
5978     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5979 				"Could not send object.");
5980     return -1;
5981   }
5982 
5983   add_object_to_cache(device, filedata->item_id);
5984 
5985   /*
5986    * Get the device-assigned parent_id from the cache.
5987    * The operation that adds it to the cache will
5988    * look it up from the device, so we get the new
5989    * parent_id from the cache.
5990    */
5991   newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5992   if (newfilemeta != NULL) {
5993     filedata->parent_id = newfilemeta->parent_id;
5994     filedata->storage_id = newfilemeta->storage_id;
5995     LIBMTP_destroy_file_t(newfilemeta);
5996   } else {
5997     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5998 			    "LIBMTP_Send_File_From_File_Descriptor(): "
5999 			    "Could not retrieve updated metadata.");
6000     return -1;
6001   }
6002 
6003   return 0;
6004 }
6005 
6006 /**
6007  * This function sends a generic file from a handler function to an
6008  * MTP device. A filename and a set of metadata must be
6009  * given as input.
6010  *
6011  * This can potentially be used for sending in a stream of unknown
6012  * length. Send music files with
6013  * <code>LIBMTP_Send_Track_From_Handler()</code>
6014  *
6015  * @param device a pointer to the device to send the file to.
6016  * @param get_func the function to call to get data to write
6017  * @param priv a user-defined pointer that is passed along to
6018  *        <code>get_func</code>. If not used, this is set to NULL.
6019  * @param filedata a file metadata set to be written along with the file.
6020  *        After this call the field <code>filedata-&gt;item_id</code>
6021  *        will contain the new file ID. Other fields such
6022  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
6023  *        or <code>filedata-&gt;storage_id</code> may also change during this
6024  *        operation due to device restrictions, so do not rely on the
6025  *        contents of this struct to be preserved in any way.
6026  *        <ul>
6027  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
6028  *        (e.g. folder) to store this file in. If this is 0,
6029  *        the file will be stored in the root folder.
6030  *        <li><code>filedata-&gt;storage_id</code> should be set to the
6031  *        desired storage (e.g. memory card or whatever your device
6032  *        presents) to store this file in. Setting this to 0 will store
6033  *        the file on the primary storage.
6034  *        </ul>
6035  * @param callback a progress indicator function or NULL to ignore.
6036  * @param data a user-defined pointer that is passed along to
6037  *             the <code>progress</code> function in order to
6038  *             pass along some user defined data to the progress
6039  *             updates. If not used, set this to NULL.
6040  * @return 0 if the transfer was successful, any other value means
6041  *           failure.
6042  * @see LIBMTP_Send_File_From_File()
6043  * @see LIBMTP_Send_Track_From_File_Descriptor()
6044  * @see LIBMTP_Delete_Object()
6045  */
6046 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
6047 			 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
6048        LIBMTP_progressfunc_t const callback, void const * const data)
6049 {
6050   uint16_t ret;
6051   PTPParams *params = (PTPParams *) device->params;
6052   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6053   LIBMTP_file_t *newfilemeta;
6054 
6055   if (send_file_object_info(device, filedata))
6056   {
6057     // no need to output an error since send_file_object_info will already have done so
6058     return -1;
6059   }
6060 
6061   // Callbacks
6062   ptp_usb->callback_active = 1;
6063   // The callback will deactivate itself after this amount of data has been sent
6064   // One BULK header for the request, one for the data phase. No parameters to the request.
6065   ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
6066   ptp_usb->current_transfer_complete = 0;
6067   ptp_usb->current_transfer_callback = callback;
6068   ptp_usb->current_transfer_callback_data = data;
6069 
6070   MTPDataHandler mtp_handler;
6071   mtp_handler.getfunc = get_func;
6072   mtp_handler.putfunc = NULL;
6073   mtp_handler.priv = priv;
6074 
6075   PTPDataHandler handler;
6076   handler.getfunc = get_func_wrapper;
6077   handler.putfunc = NULL;
6078   handler.priv = &mtp_handler;
6079 
6080   ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
6081 
6082   ptp_usb->callback_active = 0;
6083   ptp_usb->current_transfer_callback = NULL;
6084   ptp_usb->current_transfer_callback_data = NULL;
6085 
6086   if (ret == PTP_ERROR_CANCEL) {
6087     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
6088     return -1;
6089   }
6090   if (ret != PTP_RC_OK) {
6091     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
6092 				"Could not send object.");
6093     return -1;
6094   }
6095 
6096   add_object_to_cache(device, filedata->item_id);
6097 
6098   /*
6099    * Get the device-assined parent_id from the cache.
6100    * The operation that adds it to the cache will
6101    * look it up from the device, so we get the new
6102    * parent_id from the cache.
6103    */
6104   newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
6105   if (newfilemeta != NULL) {
6106     filedata->parent_id = newfilemeta->parent_id;
6107     filedata->storage_id = newfilemeta->storage_id;
6108     LIBMTP_destroy_file_t(newfilemeta);
6109   } else {
6110     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
6111 			    "LIBMTP_Send_File_From_Handler(): "
6112 			    "Could not retrieve updated metadata.");
6113     return -1;
6114   }
6115 
6116   return 0;
6117 }
6118 
6119 /**
6120  * This function sends the file object info, ready for sendobject
6121  * @param device a pointer to the device to send the file to.
6122  * @param filedata a file metadata set to be written along with the file.
6123  * @return 0 if the transfer was successful, any other value means
6124  *           failure.
6125  */
6126 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
6127 {
6128   PTPParams *params = (PTPParams *) device->params;
6129   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6130   uint32_t store;
6131   int use_primary_storage = 1;
6132   uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
6133   LIBMTP_devicestorage_t *storage;
6134   uint32_t localph = filedata->parent_id;
6135   uint16_t ret;
6136   int i;
6137 
6138 #if 0
6139   // Sanity check: no zerolength files on some devices?
6140   // If the zerolength files cause problems on some devices,
6141   // then add a bug flag for this.
6142   if (filedata->filesize == 0) {
6143     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
6144 			    "File of zero size.");
6145     return -1;
6146   }
6147 #endif
6148   if (filedata->storage_id != 0) {
6149     store = filedata->storage_id;
6150   } else {
6151     store = get_suggested_storage_id(device, filedata->filesize, localph);
6152   }
6153 
6154   // Detect if something non-primary is in use.
6155   storage = device->storage;
6156   if (storage != NULL && store != storage->id) {
6157     use_primary_storage = 0;
6158   }
6159 
6160   /*
6161    * If no destination folder was given, look up a default
6162    * folder if possible. Perhaps there is some way of retrieveing
6163    * the default folder for different forms of content, what
6164    * do I know, we use a fixed list in lack of any better method.
6165    * Some devices obviously need to have their files in certain
6166    * folders in order to find/display them at all (hello Creative),
6167    * so we have to have a method for this. We only do this if the
6168    * primary storage is in use.
6169    */
6170 
6171   if (localph == 0 && use_primary_storage) {
6172     if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
6173       localph = device->default_music_folder;
6174     } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
6175       localph = device->default_video_folder;
6176     } else if (of == PTP_OFC_EXIF_JPEG ||
6177 	       of == PTP_OFC_JP2 ||
6178 	       of == PTP_OFC_JPX ||
6179 	       of == PTP_OFC_JFIF ||
6180 	       of == PTP_OFC_TIFF ||
6181 	       of == PTP_OFC_TIFF_IT ||
6182 	       of == PTP_OFC_BMP ||
6183 	       of == PTP_OFC_GIF ||
6184 	       of == PTP_OFC_PICT ||
6185 	       of == PTP_OFC_PNG ||
6186 	       of == PTP_OFC_MTP_WindowsImageFormat) {
6187       localph = device->default_picture_folder;
6188     } else if (of == PTP_OFC_MTP_vCalendar1 ||
6189 	       of == PTP_OFC_MTP_vCalendar2 ||
6190 	       of == PTP_OFC_MTP_UndefinedContact ||
6191 	       of == PTP_OFC_MTP_vCard2 ||
6192 	       of == PTP_OFC_MTP_vCard3 ||
6193 	       of == PTP_OFC_MTP_UndefinedCalendarItem) {
6194       localph = device->default_organizer_folder;
6195     } else if (of == PTP_OFC_Text) {
6196       localph = device->default_text_folder;
6197     }
6198   }
6199 
6200   // Here we wire the type to unknown on bugged, but
6201   // Ogg or FLAC-supportive devices.
6202   if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
6203     of = PTP_OFC_Undefined;
6204   }
6205   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
6206     of = PTP_OFC_Undefined;
6207   }
6208 
6209   if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
6210       !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
6211     /*
6212      * MTP enhanched does it this way (from a sniff):
6213      * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6214      *    20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
6215      *    FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
6216      *    Length: 0x00000020
6217      *    Type:   0x0001 PTP_USB_CONTAINER_COMMAND
6218      *    Code:   0x9808
6219      *    Transaction ID: 0x0000001B
6220      *    Param1: 0x00010001 <- store
6221      *    Param2: 0xffffffff <- parent handle (-1 ?)
6222      *    Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
6223      *    Param4: 0x00000000 <- file length MSB (-0x0c header len)
6224      *    Param5: 0x00005e12 <- file length LSB (-0x0c header len)
6225      *
6226      * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6227      *    46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
6228      *    00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
6229      *    00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
6230      *    00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
6231      *    00 4F DC 02 00 01                               - dc4f = non consumable
6232      *    Length: 0x00000046
6233      *    Type:   0x0002 PTP_USB_CONTAINER_DATA
6234      *    Code:   0x9808
6235      *    Transaction ID: 0x0000001B
6236      *    Metadata....
6237      *    0x00000003 <- Number of metadata items
6238      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6239      *    0xdc07     <- metadata type: file name
6240      *    0xffff     <- metadata type: string
6241      *    0x0d       <- number of (uint16_t) characters
6242      *    4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
6243      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6244      *    0xdc03     <- metadata type: protection status
6245      *    0x0004     <- metadata type: uint16_t
6246      *    0x0000     <- not protected
6247      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6248      *    0xdc4f     <- non consumable
6249      *    0x0002     <- metadata type: uint8_t
6250      *    0x01       <- non-consumable (this device cannot display PDF)
6251      *
6252      * <- Read 0x18 bytes back
6253      *    18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
6254      *    00 00 00 00 01 40 00 00
6255      *    Length: 0x000000018
6256      *    Type:   0x0003 PTP_USB_CONTAINER_RESPONSE
6257      *    Code:   0x2001 PTP_OK
6258      *    Transaction ID: 0x0000001B
6259      *    Param1: 0x00010001 <- store
6260      *    Param2: 0x00000000 <- parent handle
6261      *    Param3: 0x00004001 <- new file/object ID
6262      *
6263      * -> PTP_OC_SendObject (0x100d)
6264      *    0C 00 00 00 01 00 0D 10 1C 00 00 00
6265      * -> ... all the bytes ...
6266      * <- Read 0x0c bytes back
6267      *    0C 00 00 00 03 00 01 20 1C 00 00 00
6268      *    ... Then update metadata one-by one, actually (instead of sending it first!) ...
6269      */
6270     MTPProperties *props = NULL;
6271     int nrofprops = 0;
6272     MTPProperties *prop = NULL;
6273     uint16_t *properties = NULL;
6274     uint32_t propcnt = 0;
6275 
6276     // default parent handle
6277     if (localph == 0)
6278       localph = 0xFFFFFFFFU; // Set to -1
6279 
6280     // Must be 0x00000000U for new objects
6281     filedata->item_id = 0x00000000U;
6282 
6283     ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
6284 
6285     for (i=0;i<propcnt;i++) {
6286       PTPObjectPropDesc opd;
6287 
6288       ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
6289       if (ret != PTP_RC_OK) {
6290 	add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6291 				"could not get property description.");
6292       } else if (opd.GetSet) {
6293 	switch (properties[i]) {
6294 	case PTP_OPC_ObjectFileName:
6295 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6296 	  prop->ObjectHandle = filedata->item_id;
6297 	  prop->property = PTP_OPC_ObjectFileName;
6298 	  prop->datatype = PTP_DTC_STR;
6299 	  if (filedata->filename != NULL) {
6300 	    prop->propval.str = strdup(filedata->filename);
6301 	    if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6302 	      strip_7bit_from_utf8(prop->propval.str);
6303 	    }
6304 	  }
6305 	  break;
6306 	case PTP_OPC_ProtectionStatus:
6307 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6308 	  prop->ObjectHandle = filedata->item_id;
6309 	  prop->property = PTP_OPC_ProtectionStatus;
6310 	  prop->datatype = PTP_DTC_UINT16;
6311 	  prop->propval.u16 = 0x0000U; /* Not protected */
6312 	  break;
6313 	case PTP_OPC_NonConsumable:
6314 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6315 	  prop->ObjectHandle = filedata->item_id;
6316 	  prop->property = PTP_OPC_NonConsumable;
6317 	  prop->datatype = PTP_DTC_UINT8;
6318 	  prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
6319 	  break;
6320 	case PTP_OPC_Name:
6321 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6322 	  prop->ObjectHandle = filedata->item_id;
6323 	  prop->property = PTP_OPC_Name;
6324 	  prop->datatype = PTP_DTC_STR;
6325 	  if (filedata->filename != NULL)
6326 	    prop->propval.str = strdup(filedata->filename);
6327 	  break;
6328 	case PTP_OPC_DateModified:
6329 	  // Tag with current time if that is supported
6330 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6331 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6332 	    prop->ObjectHandle = filedata->item_id;
6333 	    prop->property = PTP_OPC_DateModified;
6334 	    prop->datatype = PTP_DTC_STR;
6335 	    prop->propval.str = get_iso8601_stamp();
6336 	    filedata->modificationdate = time(NULL);
6337 	  }
6338 	  break;
6339 	}
6340       }
6341       ptp_free_objectpropdesc(&opd);
6342     }
6343     free(properties);
6344 
6345     ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
6346 				     of, filedata->filesize, props, nrofprops);
6347 
6348     /* Free property list */
6349     ptp_destroy_object_prop_list(props, nrofprops);
6350 
6351     if (ret != PTP_RC_OK) {
6352       add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
6353 				  "Could not send object property list.");
6354       if (ret == PTP_RC_AccessDenied) {
6355 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6356       }
6357       return -1;
6358     }
6359   } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
6360     PTPObjectInfo new_file;
6361 
6362     memset(&new_file, 0, sizeof(PTPObjectInfo));
6363 
6364     new_file.Filename = filedata->filename;
6365     if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6366       strip_7bit_from_utf8(new_file.Filename);
6367     }
6368     if (filedata->filesize > 0xFFFFFFFFL) {
6369       // This is a kludge in the MTP standard for large files.
6370       new_file.ObjectCompressedSize = (uint32_t) 0xFFFFFFFF;
6371     } else {
6372       new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
6373     }
6374     new_file.ObjectFormat = of;
6375     new_file.StorageID = store;
6376     new_file.ParentObject = localph;
6377     new_file.ModificationDate = time(NULL);
6378 
6379     // Create the object
6380     ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
6381 
6382     if (ret != PTP_RC_OK) {
6383       add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6384 				  "Could not send object info.");
6385       if (ret == PTP_RC_AccessDenied) {
6386 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6387       }
6388       return -1;
6389     }
6390     // NOTE: the char* pointers inside new_file are not copies so don't
6391     // try to destroy this objectinfo!
6392   }
6393 
6394   // Now there IS an object with this parent handle.
6395   filedata->parent_id = localph;
6396 
6397   return 0;
6398 }
6399 
6400 /**
6401  * This function updates the MTP track object metadata on a
6402  * single file identified by an object ID.
6403  * @param device a pointer to the device to update the track
6404  *        metadata on.
6405  * @param metadata a track metadata set to be written to the file.
6406  *        notice that the <code>track_id</code> field of the
6407  *        metadata structure must be correct so that the
6408  *        function can update the right file. If some properties
6409  *        of this metadata are set to NULL (strings) or 0
6410  *        (numerical values) they will be discarded and the
6411  *        track will not be tagged with these blank values.
6412  * @return 0 on success, any other value means failure. If some
6413  *        or all of the properties fail to update we will still
6414  *        return success. On some devices (notably iRiver T30)
6415  *        properties that exist cannot be updated.
6416  */
6417 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
6418 				 LIBMTP_track_t const * const metadata)
6419 {
6420   uint16_t ret;
6421   PTPParams *params = (PTPParams *) device->params;
6422   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6423   uint32_t i;
6424   uint16_t *properties = NULL;
6425   uint32_t propcnt = 0;
6426 
6427   // First see which properties can be set on this file format and apply accordingly
6428   // i.e only try to update this metadata for object tags that exist on the current player.
6429   ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
6430   if (ret != PTP_RC_OK) {
6431     // Just bail out for now, nothing is ever set.
6432     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6433 			    "could not retrieve supported object properties.");
6434     return -1;
6435   }
6436   if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6437       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6438     MTPProperties *props = NULL;
6439     MTPProperties *prop = NULL;
6440     int nrofprops = 0;
6441 
6442     for (i=0;i<propcnt;i++) {
6443       PTPObjectPropDesc opd;
6444 
6445       ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6446       if (ret != PTP_RC_OK) {
6447 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6448 				"could not get property description.");
6449       } else if (opd.GetSet) {
6450 	switch (properties[i]) {
6451 	case PTP_OPC_Name:
6452 	  if (metadata->title == NULL)
6453 	    break;
6454 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6455 	  prop->ObjectHandle = metadata->item_id;
6456 	  prop->property = PTP_OPC_Name;
6457 	  prop->datatype = PTP_DTC_STR;
6458 	  prop->propval.str = strdup(metadata->title);
6459 	  break;
6460 	case PTP_OPC_AlbumName:
6461 	  if (metadata->album == NULL)
6462 	    break;
6463 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6464 	  prop->ObjectHandle = metadata->item_id;
6465 	  prop->property = PTP_OPC_AlbumName;
6466 	  prop->datatype = PTP_DTC_STR;
6467 	  prop->propval.str = strdup(metadata->album);
6468 	  break;
6469 	case PTP_OPC_Artist:
6470 	  if (metadata->artist == NULL)
6471 	    break;
6472 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6473 	  prop->ObjectHandle = metadata->item_id;
6474 	  prop->property = PTP_OPC_Artist;
6475 	  prop->datatype = PTP_DTC_STR;
6476 	  prop->propval.str = strdup(metadata->artist);
6477 	  break;
6478 	case PTP_OPC_Composer:
6479 	  if (metadata->composer == NULL)
6480 	    break;
6481 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6482 	  prop->ObjectHandle = metadata->item_id;
6483 	  prop->property = PTP_OPC_Composer;
6484 	  prop->datatype = PTP_DTC_STR;
6485 	  prop->propval.str = strdup(metadata->composer);
6486 	  break;
6487 	case PTP_OPC_Genre:
6488 	  if (metadata->genre == NULL)
6489 	    break;
6490 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6491 	  prop->ObjectHandle = metadata->item_id;
6492 	  prop->property = PTP_OPC_Genre;
6493 	  prop->datatype = PTP_DTC_STR;
6494 	  prop->propval.str = strdup(metadata->genre);
6495 	  break;
6496 	case PTP_OPC_Duration:
6497 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6498 	  prop->ObjectHandle = metadata->item_id;
6499 	  prop->property = PTP_OPC_Duration;
6500 	  prop->datatype = PTP_DTC_UINT32;
6501 	  prop->propval.u32 = adjust_u32(metadata->duration, &opd);
6502 	  break;
6503 	case PTP_OPC_Track:
6504 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6505 	  prop->ObjectHandle = metadata->item_id;
6506 	  prop->property = PTP_OPC_Track;
6507 	  prop->datatype = PTP_DTC_UINT16;
6508 	  prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
6509 	  break;
6510 	case PTP_OPC_OriginalReleaseDate:
6511 	  if (metadata->date == NULL)
6512 	    break;
6513 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6514 	  prop->ObjectHandle = metadata->item_id;
6515 	  prop->property = PTP_OPC_OriginalReleaseDate;
6516 	  prop->datatype = PTP_DTC_STR;
6517 	  prop->propval.str = strdup(metadata->date);
6518 	  break;
6519 	case PTP_OPC_SampleRate:
6520 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6521 	  prop->ObjectHandle = metadata->item_id;
6522 	  prop->property = PTP_OPC_SampleRate;
6523 	  prop->datatype = PTP_DTC_UINT32;
6524 	  prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
6525 	  break;
6526 	case PTP_OPC_NumberOfChannels:
6527 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6528 	  prop->ObjectHandle = metadata->item_id;
6529 	  prop->property = PTP_OPC_NumberOfChannels;
6530 	  prop->datatype = PTP_DTC_UINT16;
6531 	  prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
6532 	  break;
6533 	case PTP_OPC_AudioWAVECodec:
6534 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6535 	  prop->ObjectHandle = metadata->item_id;
6536 	  prop->property = PTP_OPC_AudioWAVECodec;
6537 	  prop->datatype = PTP_DTC_UINT32;
6538 	  prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
6539 	  break;
6540 	case PTP_OPC_AudioBitRate:
6541 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6542 	  prop->ObjectHandle = metadata->item_id;
6543 	  prop->property = PTP_OPC_AudioBitRate;
6544 	  prop->datatype = PTP_DTC_UINT32;
6545 	  prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
6546 	  break;
6547 	case PTP_OPC_BitRateType:
6548 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6549 	  prop->ObjectHandle = metadata->item_id;
6550 	  prop->property = PTP_OPC_BitRateType;
6551 	  prop->datatype = PTP_DTC_UINT16;
6552 	  prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
6553 	  break;
6554 	case PTP_OPC_Rating:
6555 	  // TODO: shall this be set for rating 0?
6556 	  if (metadata->rating == 0)
6557 	    break;
6558 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6559 	  prop->ObjectHandle = metadata->item_id;
6560 	  prop->property = PTP_OPC_Rating;
6561 	  prop->datatype = PTP_DTC_UINT16;
6562 	  prop->propval.u16 = adjust_u16(metadata->rating, &opd);
6563 	  break;
6564 	case PTP_OPC_UseCount:
6565 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6566 	  prop->ObjectHandle = metadata->item_id;
6567 	  prop->property = PTP_OPC_UseCount;
6568 	  prop->datatype = PTP_DTC_UINT32;
6569 	  prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
6570 	  break;
6571 	case PTP_OPC_DateModified:
6572 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6573 	    // Tag with current time if that is supported
6574 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6575 	    prop->ObjectHandle = metadata->item_id;
6576 	    prop->property = PTP_OPC_DateModified;
6577 	    prop->datatype = PTP_DTC_STR;
6578 	    prop->propval.str = get_iso8601_stamp();
6579 	  }
6580 	  break;
6581 	default:
6582 	  break;
6583 	}
6584       }
6585       ptp_free_objectpropdesc(&opd);
6586     }
6587 
6588     // NOTE: File size is not updated, this should not change anyway.
6589     // neither will we change the filename.
6590 
6591     ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6592 
6593     ptp_destroy_object_prop_list(props, nrofprops);
6594 
6595     if (ret != PTP_RC_OK) {
6596       // TODO: return error of which property we couldn't set
6597       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6598 			      "could not set object property list.");
6599       free(properties);
6600       return -1;
6601     }
6602 
6603   } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6604     for (i=0;i<propcnt;i++) {
6605       PTPObjectPropDesc opd;
6606 
6607       ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6608       if (ret != PTP_RC_OK) {
6609 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6610 				"could not get property description.");
6611       } else if (opd.GetSet) {
6612 	switch (properties[i]) {
6613 	case PTP_OPC_Name:
6614 	  // Update title
6615 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6616 	  if (ret != 0) {
6617 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6618 				    "could not set track title.");
6619 	  }
6620 	  break;
6621 	case PTP_OPC_AlbumName:
6622 	  // Update album
6623 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6624 	  if (ret != 0) {
6625 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6626 				    "could not set track album name.");
6627 	  }
6628 	  break;
6629 	case PTP_OPC_Artist:
6630 	  // Update artist
6631 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6632 	  if (ret != 0) {
6633 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6634 				    "could not set track artist name.");
6635 	  }
6636 	  break;
6637 	case PTP_OPC_Composer:
6638 	  // Update composer
6639 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6640 	  if (ret != 0) {
6641 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6642 				    "could not set track composer name.");
6643 	  }
6644 	  break;
6645 	case PTP_OPC_Genre:
6646 	  // Update genre (but only if valid)
6647 	  if (metadata->genre) {
6648 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6649 	    if (ret != 0) {
6650 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6651 				      "could not set genre.");
6652 	    }
6653 	  }
6654 	  break;
6655 	case PTP_OPC_Duration:
6656 	  // Update duration
6657 	  if (metadata->duration != 0) {
6658 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6659 	    if (ret != 0) {
6660 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6661 				      "could not set track duration.");
6662 	    }
6663 	  }
6664 	  break;
6665 	case PTP_OPC_Track:
6666 	  // Update track number.
6667 	  if (metadata->tracknumber != 0) {
6668 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6669 	    if (ret != 0) {
6670 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6671 				      "could not set track tracknumber.");
6672 	    }
6673 	  }
6674 	  break;
6675 	case PTP_OPC_OriginalReleaseDate:
6676 	  // Update creation datetime
6677 	  // The date can be zero, but some devices do not support setting zero
6678 	  // dates (and it seems that a zero date should never be set anyway)
6679 	  if (metadata->date) {
6680 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6681 	    if (ret != 0) {
6682 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6683 				      "could not set track release date.");
6684 	    }
6685 	  }
6686 	  break;
6687 	  // These are, well not so important.
6688 	case PTP_OPC_SampleRate:
6689 	  // Update sample rate
6690 	  if (metadata->samplerate != 0) {
6691 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6692 	    if (ret != 0) {
6693 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6694 				      "could not set samplerate.");
6695 	    }
6696 	  }
6697 	  break;
6698 	case PTP_OPC_NumberOfChannels:
6699 	  // Update number of channels
6700 	  if (metadata->nochannels != 0) {
6701 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6702 	  if (ret != 0) {
6703 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6704 				    "could not set number of channels.");
6705 	  }
6706 	}
6707 	  break;
6708 	case PTP_OPC_AudioWAVECodec:
6709 	  // Update WAVE codec
6710 	  if (metadata->wavecodec != 0) {
6711 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6712 	    if (ret != 0) {
6713 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6714 				      "could not set WAVE codec.");
6715 	    }
6716 	  }
6717 	  break;
6718 	case PTP_OPC_AudioBitRate:
6719 	  // Update bitrate
6720 	  if (metadata->bitrate != 0) {
6721 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6722 	    if (ret != 0) {
6723 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6724 				      "could not set bitrate.");
6725 	  }
6726 	  }
6727 	  break;
6728 	case PTP_OPC_BitRateType:
6729 	  // Update bitrate type
6730 	  if (metadata->bitratetype != 0) {
6731 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6732 	    if (ret != 0) {
6733 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6734 				      "could not set bitratetype.");
6735 	    }
6736 	  }
6737 	  break;
6738 	case PTP_OPC_Rating:
6739 	  // Update user rating
6740 	  // TODO: shall this be set for rating 0?
6741 	  if (metadata->rating != 0) {
6742 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6743 	    if (ret != 0) {
6744 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6745 				      "could not set user rating.");
6746 	    }
6747 	  }
6748 	  break;
6749 	case PTP_OPC_UseCount:
6750 	  // Update use count, set even to zero if desired.
6751 	  ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6752 	  if (ret != 0) {
6753 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6754 				  "could not set use count.");
6755 	  }
6756 	  break;
6757 	case PTP_OPC_DateModified:
6758 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6759 	    // Update modification time if supported
6760 	    char *tmpstamp = get_iso8601_stamp();
6761 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6762 	    if (ret != 0) {
6763 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6764 				      "could not set modification date.");
6765 	    }
6766 	    free(tmpstamp);
6767 	  }
6768 	  break;
6769 
6770 	  // NOTE: File size is not updated, this should not change anyway.
6771 	  // neither will we change the filename.
6772 	default:
6773 	  break;
6774 	}
6775       }
6776       ptp_free_objectpropdesc(&opd);
6777     }
6778   } else {
6779     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6780                             "Your device doesn't seem to support any known way of setting metadata.");
6781     free(properties);
6782     return -1;
6783   }
6784 
6785   // update cached object properties if metadata cache exists
6786   update_metadata_cache(device, metadata->item_id);
6787 
6788   free(properties);
6789 
6790   return 0;
6791 }
6792 
6793 /**
6794  * This function deletes a single file, track, playlist, folder or
6795  * any other object off the MTP device, identified by the object ID.
6796  *
6797  * If you delete a folder, there is no guarantee that the device will
6798  * really delete all the files that were in that folder, rather it is
6799  * expected that they will not be deleted, and will turn up in object
6800  * listings with parent set to a non-existant object ID. The safe way
6801  * to do this is to recursively delete all files (and folders) contained
6802  * in the folder, then the folder itself.
6803  *
6804  * @param device a pointer to the device to delete the object from.
6805  * @param object_id the object to delete.
6806  * @return 0 on success, any other value means failure.
6807  */
6808 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6809 			 uint32_t object_id)
6810 {
6811   uint16_t ret;
6812   PTPParams *params = (PTPParams *) device->params;
6813 
6814   ret = ptp_deleteobject(params, object_id, 0);
6815   if (ret != PTP_RC_OK) {
6816     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6817     return -1;
6818   }
6819 
6820   return 0;
6821 }
6822 
6823 /**
6824  * The function moves an object from one location on a device to another
6825  * location.
6826  *
6827  * The semantics of moving a folder are not defined in the spec, but it
6828  * appears to do the right thing when tested (but devices that implement
6829  * this operation are rare).
6830  *
6831  * Note that moving an object may take a significant amount of time,
6832  * particularly if being moved between storages. MTP does not provide
6833  * any kind of progress mechanism, so the operation will simply block
6834  * for the duration.
6835  *
6836  * @param device a pointer to the device where the object exists.
6837  * @param object_id the object to move.
6838  * @param storage_id the id of the destination storage.
6839  * @param parent_id the id of the destination parent object (folder).
6840  *	  If the destination is the root of the storage, pass '0'.
6841  * @return 0 on success, any other value means failure.
6842  */
6843 int LIBMTP_Move_Object(LIBMTP_mtpdevice_t *device,
6844 		       uint32_t object_id,
6845 		       uint32_t storage_id,
6846 		       uint32_t parent_id)
6847 {
6848   uint16_t ret;
6849   PTPParams *params = (PTPParams *) device->params;
6850 
6851   ret = ptp_moveobject(params, object_id, storage_id, parent_id);
6852   if (ret != PTP_RC_OK) {
6853     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Move_Object(): could not move object.");
6854     return -1;
6855   }
6856 
6857   return 0;
6858 }
6859 
6860 /**
6861  * The function copies an object from one location on a device to another
6862  * location.
6863  *
6864  * The semantics of copying a folder are not defined in the spec, but it
6865  * appears to do the right thing when tested (but devices that implement
6866  * this operation are rare).
6867  *
6868  * Note that copying an object may take a significant amount of time.
6869  * MTP does not provide any kind of progress mechanism, so the operation
6870  * will simply block for the duration.
6871  *
6872  * @param device a pointer to the device where the object exists.
6873  * @param object_id the object to copy.
6874  * @param storage_id the id of the destination storage.
6875  * @param parent_id the id of the destination parent object (folder).
6876  *	  If the destination is the root of the storage, pass '0'.
6877  * @return 0 on success, any other value means failure.
6878  */
6879 int LIBMTP_Copy_Object(LIBMTP_mtpdevice_t *device,
6880 		       uint32_t object_id,
6881 		       uint32_t storage_id,
6882 		       uint32_t parent_id)
6883 {
6884   uint16_t ret;
6885   PTPParams *params = (PTPParams *) device->params;
6886 
6887   ret = ptp_copyobject(params, object_id, storage_id, parent_id);
6888   if (ret != PTP_RC_OK) {
6889     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Copy_Object(): could not copy object.");
6890     return -1;
6891   }
6892 
6893   return 0;
6894 }
6895 
6896 /**
6897  * Internal function to update an object filename property.
6898  */
6899 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6900 			       uint32_t object_id, uint16_t ptp_type,
6901 			       const char **newname_ptr)
6902 {
6903   PTPParams             *params = (PTPParams *) device->params;
6904   PTP_USB               *ptp_usb = (PTP_USB*) device->usbinfo;
6905   PTPObjectPropDesc     opd;
6906   uint16_t              ret;
6907   char                  *newname;
6908 
6909   // See if we can modify the filename on this kind of files.
6910   ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6911   if (ret != PTP_RC_OK) {
6912     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6913 			    "could not get property description.");
6914     return -1;
6915   }
6916 
6917   if (!opd.GetSet) {
6918     ptp_free_objectpropdesc(&opd);
6919     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6920             " property is not settable.");
6921     // TODO: we COULD actually upload/download the object here, if we feel
6922     //       like wasting time for the user.
6923     return -1;
6924   }
6925 
6926   newname = strdup(*newname_ptr);
6927 
6928   if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6929     strip_7bit_from_utf8(newname);
6930   }
6931 
6932   if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6933       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6934     MTPProperties *props = NULL;
6935     MTPProperties *prop = NULL;
6936     int nrofprops = 0;
6937 
6938     prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6939     prop->ObjectHandle = object_id;
6940     prop->property = PTP_OPC_ObjectFileName;
6941     prop->datatype = PTP_DTC_STR;
6942     prop->propval.str = newname;
6943 
6944     ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6945 
6946     ptp_destroy_object_prop_list(props, nrofprops);
6947 
6948     if (ret != PTP_RC_OK) {
6949         add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6950               " could not set object property list.");
6951         ptp_free_objectpropdesc(&opd);
6952         return -1;
6953     }
6954   } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6955     ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6956     if (ret != 0) {
6957       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6958               " could not set object filename.");
6959       ptp_free_objectpropdesc(&opd);
6960       return -1;
6961     }
6962   } else {
6963     free(newname);
6964     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6965               " your device doesn't seem to support any known way of setting metadata.");
6966     ptp_free_objectpropdesc(&opd);
6967     return -1;
6968   }
6969 
6970   ptp_free_objectpropdesc(&opd);
6971 
6972   // update cached object properties if metadata cache exists
6973   update_metadata_cache(device, object_id);
6974 
6975   return 0;
6976 }
6977 
6978 /**
6979  * This function renames a single file.
6980  * This simply means that the PTP_OPC_ObjectFileName property
6981  * is updated, if this is supported by the device.
6982  *
6983  * @param device a pointer to the device that contains the file.
6984  * @param file the file metadata of the file to rename.
6985  *        On success, the filename member is updated. Be aware, that
6986  *        this name can be different than newname depending of device restrictions.
6987  * @param newname the new filename for this object.
6988  * @return 0 on success, any other value means failure.
6989  */
6990 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6991                    LIBMTP_file_t *file, const char *newname)
6992 {
6993   int         ret;
6994 
6995   ret = set_object_filename(device, file->item_id,
6996 			    map_libmtp_type_to_ptp_type(file->filetype),
6997 			    &newname);
6998 
6999   if (ret != 0) {
7000     return ret;
7001   }
7002 
7003   free(file->filename);
7004   file->filename = strdup(newname);
7005   return ret;
7006 }
7007 
7008 /**
7009  * This function renames a single folder.
7010  * This simply means that the PTP_OPC_ObjectFileName property
7011  * is updated, if this is supported by the device.
7012  *
7013  * @param device a pointer to the device that contains the file.
7014  * @param folder the folder metadata of the folder to rename.
7015  *        On success, the name member is updated. Be aware, that
7016  *        this name can be different than newname depending of device restrictions.
7017  * @param newname the new name for this object.
7018  * @return 0 on success, any other value means failure.
7019  */
7020 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
7021                    LIBMTP_folder_t *folder, const char* newname)
7022 {
7023   int ret;
7024 
7025   ret = set_object_filename(device, folder->folder_id,
7026 			    PTP_OFC_Association,
7027 			    &newname);
7028 
7029   if (ret != 0) {
7030     return ret;
7031     }
7032 
7033   free(folder->name);
7034   folder->name = strdup(newname);
7035   return ret;
7036 }
7037 
7038 /**
7039  * This function renames a single track.
7040  * This simply means that the PTP_OPC_ObjectFileName property
7041  * is updated, if this is supported by the device.
7042  *
7043  * @param device a pointer to the device that contains the file.
7044  * @param track the track metadata of the track to rename.
7045  *        On success, the filename member is updated. Be aware, that
7046  *        this name can be different than newname depending of device restrictions.
7047  * @param newname the new filename for this object.
7048  * @return 0 on success, any other value means failure.
7049  */
7050 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
7051                    LIBMTP_track_t *track, const char* newname)
7052 {
7053   int         ret;
7054 
7055   ret = set_object_filename(device, track->item_id,
7056 			    map_libmtp_type_to_ptp_type(track->filetype),
7057 			    &newname);
7058 
7059   if (ret != 0) {
7060     return ret;
7061   }
7062 
7063   free(track->filename);
7064   track->filename = strdup(newname);
7065   return ret;
7066 }
7067 
7068 /**
7069  * This function renames a single playlist object file holder.
7070  * This simply means that the <code>PTP_OPC_ObjectFileName</code>
7071  * property is updated, if this is supported by the device.
7072  * The playlist filename should nominally end with an extension
7073  * like ".pla".
7074  *
7075  * NOTE: if you want to change the metadata the device display
7076  * about a playlist you must <i>not</i> use this function,
7077  * use <code>LIBMTP_Update_Playlist()</code> instead!
7078  *
7079  * @param device a pointer to the device that contains the file.
7080  * @param playlist the playlist metadata of the playlist to rename.
7081  *        On success, the name member is updated. Be aware, that
7082  *        this name can be different than newname depending of device restrictions.
7083  * @param newname the new name for this object.
7084  * @return 0 on success, any other value means failure.
7085  * @see LIBMTP_Update_Playlist()
7086  */
7087 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
7088                    LIBMTP_playlist_t *playlist, const char* newname)
7089 {
7090   int ret;
7091 
7092   ret = set_object_filename(device, playlist->playlist_id,
7093 			    PTP_OFC_MTP_AbstractAudioVideoPlaylist,
7094 			    &newname);
7095 
7096   if (ret != 0) {
7097     return ret;
7098   }
7099 
7100   free(playlist->name);
7101   playlist->name = strdup(newname);
7102   return ret;
7103 }
7104 
7105 /**
7106  * This function renames a single album.
7107  * This simply means that the <code>PTP_OPC_ObjectFileName</code>
7108  * property is updated, if this is supported by the device.
7109  * The album filename should nominally end with an extension
7110  * like ".alb".
7111  *
7112  * NOTE: if you want to change the metadata the device display
7113  * about a playlist you must <i>not</i> use this function,
7114  * use <code>LIBMTP_Update_Album()</code> instead!
7115  *
7116  * @param device a pointer to the device that contains the file.
7117  * @param album the album metadata of the album to rename.
7118  *        On success, the name member is updated. Be aware, that
7119  *        this name can be different than newname depending of device restrictions.
7120  * @param newname the new name for this object.
7121  * @return 0 on success, any other value means failure.
7122  * @see LIBMTP_Update_Album()
7123  */
7124 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
7125                    LIBMTP_album_t *album, const char* newname)
7126 {
7127   int ret;
7128 
7129   ret = set_object_filename(device, album->album_id,
7130 			    PTP_OFC_MTP_AbstractAudioAlbum,
7131 			    &newname);
7132 
7133   if (ret != 0) {
7134     return ret;
7135   }
7136 
7137   free(album->name);
7138   album->name = strdup(newname);
7139   return ret;
7140 }
7141 
7142 /**
7143  * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
7144  * NOT TO USE IT.
7145  *
7146  * @see LIBMTP_Set_File_Name()
7147  * @see LIBMTP_Set_Track_Name()
7148  * @see LIBMTP_Set_Folder_Name()
7149  * @see LIBMTP_Set_Playlist_Name()
7150  * @see LIBMTP_Set_Album_Name()
7151  */
7152 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
7153                    uint32_t object_id, char* newname)
7154 {
7155   int             ret;
7156   LIBMTP_file_t   *file;
7157 
7158   file = LIBMTP_Get_Filemetadata(device, object_id);
7159 
7160   if (file == NULL) {
7161     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
7162 			    "could not get file metadata for target object.");
7163     return -1;
7164   }
7165 
7166   ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
7167 
7168   free(file);
7169 
7170   return ret;
7171 }
7172 
7173 /**
7174  * Helper function. This indicates if a track exists on the device
7175  * @param device a pointer to the device to get the track from.
7176  * @param id the track ID of the track to retrieve.
7177  * @return TRUE (!=0) if the track exists, FALSE (0) if not
7178  */
7179 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
7180            uint32_t const id)
7181 {
7182   PTPParams *params = (PTPParams *) device->params;
7183   uint16_t ret;
7184   PTPObject *ob;
7185 
7186   ret = ptp_object_want (params, id, 0, &ob);
7187   if (ret == PTP_RC_OK)
7188       return -1;
7189   return 0;
7190 }
7191 
7192 /**
7193  * This creates a new folder structure and allocates memory
7194  * for it. Notice that if you add strings to this structure they
7195  * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
7196  * operation later, so be careful of using strdup() when assigning
7197  * strings, e.g.:
7198  *
7199  * @return a pointer to the newly allocated folder structure.
7200  * @see LIBMTP_destroy_folder_t()
7201  */
7202 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
7203 {
7204   LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
7205   if (new == NULL) {
7206     return NULL;
7207   }
7208   new->folder_id = 0;
7209   new->parent_id = 0;
7210   new->storage_id = 0;
7211   new->name = NULL;
7212   new->sibling = NULL;
7213   new->child = NULL;
7214   return new;
7215 }
7216 
7217 /**
7218  * This recursively deletes the memory for a folder structure.
7219  * This shall typically be called on a top-level folder list to
7220  * detsroy the entire folder tree.
7221  *
7222  * @param folder folder structure to destroy
7223  * @see LIBMTP_new_folder_t()
7224  */
7225 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
7226 {
7227 
7228   if(folder == NULL) {
7229      return;
7230   }
7231 
7232   //Destroy from the bottom up
7233   if(folder->child != NULL) {
7234      LIBMTP_destroy_folder_t(folder->child);
7235   }
7236 
7237   if(folder->sibling != NULL) {
7238     LIBMTP_destroy_folder_t(folder->sibling);
7239   }
7240 
7241   if(folder->name != NULL) {
7242     free(folder->name);
7243   }
7244 
7245   free(folder);
7246 }
7247 
7248 /**
7249  * Helper function. Returns a folder structure for a
7250  * specified id.
7251  *
7252  * @param folderlist list of folders to search
7253  * @id id of folder to look for
7254  * @return a folder or NULL if not found
7255  */
7256 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
7257 {
7258   LIBMTP_folder_t *ret = NULL;
7259 
7260   if(folderlist == NULL) {
7261     return NULL;
7262   }
7263 
7264   if(folderlist->folder_id == id) {
7265     return folderlist;
7266   }
7267 
7268   if(folderlist->sibling) {
7269     ret = LIBMTP_Find_Folder(folderlist->sibling, id);
7270   }
7271 
7272   if(folderlist->child && ret == NULL) {
7273     ret = LIBMTP_Find_Folder(folderlist->child, id);
7274   }
7275 
7276   return ret;
7277 }
7278 
7279 /**
7280  * Function used to recursively get subfolders from params.
7281  */
7282 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
7283 {
7284   LIBMTP_folder_t *retfolders = NULL;
7285   LIBMTP_folder_t *children, *iter, *curr;
7286 
7287   iter = list->sibling;
7288   while(iter != list) {
7289     if (iter->parent_id != parent) {
7290       iter = iter->sibling;
7291       continue;
7292     }
7293 
7294     /* We know that iter is a child of 'parent', therefore we can safely
7295      * hold on to 'iter' locally since no one else will steal it
7296      * from the 'list' as we recurse. */
7297     children = get_subfolders_for_folder(list, iter->folder_id);
7298 
7299     curr = iter;
7300     iter = iter->sibling;
7301 
7302     // Remove curr from the list.
7303     curr->child->sibling = curr->sibling;
7304     curr->sibling->child = curr->child;
7305 
7306     // Attach the children to curr.
7307     curr->child = children;
7308 
7309     // Put this folder into the list of siblings.
7310     curr->sibling = retfolders;
7311     retfolders = curr;
7312   }
7313 
7314   return retfolders;
7315 }
7316 
7317 /**
7318  * This returns a list of all folders available
7319  * on the current MTP device.
7320  *
7321  * @param device a pointer to the device to get the folder listing for.
7322  * @param storage a storage ID to get the folder list from
7323  * @return a list of folders
7324  */
7325  LIBMTP_folder_t *LIBMTP_Get_Folder_List_For_Storage(LIBMTP_mtpdevice_t *device,
7326 						    uint32_t const storage)
7327 {
7328   PTPParams *params = (PTPParams *) device->params;
7329   LIBMTP_folder_t head, *rv;
7330   int i;
7331 
7332   // Get all the handles if we haven't already done that
7333   if (params->nrofobjects == 0) {
7334     flush_handles(device);
7335   }
7336 
7337   /*
7338    * This creates a temporary list of the folders, this is in a
7339    * reverse order and uses the Folder pointers that are already
7340    * in the Folder structure. From this we can then build up the
7341    * folder hierarchy with only looking at this temporary list,
7342    * and removing the folders from this temporary list as we go.
7343    * This significantly reduces the number of operations that we
7344    * have to do in building the folder hierarchy. Also since the
7345    * temp list is in reverse order, when we prepend to the sibling
7346    * list things are in the same order as they were originally
7347    * in the handle list.
7348    */
7349   head.sibling = &head;
7350   head.child = &head;
7351   for (i = 0; i < params->nrofobjects; i++) {
7352     LIBMTP_folder_t *folder;
7353     PTPObject *ob;
7354 
7355     ob = &params->objects[i];
7356     if (ob->oi.ObjectFormat != PTP_OFC_Association) {
7357       continue;
7358     }
7359 
7360     if (storage != PTP_GOH_ALL_STORAGE && storage != ob->oi.StorageID) {
7361       continue;
7362     }
7363 
7364     /*
7365      * Do we know how to handle these? They are part
7366      * of the MTP 1.0 specification paragraph 3.6.4.
7367      * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
7368      * should be called on these to get the contained objects, but
7369      * we basically don't care. Hopefully parent_id is maintained for all
7370      * children, because we rely on that instead.
7371      */
7372     if (ob->oi.AssociationDesc != 0x00000000U) {
7373       LIBMTP_INFO("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
7374     }
7375 
7376     // Create a folder struct...
7377     folder = LIBMTP_new_folder_t();
7378     if (folder == NULL) {
7379       // malloc failure or so.
7380       return NULL;
7381     }
7382     folder->folder_id = ob->oid;
7383     folder->parent_id = ob->oi.ParentObject;
7384     folder->storage_id = ob->oi.StorageID;
7385     folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
7386 
7387     // pretend sibling says next, and child says prev.
7388     folder->sibling = head.sibling;
7389     folder->child = &head;
7390     head.sibling->child = folder;
7391     head.sibling = folder;
7392   }
7393 
7394   // We begin at the given root folder and get them all recursively
7395   rv = get_subfolders_for_folder(&head, 0x00000000U);
7396 
7397   // Some buggy devices may have some files in the "root folder"
7398   // 0xffffffff so if 0x00000000 didn't return any folders,
7399   // look for children of the root 0xffffffffU
7400   if (rv == NULL) {
7401     rv = get_subfolders_for_folder(&head, 0xffffffffU);
7402     if (rv != NULL)
7403       LIBMTP_ERROR("Device have files in \"root folder\" 0xffffffffU - "
7404 		   "this is a firmware bug (but continuing)\n");
7405   }
7406 
7407   // The temp list should be empty. Clean up any orphans just in case.
7408   while(head.sibling != &head) {
7409     LIBMTP_folder_t *curr = head.sibling;
7410 
7411     LIBMTP_INFO("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
7412 	   curr->folder_id,
7413 	   curr->name);
7414     curr->sibling->child = curr->child;
7415     curr->child->sibling = curr->sibling;
7416     curr->child = NULL;
7417     curr->sibling = NULL;
7418     LIBMTP_destroy_folder_t(curr);
7419   }
7420 
7421   return rv;
7422 }
7423 
7424 /**
7425  * This returns a list of all folders available
7426  * on the current MTP device.
7427  *
7428  * @param device a pointer to the device to get the folder listing for.
7429  * @return a list of folders
7430  */
7431 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
7432 {
7433   return LIBMTP_Get_Folder_List_For_Storage(device, PTP_GOH_ALL_STORAGE);
7434 }
7435 
7436 /**
7437  * This create a folder on the current MTP device. The PTP name
7438  * for a folder is "association". The PTP/MTP devices does not
7439  * have an internal "folder" concept really, it contains a flat
7440  * list of all files and some file are "associations" that other
7441  * files and folders may refer to as its "parent".
7442  *
7443  * @param device a pointer to the device to create the folder on.
7444  * @param name the name of the new folder. Note this can be modified
7445  *        if the device does not support all the characters in the
7446  *        name.
7447  * @param parent_id id of parent folder to add the new folder to,
7448  *        or 0xFFFFFFFF to put it in the root directory.
7449  * @param storage_id id of the storage to add this new folder to.
7450  *        notice that you cannot mismatch storage id and parent id:
7451  *        they must both be on the same storage! Pass in 0 if you
7452  *        want to create this folder on the default storage.
7453  * @return id to new folder or 0 if an error occurred
7454  */
7455 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
7456 			      uint32_t parent_id, uint32_t storage_id)
7457 {
7458   PTPParams *params = (PTPParams *) device->params;
7459   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7460   uint32_t parenthandle = 0;
7461   uint32_t store;
7462   PTPObjectInfo new_folder;
7463   uint16_t ret;
7464   uint32_t new_id = 0;
7465 
7466   if (storage_id == 0) {
7467     // I'm just guessing that a folder may require 512 bytes
7468     store = get_suggested_storage_id(device, 512, parent_id);
7469   } else {
7470     store = storage_id;
7471   }
7472   parenthandle = parent_id;
7473 
7474   memset(&new_folder, 0, sizeof(new_folder));
7475   new_folder.Filename = name;
7476   if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7477     strip_7bit_from_utf8(new_folder.Filename);
7478   }
7479   new_folder.ObjectCompressedSize = 0;
7480   new_folder.ObjectFormat = PTP_OFC_Association;
7481   new_folder.ProtectionStatus = PTP_PS_NoProtection;
7482   new_folder.AssociationType = PTP_AT_GenericFolder;
7483   new_folder.ParentObject = parent_id;
7484   new_folder.StorageID = store;
7485 
7486   // Create the object
7487   if (!(params->device_flags & DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST) &&
7488 	ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
7489 	MTPProperties *props = (MTPProperties*)calloc(2,sizeof(MTPProperties));
7490 
7491 	props[0].property = PTP_OPC_ObjectFileName;
7492 	props[0].datatype = PTP_DTC_STR;
7493 	props[0].propval.str = name;
7494 
7495 	props[1].property = PTP_OPC_Name;
7496 	props[1].datatype = PTP_DTC_STR;
7497 	props[1].propval.str = name;
7498 
7499 	ret = ptp_mtp_sendobjectproplist(params, &store, &parenthandle, &new_id, PTP_OFC_Association,
7500 			0, props, 1);
7501 	free(props);
7502   } else {
7503 	ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
7504   }
7505 
7506   if (ret != PTP_RC_OK) {
7507     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
7508     if (ret == PTP_RC_AccessDenied) {
7509       add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7510     }
7511     return 0;
7512   }
7513   // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
7514   // several strings.
7515 
7516   add_object_to_cache(device, new_id);
7517 
7518   return new_id;
7519 }
7520 
7521 /**
7522  * This creates a new playlist metadata structure and allocates memory
7523  * for it. Notice that if you add strings to this structure they
7524  * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
7525  * operation later, so be careful of using strdup() when assigning
7526  * strings, e.g.:
7527  *
7528  * <pre>
7529  * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
7530  * pl->name = strdup(str);
7531  * ....
7532  * LIBMTP_destroy_playlist_t(pl);
7533  * </pre>
7534  *
7535  * @return a pointer to the newly allocated metadata structure.
7536  * @see LIBMTP_destroy_playlist_t()
7537  */
7538 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
7539 {
7540   LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
7541   if (new == NULL) {
7542     return NULL;
7543   }
7544   new->playlist_id = 0;
7545   new->parent_id = 0;
7546   new->storage_id = 0;
7547   new->name = NULL;
7548   new->tracks = NULL;
7549   new->no_tracks = 0;
7550   new->next = NULL;
7551   return new;
7552 }
7553 
7554 /**
7555  * This destroys a playlist metadata structure and deallocates the memory
7556  * used by it, including any strings. Never use a track metadata
7557  * structure again after calling this function on it.
7558  * @param playlist the playlist metadata to destroy.
7559  * @see LIBMTP_new_playlist_t()
7560  */
7561 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
7562 {
7563   if (playlist == NULL) {
7564     return;
7565   }
7566   if (playlist->name != NULL)
7567     free(playlist->name);
7568   if (playlist->tracks != NULL)
7569     free(playlist->tracks);
7570   free(playlist);
7571   return;
7572 }
7573 
7574 /**
7575  * This function returns a list of the playlists available on the
7576  * device. Typical usage:
7577  *
7578  * <pre>
7579  * </pre>
7580  *
7581  * @param device a pointer to the device to get the playlist listing from.
7582  * @return a playlist list on success, else NULL. If there are no playlists
7583  *         on the device, NULL will be returned as well.
7584  * @see LIBMTP_Get_Playlist()
7585  */
7586 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
7587 {
7588   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7589   const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7590   PTPParams *params = (PTPParams *) device->params;
7591   LIBMTP_playlist_t *retlists = NULL;
7592   LIBMTP_playlist_t *curlist = NULL;
7593   uint32_t i;
7594 
7595   // Get all the handles if we haven't already done that
7596   if (params->nrofobjects == 0) {
7597     flush_handles(device);
7598   }
7599 
7600   for (i = 0; i < params->nrofobjects; i++) {
7601     LIBMTP_playlist_t *pl;
7602     PTPObject *ob;
7603     uint16_t ret;
7604 
7605     ob = &params->objects[i];
7606 
7607     // Ignore stuff that isn't playlists
7608 
7609     // For Samsung players we must look for the .spl extension explicitly since
7610     // playlists are not stored as playlist objects.
7611     if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7612       // Allocate a new playlist type
7613       pl = LIBMTP_new_playlist_t();
7614       spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7615     }
7616     else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7617       continue;
7618     }
7619     else {
7620       // Allocate a new playlist type
7621       pl = LIBMTP_new_playlist_t();
7622 
7623       // Try to look up proper name, else use the oi->Filename field.
7624       pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7625       if (pl->name == NULL) {
7626 	pl->name = strdup(ob->oi.Filename);
7627       }
7628       pl->playlist_id = ob->oid;
7629       pl->parent_id = ob->oi.ParentObject;
7630       pl->storage_id = ob->oi.StorageID;
7631 
7632       // Then get the track listing for this playlist
7633       ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7634       if (ret != PTP_RC_OK) {
7635         add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
7636 				    "could not get object references.");
7637         pl->tracks = NULL;
7638         pl->no_tracks = 0;
7639       }
7640     }
7641 
7642     // Add playlist to a list that will be returned afterwards.
7643     if (retlists == NULL) {
7644       retlists = pl;
7645       curlist = pl;
7646     } else {
7647       curlist->next = pl;
7648       curlist = pl;
7649     }
7650 
7651     // Call callback here if we decide to add that possibility...
7652   }
7653   return retlists;
7654 }
7655 
7656 
7657 /**
7658  * This function retrieves an individual playlist from the device.
7659  * @param device a pointer to the device to get the playlist from.
7660  * @param plid the unique ID of the playlist to retrieve.
7661  * @return a valid playlist metadata post or NULL on failure.
7662  * @see LIBMTP_Get_Playlist_List()
7663  */
7664 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
7665 {
7666   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7667   const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7668   PTPParams *params = (PTPParams *) device->params;
7669   PTPObject *ob;
7670   LIBMTP_playlist_t *pl;
7671   uint16_t ret;
7672 
7673   // Get all the handles if we haven't already done that
7674   if (params->nrofobjects == 0) {
7675     flush_handles(device);
7676   }
7677 
7678   ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7679   if (ret != PTP_RC_OK)
7680     return NULL;
7681 
7682   // For Samsung players we must look for the .spl extension explicitly since
7683   // playlists are not stored as playlist objects.
7684   if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7685     // Allocate a new playlist type
7686     pl = LIBMTP_new_playlist_t();
7687     spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7688     return pl;
7689   }
7690 
7691   // Ignore stuff that isn't playlists
7692   else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7693     return NULL;
7694   }
7695 
7696   // Allocate a new playlist type
7697   pl = LIBMTP_new_playlist_t();
7698 
7699   pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7700   if (pl->name == NULL) {
7701     pl->name = strdup(ob->oi.Filename);
7702   }
7703   pl->playlist_id = ob->oid;
7704   pl->parent_id = ob->oi.ParentObject;
7705   pl->storage_id = ob->oi.StorageID;
7706 
7707   // Then get the track listing for this playlist
7708   ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7709   if (ret != PTP_RC_OK) {
7710     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7711     pl->tracks = NULL;
7712     pl->no_tracks = 0;
7713   }
7714 
7715   return pl;
7716 }
7717 
7718 /**
7719  * This function creates a new abstract list such as a playlist
7720  * or an album.
7721  *
7722  * @param device a pointer to the device to create the new abstract list
7723  *        on.
7724  * @param name the name of the new abstract list.
7725  * @param artist the artist of the new abstract list or NULL.
7726  * @param genre the genre of the new abstract list or NULL.
7727  * @param parenthandle the handle of the parent or 0 for no parent
7728  *        i.e. the root folder.
7729  * @param objectformat the abstract list type to create.
7730  * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7731  *        "file" created by this operation.
7732  * @param newid a pointer to a variable that will hold the new object
7733  *        ID if this call is successful.
7734  * @param tracks an array of tracks to associate with this list.
7735  * @param no_tracks the number of tracks in the list.
7736  * @return 0 on success, any other value means failure.
7737  */
7738 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7739 				    char const * const name,
7740 				    char const * const artist,
7741 				    char const * const composer,
7742 				    char const * const genre,
7743 				    uint32_t const parenthandle,
7744 				    uint32_t const storageid,
7745 				    uint16_t const objectformat,
7746 				    char const * const suffix,
7747 				    uint32_t * const newid,
7748 				    uint32_t const * const tracks,
7749 				    uint32_t const no_tracks)
7750 
7751 {
7752   int i;
7753   int supported = 0;
7754   uint16_t ret;
7755   uint16_t *properties = NULL;
7756   uint32_t propcnt = 0;
7757   uint32_t store;
7758   uint32_t localph = parenthandle;
7759   uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7760   PTPParams *params = (PTPParams *) device->params;
7761   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7762   char fname[256];
7763   //uint8_t data[2];
7764 
7765   // NULL check
7766   if (!name) {
7767     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): list name was NULL, using default name \"Unknown\"");
7768     return -1;
7769   }
7770 
7771   if (storageid == 0) {
7772     // I'm just guessing that an abstract list may require 512 bytes
7773     store = get_suggested_storage_id(device, 512, localph);
7774   } else {
7775     store = storageid;
7776   }
7777 
7778   // Check if we can create an object of this type
7779   for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7780     if (params->deviceinfo.ImageFormats[i] == objectformat) {
7781       supported = 1;
7782       break;
7783     }
7784   }
7785   if (!supported) {
7786     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type");
7787     LIBMTP_ERROR("Unsupported abstract list type: %04x\n", objectformat);
7788     return -1;
7789   }
7790 
7791   // add the new suffix if it isn't there
7792   fname[0] = '\0';
7793   if (strlen(name) > strlen(suffix)) {
7794     char const * const suff = &name[strlen(name)-strlen(suffix)];
7795     if (!strcmp(suff, suffix)) {
7796       // Home free.
7797       strncpy(fname, name, sizeof(fname));
7798     }
7799   }
7800   // If it didn't end with "<suffix>" then add that here.
7801   if (fname[0] == '\0') {
7802     strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7803     strcat(fname, suffix);
7804     fname[sizeof(fname)-1] = '\0';
7805   }
7806 
7807   if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7808       !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7809     MTPProperties *props = NULL;
7810     MTPProperties *prop = NULL;
7811     int nrofprops = 0;
7812 
7813     *newid = 0x00000000U;
7814 
7815     ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7816 
7817     for (i=0;i<propcnt;i++) {
7818       PTPObjectPropDesc opd;
7819 
7820       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7821       if (ret != PTP_RC_OK) {
7822 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7823 				"could not get property description.");
7824       } else if (opd.GetSet) {
7825 	switch (properties[i]) {
7826 	case PTP_OPC_ObjectFileName:
7827 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7828 	  prop->ObjectHandle = *newid;
7829 	  prop->property = PTP_OPC_ObjectFileName;
7830 	  prop->datatype = PTP_DTC_STR;
7831 	  prop->propval.str = strdup(fname);
7832 	  if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7833 	    strip_7bit_from_utf8(prop->propval.str);
7834 	  }
7835 	  break;
7836 	case PTP_OPC_ProtectionStatus:
7837 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7838 	  prop->ObjectHandle = *newid;
7839 	  prop->property = PTP_OPC_ProtectionStatus;
7840 	  prop->datatype = PTP_DTC_UINT16;
7841 	  prop->propval.u16 = 0x0000U; /* Not protected */
7842 	  break;
7843 	case PTP_OPC_NonConsumable:
7844 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7845 	  prop->ObjectHandle = *newid;
7846 	  prop->property = PTP_OPC_NonConsumable;
7847 	  prop->datatype = PTP_DTC_UINT8;
7848 	  prop->propval.u8 = nonconsumable;
7849 	  break;
7850 	case PTP_OPC_Name:
7851 	  if (name != NULL) {
7852 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7853 	    prop->ObjectHandle = *newid;
7854 	    prop->property = PTP_OPC_Name;
7855 	    prop->datatype = PTP_DTC_STR;
7856 	    prop->propval.str = strdup(name);
7857 	  }
7858 	  break;
7859 	case PTP_OPC_AlbumArtist:
7860 	  if (artist != NULL) {
7861 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7862 	    prop->ObjectHandle = *newid;
7863 	    prop->property = PTP_OPC_AlbumArtist;
7864 	    prop->datatype = PTP_DTC_STR;
7865 	    prop->propval.str = strdup(artist);
7866 	  }
7867 	  break;
7868 	case PTP_OPC_Artist:
7869 	  if (artist != NULL) {
7870 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7871 	    prop->ObjectHandle = *newid;
7872 	    prop->property = PTP_OPC_Artist;
7873 	    prop->datatype = PTP_DTC_STR;
7874 	    prop->propval.str = strdup(artist);
7875 	  }
7876 	  break;
7877 	case PTP_OPC_Composer:
7878 	  if (composer != NULL) {
7879 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7880 	    prop->ObjectHandle = *newid;
7881 	    prop->property = PTP_OPC_Composer;
7882 	    prop->datatype = PTP_DTC_STR;
7883 	    prop->propval.str = strdup(composer);
7884 	  }
7885 	  break;
7886 	case PTP_OPC_Genre:
7887 	  if (genre != NULL) {
7888 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7889 	    prop->ObjectHandle = *newid;
7890 	    prop->property = PTP_OPC_Genre;
7891 	    prop->datatype = PTP_DTC_STR;
7892 	    prop->propval.str = strdup(genre);
7893 	  }
7894 	  break;
7895  	case PTP_OPC_DateModified:
7896 	  // Tag with current time if that is supported
7897 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7898 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7899 	    prop->ObjectHandle = *newid;
7900 	    prop->property = PTP_OPC_DateModified;
7901 	    prop->datatype = PTP_DTC_STR;
7902 	    prop->propval.str = get_iso8601_stamp();
7903 	  }
7904 	  break;
7905 	}
7906       }
7907       ptp_free_objectpropdesc(&opd);
7908     }
7909     free(properties);
7910 
7911     ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7912 				     objectformat, 0, props, nrofprops);
7913 
7914     /* Free property list */
7915     ptp_destroy_object_prop_list(props, nrofprops);
7916 
7917     if (ret != PTP_RC_OK) {
7918       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7919       if (ret == PTP_RC_AccessDenied) {
7920 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7921       }
7922       return -1;
7923     }
7924 
7925     // now send the blank object
7926     ret = ptp_sendobject(params, NULL, 0);
7927     if (ret != PTP_RC_OK) {
7928       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7929       return -1;
7930     }
7931 
7932   } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7933     PTPObjectInfo new_object;
7934 
7935     new_object.Filename = fname;
7936     if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7937       strip_7bit_from_utf8(new_object.Filename);
7938     }
7939     // At one point this had to be one
7940     new_object.ObjectCompressedSize = 0;
7941     new_object.ObjectFormat = objectformat;
7942 
7943     // Create the object
7944     ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7945     if (ret != PTP_RC_OK) {
7946       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7947       if (ret == PTP_RC_AccessDenied) {
7948 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7949       }
7950       return -1;
7951     }
7952     // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7953     // not copies.
7954 
7955 #if 0
7956     /*
7957      * At one time we had to send this one blank data byte.
7958      * If we didn't, the handle will not be created and thus there is
7959      * no playlist. Possibly this was masking some bug, so removing it
7960      * now.
7961      */
7962     data[0] = '\0';
7963     data[1] = '\0';
7964     ret = ptp_sendobject(params, data, 1);
7965     if (ret != PTP_RC_OK) {
7966       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7967       return -1;
7968     }
7969 #endif
7970 
7971     // set the properties one by one
7972     ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7973 
7974     for (i=0;i<propcnt;i++) {
7975       PTPObjectPropDesc opd;
7976 
7977       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7978       if (ret != PTP_RC_OK) {
7979 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7980 				"could not get property description.");
7981       } else if (opd.GetSet) {
7982 	switch (properties[i]) {
7983 	case PTP_OPC_Name:
7984 	  if (name != NULL) {
7985 	    ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7986 	    if (ret != 0) {
7987 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7988 	      return -1;
7989 	    }
7990 	  }
7991 	  break;
7992 	case PTP_OPC_AlbumArtist:
7993 	  if (artist != NULL) {
7994 	    ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7995 	    if (ret != 0) {
7996 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7997 	      return -1;
7998 	    }
7999 	  }
8000 	  break;
8001 	case PTP_OPC_Artist:
8002 	  if (artist != NULL) {
8003 	    ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
8004 	    if (ret != 0) {
8005 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
8006 	      return -1;
8007 	    }
8008 	  }
8009 	  break;
8010 	case PTP_OPC_Composer:
8011 	  if (composer != NULL) {
8012 	    ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
8013 	    if (ret != 0) {
8014 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
8015 	      return -1;
8016 	    }
8017 	  }
8018 	  break;
8019 	case PTP_OPC_Genre:
8020 	  if (genre != NULL) {
8021 	    ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
8022 	    if (ret != 0) {
8023 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
8024 	      return -1;
8025 	    }
8026 	  }
8027 	  break;
8028  	case PTP_OPC_DateModified:
8029 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8030 	    ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
8031 	    if (ret != 0) {
8032 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
8033 	      return -1;
8034 	    }
8035 	  }
8036 	  break;
8037 	}
8038       }
8039       ptp_free_objectpropdesc(&opd);
8040     }
8041     free(properties);
8042   }
8043 
8044   if (no_tracks > 0) {
8045     // Add tracks to the list as object references.
8046     ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
8047     if (ret != PTP_RC_OK) {
8048       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
8049       return -1;
8050     }
8051   }
8052 
8053   add_object_to_cache(device, *newid);
8054 
8055   return 0;
8056 }
8057 
8058 /**
8059  * This updates the metadata and track listing
8060  * for an abstract list.
8061  * @param device a pointer to the device that the abstract list
8062  *        resides on.
8063  * @param name the name of the abstract list.
8064  * @param artist the artist of the abstract list or NULL.
8065  * @param genre the genre of the abstract list or NULL.
8066  * @param objecthandle the object to be updated.
8067  * @param objectformat the abstract list type to update.
8068  * @param tracks an array of tracks to associate with this list.
8069  * @param no_tracks the number of tracks in the list.
8070  * @return 0 on success, any other value means failure.
8071  */
8072 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
8073 				char const * const name,
8074 				char const * const artist,
8075 				char const * const composer,
8076 				char const * const genre,
8077 				uint32_t const objecthandle,
8078 				uint16_t const objectformat,
8079 				uint32_t const * const tracks,
8080 				uint32_t const no_tracks)
8081 {
8082   uint16_t ret;
8083   PTPParams *params = (PTPParams *) device->params;
8084   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8085   uint16_t *properties = NULL;
8086   uint32_t propcnt = 0;
8087   int i;
8088 
8089   // First see which properties can be set
8090   // i.e only try to update this metadata for object tags that exist on the current player.
8091   ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
8092   if (ret != PTP_RC_OK) {
8093     // Just bail out for now, nothing is ever set.
8094     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8095 			    "could not retrieve supported object properties.");
8096     return -1;
8097   }
8098   if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
8099       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
8100     MTPProperties *props = NULL;
8101     MTPProperties *prop = NULL;
8102     int nrofprops = 0;
8103 
8104     for (i=0;i<propcnt;i++) {
8105       PTPObjectPropDesc opd;
8106 
8107       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
8108       if (ret != PTP_RC_OK) {
8109 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8110 				"could not get property description.");
8111       } else if (opd.GetSet) {
8112 	switch (properties[i]) {
8113 	case PTP_OPC_Name:
8114 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8115 	  prop->ObjectHandle = objecthandle;
8116 	  prop->property = PTP_OPC_Name;
8117 	  prop->datatype = PTP_DTC_STR;
8118 	  if (name != NULL)
8119 	    prop->propval.str = strdup(name);
8120 	  break;
8121 	case PTP_OPC_AlbumArtist:
8122 	  if (artist != NULL) {
8123 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8124 	    prop->ObjectHandle = objecthandle;
8125 	    prop->property = PTP_OPC_AlbumArtist;
8126 	    prop->datatype = PTP_DTC_STR;
8127 	    prop->propval.str = strdup(artist);
8128 	  }
8129 	  break;
8130 	case PTP_OPC_Artist:
8131 	  if (artist != NULL) {
8132 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8133 	    prop->ObjectHandle = objecthandle;
8134 	    prop->property = PTP_OPC_Artist;
8135 	    prop->datatype = PTP_DTC_STR;
8136 	    prop->propval.str = strdup(artist);
8137 	  }
8138 	  break;
8139 	case PTP_OPC_Composer:
8140 	  if (composer != NULL) {
8141 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8142 	    prop->ObjectHandle = objecthandle;
8143 	    prop->property = PTP_OPC_Composer;
8144 	    prop->datatype = PTP_DTC_STR;
8145 	    prop->propval.str = strdup(composer);
8146 	  }
8147 	  break;
8148 	case PTP_OPC_Genre:
8149 	  if (genre != NULL) {
8150 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8151 	    prop->ObjectHandle = objecthandle;
8152 	    prop->property = PTP_OPC_Genre;
8153 	    prop->datatype = PTP_DTC_STR;
8154 	    prop->propval.str = strdup(genre);
8155 	  }
8156 	  break;
8157  	case PTP_OPC_DateModified:
8158 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8159 	    // Tag with current time if that is supported
8160 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8161 	    prop->ObjectHandle = objecthandle;
8162 	    prop->property = PTP_OPC_DateModified;
8163 	    prop->datatype = PTP_DTC_STR;
8164 	    prop->propval.str = get_iso8601_stamp();
8165 	  }
8166 	  break;
8167 	default:
8168 	  break;
8169 	}
8170       }
8171       ptp_free_objectpropdesc(&opd);
8172     }
8173 
8174     // proplist could be NULL if we can't write any properties
8175     if (props != NULL) {
8176       ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
8177 
8178       ptp_destroy_object_prop_list(props, nrofprops);
8179 
8180       if (ret != PTP_RC_OK) {
8181         // TODO: return error of which property we couldn't set
8182         add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8183                                 "could not set object property list.");
8184         free(properties);
8185         return -1;
8186       }
8187     }
8188 
8189   } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
8190     for (i=0;i<propcnt;i++) {
8191       switch (properties[i]) {
8192       case PTP_OPC_Name:
8193 	// Update title
8194 	ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
8195 	if (ret != 0) {
8196 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8197 				  "could not set title.");
8198 	}
8199 	break;
8200       case PTP_OPC_AlbumArtist:
8201 	// Update album artist
8202 	ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
8203 	if (ret != 0) {
8204 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8205 				  "could not set album artist name.");
8206 	}
8207 	break;
8208       case PTP_OPC_Artist:
8209 	// Update artist
8210 	ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
8211 	if (ret != 0) {
8212 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8213 				  "could not set artist name.");
8214 	}
8215 	break;
8216       case PTP_OPC_Composer:
8217 	// Update composer
8218 	ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
8219 	if (ret != 0) {
8220 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8221 				  "could not set composer name.");
8222 	}
8223 	break;
8224       case PTP_OPC_Genre:
8225 	// Update genre (but only if valid)
8226 	if(genre) {
8227 	  ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
8228 	  if (ret != 0) {
8229 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8230 				    "could not set genre.");
8231 	  }
8232         }
8233 	break;
8234       case PTP_OPC_DateModified:
8235 	// Update date modified
8236 	if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8237 	  char *tmpdate = get_iso8601_stamp();
8238 	  ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
8239 	  if (ret != 0) {
8240 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8241 				    "could not set modification date.");
8242 	  }
8243 	  free(tmpdate);
8244 	}
8245 	break;
8246       default:
8247 	break;
8248       }
8249     }
8250   } else {
8251     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8252                             "Your device doesn't seem to support any known way of setting metadata.");
8253     free(properties);
8254     return -1;
8255   }
8256 
8257   // Then the object references...
8258   ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
8259   if (ret != PTP_RC_OK) {
8260     add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
8261     free(properties);
8262     return -1;
8263   }
8264 
8265   free(properties);
8266 
8267   update_metadata_cache(device, objecthandle);
8268 
8269   return 0;
8270 }
8271 
8272 
8273 /**
8274  * This routine creates a new playlist based on the metadata
8275  * supplied. If the <code>tracks</code> field of the metadata
8276  * contains a track listing, these tracks will be added to the
8277  * playlist.
8278  * @param device a pointer to the device to create the new playlist on.
8279  * @param metadata the metadata for the new playlist. If the function
8280  *        exits with success, the <code>playlist_id</code> field of this
8281  *        struct will contain the new playlist ID of the playlist.
8282  *        <ul>
8283  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
8284  *        (e.g. folder) to store this track in. Since some
8285  *        devices are a bit picky about where files
8286  *        are placed, a default folder will be chosen if libmtp
8287  *        has detected one for the current filetype and this
8288  *        parameter is set to 0. If this is 0 and no default folder
8289  *        can be found, the file will be stored in the root folder.
8290  *        <li><code>metadata-&gt;storage_id</code> should be set to the
8291  *        desired storage (e.g. memory card or whatever your device
8292  *        presents) to store this track in. Setting this to 0 will store
8293  *        the track on the primary storage.
8294  *        </ul>
8295  * @return 0 on success, any other value means failure.
8296  * @see LIBMTP_Update_Playlist()
8297  * @see LIBMTP_Delete_Object()
8298  */
8299 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
8300 			       LIBMTP_playlist_t * const metadata)
8301 {
8302   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8303   uint32_t localph = metadata->parent_id;
8304 
8305   // Use a default folder if none given
8306   if (localph == 0) {
8307     if (device->default_playlist_folder != 0)
8308       localph = device->default_playlist_folder;
8309     else
8310       localph = device->default_music_folder;
8311   }
8312   metadata->parent_id = localph;
8313 
8314   // Samsung needs its own special type of playlists
8315   if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8316     return playlist_t_to_spl(device, metadata);
8317   }
8318 
8319   // Just create a new abstract audio/video playlist...
8320   return create_new_abstract_list(device,
8321 				  metadata->name,
8322 				  NULL,
8323 				  NULL,
8324 				  NULL,
8325 				  localph,
8326 				  metadata->storage_id,
8327 				  PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8328 				  get_playlist_extension(ptp_usb),
8329 				  &metadata->playlist_id,
8330 				  metadata->tracks,
8331 				  metadata->no_tracks);
8332 }
8333 
8334 /**
8335  * This routine updates a playlist based on the metadata
8336  * supplied. If the <code>tracks</code> field of the metadata
8337  * contains a track listing, these tracks will be added to the
8338  * playlist in place of those already present, i.e. the
8339  * previous track listing will be deleted. For Samsung devices the
8340  * playlist id (metadata->playlist_id) is likely to change.
8341  * @param device a pointer to the device to create the new playlist on.
8342  * @param metadata the metadata for the playlist to be updated.
8343  *                 notice that the field <code>playlist_id</code>
8344  *                 must contain the appropriate playlist ID. Playlist ID
8345  *                 be modified to a new playlist ID by the time the
8346  *                 function returns since edit-in-place is not always possible.
8347  * @return 0 on success, any other value means failure.
8348  * @see LIBMTP_Create_New_Playlist()
8349  * @see LIBMTP_Delete_Object()
8350  */
8351 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
8352 			   LIBMTP_playlist_t * const metadata)
8353 {
8354 
8355   // Samsung needs its own special type of playlists
8356   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8357   if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8358     return update_spl_playlist(device, metadata);
8359   }
8360 
8361   return update_abstract_list(device,
8362 			      metadata->name,
8363 			      NULL,
8364 			      NULL,
8365 			      NULL,
8366 			      metadata->playlist_id,
8367 			      PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8368 			      metadata->tracks,
8369 			      metadata->no_tracks);
8370 }
8371 
8372 /**
8373  * This creates a new album metadata structure and allocates memory
8374  * for it. Notice that if you add strings to this structure they
8375  * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
8376  * operation later, so be careful of using strdup() when assigning
8377  * strings.
8378  *
8379  * @return a pointer to the newly allocated metadata structure.
8380  * @see LIBMTP_destroy_album_t()
8381  */
8382 LIBMTP_album_t *LIBMTP_new_album_t(void)
8383 {
8384   LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
8385   if (new == NULL) {
8386     return NULL;
8387   }
8388   new->album_id = 0;
8389   new->parent_id = 0;
8390   new->storage_id = 0;
8391   new->name = NULL;
8392   new->artist = NULL;
8393   new->composer = NULL;
8394   new->genre = NULL;
8395   new->tracks = NULL;
8396   new->no_tracks = 0;
8397   new->next = NULL;
8398   return new;
8399 }
8400 
8401 /**
8402  * This recursively deletes the memory for an album structure
8403  *
8404  * @param album structure to destroy
8405  * @see LIBMTP_new_album_t()
8406  */
8407 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
8408 {
8409   if (album == NULL) {
8410     return;
8411   }
8412   if (album->name != NULL)
8413     free(album->name);
8414   if (album->artist != NULL)
8415     free(album->artist);
8416   if (album->composer != NULL)
8417     free(album->composer);
8418   if (album->genre != NULL)
8419     free(album->genre);
8420   if (album->tracks != NULL)
8421     free(album->tracks);
8422   free(album);
8423   return;
8424 }
8425 
8426 /**
8427  * This function maps and copies a property onto the album metadata if applicable.
8428  */
8429 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
8430 					    MTPProperties *prop, LIBMTP_album_t *alb)
8431 {
8432   switch (prop->property) {
8433   case PTP_OPC_Name:
8434     if (prop->propval.str != NULL)
8435       alb->name = strdup(prop->propval.str);
8436     else
8437       alb->name = NULL;
8438     break;
8439   case PTP_OPC_AlbumArtist:
8440     if (prop->propval.str != NULL) {
8441       // This should take precedence over plain "Artist"
8442       if (alb->artist != NULL)
8443 	free(alb->artist);
8444       alb->artist = strdup(prop->propval.str);
8445     } else
8446       alb->artist = NULL;
8447     break;
8448   case PTP_OPC_Artist:
8449     if (prop->propval.str != NULL) {
8450       // Only use of AlbumArtist is not set
8451       if (alb->artist == NULL)
8452 	alb->artist = strdup(prop->propval.str);
8453     } else
8454       alb->artist = NULL;
8455     break;
8456   case PTP_OPC_Composer:
8457     if (prop->propval.str != NULL)
8458       alb->composer = strdup(prop->propval.str);
8459     else
8460       alb->composer = NULL;
8461     break;
8462   case PTP_OPC_Genre:
8463     if (prop->propval.str != NULL)
8464       alb->genre = strdup(prop->propval.str);
8465     else
8466       alb->genre = NULL;
8467     break;
8468   }
8469 }
8470 
8471 /**
8472  * This function retrieves the album metadata for an album
8473  * given by a unique ID.
8474  * @param device a pointer to the device to get the track metadata off.
8475  * @param alb an album metadata metadata set to fill in.
8476  */
8477 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
8478 			       LIBMTP_album_t *alb)
8479 {
8480   uint16_t ret;
8481   PTPParams *params = (PTPParams *) device->params;
8482   uint32_t i;
8483   MTPProperties *prop;
8484   PTPObject *ob;
8485 
8486   /*
8487    * If we have a cached, large set of metadata, then use it!
8488    */
8489   ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
8490   if (ob->mtpprops) {
8491     prop = ob->mtpprops;
8492     for (i=0;i<ob->nrofmtpprops;i++,prop++)
8493       pick_property_to_album_metadata(device, prop, alb);
8494   } else {
8495     uint16_t *props = NULL;
8496     uint32_t propcnt = 0;
8497 
8498     // First see which properties can be retrieved for albums
8499     ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
8500     if (ret != PTP_RC_OK) {
8501       add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
8502       // Just bail out for now, nothing is ever set.
8503       return;
8504     } else {
8505       for (i=0;i<propcnt;i++) {
8506 	switch (props[i]) {
8507 	case PTP_OPC_Name:
8508 	  alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
8509 	  break;
8510 	case PTP_OPC_AlbumArtist:
8511 	  if (alb->artist != NULL)
8512 	    free(alb->artist);
8513 	  alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
8514 	  break;
8515 	case PTP_OPC_Artist:
8516 	  if (alb->artist == NULL)
8517 	    alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
8518 	  break;
8519 	case PTP_OPC_Composer:
8520 	  alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
8521 	  break;
8522 	case PTP_OPC_Genre:
8523 	  alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
8524 	  break;
8525 	default:
8526 	  break;
8527 	}
8528       }
8529       free(props);
8530     }
8531   }
8532 }
8533 
8534 
8535 /**
8536  * This function returns a list of the albums available on the
8537  * device.
8538  *
8539  * @param device a pointer to the device to get the album listing from.
8540  * @return an album list on success, else NULL. If there are no albums
8541  *         on the device, NULL will be returned as well.
8542  * @see LIBMTP_Get_Album()
8543  */
8544 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
8545 {
8546 	// Read all storage devices
8547 	return LIBMTP_Get_Album_List_For_Storage(device, 0);
8548 }
8549 
8550 
8551 /**
8552  * This function returns a list of the albums available on the
8553  * device. You can filter on the storage ID.
8554  *
8555  * @param device a pointer to the device to get the album listing from.
8556  * @param storage_id ID of device storage (if null, all storages)
8557  *
8558  * @return an album list on success, else NULL. If there are no albums
8559  *         on the device, NULL will be returned as well.
8560  * @see LIBMTP_Get_Album()
8561  */
8562 LIBMTP_album_t *LIBMTP_Get_Album_List_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id)
8563 {
8564   PTPParams *params = (PTPParams *) device->params;
8565   LIBMTP_album_t *retalbums = NULL;
8566   LIBMTP_album_t *curalbum = NULL;
8567   uint32_t i;
8568 
8569   // Get all the handles if we haven't already done that
8570   if (params->nrofobjects == 0)
8571     flush_handles(device);
8572 
8573   for (i = 0; i < params->nrofobjects; i++) {
8574     LIBMTP_album_t *alb;
8575     PTPObject *ob;
8576     uint16_t ret;
8577 
8578     ob = &params->objects[i];
8579 
8580     // Ignore stuff that isn't an album
8581     if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
8582       continue;
8583 
8584 	// Ignore stuff that isn't into the storage device
8585 	if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
8586 		continue;
8587 
8588     // Allocate a new album type
8589     alb = LIBMTP_new_album_t();
8590     alb->album_id = ob->oid;
8591     alb->parent_id = ob->oi.ParentObject;
8592     alb->storage_id = ob->oi.StorageID;
8593 
8594     // Fetch supported metadata
8595     get_album_metadata(device, alb);
8596 
8597     // Then get the track listing for this album
8598     ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8599     if (ret != PTP_RC_OK) {
8600       add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
8601       alb->tracks = NULL;
8602       alb->no_tracks = 0;
8603     }
8604 
8605     // Add album to a list that will be returned afterwards.
8606     if (retalbums == NULL) {
8607       retalbums = alb;
8608       curalbum = alb;
8609     } else {
8610       curalbum->next = alb;
8611       curalbum = alb;
8612     }
8613 
8614   }
8615   return retalbums;
8616 }
8617 
8618 /**
8619  * This function retrieves an individual album from the device.
8620  * @param device a pointer to the device to get the album from.
8621  * @param albid the unique ID of the album to retrieve.
8622  * @return a valid album metadata or NULL on failure.
8623  * @see LIBMTP_Get_Album_List()
8624  */
8625 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
8626 {
8627   PTPParams *params = (PTPParams *) device->params;
8628   uint16_t ret;
8629   PTPObject *ob;
8630   LIBMTP_album_t *alb;
8631 
8632   // Get all the handles if we haven't already done that
8633   if (params->nrofobjects == 0)
8634     flush_handles(device);
8635 
8636   ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8637   if (ret != PTP_RC_OK)
8638     return NULL;
8639 
8640   // Ignore stuff that isn't an album
8641   if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
8642     return NULL;
8643 
8644   // Allocate a new album type
8645   alb = LIBMTP_new_album_t();
8646   alb->album_id = ob->oid;
8647   alb->parent_id = ob->oi.ParentObject;
8648   alb->storage_id = ob->oi.StorageID;
8649 
8650   // Fetch supported metadata
8651   get_album_metadata(device, alb);
8652 
8653   // Then get the track listing for this album
8654   ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8655   if (ret != PTP_RC_OK) {
8656     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
8657     alb->tracks = NULL;
8658     alb->no_tracks = 0;
8659   }
8660 
8661   return alb;
8662 }
8663 
8664 /**
8665  * This routine creates a new album based on the metadata
8666  * supplied. If the <code>tracks</code> field of the metadata
8667  * contains a track listing, these tracks will be added to the
8668  * album.
8669  * @param device a pointer to the device to create the new album on.
8670  * @param metadata the metadata for the new album. If the function
8671  *        exits with success, the <code>album_id</code> field of this
8672  *        struct will contain the new ID of the album.
8673  *        <ul>
8674  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
8675  *        (e.g. folder) to store this track in. Since some
8676  *        devices are a bit picky about where files
8677  *        are placed, a default folder will be chosen if libmtp
8678  *        has detected one for the current filetype and this
8679  *        parameter is set to 0. If this is 0 and no default folder
8680  *        can be found, the file will be stored in the root folder.
8681  *        <li><code>metadata-&gt;storage_id</code> should be set to the
8682  *        desired storage (e.g. memory card or whatever your device
8683  *        presents) to store this track in. Setting this to 0 will store
8684  *        the track on the primary storage.
8685  *        </ul>
8686  * @return 0 on success, any other value means failure.
8687  * @see LIBMTP_Update_Album()
8688  * @see LIBMTP_Delete_Object()
8689  */
8690 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
8691 			    LIBMTP_album_t * const metadata)
8692 {
8693   uint32_t localph = metadata->parent_id;
8694 
8695   // Use a default folder if none given
8696   if (localph == 0) {
8697     if (device->default_album_folder != 0)
8698       localph = device->default_album_folder;
8699     else
8700       localph = device->default_music_folder;
8701   }
8702   metadata->parent_id = localph;
8703 
8704   // Just create a new abstract album...
8705   return create_new_abstract_list(device,
8706 				  metadata->name,
8707 				  metadata->artist,
8708 				  metadata->composer,
8709 				  metadata->genre,
8710 				  localph,
8711 				  metadata->storage_id,
8712 				  PTP_OFC_MTP_AbstractAudioAlbum,
8713 				  ".alb",
8714 				  &metadata->album_id,
8715 				  metadata->tracks,
8716 				  metadata->no_tracks);
8717 }
8718 
8719 /**
8720  * This creates a new sample data metadata structure and allocates memory
8721  * for it. Notice that if you add strings to this structure they
8722  * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
8723  * operation later, so be careful of using strdup() when assigning
8724  * strings.
8725  *
8726  * @return a pointer to the newly allocated metadata structure.
8727  * @see LIBMTP_destroy_sampledata_t()
8728  */
8729 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
8730 {
8731   LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
8732   if (new == NULL) {
8733     return NULL;
8734   }
8735   new->height=0;
8736   new->width = 0;
8737   new->data = NULL;
8738   new->duration = 0;
8739   new->size = 0;
8740   return new;
8741 }
8742 
8743 /**
8744  * This destroys a file sample metadata type.
8745  * @param sample the file sample metadata to be destroyed.
8746  */
8747 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8748 {
8749   if (sample == NULL) {
8750     return;
8751   }
8752   if (sample->data != NULL) {
8753     free(sample->data);
8754   }
8755   free(sample);
8756 }
8757 
8758 /**
8759  * This routine figures out whether a certain filetype supports
8760  * representative samples (small thumbnail images) or not. This
8761  * typically applies to JPEG files, MP3 files and Album abstract
8762  * playlists, but in theory any filetype could support representative
8763  * samples.
8764  * @param device a pointer to the device which is to be examined.
8765  * @param filetype the fileype to examine, and return the representative sample
8766  *        properties for.
8767  * @param sample this will contain a new sample type with the fields
8768  *        filled in with suitable default values. For example, the
8769  *        supported sample type will be set, the supported height and
8770  *        width will be set to max values if it is an image sample,
8771  *        and duration will also be given some suitable default value
8772  *        which should not be exceeded on audio samples. If the
8773  *        device does not support samples for this filetype, this
8774  *        pointer will be NULL. If it is not NULL, the user must
8775  *        destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8776  *        after use.
8777  * @return 0 on success, any other value means failure.
8778  * @see LIBMTP_Send_Representative_Sample()
8779  * @see LIBMTP_Create_New_Album()
8780  */
8781 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8782 					    LIBMTP_filetype_t const filetype,
8783 					    LIBMTP_filesampledata_t ** sample)
8784 {
8785   uint16_t ret;
8786   PTPParams *params = (PTPParams *) device->params;
8787   uint16_t *props = NULL;
8788   uint32_t propcnt = 0;
8789   int i;
8790   // TODO: Get rid of these when we can properly query the device.
8791   int support_data = 0;
8792   int support_format = 0;
8793   int support_height = 0;
8794   int support_width = 0;
8795   int support_duration = 0;
8796   int support_size = 0;
8797 
8798   PTPObjectPropDesc opd_height;
8799   PTPObjectPropDesc opd_width;
8800   PTPObjectPropDesc opd_format;
8801   PTPObjectPropDesc opd_duration;
8802   PTPObjectPropDesc opd_size;
8803 
8804   // Default to no type supported.
8805   *sample = NULL;
8806 
8807   ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8808   if (ret != PTP_RC_OK) {
8809     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8810     return -1;
8811   }
8812   /*
8813    * TODO: when walking through these object properties, make calls to
8814    * a new function in ptp.h/ptp.c that can send the command
8815    * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8816    * supported.
8817    */
8818   for (i = 0; i < propcnt; i++) {
8819     switch(props[i]) {
8820     case PTP_OPC_RepresentativeSampleData:
8821       support_data = 1;
8822       break;
8823     case PTP_OPC_RepresentativeSampleFormat:
8824       support_format = 1;
8825       break;
8826     case PTP_OPC_RepresentativeSampleSize:
8827       support_size = 1;
8828       break;
8829     case PTP_OPC_RepresentativeSampleHeight:
8830       support_height = 1;
8831       break;
8832     case PTP_OPC_RepresentativeSampleWidth:
8833       support_width = 1;
8834       break;
8835     case PTP_OPC_RepresentativeSampleDuration:
8836       support_duration = 1;
8837       break;
8838     default:
8839       break;
8840     }
8841   }
8842   free(props);
8843 
8844   if (support_data && support_format && support_height && support_width && !support_duration) {
8845     // Something that supports height and width and not duration is likely to be JPEG
8846     LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8847     /*
8848      * Populate the sample format with the first supported format
8849      *
8850      * TODO: figure out how to pass back more than one format if more are
8851      * supported by the device.
8852      */
8853     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8854     retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8855     ptp_free_objectpropdesc(&opd_format);
8856     /* Populate the maximum image height */
8857     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8858     retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8859     ptp_free_objectpropdesc(&opd_width);
8860     /* Populate the maximum image width */
8861     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8862     retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8863     ptp_free_objectpropdesc(&opd_height);
8864     /* Populate the maximum size */
8865     if (support_size) {
8866       ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8867       retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8868       ptp_free_objectpropdesc(&opd_size);
8869     }
8870     *sample = retsam;
8871   } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8872     // Another qualified guess
8873     LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8874     /*
8875      * Populate the sample format with the first supported format
8876      *
8877      * TODO: figure out how to pass back more than one format if more are
8878      * supported by the device.
8879      */
8880     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8881     retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8882     ptp_free_objectpropdesc(&opd_format);
8883     /* Populate the maximum duration */
8884     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8885     retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8886     ptp_free_objectpropdesc(&opd_duration);
8887     /* Populate the maximum size */
8888     if (support_size) {
8889       ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8890       retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8891       ptp_free_objectpropdesc(&opd_size);
8892     }
8893     *sample = retsam;
8894   }
8895   return 0;
8896 }
8897 
8898 /**
8899  * This routine sends representative sample data for an object.
8900  * This uses the RepresentativeSampleData property of the album,
8901  * if the device supports it. The data should be of a format acceptable
8902  * to the player (for iRiver and Creative, this seems to be JPEG) and
8903  * must not be too large. (for a Creative, max seems to be about 20KB.)
8904  * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8905  * maximum size, dimensions, etc..
8906  * @param device a pointer to the device which the object is on.
8907  * @param id unique id of the object to set artwork for.
8908  * @param pointer to LIBMTP_filesampledata_t struct containing data
8909  * @return 0 on success, any other value means failure.
8910  * @see LIBMTP_Get_Representative_Sample()
8911  * @see LIBMTP_Get_Representative_Sample_Format()
8912  * @see LIBMTP_Create_New_Album()
8913  */
8914 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8915                           uint32_t const id,
8916                           LIBMTP_filesampledata_t *sampledata)
8917 {
8918   uint16_t ret;
8919   PTPParams *params = (PTPParams *) device->params;
8920   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8921   PTPPropertyValue propval;
8922   PTPObject *ob;
8923   uint32_t i;
8924   uint16_t *props = NULL;
8925   uint32_t propcnt = 0;
8926   int supported = 0;
8927 
8928   // get the file format for the object we're going to send representative data for
8929   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8930   if (ret != PTP_RC_OK) {
8931     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8932     return -1;
8933   }
8934 
8935   // check that we can send representative sample data for this object format
8936   ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8937   if (ret != PTP_RC_OK) {
8938     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8939     return -1;
8940   }
8941 
8942   for (i = 0; i < propcnt; i++) {
8943     if (props[i] == PTP_OPC_RepresentativeSampleData) {
8944       supported = 1;
8945       break;
8946     }
8947   }
8948   if (!supported) {
8949     free(props);
8950     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8951     return -1;
8952   }
8953   free(props);
8954 
8955   // Go ahead and send the data
8956   propval.a.count = sampledata->size;
8957   propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8958   for (i = 0; i < sampledata->size; i++) {
8959     propval.a.v[i].u8 = sampledata->data[i];
8960   }
8961 
8962   ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8963 				   &propval,PTP_DTC_AUINT8);
8964   if (ret != PTP_RC_OK) {
8965     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8966     free(propval.a.v);
8967     return -1;
8968   }
8969   free(propval.a.v);
8970 
8971   /* Set the height and width if the sample is an image, otherwise just
8972    * set the duration and size */
8973   switch(sampledata->filetype) {
8974   case LIBMTP_FILETYPE_JPEG:
8975   case LIBMTP_FILETYPE_JFIF:
8976   case LIBMTP_FILETYPE_TIFF:
8977   case LIBMTP_FILETYPE_BMP:
8978   case LIBMTP_FILETYPE_GIF:
8979   case LIBMTP_FILETYPE_PICT:
8980   case LIBMTP_FILETYPE_PNG:
8981     if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8982       // For images, set the height and width
8983       set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8984       set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8985     }
8986     break;
8987   default:
8988     // For anything not an image, set the duration and size
8989     set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8990     set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8991     break;
8992   }
8993 
8994   return 0;
8995 }
8996 
8997 /**
8998  * This routine gets representative sample data for an object.
8999  * This uses the RepresentativeSampleData property of the album,
9000  * if the device supports it.
9001  * @param device a pointer to the device which the object is on.
9002  * @param id unique id of the object to get data for.
9003  * @param pointer to LIBMTP_filesampledata_t struct to receive data
9004  * @return 0 on success, any other value means failure.
9005  * @see LIBMTP_Send_Representative_Sample()
9006  * @see LIBMTP_Get_Representative_Sample_Format()
9007  * @see LIBMTP_Create_New_Album()
9008  */
9009 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
9010                           uint32_t const id,
9011                           LIBMTP_filesampledata_t *sampledata)
9012 {
9013   uint16_t ret;
9014   PTPParams *params = (PTPParams *) device->params;
9015   PTPPropertyValue propval;
9016   PTPObject *ob;
9017   uint32_t i;
9018   uint16_t *props = NULL;
9019   uint32_t propcnt = 0;
9020   int supported = 0;
9021 
9022   // get the file format for the object we're going to send representative data for
9023   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
9024   if (ret != PTP_RC_OK) {
9025     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
9026     return -1;
9027   }
9028 
9029   // check that we can store representative sample data for this object format
9030   ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
9031   if (ret != PTP_RC_OK) {
9032     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
9033     return -1;
9034   }
9035 
9036   for (i = 0; i < propcnt; i++) {
9037     if (props[i] == PTP_OPC_RepresentativeSampleData) {
9038       supported = 1;
9039       break;
9040     }
9041   }
9042   if (!supported) {
9043     free(props);
9044     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
9045     return -1;
9046   }
9047   free(props);
9048 
9049   // Get the data
9050   ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
9051 				   &propval,PTP_DTC_AUINT8);
9052   if (ret != PTP_RC_OK) {
9053     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
9054     return -1;
9055   }
9056 
9057   // Store it
9058   sampledata->size = propval.a.count;
9059   sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
9060   for (i = 0; i < propval.a.count; i++) {
9061     sampledata->data[i] = propval.a.v[i].u8;
9062   }
9063   free(propval.a.v);
9064 
9065   // Get the other properties
9066   sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
9067   sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
9068   sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
9069   sampledata->filetype = map_ptp_type_to_libmtp_type(
9070         get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
9071 
9072   return 0;
9073 }
9074 
9075 /**
9076  * Retrieve the thumbnail for a file.
9077  * @param device a pointer to the device to get the thumbnail from.
9078  * @param id the object ID of the file to retrieve the thumbnail for.
9079  * @return 0 on success, any other value means failure.
9080  */
9081 int LIBMTP_Get_Thumbnail(LIBMTP_mtpdevice_t *device, uint32_t const id,
9082                          unsigned char **data, unsigned int *size)
9083 {
9084   PTPParams *params = (PTPParams *) device->params;
9085   uint16_t ret;
9086 
9087   ret = ptp_getthumb(params, id, data, size);
9088   if (ret == PTP_RC_OK)
9089       return 0;
9090   return -1;
9091 }
9092 
9093 
9094 int LIBMTP_GetPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9095                             uint64_t offset, uint32_t maxbytes,
9096                             unsigned char **data, unsigned int *size)
9097 {
9098   PTPParams	*params = (PTPParams *) device->params;
9099   uint16_t	ret;
9100   LIBMTP_file_t	*mtpfile = LIBMTP_Get_Filemetadata(device, id);
9101 
9102   if (!mtpfile) {
9103       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9104         "LIBMTP_GetPartialObject: could not find mtpfile");
9105     *size = 0;
9106     return -1;
9107   }
9108 
9109   /* Some devices do not like reading over the end and hang instead of progressing */
9110   if (offset >= mtpfile->filesize) {
9111     *size = 0;
9112     LIBMTP_destroy_file_t (mtpfile);
9113     return 0;
9114   }
9115   if (offset + maxbytes > mtpfile->filesize) {
9116     maxbytes = mtpfile->filesize - offset;
9117   }
9118 
9119   /* do not need it anymore */
9120   LIBMTP_destroy_file_t (mtpfile);
9121 
9122   /* The MTP stack of Samsung Galaxy devices has a mysterious bug in
9123    * GetPartialObject. When GetPartialObject is invoked to read the
9124    * last bytes of a file and the amount of data to read is such that
9125    * the last USB packet sent in the reply matches exactly the USB 2.0
9126    * packet size, then the Samsung Galaxy device hangs, resulting in a
9127    * timeout error.
9128    * As a workaround, we read one less byte instead of reaching the
9129    * end of the file, forcing the caller to perform an additional read
9130    * to get the last byte (i.e. the final read that would fail is
9131    * replaced with two partial reads that succeed).
9132    */
9133   if ((params->device_flags & DEVICE_FLAG_SAMSUNG_OFFSET_BUG) &&
9134       (maxbytes % PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) == (PTP_USB_BULK_HS_MAX_PACKET_LEN_READ - PTP_USB_BULK_HDR_LEN)) {
9135     maxbytes--;
9136   }
9137 
9138   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_GetPartialObject64)) {
9139     if  (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
9140       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9141         "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject not supported");
9142       return -1;
9143     }
9144 
9145     if (offset >> 32 != 0) {
9146       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9147         "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject only supports 32bit offsets");
9148       return -1;
9149     }
9150 
9151     ret = ptp_getpartialobject(params, id, (uint32_t)offset, maxbytes, data, size);
9152   } else {
9153     ret = ptp_android_getpartialobject64(params, id, offset, maxbytes, data, size);
9154   }
9155   if (ret == PTP_RC_OK)
9156       return 0;
9157   return -1;
9158 }
9159 
9160 
9161 int LIBMTP_SendPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9162                              uint64_t offset, unsigned char *data, unsigned int size)
9163 {
9164   PTPParams *params = (PTPParams *) device->params;
9165   uint16_t ret;
9166 
9167   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_SendPartialObject)) {
9168     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9169       "LIBMTP_SendPartialObject: PTP_OC_ANDROID_SendPartialObject not supported");
9170     return -1;
9171   }
9172 
9173   ret = ptp_android_sendpartialobject(params, id, offset, data, size);
9174   if (ret == PTP_RC_OK)
9175       return 0;
9176   return -1;
9177 }
9178 
9179 
9180 int LIBMTP_BeginEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9181 {
9182   PTPParams *params = (PTPParams *) device->params;
9183   uint16_t ret;
9184 
9185   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_BeginEditObject)) {
9186     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9187       "LIBMTP_BeginEditObject: PTP_OC_ANDROID_BeginEditObject not supported");
9188     return -1;
9189   }
9190 
9191   ret = ptp_android_begineditobject(params, id);
9192   if (ret == PTP_RC_OK)
9193       return 0;
9194   return -1;
9195 }
9196 
9197 
9198 int LIBMTP_EndEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9199 {
9200   PTPParams *params = (PTPParams *) device->params;
9201   uint16_t ret;
9202 
9203   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_EndEditObject)) {
9204     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9205       "LIBMTP_EndEditObject: PTP_OC_ANDROID_EndEditObject not supported");
9206     return -1;
9207   }
9208 
9209   ret = ptp_android_endeditobject(params, id);
9210   if (ret == PTP_RC_OK) {
9211       // update cached object properties if metadata cache exists
9212       update_metadata_cache(device, id);
9213       return 0;
9214   }
9215   return -1;
9216 }
9217 
9218 
9219 int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9220                           uint64_t offset)
9221 {
9222   PTPParams *params = (PTPParams *) device->params;
9223   uint16_t ret;
9224 
9225   if (!ptp_operation_issupported(params, PTP_OC_ANDROID_TruncateObject)) {
9226     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9227       "LIBMTP_TruncateObject: PTP_OC_ANDROID_TruncateObject not supported");
9228     return -1;
9229   }
9230 
9231   ret = ptp_android_truncate(params, id, offset);
9232   if (ret == PTP_RC_OK)
9233       return 0;
9234   return -1;
9235 }
9236 
9237 
9238 /**
9239  * This routine updates an album based on the metadata
9240  * supplied. If the <code>tracks</code> field of the metadata
9241  * contains a track listing, these tracks will be added to the
9242  * album in place of those already present, i.e. the
9243  * previous track listing will be deleted.
9244  * @param device a pointer to the device to create the new album on.
9245  * @param metadata the metadata for the album to be updated.
9246  *                 notice that the field <code>album_id</code>
9247  *                 must contain the appropriate album ID.
9248  * @return 0 on success, any other value means failure.
9249  * @see LIBMTP_Create_New_Album()
9250  * @see LIBMTP_Delete_Object()
9251  */
9252 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
9253 			   LIBMTP_album_t const * const metadata)
9254 {
9255   return update_abstract_list(device,
9256 			      metadata->name,
9257 			      metadata->artist,
9258 			      metadata->composer,
9259 			      metadata->genre,
9260 			      metadata->album_id,
9261 			      PTP_OFC_MTP_AbstractAudioAlbum,
9262 			      metadata->tracks,
9263 			      metadata->no_tracks);
9264 }
9265 
9266 /**
9267  * Dummy function needed to interface to upstream
9268  * ptp.c/ptp.h files.
9269  */
9270 void ptp_nikon_getptpipguid (unsigned char* guid) {
9271   return;
9272 }
9273 
9274 /**
9275  * Add an object to cache.
9276  * @param device the device which may have a cache to which the object should be added.
9277  * @param object_id the object to add to the cache.
9278  */
9279 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9280 {
9281   PTPParams *params = (PTPParams *)device->params;
9282   uint16_t ret;
9283 
9284   ret = ptp_add_object_to_cache(params, object_id);
9285   if (ret != PTP_RC_OK) {
9286     add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
9287   }
9288 }
9289 
9290 
9291 /**
9292  * Update cache after object has been modified
9293  * @param device the device which may have a cache to which the object should be updated.
9294  * @param object_id the object to update.
9295  */
9296 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9297 {
9298   PTPParams *params = (PTPParams *)device->params;
9299 
9300   ptp_remove_object_from_cache(params, object_id);
9301   add_object_to_cache(device, object_id);
9302 }
9303 
9304 
9305 /**
9306  * Issue custom (e.g. vendor specific) operation (without data phase)
9307  * @param device a pointer to the device to send custom operation to.
9308  * @param code operation code to send.
9309  * @param n_param number of parameters passed.
9310  * @param ... uint32_t operation specific parameters.
9311  */
9312 int LIBMTP_Custom_Operation(LIBMTP_mtpdevice_t *device, uint16_t code, int n_param, ...)
9313 {
9314   PTPParams *params = (PTPParams *) device->params;
9315   PTPContainer ptp;
9316   va_list args;
9317   uint16_t ret;
9318   int i;
9319 
9320   ptp.Code = code;
9321   ptp.Nparam = n_param;
9322   va_start(args, n_param);
9323   for (i = 0; i < n_param; i++)
9324     (&ptp.Param1)[i] = va_arg(args, uint32_t);
9325   va_end(args);
9326 
9327   ret = ptp_transaction_new(params, &ptp, PTP_DP_NODATA, 0, NULL);
9328 
9329   if (ret != PTP_RC_OK) {
9330     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Custom_Operation(): failed to execute operation.");
9331     return -1;
9332   }
9333 
9334   return 0;
9335 }
9336