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