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