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