1 /*
2  *
3  *   File: mtp.c
4  *
5  *   Copyright (C) 2009-2013 Darran Kartaschew
6  *
7  *   This file is part of the gMTP package.
8  *
9  *   gMTP is free software; you can redistribute it and/or modify
10  *   it under the terms of the BSD License as included within the
11  *   file 'COPYING' located in the root directory
12  *
13  */
14 
15 #include "mtp.h"
16 
17 #include <glib/gprintf.h>
18 #include <libgen.h>
19 #include <sys/stat.h>
20 #include <strings.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <utime.h>
25 #include <unistd.h>
26 
27 #include "main.h"
28 #include "callbacks.h"
29 #include "interface.h"
30 #include "prefs.h"
31 #include "metatag_info.h"
32 #include "progress.h"
33 
34 // Array with file extensions matched to internal libmtp file types;
35 // See find_filetype() for usage;
36 MTP_file_ext_struct file_ext[] = {
37     {"wav", LIBMTP_FILETYPE_WAV},
38     {"mp3", LIBMTP_FILETYPE_MP3},
39     {"wma", LIBMTP_FILETYPE_WMA},
40     {"ogg", LIBMTP_FILETYPE_OGG},
41     {"mp4", LIBMTP_FILETYPE_MP4},
42     {"wmv", LIBMTP_FILETYPE_WMV},
43     {"avi", LIBMTP_FILETYPE_AVI},
44     {"mpeg", LIBMTP_FILETYPE_MPEG},
45     {"mpg", LIBMTP_FILETYPE_MPEG},
46     {"asf", LIBMTP_FILETYPE_ASF},
47     {"qt", LIBMTP_FILETYPE_QT},
48     {"mov", LIBMTP_FILETYPE_QT},
49     {"wma", LIBMTP_FILETYPE_WMA},
50     {"jpg", LIBMTP_FILETYPE_JPEG},
51     {"jpeg", LIBMTP_FILETYPE_JPEG},
52     {"jfif", LIBMTP_FILETYPE_JFIF},
53     {"tif", LIBMTP_FILETYPE_TIFF},
54     {"tiff", LIBMTP_FILETYPE_TIFF},
55     {"bmp", LIBMTP_FILETYPE_BMP},
56     {"gif", LIBMTP_FILETYPE_GIF},
57     {"pic", LIBMTP_FILETYPE_PICT},
58     {"pict", LIBMTP_FILETYPE_PICT},
59     {"png", LIBMTP_FILETYPE_PNG},
60     {"wmf", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT},
61     {"ics", LIBMTP_FILETYPE_VCALENDAR2},
62     {"exe", LIBMTP_FILETYPE_WINEXEC},
63     {"com", LIBMTP_FILETYPE_WINEXEC},
64     {"bat", LIBMTP_FILETYPE_WINEXEC},
65     {"dll", LIBMTP_FILETYPE_WINEXEC},
66     {"sys", LIBMTP_FILETYPE_WINEXEC},
67     {"txt", LIBMTP_FILETYPE_TEXT},
68     {"aac", LIBMTP_FILETYPE_AAC},
69     {"mp2", LIBMTP_FILETYPE_MP2},
70     {"flac", LIBMTP_FILETYPE_FLAC},
71     {"m4a", LIBMTP_FILETYPE_M4A},
72     {"doc", LIBMTP_FILETYPE_DOC},
73     {"xml", LIBMTP_FILETYPE_XML},
74     {"xls", LIBMTP_FILETYPE_XLS},
75     {"ppt", LIBMTP_FILETYPE_PPT},
76     {"mht", LIBMTP_FILETYPE_MHT},
77     {"jp2", LIBMTP_FILETYPE_JP2},
78     {"jpx", LIBMTP_FILETYPE_JPX},
79     {"bin", LIBMTP_FILETYPE_FIRMWARE},
80     {"vcf", LIBMTP_FILETYPE_VCARD3},
81     {"alb", LIBMTP_FILETYPE_ALBUM},
82     {"pla", LIBMTP_FILETYPE_PLAYLIST}
83 };
84 
85 static gchar* blank_ext = "";
86 
87 // Ignore Album errors?
88 
89 gboolean AlbumErrorIgnore = FALSE;
90 
91 // ************************************************************************************************
92 
deviceConnect()93 guint deviceConnect() {
94     gint error;
95     if (DeviceMgr.deviceConnected == TRUE) {
96         // We must be wanting to disconnect the device.
97         return deviceDisconnect();
98     } else {
99         error = LIBMTP_Detect_Raw_Devices(&DeviceMgr.rawdevices, &DeviceMgr.numrawdevices);
100         switch (error) {
101             case LIBMTP_ERROR_NONE:
102                 break;
103             case LIBMTP_ERROR_NO_DEVICE_ATTACHED:
104                 g_fprintf(stderr, _("Detect: No raw devices found.\n"));
105                 displayError(_("Detect: No raw devices found.\n"));
106                 return MTP_GENERAL_FAILURE;
107             case LIBMTP_ERROR_CONNECTING:
108                 g_fprintf(stderr, _("Detect: There has been an error connecting. \n"));
109                 displayError(_("Detect: There has been an error connecting. \n"));
110                 return MTP_GENERAL_FAILURE;
111             case LIBMTP_ERROR_MEMORY_ALLOCATION:
112                 g_fprintf(stderr, _("Detect: Encountered a Memory Allocation Error. \n"));
113                 displayError(_("Detect: Encountered a Memory Allocation Error. \n"));
114                 return MTP_GENERAL_FAILURE;
115             default:
116                 // Some other generic error, so let's exit.
117                 g_fprintf(stderr, _("Detect: There has been an error connecting. \n"));
118                 displayError(_("Detect: There has been an error connecting. \n"));
119                 return MTP_GENERAL_FAILURE;
120         }
121         // We have at least 1 raw device, so we connect to the first device.
122         if (DeviceMgr.numrawdevices > 1) {
123             DeviceMgr.rawdeviceID = displayMultiDeviceDialog();
124             if (DeviceMgr.rawdeviceID == -1) {
125                 return deviceDisconnect();
126             }
127             if (!Preferences.use_alt_access_method) {
128                 DeviceMgr.device = LIBMTP_Open_Raw_Device(&DeviceMgr.rawdevices[DeviceMgr.rawdeviceID]);
129             } else {
130                 DeviceMgr.device = LIBMTP_Open_Raw_Device_Uncached(&DeviceMgr.rawdevices[DeviceMgr.rawdeviceID]);
131             }
132         } else {
133             // Connect to the first device.
134             if (!Preferences.use_alt_access_method) {
135                 DeviceMgr.device = LIBMTP_Open_Raw_Device(&DeviceMgr.rawdevices[0]);
136             } else {
137                 DeviceMgr.device = LIBMTP_Open_Raw_Device_Uncached(&DeviceMgr.rawdevices[0]);
138             }
139             DeviceMgr.rawdeviceID = 0;
140         }
141         if (DeviceMgr.device == NULL) {
142             g_fprintf(stderr, _("Detect: Unable to open raw device?\n"));
143             displayError(_("Detect: Unable to open raw device?\n"));
144             LIBMTP_Dump_Errorstack(DeviceMgr.device);
145             LIBMTP_Clear_Errorstack(DeviceMgr.device);
146             DeviceMgr.deviceConnected = FALSE;
147             return MTP_GENERAL_FAILURE;
148         }
149 
150         LIBMTP_Dump_Errorstack(DeviceMgr.device);
151         LIBMTP_Clear_Errorstack(DeviceMgr.device);
152 
153 
154         // We have a successful device connect, but lets check for multiple storageIDs.
155         if (DeviceMgr.device->storage == NULL) {
156             g_fprintf(stderr, _("Detect: No available Storage found on device?\n"));
157             displayError(_("Detect: No available Storage found on device?\n"));
158             LIBMTP_Dump_Errorstack(DeviceMgr.device);
159             LIBMTP_Clear_Errorstack(DeviceMgr.device);
160             deviceDisconnect();
161             return MTP_GENERAL_FAILURE;
162         }
163         if (DeviceMgr.device->storage->next != NULL) {
164             // Oops we have multiple storage IDs.
165             DeviceMgr.storagedeviceID = displayDeviceStorageDialog();
166             if (DeviceMgr.storagedeviceID == -1) {
167                 return deviceDisconnect();
168             }
169         } else {
170             DeviceMgr.storagedeviceID = MTP_DEVICE_SINGLE_STORAGE;
171         }
172         DeviceMgr.deviceConnected = TRUE;
173 
174         currentFolderID = 0;
175         DeviceMgr.devicename = NULL;
176         DeviceMgr.manufacturername = NULL;
177         DeviceMgr.modelname = NULL;
178         DeviceMgr.serialnumber = NULL;
179         DeviceMgr.deviceversion = NULL;
180         //DeviceMgr.syncpartner = NULL;
181         //DeviceMgr.sectime = NULL;
182         DeviceMgr.devcert = NULL;
183         DeviceMgr.Vendor = NULL;
184         DeviceMgr.Product = NULL;
185         DeviceMgr.devicestorage = NULL;
186 
187         // if in alt connection mode;
188         if (Preferences.use_alt_access_method) {
189             if (stackFolderIDs != NULL) {
190                 g_queue_free(stackFolderIDs);
191             }
192             stackFolderIDs = g_queue_new();
193             if (stackFolderNames != NULL) {
194                 g_queue_free(stackFolderNames);
195             }
196             stackFolderNames = g_queue_new();
197         }
198         return MTP_SUCCESS;
199     }
200 }
201 
202 // ************************************************************************************************
203 
deviceDisconnect()204 guint deviceDisconnect() {
205     if (DeviceMgr.deviceConnected == FALSE) {
206         DeviceMgr.deviceConnected = FALSE;
207         return MTP_NO_DEVICE;
208     } else {
209         DeviceMgr.deviceConnected = FALSE;
210         LIBMTP_Release_Device(DeviceMgr.device);
211         g_free(DeviceMgr.rawdevices);
212         // Now clean up the dymanic data in struc that get's loaded when displaying the properties dialog.
213         if (DeviceMgr.devicename != NULL) g_string_free(DeviceMgr.devicename, TRUE);
214         if (DeviceMgr.manufacturername != NULL) g_string_free(DeviceMgr.manufacturername, TRUE);
215         if (DeviceMgr.modelname != NULL) g_string_free(DeviceMgr.modelname, TRUE);
216         if (DeviceMgr.serialnumber != NULL) g_string_free(DeviceMgr.serialnumber, TRUE);
217         if (DeviceMgr.deviceversion != NULL) g_string_free(DeviceMgr.deviceversion, TRUE);
218         //if (DeviceMgr.syncpartner != NULL) g_string_free(DeviceMgr.syncpartner, TRUE);
219         //if (DeviceMgr.sectime != NULL) g_string_free(DeviceMgr.sectime, TRUE);
220         if (DeviceMgr.devcert != NULL) g_string_free(DeviceMgr.devcert, TRUE);
221         if (DeviceMgr.Vendor != NULL) g_string_free(DeviceMgr.Vendor, TRUE);
222         if (DeviceMgr.Product != NULL) g_string_free(DeviceMgr.Product, TRUE);
223         g_free(DeviceMgr.filetypes);
224         return MTP_SUCCESS;
225     }
226 }
227 
228 // ************************************************************************************************
229 
deviceProperties()230 void deviceProperties() {
231     gint ret;
232 
233     // We first see if we have a connected device, and then extract the information from it.
234     if (DeviceMgr.deviceConnected == TRUE) {
235         // Lets get our information. Let's start with the raw information.
236         if (DeviceMgr.Vendor != NULL) g_string_free(DeviceMgr.Vendor, TRUE);
237         if (DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].device_entry.vendor == NULL) {
238             DeviceMgr.Vendor = g_string_new(_("Unknown"));
239         } else {
240             DeviceMgr.Vendor = g_string_new(DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].device_entry.vendor);
241         }
242         if (DeviceMgr.Product != NULL) g_string_free(DeviceMgr.Product, TRUE);
243         if (DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].device_entry.product == NULL) {
244             DeviceMgr.Product = g_string_new(_("Unknown"));
245         } else {
246             DeviceMgr.Product = g_string_new(DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].device_entry.product);
247         }
248         DeviceMgr.VendorID = DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].device_entry.vendor_id;
249         DeviceMgr.ProductID = DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].device_entry.product_id;
250         DeviceMgr.BusLoc = DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].bus_location;
251         DeviceMgr.DeviceID = DeviceMgr.rawdevices[DeviceMgr.rawdeviceID].devnum;
252 
253         // Now lets get our other information.
254         // Nice name:
255         gchar *tmp_string = LIBMTP_Get_Friendlyname(DeviceMgr.device);
256         if (DeviceMgr.devicename != NULL) g_string_free(DeviceMgr.devicename, TRUE);
257         if (tmp_string == NULL) {
258             DeviceMgr.devicename = g_string_new(_("N/A"));
259         } else {
260             DeviceMgr.devicename = g_string_new(tmp_string);
261             g_free(tmp_string);
262         }
263         // Battery Level
264         ret = LIBMTP_Get_Batterylevel(DeviceMgr.device, &DeviceMgr.maxbattlevel, &DeviceMgr.currbattlevel);
265         if (ret != 0) {
266             // Silently ignore. Some devices does not support getting the
267             // battery level.
268             DeviceMgr.maxbattlevel = 0;
269             DeviceMgr.currbattlevel = 0;
270             LIBMTP_Clear_Errorstack(DeviceMgr.device);
271         }
272         // Manufacturer Name.
273         tmp_string = LIBMTP_Get_Manufacturername(DeviceMgr.device);
274         if (DeviceMgr.manufacturername != NULL) g_string_free(DeviceMgr.manufacturername, TRUE);
275         if (tmp_string == NULL) {
276             DeviceMgr.manufacturername = g_string_new(_("N/A"));
277         } else {
278             DeviceMgr.manufacturername = g_string_new(tmp_string);
279             g_free(tmp_string);
280         }
281         // Model Number,
282         tmp_string = LIBMTP_Get_Modelname(DeviceMgr.device);
283         if (DeviceMgr.modelname != NULL) g_string_free(DeviceMgr.modelname, TRUE);
284         if (tmp_string == NULL) {
285             DeviceMgr.modelname = g_string_new(_("N/A"));
286         } else {
287             DeviceMgr.modelname = g_string_new(tmp_string);
288             g_free(tmp_string);
289         }
290         // Serial Number.
291         tmp_string = LIBMTP_Get_Serialnumber(DeviceMgr.device);
292         if (DeviceMgr.serialnumber != NULL) g_string_free(DeviceMgr.serialnumber, TRUE);
293         if (tmp_string == NULL) {
294             DeviceMgr.serialnumber = g_string_new(_("N/A"));
295         } else {
296             DeviceMgr.serialnumber = g_string_new(tmp_string);
297             g_free(tmp_string);
298         }
299         // Device Version.
300         tmp_string = LIBMTP_Get_Deviceversion(DeviceMgr.device);
301         if (DeviceMgr.deviceversion != NULL) g_string_free(DeviceMgr.deviceversion, TRUE);
302         if (tmp_string == NULL) {
303             DeviceMgr.deviceversion = g_string_new(_("N/A"));
304         } else {
305             DeviceMgr.deviceversion = g_string_new(tmp_string);
306             g_free(tmp_string);
307         }
308         // Storage.
309         if (DeviceMgr.devicestorage == NULL) {
310             if (LIBMTP_Get_Storage(DeviceMgr.device, 0) < 0) {
311                 // We have an error getting our storage, so let the user know and then disconnect the device.
312                 displayError("Failed to get storage parameters from the device - need to disconnect.");
313                 on_deviceConnect_activate(NULL, NULL);
314                 return;
315             }
316             if (DeviceMgr.storagedeviceID == MTP_DEVICE_SINGLE_STORAGE) {
317                 DeviceMgr.devicestorage = DeviceMgr.device->storage;
318             } else {
319                 DeviceMgr.devicestorage = getCurrentDeviceStoragePtr(DeviceMgr.storagedeviceID);
320             }
321             // Supported filetypes;
322             ret = LIBMTP_Get_Supported_Filetypes(DeviceMgr.device, &DeviceMgr.filetypes, &DeviceMgr.filetypes_len);
323             if (ret != 0) {
324                 LIBMTP_Dump_Errorstack(DeviceMgr.device);
325                 LIBMTP_Clear_Errorstack(DeviceMgr.device);
326             }
327         }
328     } else {
329         // Set to to none.
330         g_fprintf(stderr, _("DevicePropeties: How did I get called?\n"));
331         DeviceMgr.device = NULL;
332     }
333 }
334 
335 // ************************************************************************************************
336 
clearDeviceFiles(LIBMTP_file_t * filelist)337 void clearDeviceFiles(LIBMTP_file_t * filelist) {
338     if (filelist != NULL) {
339         if (filelist->next != NULL) {
340             clearDeviceFiles(filelist->next);
341             filelist->next = NULL;
342         }
343         LIBMTP_destroy_file_t(filelist);
344     }
345 }
346 
347 // ************************************************************************************************
348 
clearAlbumStruc(LIBMTP_album_t * albumlist)349 void clearAlbumStruc(LIBMTP_album_t * albumlist) {
350     if (albumlist != NULL) {
351         if (albumlist->next != NULL) {
352             clearAlbumStruc(albumlist->next);
353             albumlist->next = NULL;
354         }
355         LIBMTP_destroy_album_t(albumlist);
356     }
357 }
358 
359 // ************************************************************************************************
360 
clearDevicePlaylist(LIBMTP_playlist_t * playlist_list)361 void clearDevicePlaylist(LIBMTP_playlist_t * playlist_list) {
362     if (playlist_list != NULL) {
363         if (playlist_list->next != NULL) {
364             clearDevicePlaylist(playlist_list->next);
365             playlist_list->next = NULL;
366         }
367         LIBMTP_destroy_playlist_t(playlist_list);
368     }
369 }
370 
371 // ************************************************************************************************
372 
clearDeviceTracks(LIBMTP_track_t * tracklist)373 void clearDeviceTracks(LIBMTP_track_t * tracklist) {
374     if (tracklist != NULL) {
375         if (tracklist->next != NULL) {
376             clearDeviceTracks(tracklist->next);
377             tracklist->next = NULL;
378         }
379         LIBMTP_destroy_track_t(tracklist);
380     }
381 }
382 
383 // ************************************************************************************************
384 
printFolders(LIBMTP_folder_t * fold)385 void printFolders(LIBMTP_folder_t *fold) {
386     while (fold != NULL) {
387         g_printf("folder: %s\n", fold->name);
388         if (fold->child != NULL) {
389             printFolders(fold->child);
390         }
391         fold = fold->sibling;
392     }
393 }
394 
395 // ************************************************************************************************
396 
deviceRescan()397 void deviceRescan() {
398 
399     //g_print("You selected deviceRescan\n");
400     // First we clear the file and folder list...
401     fileListClear();
402     folderListClear();
403     // Now clear the folder/file structures.
404     if (deviceFolders != NULL)
405         LIBMTP_destroy_folder_t(deviceFolders);
406     if (deviceFiles != NULL)
407         clearDeviceFiles(deviceFiles);
408     // Add in track, playlist globals as well.
409     deviceFolders = NULL;
410     deviceFiles = NULL;
411     // Now get started.
412     if (DeviceMgr.deviceConnected) {
413         // Get a list of folder on the device. (Note: this may fail on some devices, and we end up with zero folders being listed)
414         deviceFolders = LIBMTP_Get_Folder_List_For_Storage(DeviceMgr.device, DeviceMgr.devicestorage->id);
415         if (deviceFolders == NULL) {
416             LIBMTP_Dump_Errorstack(DeviceMgr.device);
417             LIBMTP_Clear_Errorstack(DeviceMgr.device);
418         }
419         // Now get a list of files from the device.
420         if (!Preferences.use_alt_access_method) {
421             deviceFiles = LIBMTP_Get_Filelisting_With_Callback(DeviceMgr.device, NULL, NULL);
422         } else {
423             // Alternate access method ONLY gets the files for the CURRENT FOLDER ONLY. This should help some Android based devices.
424             deviceFiles = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, currentFolderID);
425         }
426         if (deviceFiles == NULL) {
427             LIBMTP_Dump_Errorstack(DeviceMgr.device);
428             LIBMTP_Clear_Errorstack(DeviceMgr.device);
429         }
430         devicePlayLists = getPlaylists();
431         deviceTracks = getTracks();
432         fileListAdd();
433         folderListAdd(deviceFolders, NULL);
434         // Now update the storage...
435         if (DeviceMgr.devicestorage == NULL) {
436             if (LIBMTP_Get_Storage(DeviceMgr.device, 0) < 0) {
437                 // We have an error getting our storage, so let the user know and then disconnect the device.
438                 displayError(_("Failed to get storage parameters from the device - need to disconnect."));
439                 on_deviceConnect_activate(NULL, NULL);
440                 return;
441             }
442             if (DeviceMgr.storagedeviceID == MTP_DEVICE_SINGLE_STORAGE) {
443                 DeviceMgr.devicestorage = DeviceMgr.device->storage;
444             } else {
445                 DeviceMgr.devicestorage = getCurrentDeviceStoragePtr(DeviceMgr.storagedeviceID);
446             }
447         }
448         // Update the status bar.
449         gchar* tmp_string;
450         if (DeviceMgr.storagedeviceID == MTP_DEVICE_SINGLE_STORAGE) {
451             tmp_string = g_strdup_printf(_("Connected to %s - %d MB free"), DeviceMgr.devicename->str,
452                     (int) (DeviceMgr.devicestorage->FreeSpaceInBytes / MEGABYTE));
453         } else {
454             if (DeviceMgr.devicestorage->StorageDescription != NULL) {
455                 tmp_string = g_strdup_printf(_("Connected to %s (%s) - %d MB free"), DeviceMgr.devicename->str,
456                         DeviceMgr.devicestorage->StorageDescription,
457                         (int) (DeviceMgr.devicestorage->FreeSpaceInBytes / MEGABYTE));
458             } else {
459                 tmp_string = g_strdup_printf(_("Connected to %s - %d MB free"), DeviceMgr.devicename->str,
460                         (int) (DeviceMgr.devicestorage->FreeSpaceInBytes / MEGABYTE));
461             }
462         }
463         statusBarSet(tmp_string);
464         g_free(tmp_string);
465     } else {
466         g_fprintf(stderr, _("Rescan: How did I get called?\n"));
467     }
468 }
469 
470 // ************************************************************************************************
471 
getCurrentDeviceStoragePtr(gint StorageID)472 LIBMTP_devicestorage_t* getCurrentDeviceStoragePtr(gint StorageID) {
473     LIBMTP_devicestorage_t* deviceStorage = DeviceMgr.device->storage;
474     gint i = 0;
475     // This is easy, as the gint is the number of hops we need to do to get to our target.
476     if (StorageID == MTP_DEVICE_SINGLE_STORAGE)
477         return DeviceMgr.device->storage;
478     if (StorageID == 0)
479         return DeviceMgr.device->storage;
480     for (i = 0; i < StorageID; i++) {
481         deviceStorage = deviceStorage->next;
482         if (deviceStorage == NULL) // Oops, off the end
483             return DeviceMgr.device->storage;
484     }
485     return deviceStorage;
486 }
487 
488 // ************************************************************************************************
489 
getParentFolderID(LIBMTP_folder_t * tmpfolder,uint32_t currentFolderID)490 uint32_t getParentFolderID(LIBMTP_folder_t *tmpfolder, uint32_t currentFolderID) {
491     uint32_t parentID = 0;
492     if (tmpfolder == NULL) {
493         return 0;
494     }
495     if (tmpfolder->folder_id == currentFolderID) {
496         parentID = tmpfolder->parent_id;
497         return parentID;
498     }
499     parentID = getParentFolderID(tmpfolder->child, currentFolderID);
500     if (parentID != 0)
501         return parentID;
502     parentID = getParentFolderID(tmpfolder->sibling, currentFolderID);
503     return parentID;
504 }
505 
506 // ************************************************************************************************
507 
getParentFolderPtr(LIBMTP_folder_t * tmpfolder,uint32_t currentFolderID)508 LIBMTP_folder_t* getParentFolderPtr(LIBMTP_folder_t *tmpfolder, uint32_t currentFolderID) {
509     LIBMTP_folder_t* parentID = NULL;
510     if (tmpfolder == NULL) {
511         return tmpfolder;
512     }
513     if (tmpfolder->parent_id == currentFolderID) {
514         return tmpfolder;
515     }
516     parentID = getParentFolderPtr(tmpfolder->child, currentFolderID);
517     if (parentID != NULL)
518         return parentID;
519     parentID = getParentFolderPtr(tmpfolder->sibling, currentFolderID);
520     return parentID;
521 }
522 
523 // ************************************************************************************************
524 
getCurrentFolderPtr(LIBMTP_folder_t * tmpfolder,uint32_t FolderID)525 LIBMTP_folder_t* getCurrentFolderPtr(LIBMTP_folder_t *tmpfolder, uint32_t FolderID) {
526     LIBMTP_folder_t* parentID = NULL;
527     if (tmpfolder == NULL) {
528         return tmpfolder;
529     }
530     if (tmpfolder->folder_id == FolderID) {
531         return tmpfolder;
532     }
533     parentID = getCurrentFolderPtr(tmpfolder->child, FolderID);
534     if (parentID != NULL)
535         return parentID;
536     parentID = getCurrentFolderPtr(tmpfolder->sibling, FolderID);
537     return parentID;
538 }
539 
540 // ************************************************************************************************
541 
filesUpateFileList()542 void filesUpateFileList() {
543     if (deviceFiles != NULL) {
544         clearDeviceFiles(deviceFiles);
545     }
546     deviceFiles = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, currentFolderID);
547     if (deviceFiles == NULL) {
548         LIBMTP_Dump_Errorstack(DeviceMgr.device);
549         LIBMTP_Clear_Errorstack(DeviceMgr.device);
550     }
551 }
552 
553 // ************************************************************************************************
554 
filesAdd(gchar * filename)555 void filesAdd(gchar* filename) {
556     struct stat sb;
557 
558     // Maybe something went wrong, so we disconnected. If so, then simple exit....
559     if (DeviceMgr.deviceConnected == FALSE) {
560         return;
561     }
562 
563     if (progressDialog_killed == TRUE) {
564         return;
565     }
566 
567     if (stat(filename, &sb) == -1) {
568         perror("stat");
569         return;
570     }
571 
572     uint64_t filesize = sb.st_size;
573     if (filesize > DeviceMgr.devicestorage->FreeSpaceInBytes) {
574         g_fprintf(stderr, _("Unable to add %s due to insufficient space: filesize = %llu, freespace = %llu\n"),
575                 filename,
576                 (unsigned long long int) filesize,
577                 (unsigned long long int) DeviceMgr.devicestorage->FreeSpaceInBytes);
578         displayError(_("Unable to add file due to insufficient space"));
579         return;
580     }
581 
582     gchar *filename_stripped = basename(filename);
583     //displayProgressBar(_("File Upload"));
584     setProgressFilename((filename_stripped));
585 
586     // What we need to do is work what type of file we are sending
587     // and either use the general file send, or
588     // use the track send function.
589     gint ret = find_filetype(filename_stripped);
590 
591     gboolean useTrack = (ret == LIBMTP_FILETYPE_MP3) ||
592             (ret == LIBMTP_FILETYPE_OGG) ||
593             (ret == LIBMTP_FILETYPE_FLAC) ||
594             (ret == LIBMTP_FILETYPE_WMA);
595 
596     if (Preferences.allmediaasfiles) {
597         useTrack = FALSE;
598     }
599 
600     if (useTrack) {
601         // We have an MP3/Ogg/FLAC/WMA file.
602         LIBMTP_track_t *trackfile = LIBMTP_new_track_t();
603 
604         trackfile->filesize = filesize;
605         trackfile->filename = g_strdup(filename_stripped);
606         trackfile->filetype = find_filetype(filename_stripped);
607         trackfile->parent_id = currentFolderID;
608         trackfile->storage_id = DeviceMgr.devicestorage->id;
609         trackfile->album = NULL;
610         trackfile->title = NULL;
611         trackfile->artist = NULL;
612         trackfile->date = NULL;
613         trackfile->genre = NULL;
614         trackfile->tracknumber = 0;
615 
616         LIBMTP_album_t *albuminfo = LIBMTP_new_album_t();
617         albuminfo->parent_id = currentFolderID;
618         albuminfo->storage_id = DeviceMgr.devicestorage->id;
619         albuminfo->album_id = 0;
620         // Let's collect our metadata from the file, typically id3 tag data.
621         switch (ret) {
622             case LIBMTP_FILETYPE_MP3:
623                 // We have an MP3 file, so use id3tag to read the metadata.
624                 get_id3_tags(filename, trackfile);
625                 break;
626             case LIBMTP_FILETYPE_OGG:
627                 get_ogg_tags(filename, trackfile);
628                 break;
629             case LIBMTP_FILETYPE_FLAC:
630                 get_flac_tags(filename, trackfile);
631                 break;
632             case LIBMTP_FILETYPE_WMA:
633                 get_asf_tags(filename, trackfile);
634                 break;
635                 //break;
636 
637         }
638         // Add some data if it's all blank so we don't freak out some players.
639         if (trackfile->album == NULL)
640             trackfile->album = NULL;
641         if (trackfile->title == NULL)
642             trackfile->title = g_strdup(filename_stripped);
643         if (trackfile->artist == NULL)
644             trackfile->artist = g_strdup(_("<Unknown>"));
645         if (trackfile->date == NULL) {
646             trackfile->date = g_strdup("");
647         } else {
648             if (strlen(trackfile->date) == 4) {
649                 // only have year part, so extend it.
650                 trackfile->date = g_strconcat(trackfile->date, "0101T000000", NULL);
651             }
652         }
653         if (trackfile->genre == NULL)
654             trackfile->genre = g_strdup(_("<Unknown>"));
655 
656         // Update our album info, if we actually have an album.
657         if (trackfile->album != NULL) {
658             albuminfo->name = g_strdup(trackfile->album);
659             albuminfo->artist = g_strdup(trackfile->artist);
660             albuminfo->composer = NULL;
661             albuminfo->genre = g_strdup(trackfile->genre);
662         }
663 
664         // If we need a playlist, then ask for it.
665         if (addTrackPlaylistID == GMTP_REQUIRE_PLAYLIST) {
666             addTrackPlaylistID = displayAddTrackPlaylistDialog(TRUE);
667         }
668 
669         // Now send the track
670         ret = LIBMTP_Send_Track_From_File(DeviceMgr.device, filename, trackfile, fileprogress, NULL);
671         if (ret != 0) {
672             LIBMTP_error_t* error = LIBMTP_Get_Errorstack(DeviceMgr.device);
673             if (error != NULL && error->errornumber != LIBMTP_ERROR_CANCELLED) {
674                 // Report the error in sending the file.
675                 g_fprintf(stderr, _("Error sending track.\n"));
676                 displayError(g_strdup_printf(_("Error code %d sending track to device: %s"), ret, filename));
677                 destroyProgressBar();
678                 progressDialog_killed = TRUE;
679             } else {
680                 g_fprintf(stderr, _("Transfer canceled."));
681                 displayInformation(_("Transfer canceled."));
682             }
683             LIBMTP_Dump_Errorstack(DeviceMgr.device);
684             LIBMTP_Clear_Errorstack(DeviceMgr.device);
685         } else {
686             // Adjust device storage.
687             DeviceMgr.devicestorage->FreeSpaceInBytes -= filesize;
688             DeviceMgr.devicestorage->FreeSpaceInObjects--;
689 
690             // Only update Album data if transfer was successful.
691             if (trackfile->album != NULL) {
692                 albumAddTrackToAlbum(albuminfo, trackfile);
693             }
694 
695             // Now add to playlist if needed...
696             if ((addTrackPlaylistID != GMTP_REQUIRE_PLAYLIST) && (addTrackPlaylistID != GMTP_NO_PLAYLIST)) {
697                 // addTrackPlaylistID has the ID of the playlist, and trackfile is the track we need to
698                 // add to that playlist.
699 
700                 // Find the playlist.
701                 LIBMTP_playlist_t* tmpplaylist = devicePlayLists;
702                 while (tmpplaylist != NULL) {
703                     if (tmpplaylist->playlist_id != (uint32_t) addTrackPlaylistID) {
704                         // Don't have it.
705                         tmpplaylist = tmpplaylist->next;
706                     } else {
707                         //We have found it.
708                         playlistAddTrack(tmpplaylist, trackfile);
709                         tmpplaylist = NULL;
710                     }
711                 }
712             }
713         }
714         LIBMTP_destroy_track_t(trackfile);
715         LIBMTP_destroy_album_t(albuminfo);
716     } else {
717         // Generic file upload.
718         LIBMTP_file_t *genfile = LIBMTP_new_file_t();
719         genfile->filesize = filesize;
720         genfile->filename = g_strdup(filename_stripped);
721         genfile->filetype = find_filetype(filename_stripped);
722         genfile->parent_id = currentFolderID;
723         genfile->storage_id = DeviceMgr.devicestorage->id;
724 
725         // Only import the file if it's not a Playlist or Album. (Bad mojo if this happens).
726         if ((genfile->filetype != LIBMTP_FILETYPE_ALBUM) && (genfile->filetype != LIBMTP_FILETYPE_PLAYLIST)) {
727             ret = LIBMTP_Send_File_From_File(DeviceMgr.device, filename, genfile, fileprogress, NULL);
728             if (ret != 0) {
729                 LIBMTP_error_t* error = LIBMTP_Get_Errorstack(DeviceMgr.device);
730                 if (error != NULL && error->errornumber != LIBMTP_ERROR_CANCELLED) {
731                     // Report the error in sending the file.
732                     g_fprintf(stderr, _("Error sending file %s.\n"), filename);
733                     displayError(g_strconcat(_("Error sending file: "), filename, NULL));
734                     destroyProgressBar();
735                     progressDialog_killed = TRUE;
736                 } else {
737                     g_fprintf(stderr, _("Transfer canceled."));
738                     displayInformation(_("Transfer canceled."));
739                 }
740 
741                 LIBMTP_Dump_Errorstack(DeviceMgr.device);
742                 LIBMTP_Clear_Errorstack(DeviceMgr.device);
743             } else {
744                 // Adjust device storage.
745                 DeviceMgr.devicestorage->FreeSpaceInBytes -= filesize;
746                 DeviceMgr.devicestorage->FreeSpaceInObjects--;
747             }
748         }
749         LIBMTP_destroy_file_t(genfile);
750     }
751 
752     // Now update the storage...
753     if (DeviceMgr.devicestorage == NULL) {
754         if (LIBMTP_Get_Storage(DeviceMgr.device, 0) < 0) {
755             // We have an error getting our storage, so let the user know and then disconnect the device.
756             displayError("Failed to get storage parameters from the device - need to disconnect.");
757             on_deviceConnect_activate(NULL, NULL);
758             return;
759         }
760         if (DeviceMgr.storagedeviceID == MTP_DEVICE_SINGLE_STORAGE) {
761             DeviceMgr.devicestorage = DeviceMgr.device->storage;
762         } else {
763             DeviceMgr.devicestorage = getCurrentDeviceStoragePtr(DeviceMgr.storagedeviceID);
764         }
765     }
766 }
767 
768 // ************************************************************************************************
769 
filesDelete(gchar * filename,uint32_t objectID)770 void filesDelete(gchar* filename, uint32_t objectID) {
771     gint ret = 1;
772     GSList *node;
773     //FileListStruc *fileptr;
774     uint64_t filesize = 0;
775     // Maybe something went wrong, so we disconnected. If so, then simple exit....
776     if (DeviceMgr.deviceConnected == FALSE)
777         return;
778 
779     // Now remove the item from the searchlist if we are in search mode.
780     if (inFindMode == TRUE) {
781         // searchList
782         node = searchList;
783         while (node != NULL) {
784             FileListStruc *fileptr = node->data;
785             if (fileptr->itemid == objectID) {
786                 // remove this node from the main list;
787                 searchList = g_slist_delete_link(searchList, node);
788                 g_free_search(fileptr);
789                 node = NULL;
790             } else {
791                 node = node->next;
792             }
793         }
794     }
795     // Get the filesize of the object.
796     LIBMTP_file_t * files = deviceFiles;
797     while (files != NULL) {
798         if (files->item_id == objectID) {
799             filesize = files->filesize;
800             files = NULL;
801         } else {
802             files = files->next;
803         }
804     }
805 
806     // Delete the file based on the object ID.
807     ret = LIBMTP_Delete_Object(DeviceMgr.device, objectID);
808     if (ret != 0) {
809         LIBMTP_Dump_Errorstack(DeviceMgr.device);
810         LIBMTP_Clear_Errorstack(DeviceMgr.device);
811         g_fprintf(stderr, _("\nFailed to delete file %s\n"), filename);
812         displayError(g_strconcat(_("Failed to delete file: "), filename, NULL));
813     } else {
814         // Adjust device storage.
815         DeviceMgr.devicestorage->FreeSpaceInBytes += filesize;
816         DeviceMgr.devicestorage->FreeSpaceInObjects++;
817     }
818 }
819 
820 // ************************************************************************************************
821 
filesDownload(gchar * filename,uint32_t objectID)822 void filesDownload(gchar* filename, uint32_t objectID) {
823     gchar* fullfilename = NULL;
824 
825     // Maybe something went wrong, so we disconnected. If so, then simple exit....
826     if (DeviceMgr.deviceConnected == FALSE) {
827         return;
828     }
829     if (progressDialog_killed == TRUE) {
830         return;
831     }
832 
833     //displayProgressBar(_("File download"));
834     setProgressFilename(filename);
835     // Download the file based on the objectID.
836     fullfilename = g_strdup_printf("%s/%s", Preferences.fileSystemDownloadPath->str, filename);
837     if ((LIBMTP_Get_File_To_File(DeviceMgr.device, objectID, fullfilename, fileprogress, NULL)) != 0) {
838         LIBMTP_error_t* error = LIBMTP_Get_Errorstack(DeviceMgr.device);
839         if (error != NULL && error->errornumber != LIBMTP_ERROR_CANCELLED) {
840             g_fprintf(stderr, _("\nError getting file from MTP device.\n"));
841             displayError(_("Error getting file from MTP device."));
842             destroyProgressBar();
843             progressDialog_killed = TRUE;
844         } else {
845             g_fprintf(stderr, _("Transfer canceled."));
846             displayInformation(_("Transfer canceled."));
847         }
848         LIBMTP_Dump_Errorstack(DeviceMgr.device);
849         LIBMTP_Clear_Errorstack(DeviceMgr.device);
850 
851     } else {
852         // Download complete...
853         if (Preferences.retain_timestamp == TRUE) {
854             LIBMTP_file_t *genfile = deviceFiles;
855             while (genfile != NULL) {
856                 if (genfile->item_id == objectID) {
857                     // We have our file, so update it.
858                     time_t modificationdate = genfile->modificationdate;
859                     struct utimbuf filetime;
860                     filetime.actime = modificationdate;
861                     filetime.modtime = modificationdate;
862                     utime(fullfilename, &filetime);
863                     genfile = NULL; // break our loop...
864                 } else {
865                     genfile = genfile->next;
866                 }
867             }
868         }
869     }
870     //destroyProgressBar();
871     g_free(fullfilename);
872 }
873 
874 // ************************************************************************************************
875 
filesRename(gchar * filename,uint32_t ObjectID)876 void filesRename(gchar* filename, uint32_t ObjectID) {
877     // We must first determine, if this is a file, a folder, playlist or album
878     // and use the correct API.
879     LIBMTP_file_t *genfile = NULL;
880     LIBMTP_album_t *albuminfo = NULL;
881     LIBMTP_album_t *albumlist = NULL;
882     LIBMTP_playlist_t *playlist = NULL;
883     LIBMTP_folder_t *folder = NULL;
884     GSList *node;
885 
886     if (filename == NULL) {
887         return;
888     }
889     if (ObjectID == 0) {
890         return;
891     }
892 
893     // Now remove the item from the searchlist if we are in search mode.
894     if (inFindMode == TRUE) {
895         // searchList
896         node = searchList;
897         while (node != NULL) {
898             FileListStruc *fileptr = node->data;
899             if (fileptr->itemid == ObjectID) {
900                 // update the filename appropriately;
901                 g_free(fileptr->filename);
902                 fileptr->filename = g_strdup(filename);
903                 node = NULL;
904             } else {
905                 node = node->next;
906             }
907         }
908     }
909 
910     // Lets scan files first.
911     genfile = deviceFiles;
912     while (genfile != NULL) {
913         if (genfile->item_id == ObjectID) {
914             // We have our file, so update it.
915             LIBMTP_Set_File_Name(DeviceMgr.device, genfile, filename);
916             deviceRescan();
917             return;
918         }
919         genfile = genfile->next;
920     }
921 
922     // Lets scan our albums.
923     albuminfo = LIBMTP_Get_Album_List_For_Storage(DeviceMgr.device, DeviceMgr.devicestorage->id);
924     albumlist = albuminfo;
925     while (albuminfo != NULL) {
926         if (albuminfo->album_id == ObjectID) {
927             LIBMTP_Set_Album_Name(DeviceMgr.device, albuminfo, filename);
928             deviceRescan();
929             clearAlbumStruc(albumlist);
930             return;
931         }
932         albuminfo = albuminfo->next;
933     }
934     clearAlbumStruc(albumlist);
935 
936     // Let's scan our playlists.
937     playlist = devicePlayLists;
938     while (playlist != NULL) {
939         if (playlist->playlist_id == ObjectID) {
940             // We have our playlist, so update it.
941             LIBMTP_Set_Playlist_Name(DeviceMgr.device, playlist, filename);
942             deviceRescan();
943             return;
944         }
945         playlist = playlist->next;
946     }
947 
948     // Lets scan our folders;
949     folder = deviceFolders;
950     folder = LIBMTP_Find_Folder(folder, ObjectID);
951     if (folder != NULL) {
952         LIBMTP_Set_Folder_Name(DeviceMgr.device, folder, filename);
953         deviceRescan();
954         return;
955     }
956 
957 }
958 
959 // ************************************************************************************************
960 
folderAdd(gchar * foldername)961 guint32 folderAdd(gchar* foldername) {
962     guint32 res = LIBMTP_Create_Folder(DeviceMgr.device, foldername, currentFolderID, DeviceMgr.devicestorage->id);
963     if (res == 0) {
964         g_fprintf(stderr, _("Folder creation failed: %s\n"), foldername);
965         displayError(g_strconcat(_("Folder creation failed:"), foldername, NULL));
966         LIBMTP_Dump_Errorstack(DeviceMgr.device);
967         LIBMTP_Clear_Errorstack(DeviceMgr.device);
968     }
969     return res;
970 }
971 
972 // ************************************************************************************************
973 
folderDelete(LIBMTP_folder_t * folderptr,guint level)974 void folderDelete(LIBMTP_folder_t* folderptr, guint level) {
975 
976     if (folderptr == NULL) {
977         // Sanity check for rogue data or exit here operation, that is no child/sibling to work on.
978         return;
979     }
980     // This is fun, as we have to find all child folders, delete those, as well as all files contained within...
981     // First iterate through all child folders and remove those files in those folders.
982     // But first we need to get the folder structure pointer based on the objectID, so we know where to start.
983     // So now we have our structure to the current select folder, so we need to cycle through all children and remove any files contained within.
984     folderDeleteChildrenFiles(folderptr->folder_id);
985     // Now cycle through folders contained in this folder and delete those;
986     folderDelete(folderptr->child, level + 1);
987     if (level != 0)
988         folderDelete(folderptr->sibling, level + 1);
989     // That should clear all the children.
990 
991     // Now remove the item from the searchlist if we are in search mode.
992     if (inFindMode == TRUE) {
993         // searchList
994         GSList *node = searchList;
995         while (node != NULL) {
996             FileListStruc *fileptr = node->data;
997             if (fileptr->itemid == folderptr->folder_id) {
998                 // remove this node from the main list;
999                 searchList = g_slist_delete_link(searchList, node);
1000                 g_free_search(fileptr);
1001                 node = NULL;
1002             } else {
1003                 node = node->next;
1004             }
1005         }
1006     }
1007     // Now do self.
1008     guint res = LIBMTP_Delete_Object(DeviceMgr.device, folderptr->folder_id);
1009     if (res != 0) {
1010         g_fprintf(stderr, _("Couldn't delete folder %s (%x)\n"), folderptr->name, folderptr->folder_id);
1011         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1012         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1013     } else {
1014         // Adjust device storage.
1015         DeviceMgr.devicestorage->FreeSpaceInObjects++;
1016     }
1017 }
1018 
1019 // ************************************************************************************************
1020 
folderDeleteChildrenFiles(guint folderID)1021 void folderDeleteChildrenFiles(guint folderID) {
1022     LIBMTP_file_t* files = deviceFiles;
1023     while (files != NULL) {
1024         if (files->parent_id == folderID) {
1025             filesDelete(files->filename, files->item_id);
1026         }
1027         files = files->next;
1028     }
1029 }
1030 
1031 // ************************************************************************************************
1032 
folderDownload(gchar * foldername,uint32_t folderID,gboolean isParent)1033 void folderDownload(gchar *foldername, uint32_t folderID, gboolean isParent) {
1034     gchar* fullfilename = NULL;
1035     LIBMTP_folder_t* currentFolder = NULL;
1036     LIBMTP_file_t* tmpFiles = NULL;
1037 
1038     // Store our current path for safe keeping and generate our new path.
1039     GString *currentdownload_folder = g_string_new(Preferences.fileSystemDownloadPath->str);
1040     fullfilename = g_strdup_printf("%s/%s", Preferences.fileSystemDownloadPath->str, foldername);
1041 
1042     // See if folder exists, if not create it.
1043     if (g_file_test(fullfilename, G_FILE_TEST_IS_DIR) == FALSE) {
1044         if (mkdir(fullfilename, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
1045             g_fprintf(stderr, _("Folder creation failed: %s\n"), fullfilename);
1046             displayError(g_strconcat(_("Folder creation failed: "), fullfilename, NULL));
1047             // Since we can't create that directory, then we simple return from this call...
1048             return;
1049         }
1050     }
1051 
1052     if (!Preferences.use_alt_access_method) {
1053         // First we scan for all folders in the current folder, and do those first...
1054         if (folderID != 0) {
1055             currentFolder = getCurrentFolderPtr(deviceFolders, folderID);
1056         } else {
1057             // If our id = 0 then we are dealing with the root device.
1058             currentFolder = deviceFolders;
1059         }
1060 
1061         if (currentFolder == NULL) {
1062             // This means we don't exist, so bail out.
1063             return;
1064         }
1065 
1066         if (currentFolder->child != NULL) {
1067             // Now we can simple set our download path to the new path, and save all folders/files there.
1068             Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, fullfilename);
1069 
1070             // Call to download all folder/files in that folder...
1071             folderDownload(currentFolder->child->name, currentFolder->child->folder_id, FALSE);
1072 
1073             // Restore the old download path;
1074             Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, currentdownload_folder->str);
1075         }
1076 
1077         if ((isParent == FALSE) || (folderID == 0)) {
1078             if (currentFolder->sibling != NULL) {
1079                 folderDownload(currentFolder->sibling->name, currentFolder->sibling->folder_id, FALSE);
1080             }
1081         }
1082         // Now download all the files whose parentID = folderID;
1083 
1084         // Now we can simple set our download path to the new path, and save all folders/files there.
1085         Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, fullfilename);
1086 
1087         // we no longer need the full folder path, so free it's variable.
1088         g_free(fullfilename);
1089 
1090         // Start processing all our files.
1091         tmpFiles = deviceFiles;
1092         while (tmpFiles != NULL) {
1093             if ((tmpFiles->parent_id == folderID) && (tmpFiles->storage_id == DeviceMgr.devicestorage->id)) {
1094                 // We have a file in this folder, so download it...
1095                 // But first check to see if it exists, before overwriting it...
1096                 fullfilename = g_strdup_printf("%s/%s", Preferences.fileSystemDownloadPath->str, tmpFiles->filename);
1097                 // Check if file exists?
1098                 if (access(fullfilename, F_OK) != -1) {
1099                     // We have that file already?
1100                     if (Preferences.prompt_overwrite_file_op == TRUE) {
1101                         if (fileoverwriteop == MTP_ASK) {
1102                             fileoverwriteop = displayFileOverwriteDialog(tmpFiles->filename);
1103                         }
1104                         switch (fileoverwriteop) {
1105                             case MTP_ASK:
1106                                 break;
1107                             case MTP_SKIP:
1108                                 fileoverwriteop = MTP_ASK;
1109                                 break;
1110                             case MTP_SKIP_ALL:
1111                                 break;
1112                             case MTP_OVERWRITE:
1113                                 filesDownload(tmpFiles->filename, tmpFiles->item_id);
1114                                 fileoverwriteop = MTP_ASK;
1115                                 break;
1116                             case MTP_OVERWRITE_ALL:
1117                                 filesDownload(tmpFiles->filename, tmpFiles->item_id);
1118                                 break;
1119                         }
1120                     } else {
1121                         filesDownload(tmpFiles->filename, tmpFiles->item_id);
1122                     }
1123                 } else {
1124                     filesDownload(tmpFiles->filename, tmpFiles->item_id);
1125                 }
1126                 // Free our file name...
1127                 g_free(fullfilename);
1128             }
1129             // Start working on the next file...
1130             tmpFiles = tmpFiles->next;
1131         }
1132 
1133 
1134     } else {
1135         // Alt access method, we may have an invalid deviceFolders struct, so ignore for now.
1136         LIBMTP_file_t* fileList = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, folderID);
1137         if (fileList == NULL) {
1138             LIBMTP_Dump_Errorstack(DeviceMgr.device);
1139             LIBMTP_Clear_Errorstack(DeviceMgr.device);
1140             return;
1141         }
1142         // Now we can simple set our download path to the new path, and save all folders/files there.
1143         Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, fullfilename);
1144 
1145         tmpFiles = fileList;
1146         while (tmpFiles != NULL) {
1147             if(tmpFiles->filetype == LIBMTP_FILETYPE_FOLDER){
1148                 // Now we can simple set our download path to the new path, and save all folders/files there.
1149                 Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, fullfilename);
1150 
1151                 // Call to download all folder/files in that folder...
1152                 folderDownload(tmpFiles->filename, tmpFiles->item_id, FALSE);
1153 
1154                 // Restore the old download path;
1155                 Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, currentdownload_folder->str);
1156             } else {
1157                 // We have a file in this folder, so download it...
1158                 // But first check to see if it exists, before overwriting it...
1159                 gchar* fullfilename2 = g_strdup_printf("%s/%s", Preferences.fileSystemDownloadPath->str, tmpFiles->filename);
1160                 // Check if file exists?
1161                 if (access(fullfilename2, F_OK) != -1) {
1162                     // We have that file already?
1163                     if (Preferences.prompt_overwrite_file_op == TRUE) {
1164                         if (fileoverwriteop == MTP_ASK) {
1165                             fileoverwriteop = displayFileOverwriteDialog(tmpFiles->filename);
1166                         }
1167                         switch (fileoverwriteop) {
1168                             case MTP_ASK:
1169                                 break;
1170                             case MTP_SKIP:
1171                                 fileoverwriteop = MTP_ASK;
1172                                 break;
1173                             case MTP_SKIP_ALL:
1174                                 break;
1175                             case MTP_OVERWRITE:
1176                                 filesDownload(tmpFiles->filename, tmpFiles->item_id);
1177                                 fileoverwriteop = MTP_ASK;
1178                                 break;
1179                             case MTP_OVERWRITE_ALL:
1180                                 filesDownload(tmpFiles->filename, tmpFiles->item_id);
1181                                 break;
1182                         }
1183                     } else {
1184                         filesDownload(tmpFiles->filename, tmpFiles->item_id);
1185                     }
1186                 } else {
1187                     filesDownload(tmpFiles->filename, tmpFiles->item_id);
1188                 }
1189                 // Free our file name...
1190                 g_free(fullfilename2);
1191             }
1192             // Start working on the next file...
1193             tmpFiles = tmpFiles->next;
1194         }
1195         if (fileList != NULL) {
1196             clearDeviceFiles(fileList);
1197         }
1198          // we no longer need the full folder path, so free it's variable.
1199         g_free(fullfilename);
1200     }
1201 
1202     // Restore the old download path;
1203     Preferences.fileSystemDownloadPath = g_string_assign(Preferences.fileSystemDownloadPath, currentdownload_folder->str);
1204 
1205     // Clean up any tmp items;
1206     g_string_free(currentdownload_folder, TRUE);
1207 }
1208 
1209 // ************************************************************************************************
1210 
find_filetype(const gchar * filename)1211 LIBMTP_filetype_t find_filetype(const gchar * filename) {
1212     LIBMTP_filetype_t filetype = LIBMTP_FILETYPE_UNKNOWN;
1213     gchar *fileext;
1214     gint i;
1215     gint j = sizeof (file_ext) / sizeof (MTP_file_ext_struct);
1216 
1217     fileext = strrchr(filename, '.');
1218     // This accounts for the case with a filename without any "." (period).
1219     if (!fileext) {
1220         fileext = "";
1221     } else {
1222         ++fileext;
1223     }
1224     // Now cycle through the array of extensions, and get the associated
1225     // libmtp filetype.
1226     for (i = 0; i < j; i++) {
1227         if (g_ascii_strcasecmp(fileext, file_ext[i].file_extension) == 0) {
1228             filetype = file_ext[i].file_type;
1229             break;
1230         }
1231     }
1232     //if (filetype == 0) {
1233     //    filetype = LIBMTP_FILETYPE_UNKNOWN;
1234     //}
1235     return filetype;
1236 }
1237 
1238 // ************************************************************************************************
1239 
find_filetype_ext(LIBMTP_filetype_t filetype)1240 gchar* find_filetype_ext(LIBMTP_filetype_t filetype) {
1241     gint i = 0;
1242     gint j = sizeof (file_ext) / sizeof (MTP_file_ext_struct);
1243     for (i = 0; i < j; i++) {
1244         if (filetype == file_ext[i].file_type) {
1245             return file_ext[i].file_extension;
1246         }
1247     }
1248     return blank_ext;
1249 }
1250 
1251 // ************************************************************************************************
1252 
setDeviceName(gchar * devicename)1253 void setDeviceName(gchar* devicename) {
1254     gint res = 0;
1255     if (DeviceMgr.deviceConnected == TRUE) {
1256         if (devicename != NULL)
1257             res = LIBMTP_Set_Friendlyname(DeviceMgr.device, devicename);
1258         if (res != 0) {
1259             g_fprintf(stderr, _("Error: Couldn't set device name to %s\n"), devicename);
1260             LIBMTP_Dump_Errorstack(DeviceMgr.device);
1261             LIBMTP_Clear_Errorstack(DeviceMgr.device);
1262         }
1263     } else {
1264         // Set to to none.
1265         g_fprintf(stderr, _("setDeviceName: How did I get called?\n"));
1266     }
1267 }
1268 
1269 // ************************************************************************************************
1270 
fileExists(gchar * filename)1271 gboolean fileExists(gchar* filename) {
1272     // What we have to go is scan the entire file tree looking for
1273     // entries in the same folder as the current and the same
1274     // storage pool, then we do a string compare (since doing a string
1275     // compare is so much slower than comparing a few numbers).
1276     LIBMTP_file_t* tmpfile;
1277     LIBMTP_file_t* aafile = NULL;
1278     if (Preferences.use_alt_access_method) {
1279         tmpfile = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, currentFolderID);
1280         aafile = tmpfile;
1281     } else {
1282         tmpfile = deviceFiles;
1283     }
1284     while (tmpfile != NULL) {
1285         // Check for matching folder ID and storage ID.
1286         if ((tmpfile->parent_id == currentFolderID) && (tmpfile->storage_id == DeviceMgr.devicestorage->id)) {
1287             // Now test for the file name (do case insensitive cmp for those odd devices);
1288             if (g_ascii_strcasecmp(filename, tmpfile->filename) == 0){
1289                 if(aafile != NULL){
1290                     clearDeviceFiles(aafile);
1291                 }
1292                 return TRUE;
1293             }
1294         }
1295         tmpfile = tmpfile->next;
1296     }
1297     if(aafile != NULL){
1298         clearDeviceFiles(aafile);
1299     }
1300     return FALSE;
1301 }
1302 
1303 // ************************************************************************************************
1304 
getFile(gchar * filename,uint32_t folderID)1305 uint32_t getFile(gchar* filename, uint32_t folderID) {
1306     // What we have to go is scan the entire file tree looking for
1307     // entries in the same folder as the current and the same
1308     // storage pool, then we do a string compare (since doing a string
1309     // compare is so much slower than comparing a few numbers).
1310     LIBMTP_file_t* tmpfile;
1311     LIBMTP_file_t* aafile = NULL;
1312     if (Preferences.use_alt_access_method) {
1313         tmpfile = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, folderID);
1314         aafile = tmpfile;
1315     } else {
1316         tmpfile = deviceFiles;
1317     }
1318     while (tmpfile != NULL) {
1319         // Check for matching folder ID and storage ID.
1320         if ((tmpfile->parent_id == currentFolderID) && (tmpfile->storage_id == DeviceMgr.devicestorage->id)) {
1321             // Now test for the file name (do case insensitive cmp for those odd devices);
1322             if (g_ascii_strcasecmp(filename, tmpfile->filename) == 0){
1323                 uint32_t id = tmpfile->item_id;
1324                 if(aafile != NULL){
1325                     clearDeviceFiles(aafile);
1326                 }
1327                 return id;
1328             }
1329 
1330         }
1331         tmpfile = tmpfile->next;
1332     }
1333     if(aafile != NULL){
1334         clearDeviceFiles(aafile);
1335     }
1336     return -1;
1337 }
1338 
1339 // ************************************************************************************************
1340 
folderExists(gchar * foldername,uint32_t folderID)1341 gboolean folderExists(gchar *foldername, uint32_t folderID) {
1342     if (Preferences.use_alt_access_method) {
1343 
1344         LIBMTP_file_t* tmpfile = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, folderID);
1345         LIBMTP_file_t* aafile = tmpfile;
1346         while (tmpfile != NULL) {
1347             // Check for matching folder ID and storage ID.
1348             if ((tmpfile->parent_id == currentFolderID) && (tmpfile->storage_id == DeviceMgr.devicestorage->id)) {
1349                 // Now test for the file name (do case insensitive cmp for those odd devices);
1350                 if (g_ascii_strcasecmp(foldername, tmpfile->filename) == 0){
1351                     if(aafile != NULL){
1352                         clearDeviceFiles(aafile);
1353                     }
1354                     return TRUE;
1355                 }
1356             }
1357             tmpfile = tmpfile->next;
1358         }
1359         if(aafile != NULL){
1360             clearDeviceFiles(aafile);
1361         }
1362     } else {
1363 
1364         LIBMTP_folder_t* folder = getCurrentFolderPtr(deviceFolders, folderID);
1365         if (folder == NULL) {
1366             return FALSE;
1367         }
1368         // Scan for child folders with the same name.
1369         LIBMTP_folder_t* child = folder->child;
1370         while (child != NULL) {
1371             if (g_ascii_strcasecmp(foldername, child->name) == 0)
1372                 return TRUE;
1373             child = child->sibling;
1374         }
1375     }
1376     return FALSE;
1377 }
1378 
1379 // ************************************************************************************************
1380 
getFolder(gchar * foldername,uint32_t folderID)1381 uint32_t getFolder(gchar *foldername, uint32_t folderID) {
1382     if (Preferences.use_alt_access_method) {
1383         LIBMTP_file_t* tmpfile = LIBMTP_Get_Files_And_Folders(DeviceMgr.device, DeviceMgr.devicestorage->id, folderID);
1384         LIBMTP_file_t* aafile = tmpfile;
1385         while (tmpfile != NULL) {
1386             // Check for matching folder ID and storage ID.
1387             if ((tmpfile->parent_id == currentFolderID) && (tmpfile->storage_id == DeviceMgr.devicestorage->id)) {
1388                 // Now test for the file name (do case insensitive cmp for those odd devices);
1389                 if (g_ascii_strcasecmp(foldername, tmpfile->filename) == 0){
1390                     uint32_t id = tmpfile->item_id;
1391                     if(aafile != NULL){
1392                         clearDeviceFiles(aafile);
1393                     }
1394                     return id;
1395                 }
1396             }
1397             tmpfile = tmpfile->next;
1398         }
1399         if(aafile != NULL){
1400             clearDeviceFiles(aafile);
1401         }
1402     } else {
1403         LIBMTP_folder_t* folder = getCurrentFolderPtr(deviceFolders, folderID);
1404         if (folder == NULL) {
1405             return FALSE;
1406         }
1407         // Scan for child folders with the same name.
1408         LIBMTP_folder_t* child = folder->child;
1409         while (child != NULL) {
1410             if (g_ascii_strcasecmp(foldername, child->name) == 0)
1411                 return child->folder_id;
1412             child = child->sibling;
1413         }
1414     }
1415     return -1;
1416 }
1417 
1418 // ************************************************************************************************
1419 
albumAddTrackToAlbum(LIBMTP_album_t * albuminfo,LIBMTP_track_t * trackinfo)1420 void albumAddTrackToAlbum(LIBMTP_album_t* albuminfo, LIBMTP_track_t* trackinfo) {
1421     LIBMTP_album_t *album = NULL;
1422     LIBMTP_album_t *found_album = NULL;
1423     LIBMTP_album_t *album_orig = NULL;
1424     gint ret = 0;
1425 
1426     // Quick sanity check.
1427     if ((albuminfo->name == NULL) || (albuminfo->artist == NULL))
1428         return;
1429 
1430     // Lets try to find the album.
1431     album = LIBMTP_Get_Album_List_For_Storage(DeviceMgr.device, DeviceMgr.devicestorage->id);
1432     album_orig = album;
1433     while ((album != NULL) && (found_album == NULL)) {
1434         if ((album->name != NULL) && (album->artist != NULL)) {
1435             // Lets test it. We attempt to match both album name and artist.
1436             if ((g_ascii_strcasecmp(album->name, albuminfo->name) == 0) &&
1437                     (g_ascii_strcasecmp(album->artist, albuminfo->artist) == 0)) {
1438                 found_album = album;
1439             }
1440         }
1441         album = album->next;
1442     }
1443     // Some devices ignore all other fields and only retain the ablum name - so test for this as well!
1444     album = album_orig;
1445     if (found_album == NULL) {
1446         while ((album != NULL) && (found_album == NULL)) {
1447             if (album->name != NULL) {
1448                 // Lets test it. We attempt to match both album name and artist.
1449                 if (g_ascii_strcasecmp(album->name, albuminfo->name) == 0) {
1450                     found_album = album;
1451                 }
1452             }
1453             album = album->next;
1454         }
1455     }
1456 
1457     if (found_album != NULL) {
1458         // The album already exists.
1459         uint32_t *tracks;
1460         tracks = (uint32_t *) g_malloc0((found_album->no_tracks + 1) * sizeof (uint32_t));
1461         if (!tracks) {
1462             g_fprintf(stderr, _("ERROR: Failed memory allocation in albumAddTrackToAlbum()\n"));
1463             return;
1464         }
1465         found_album->no_tracks++;
1466         if (found_album->tracks != NULL) {
1467             memcpy(tracks, found_album->tracks, found_album->no_tracks * sizeof (uint32_t));
1468             free(found_album->tracks);
1469         }
1470         tracks[found_album->no_tracks - 1] = trackinfo->item_id; // This ID is only set once the track is on the device.
1471         found_album->tracks = tracks;
1472         ret = LIBMTP_Update_Album(DeviceMgr.device, found_album);
1473         g_free(tracks);
1474         found_album->tracks = NULL;
1475     } else {
1476         // New album.
1477         uint32_t *trackid;
1478         trackid = (uint32_t *) g_malloc0(sizeof (uint32_t));
1479         *trackid = trackinfo->item_id;
1480         albuminfo->tracks = trackid;
1481         albuminfo->no_tracks = 1;
1482         albuminfo->storage_id = DeviceMgr.devicestorage->id;
1483         ret = LIBMTP_Create_New_Album(DeviceMgr.device, albuminfo);
1484         g_free(trackid);
1485         albuminfo->tracks = NULL;
1486     }
1487     if (ret != 0) {
1488 
1489         if (Preferences.suppress_album_errors == FALSE) {
1490             if (AlbumErrorIgnore == FALSE) {
1491                 displayError(_("Error creating or updating album.\n(This could be due to that your device does not support albums.)\n"));
1492                 g_fprintf(stderr, _("Error creating or updating album.\n(This could be due to that your device does not support albums.)\n"));
1493             }
1494         }
1495         // Displayed the message once already per transfer...
1496         AlbumErrorIgnore = TRUE;
1497         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1498         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1499     }
1500     clearAlbumStruc(album_orig);
1501 }
1502 
1503 // ************************************************************************************************
1504 
albumAddArt(guint32 album_id,gchar * filename)1505 void albumAddArt(guint32 album_id, gchar* filename) {
1506     LIBMTP_filesampledata_t *albumart;
1507     gint ret;
1508     uint64_t filesize;
1509     uint8_t *imagedata = NULL;
1510     struct stat statbuff;
1511     FILE* fd;
1512 
1513     if (stat(filename, &statbuff) == -1) {
1514         perror("stat");
1515         return;
1516     }
1517     filesize = (uint64_t) statbuff.st_size;
1518     imagedata = g_malloc(filesize * sizeof (uint8_t));
1519     if (imagedata == NULL) {
1520         g_fprintf(stderr, _("ERROR: Failed memory allocation in albumAddArt()\n"));
1521         return;
1522     }
1523     fd = fopen(filename, "r");
1524     if (fd == NULL) {
1525         g_fprintf(stderr, _("Couldn't open image file %s\n"), filename);
1526         g_free(imagedata);
1527         return;
1528     } else {
1529         size_t i = fread(imagedata, filesize, 1, fd);
1530         fclose(fd);
1531         if (i != 1) {
1532             g_fprintf(stderr, _("Couldn't open image file %s\n"), filename);
1533             g_free(imagedata);
1534             return;
1535         }
1536     }
1537 
1538     albumart = LIBMTP_new_filesampledata_t();
1539     albumart->data = (gchar *) imagedata;
1540     albumart->size = filesize;
1541     albumart->filetype = find_filetype(basename(filename));
1542 
1543     ret = LIBMTP_Send_Representative_Sample(DeviceMgr.device, album_id, albumart);
1544     if (ret != 0) {
1545         g_fprintf(stderr, _("Couldn't send album art\n"));
1546         displayError(_("Couldn't send album art\n"));
1547         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1548         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1549     }
1550     g_free(imagedata);
1551     albumart->data = NULL;
1552 
1553     // Adjust device storage.
1554     DeviceMgr.devicestorage->FreeSpaceInBytes -= filesize;
1555     DeviceMgr.devicestorage->FreeSpaceInObjects--;
1556     LIBMTP_destroy_filesampledata_t(albumart);
1557 }
1558 
1559 // ************************************************************************************************
1560 
albumGetArt(LIBMTP_album_t * selectedAlbum)1561 LIBMTP_filesampledata_t * albumGetArt(LIBMTP_album_t* selectedAlbum) {
1562     LIBMTP_filesampledata_t *albumart = LIBMTP_new_filesampledata_t();
1563     gint ret;
1564     // Attempt to get some data
1565     ret = LIBMTP_Get_Representative_Sample(DeviceMgr.device, selectedAlbum->album_id, albumart);
1566     if (ret != 0) {
1567         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1568         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1569         LIBMTP_destroy_filesampledata_t(albumart);
1570         return NULL;
1571     }
1572     if (albumart == NULL) {
1573         // Something went wrong;
1574         return NULL;
1575     }
1576     return albumart;
1577 }
1578 
1579 // ************************************************************************************************
1580 
albumDeleteArt(guint32 album_id)1581 void albumDeleteArt(guint32 album_id) {
1582     LIBMTP_filesampledata_t *albumart = LIBMTP_new_filesampledata_t();
1583     // Attempt to send a null representative sample.
1584     albumart->data = NULL;
1585     albumart->size = 0;
1586     albumart->filetype = LIBMTP_FILETYPE_UNKNOWN;
1587 
1588     gint ret = LIBMTP_Send_Representative_Sample(DeviceMgr.device, album_id, albumart);
1589     if (ret != 0) {
1590         g_fprintf(stderr, _("Couldn't remove album art\n"));
1591         displayError(_("Couldn't remove album art\n"));
1592         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1593         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1594     }
1595     LIBMTP_destroy_filesampledata_t(albumart);
1596 }
1597 
1598 // ************************************************************************************************
1599 
getPlaylists(void)1600 LIBMTP_playlist_t* getPlaylists(void) {
1601 
1602     if (devicePlayLists != NULL)
1603         clearDevicePlaylist(devicePlayLists);
1604 
1605     devicePlayLists = LIBMTP_Get_Playlist_List(DeviceMgr.device);
1606     if (devicePlayLists == NULL) {
1607         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1608         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1609     }
1610     return devicePlayLists;
1611 }
1612 
1613 // ************************************************************************************************
1614 
getTracks(void)1615 LIBMTP_track_t* getTracks(void) {
1616     if (deviceTracks != NULL)
1617         clearDeviceTracks(deviceTracks);
1618 
1619     deviceTracks = LIBMTP_Get_Tracklisting_With_Callback(DeviceMgr.device, NULL, NULL);
1620     if (deviceTracks == NULL) {
1621         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1622         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1623     }
1624     return deviceTracks;
1625 }
1626 
1627 // ************************************************************************************************
1628 
playlistAdd(gchar * playlistname)1629 void playlistAdd(gchar* playlistname) {
1630 
1631     LIBMTP_playlist_t *playlist = LIBMTP_new_playlist_t();
1632 
1633     playlist->name = g_strdup(playlistname);
1634     playlist->no_tracks = 0;
1635     playlist->tracks = NULL;
1636     playlist->parent_id = DeviceMgr.device->default_playlist_folder;
1637     playlist->storage_id = DeviceMgr.devicestorage->id;
1638 
1639     gint ret = LIBMTP_Create_New_Playlist(DeviceMgr.device, playlist);
1640 
1641     if (ret != 0) {
1642         displayError(_("Couldn't create playlist object\n"));
1643         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1644         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1645     }
1646     LIBMTP_destroy_playlist_t(playlist);
1647 }
1648 
1649 // ************************************************************************************************
1650 
playlistDelete(LIBMTP_playlist_t * tmpplaylist)1651 void playlistDelete(LIBMTP_playlist_t * tmpplaylist) {
1652     guint res = LIBMTP_Delete_Object(DeviceMgr.device, tmpplaylist->playlist_id);
1653     if (res != 0) {
1654         displayError(_("Deleting playlist failed?\n"));
1655         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1656         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1657     }
1658 }
1659 
1660 // ************************************************************************************************
1661 
playlistUpdate(LIBMTP_playlist_t * tmpplaylist)1662 void playlistUpdate(LIBMTP_playlist_t * tmpplaylist) {
1663     guint res = LIBMTP_Update_Playlist(DeviceMgr.device, tmpplaylist);
1664     if (res != 0) {
1665         displayError(_("Updating playlist failed?\n"));
1666         LIBMTP_Dump_Errorstack(DeviceMgr.device);
1667         LIBMTP_Clear_Errorstack(DeviceMgr.device);
1668     }
1669 }
1670 
1671 // ************************************************************************************************
1672 
playlistImport(gchar * filename)1673 gchar* playlistImport(gchar * filename) {
1674     FILE* fd;
1675     gchar* playlistname = NULL;
1676     uint32_t *tracktmp = NULL;
1677     gboolean ignorepath = Preferences.ignore_path_in_playlist_import;
1678 
1679     // Build basic playlist object
1680     LIBMTP_playlist_t *playlist = LIBMTP_new_playlist_t();
1681     playlist->name = NULL;
1682     playlist->no_tracks = 0;
1683     playlist->tracks = NULL;
1684     playlist->parent_id = DeviceMgr.device->default_playlist_folder;
1685     playlist->storage_id = DeviceMgr.devicestorage->id;
1686 
1687     // Load the file, and parse.
1688     fd = fopen(filename, "r");
1689     if (fd == NULL) {
1690         g_fprintf(stderr, _("Couldn't open playlist file %s\n"), filename);
1691         displayError(_("Couldn't open playlist file\n"));
1692         LIBMTP_destroy_playlist_t(playlist);
1693         return NULL;
1694     } else {
1695         gchar* fileString = g_malloc0(GMTP_MAX_STRING);
1696         // Read file until EOF
1697         while (fgets(fileString, GMTP_MAX_STRING, fd) != NULL) {
1698             // Strip any trailing '\n' from the string...
1699             fileString = g_strchomp(fileString);
1700             if (g_ascii_strncasecmp(fileString, "#GMTPPLA: ", 10) == 0) {
1701                 // We have a playlist name marker...
1702                 playlistname = g_strdup((fileString + 10));
1703                 playlist->name = g_strdup(playlistname);
1704             } else {
1705                 // We should have a file?
1706                 // But ignore ANY line starting with a # as this is a comment line.
1707                 if ((*fileString != '#') && (*fileString != '\0')) {
1708                     uint32_t fileobject = getFileID(fileString, ignorepath);
1709                     if (fileobject != 0) {
1710                         // We have a file within our device!
1711                         playlist->no_tracks++;
1712                         if ((tracktmp = g_realloc(playlist->tracks, sizeof (uint32_t) * (playlist->no_tracks))) == NULL) {
1713                             g_fprintf(stderr, _("realloc in playlistImport failed\n"));
1714                             displayError(_("Updating playlist failed? 'realloc in playlistImport'\n"));
1715                             return NULL;
1716                         }
1717                         playlist->tracks = tracktmp;
1718                         playlist->tracks[(playlist->no_tracks - 1)] = fileobject;
1719                     }
1720                 }
1721             }
1722         }
1723         g_free(fileString);
1724         fclose(fd);
1725     }
1726     if ((playlistname == NULL) && (playlist->no_tracks > 0)) {
1727         // We have some tracks, but no playlist name.
1728         // So derive the playlist name from the filename...
1729         playlistname = g_path_get_basename(filename);
1730         // Now chop off the file extension?
1731         gchar* needle = g_strrstr(playlistname, ".");
1732         if (needle != NULL) {
1733             *needle = '\0';
1734         }
1735         // And set the name...
1736         playlist->name = g_strdup(playlistname);
1737     }
1738 
1739     // If we have something?
1740     if ((playlistname != NULL) && (playlist->no_tracks > 0)) {
1741         // Store the playlist on the device...
1742         gint ret = LIBMTP_Create_New_Playlist(DeviceMgr.device, playlist);
1743         if (ret != 0) {
1744             displayError(_("Couldn't create playlist object\n"));
1745             LIBMTP_Dump_Errorstack(DeviceMgr.device);
1746             LIBMTP_Clear_Errorstack(DeviceMgr.device);
1747             g_free(playlistname);
1748             playlistname = NULL;
1749         } else {
1750             displayInformation(_("Playlist imported.\n"));
1751         }
1752     } else {
1753         // Let the user know we found zero tracks, so didn't bother to import it.
1754         displayInformation(_("Found no tracks within the playlist that exist on this device. Did not import the playlist.\n"));
1755         g_fprintf(stderr, _("Found no tracks within the playlist that exist on this device. Did not import the playlist.\n"));
1756         // Clean up the playlist name, since we don't need it.
1757         if (playlistname != NULL) {
1758             g_free(playlistname);
1759             playlistname = NULL;
1760         }
1761     }
1762 
1763     // Clean up our playlist data structure.
1764     LIBMTP_destroy_playlist_t(playlist);
1765 
1766     // Return to caller.
1767     return playlistname;
1768 }
1769 
1770 // ************************************************************************************************
1771 
playlistExport(gchar * filename,LIBMTP_playlist_t * playlist)1772 void playlistExport(gchar * filename, LIBMTP_playlist_t * playlist) {
1773     FILE* fd;
1774     uint32_t numtracks = playlist->no_tracks;
1775     uint32_t *tracks = playlist->tracks;
1776 
1777     // Open the file to save it to...
1778     fd = fopen(filename, "w");
1779     if (fd == NULL) {
1780         g_fprintf(stderr, _("Couldn't save playlist file %s\n"), filename);
1781         displayError(_("Couldn't save playlist file\n"));
1782     } else {
1783         fprintf(fd, "#GMTPPLA: %s\n", playlist->name);
1784         fflush(fd);
1785         while (numtracks--) {
1786             uint32_t trackid = *tracks++;
1787             // We now have our track id. Let's form the complete path to the file including the filename.
1788             // Then store that string in the file...
1789             gchar* trackname = getFullFilename(trackid);
1790             if (trackname != NULL) {
1791                 fprintf(fd, "%s\n", trackname);
1792                 g_free(trackname);
1793                 trackname = NULL;
1794             }
1795         }
1796         fclose(fd);
1797     }
1798 }
1799 
1800 // ************************************************************************************************
1801 
formatStorageDevice()1802 void formatStorageDevice() {
1803     if (DeviceMgr.deviceConnected) {
1804         guint res = LIBMTP_Format_Storage(DeviceMgr.device, DeviceMgr.devicestorage);
1805         if (res != 0) {
1806             displayError(_("Format Device failed?\n"));
1807             LIBMTP_Dump_Errorstack(DeviceMgr.device);
1808             LIBMTP_Clear_Errorstack(DeviceMgr.device);
1809         }
1810     } else {
1811         g_fprintf(stderr, ("formatStorageDevice: How did I get called?\n"));
1812     }
1813 }
1814 
1815 // ************************************************************************************************
1816 
playlistAddTrack(LIBMTP_playlist_t * playlist,LIBMTP_track_t * track)1817 void playlistAddTrack(LIBMTP_playlist_t* playlist, LIBMTP_track_t* track) {
1818     LIBMTP_playlist_t* tmpplaylist = playlist;
1819     uint32_t *tmp = NULL;
1820 
1821     tmpplaylist->no_tracks++;
1822     // item_id = our track num... so append to tmpplaylist->tracks
1823     if ((tmp = g_realloc(tmpplaylist->tracks, sizeof (uint32_t) * (tmpplaylist->no_tracks))) == NULL) {
1824         g_fprintf(stderr, _("realloc in savePlayList failed\n"));
1825         displayError(_("Updating playlist failed? 'realloc in savePlayList'\n"));
1826         return;
1827     }
1828     tmpplaylist->tracks = tmp;
1829     tmpplaylist->tracks[(tmpplaylist->no_tracks - 1)] = track->item_id;
1830     playlistUpdate(tmpplaylist);
1831 }
1832 
1833 // ************************************************************************************************
1834 
playlistRemoveTrack(LIBMTP_playlist_t * playlist,LIBMTP_track_t * track,uint32_t instances)1835 void playlistRemoveTrack(LIBMTP_playlist_t* playlist, LIBMTP_track_t* track, uint32_t instances) {
1836     LIBMTP_playlist_t* tmpplaylist = playlist;
1837     uint32_t *tmp = NULL;
1838 
1839     uint32_t numtracks = tmpplaylist->no_tracks;
1840     int32_t count;
1841     int32_t count2;
1842     // item_id = our track num... so remove to tmpplaylist->tracks
1843     if ((instances == MTP_PLAYLIST_ALL_INSTANCES) || (instances == MTP_PLAYLIST_FIRST_INSTANCE)) {
1844         for (count = 0; count < (int32_t) numtracks; count++) {
1845             if (tmpplaylist->tracks[count] == track->item_id) {
1846                 // move all ones up one.
1847                 for (count2 = count; count2 < (int32_t) numtracks; count2++) {
1848                     if ((count2 + 1) != (int32_t) numtracks) {
1849                         tmpplaylist->tracks[count2] = tmpplaylist->tracks[count2 + 1];
1850                     }
1851                 }
1852                 // exit the for loop if only doing the first instance.
1853                 if (instances == MTP_PLAYLIST_FIRST_INSTANCE) {
1854                     count = numtracks;
1855                 }
1856                 tmpplaylist->no_tracks--;
1857             }
1858         }
1859     } else {
1860         for (count = numtracks - 1; count >= 0; count--) {
1861             if (tmpplaylist->tracks[count] == track->item_id) {
1862                 // move all ones up one.
1863                 for (count2 = count; count2 < (int32_t) numtracks; count2++) {
1864                     if ((count2 + 1) != (int32_t) numtracks) {
1865                         tmpplaylist->tracks[count2] = tmpplaylist->tracks[count2 + 1];
1866                     }
1867                 }
1868                 // exit the for loop if only doing the first instance.
1869                 if (instances == MTP_PLAYLIST_LAST_INSTANCE) {
1870                     count = numtracks;
1871                 }
1872                 tmpplaylist->no_tracks--;
1873             }
1874         }
1875     }
1876     // And redo the memory allocation.
1877     if ((tmp = g_realloc(tmpplaylist->tracks, sizeof (uint32_t) * (tmpplaylist->no_tracks))) == NULL) {
1878         g_fprintf(stderr, _("realloc in savePlayList failed\n"));
1879         displayError(_("Updating playlist failed? 'realloc in savePlayList'\n"));
1880         return;
1881     }
1882     tmpplaylist->tracks = tmp;
1883     playlistUpdate(tmpplaylist);
1884 }
1885 
1886 // ************************************************************************************************
1887 
getFullFilename(uint32_t item_id)1888 gchar* getFullFilename(uint32_t item_id) {
1889     gchar* fullfilename = NULL;
1890     gchar* tmpfilename = NULL;
1891     uint32_t parent_id = 0;
1892     LIBMTP_file_t* tmpfile = deviceFiles;
1893     LIBMTP_folder_t* tmpfolder = deviceFolders;
1894 
1895     // Find our file...
1896     while (tmpfile != NULL) {
1897         if (tmpfile->item_id == item_id) {
1898             fullfilename = g_strdup(tmpfile->filename);
1899             parent_id = tmpfile->parent_id;
1900             tmpfile = NULL;
1901         } else {
1902             tmpfile = tmpfile->next;
1903         }
1904     }
1905     // Let's see if we have a filename?
1906     if (fullfilename != NULL) {
1907         // Now let's prepend the parent folder names to it...
1908         while (tmpfolder != NULL) {
1909             tmpfolder = getCurrentFolderPtr(deviceFolders, parent_id);
1910             if (tmpfolder != NULL) {
1911                 // We have something.
1912                 tmpfilename = g_strdup_printf("%s/%s", tmpfolder->name, fullfilename);
1913                 g_free(fullfilename);
1914                 fullfilename = tmpfilename;
1915                 parent_id = tmpfolder->parent_id;
1916             }
1917         }
1918     }
1919     return fullfilename;
1920 }
1921 
1922 // ************************************************************************************************
1923 
getFileID(gchar * filename,gboolean ignorepath)1924 uint32_t getFileID(gchar* filename, gboolean ignorepath) {
1925     LIBMTP_file_t* files = deviceFiles;
1926 
1927     // Separate into filename and path...
1928     gchar* basefilename = g_path_get_basename(filename);
1929     gchar* dirfilename = g_path_get_dirname(filename);
1930 
1931     // If we are ignoring all path information, then simply scan all files for the filename.
1932     if (ignorepath == TRUE) {
1933         while (files != NULL) {
1934             // Ensure we only check if we are on the current storage device...
1935             if (files->storage_id == DeviceMgr.devicestorage->id) {
1936                 // See if our filename is the same.
1937                 if (g_ascii_strcasecmp(basefilename, files->filename) == 0) {
1938                     // We found our file...
1939                     g_free(basefilename);
1940                     g_free(dirfilename);
1941                     return files->item_id;
1942                 }
1943             }
1944             files = files->next;
1945         }
1946     } else {
1947         // Lets find the folderid of the path we have, so it makes searching a lot easier...
1948         uint32_t folderID = getFolderID(deviceFolders, dirfilename);
1949         if ((int32_t) folderID == -1) {
1950             // We don't have this path on the device, so no need to continue checking.
1951             g_free(basefilename);
1952             g_free(dirfilename);
1953             return 0;
1954         }
1955         while (files != NULL) {
1956             // Ensure we only check if we are on the current storage device AND the file is in the correct folder...
1957             if ((files->storage_id == DeviceMgr.devicestorage->id) && (files->parent_id == folderID)) {
1958                 // See if our filename is the same.
1959                 if (g_ascii_strcasecmp(basefilename, files->filename) == 0) {
1960                     // We found our file...
1961                     g_free(basefilename);
1962                     g_free(dirfilename);
1963                     return files->item_id;
1964                 }
1965             }
1966             files = files->next;
1967         }
1968     }
1969     g_free(basefilename);
1970     g_free(dirfilename);
1971     return 0;
1972 }
1973 
1974 // ************************************************************************************************
1975 
getFolderID(LIBMTP_folder_t * folderptr,gchar * foldername)1976 uint32_t getFolderID(LIBMTP_folder_t* folderptr, gchar* foldername) {
1977     gchar** pathcomponents;
1978     if (g_ascii_strcasecmp(foldername, ".") == 0) {
1979         // We have a root directory...
1980         return 0;
1981     }
1982     // Get the first component of the foldername.
1983     pathcomponents = g_strsplit(foldername, "/", 2);
1984     while (folderptr != NULL) {
1985         if (g_ascii_strcasecmp(pathcomponents[0], folderptr->name) == 0) {
1986             // We have found our path...
1987             // If we have of the path to process then...
1988             if (pathcomponents[1] != NULL) {
1989                 return (getFolderID(folderptr->child, pathcomponents[1]));
1990             } else {
1991                 return folderptr->folder_id;
1992             }
1993         } else {
1994             folderptr = folderptr->sibling;
1995         }
1996     }
1997     return -1;
1998 }
1999 
2000 // ************************************************************************************************
2001 
getFullFolderPath(uint32_t folderid)2002 gchar* getFullFolderPath(uint32_t folderid) {
2003 
2004     gchar* fullfilename = g_strdup("");
2005     gchar* tmpfilename = NULL;
2006     uint32_t parent_id = folderid;
2007     guint stringlength = 0;
2008     LIBMTP_folder_t* tmpfolder = deviceFolders;
2009     if (!Preferences.use_alt_access_method) {
2010         // Legacy search since we have a complete folder structure in memory.
2011         while (tmpfolder != NULL) {
2012             tmpfolder = getCurrentFolderPtr(deviceFolders, parent_id);
2013             if (tmpfolder != NULL) {
2014                 // We have something.
2015                 tmpfilename = g_strdup_printf("%s/%s", tmpfolder->name, fullfilename);
2016                 g_free(fullfilename);
2017                 fullfilename = tmpfilename;
2018                 parent_id = tmpfolder->parent_id;
2019             }
2020         }
2021 
2022 
2023     } else {
2024         // We are using alt access mode, so we need to manually query the device for
2025         // the parent folder.
2026         LIBMTP_file_t * f = LIBMTP_Get_Filemetadata(DeviceMgr.device, parent_id);
2027         while (f != NULL) {
2028             // we have the entry
2029             tmpfilename = g_strdup_printf("%s/%s", f->filename, fullfilename);
2030             g_free(fullfilename);
2031             fullfilename = tmpfilename;
2032             parent_id = f->parent_id;
2033             LIBMTP_destroy_file_t(f);
2034             f = LIBMTP_Get_Filemetadata(DeviceMgr.device, parent_id);
2035         }
2036     }
2037     // Add in leading slash if needed
2038     if (*fullfilename != '/') {
2039         tmpfilename = g_strdup_printf("/%s", fullfilename);
2040         g_free(fullfilename);
2041         fullfilename = tmpfilename;
2042     }
2043     // Remove trailing slash if needed.
2044     stringlength = strlen(fullfilename);
2045     if (stringlength > 1) {
2046         fullfilename[stringlength - 1] = '\0';
2047     }
2048     return fullfilename;
2049 }
2050 
2051 // ************************************************************************************************
2052 
filesSearch(gchar * searchstring,gboolean searchfiles,gboolean searchmeta)2053 GSList *filesSearch(gchar *searchstring, gboolean searchfiles, gboolean searchmeta) {
2054     GSList *list = NULL;
2055     GPatternSpec *pspec = g_pattern_spec_new(searchstring);
2056     LIBMTP_file_t *files = deviceFiles;
2057     GSList *folderIDs = NULL;
2058     LIBMTP_track_t *tracks = deviceTracks;
2059     FileListStruc *filestruc = NULL;
2060     gchar *tmpstring1 = NULL;
2061     gchar *tmpstring2 = NULL;
2062     gchar *tmpstring3 = NULL;
2063     gchar *tmpstring4 = NULL;
2064 
2065     uint32_t tmpFolderID = currentFolderID;
2066 
2067     // if using alt method, we cycle through all folders on the current storage device...
2068     if (Preferences.use_alt_access_method) {
2069         currentFolderID = 0;
2070         filesUpateFileList();
2071         files = deviceFiles;
2072         //buildFolderIDs(&folderIDs, deviceFolders);
2073     }
2074 
2075     if (searchfiles == TRUE) {
2076         // Search folders
2077         // ignore folder search in alt access mode...
2078         if (!Preferences.use_alt_access_method) {
2079             folderSearch(pspec, &list, deviceFolders);
2080         }
2081         // Search files.
2082         while (files != NULL) {
2083             if (files->storage_id == DeviceMgr.devicestorage->id) {
2084                 if (files->filetype == LIBMTP_FILETYPE_FOLDER) {
2085                     // Add this folder to the list to be searched.
2086                     folderIDs = g_slist_append(folderIDs, &files->item_id);
2087                 }
2088                 // Make search case insensitive.
2089                 tmpstring1 = g_utf8_strup(files->filename, -1);
2090                 if (g_pattern_match_string(pspec, tmpstring1) == TRUE) {
2091                     g_free(tmpstring1);
2092                     tmpstring1 = NULL;
2093                     // We have found a matching string...
2094                     filestruc = g_malloc(sizeof (FileListStruc));
2095                     if (filestruc == NULL) {
2096                         g_fprintf(stderr, _("malloc in filesSearch failed\n"));
2097                         displayError(_("Failed searching? 'malloc in filesSearch'\n"));
2098                         return list;
2099                     }
2100                     filestruc->filename = g_strdup(files->filename);
2101                     filestruc->filesize = files->filesize;
2102                     if (files->filetype == LIBMTP_FILETYPE_FOLDER) {
2103                         filestruc->isFolder = TRUE;
2104                     } else {
2105                         filestruc->isFolder = FALSE;
2106                     }
2107                     filestruc->itemid = files->item_id;
2108                     filestruc->filetype = files->filetype;
2109                     filestruc->location = getFullFolderPath(files->parent_id);
2110                     list = g_slist_append(list, filestruc);
2111                 } else if (searchmeta == TRUE) {
2112                     // Now if it's a track type file, eg OGG, WMA, MP3 or FLAC, get it's metadata.
2113                     // search case insensitive.
2114                     if ((files->filetype == LIBMTP_FILETYPE_MP3) ||
2115                             (files->filetype == LIBMTP_FILETYPE_OGG) ||
2116                             (files->filetype == LIBMTP_FILETYPE_FLAC) ||
2117                             (files->filetype == LIBMTP_FILETYPE_WMA)) {
2118                         LIBMTP_track_t *trackinfo = LIBMTP_Get_Trackmetadata(DeviceMgr.device, files->item_id);
2119                         if (trackinfo != NULL) {
2120                             // search case insensitive.
2121                             if (tmpstring1 != NULL) {
2122                                 g_free(tmpstring1);
2123                                 tmpstring1 = NULL;
2124                             }
2125                             tmpstring1 = g_utf8_strup(trackinfo->album, -1);
2126                             tmpstring2 = g_utf8_strup(trackinfo->artist, -1);
2127                             tmpstring3 = g_utf8_strup(trackinfo->genre, -1);
2128                             tmpstring4 = g_utf8_strup(trackinfo->title, -1);
2129                             if ((g_pattern_match_string(pspec, tmpstring1) == TRUE) ||
2130                                     (g_pattern_match_string(pspec, tmpstring2) == TRUE) ||
2131                                     (g_pattern_match_string(pspec, tmpstring3) == TRUE) ||
2132                                     (g_pattern_match_string(pspec, tmpstring4) == TRUE)) {
2133                                 // We have found a matching string...
2134                                 filestruc = g_malloc(sizeof (FileListStruc));
2135                                 if (filestruc == NULL) {
2136                                     if (tmpstring1 != NULL) {
2137                                         g_free(tmpstring1);
2138                                         tmpstring1 = NULL;
2139                                     }
2140                                     if (tmpstring2 != NULL) {
2141                                         g_free(tmpstring2);
2142                                         tmpstring2 = NULL;
2143                                     }
2144                                     if (tmpstring3 != NULL) {
2145                                         g_free(tmpstring3);
2146                                         tmpstring3 = NULL;
2147                                     }
2148                                     if (tmpstring4 != NULL) {
2149                                         g_free(tmpstring4);
2150                                         tmpstring4 = NULL;
2151                                     }
2152                                     g_fprintf(stderr, _("malloc in filesSearch failed\n"));
2153                                     displayError(_("Failed searching? 'malloc in filesSearch'\n"));
2154                                     return list;
2155                                 }
2156                                 filestruc->filename = g_strdup(files->filename);
2157                                 filestruc->filesize = files->filesize;
2158                                 filestruc->isFolder = FALSE;
2159                                 filestruc->itemid = files->item_id;
2160                                 filestruc->filetype = files->filetype;
2161                                 filestruc->location = getFullFolderPath(files->parent_id);
2162                                 list = g_slist_append(list, filestruc);
2163                             }
2164                             if (tmpstring1 != NULL) {
2165                                 g_free(tmpstring1);
2166                                 tmpstring1 = NULL;
2167                             }
2168                             if (tmpstring2 != NULL) {
2169                                 g_free(tmpstring2);
2170                                 tmpstring2 = NULL;
2171                             }
2172                             if (tmpstring3 != NULL) {
2173                                 g_free(tmpstring3);
2174                                 tmpstring3 = NULL;
2175                             }
2176                             if (tmpstring4 != NULL) {
2177                                 g_free(tmpstring4);
2178                                 tmpstring4 = NULL;
2179                             }
2180                             LIBMTP_destroy_track_t(trackinfo);
2181                         }
2182                     }
2183                 }
2184                 if (tmpstring1 != NULL) {
2185                     g_free(tmpstring1);
2186                     tmpstring1 = NULL;
2187                 }
2188             }
2189             files = files->next;
2190 
2191             // Update the file list IFF we are using the alt access method
2192             if ((files == NULL) && (Preferences.use_alt_access_method)) {
2193                 // reached the end of the current folder, so lets move onto the next folder.
2194                 while (files == NULL) {
2195                     // exit searching for file if we run out of folders.
2196                     if (folderIDs == NULL) {
2197                         break;
2198                     }
2199                     currentFolderID = *((uint32_t*) folderIDs->data);
2200                     //printf("Searching folder: %d\n", currentFolderID);
2201                     filesUpateFileList();
2202                     folderIDs = folderIDs->next;
2203                     files = deviceFiles;
2204                 }
2205             }
2206         }
2207     } else if (searchmeta == TRUE) {
2208         // Search using the Track information only.
2209         while (tracks != NULL) {
2210             // Make search case insensitive.
2211             tmpstring1 = g_utf8_strup(tracks->album, -1);
2212             tmpstring2 = g_utf8_strup(tracks->artist, -1);
2213             tmpstring3 = g_utf8_strup(tracks->genre, -1);
2214             tmpstring4 = g_utf8_strup(tracks->title, -1);
2215             if ((g_pattern_match_string(pspec, tmpstring1) == TRUE) ||
2216                     (g_pattern_match_string(pspec, tmpstring2) == TRUE) ||
2217                     (g_pattern_match_string(pspec, tmpstring3) == TRUE) ||
2218                     (g_pattern_match_string(pspec, tmpstring4) == TRUE)) {
2219                 // We have found a matching string...
2220                 filestruc = g_malloc(sizeof (FileListStruc));
2221                 if (filestruc == NULL) {
2222                     if (tmpstring1 != NULL) {
2223                         g_free(tmpstring1);
2224                         tmpstring1 = NULL;
2225                     }
2226                     if (tmpstring2 != NULL) {
2227                         g_free(tmpstring2);
2228                         tmpstring2 = NULL;
2229                     }
2230                     if (tmpstring3 != NULL) {
2231                         g_free(tmpstring3);
2232                         tmpstring3 = NULL;
2233                     }
2234                     if (tmpstring4 != NULL) {
2235                         g_free(tmpstring4);
2236                         tmpstring4 = NULL;
2237                     }
2238                     g_fprintf(stderr, _("malloc in filesSearch failed\n"));
2239                     displayError(_("Failed searching? 'malloc in filesSearch'\n"));
2240                     return list;
2241                 }
2242                 filestruc->filename = g_strdup(tracks->filename);
2243                 filestruc->filesize = tracks->filesize;
2244                 filestruc->isFolder = FALSE;
2245                 filestruc->itemid = tracks->item_id;
2246                 filestruc->filetype = tracks->filetype;
2247                 filestruc->location = getFullFolderPath(tracks->parent_id);
2248                 list = g_slist_append(list, filestruc);
2249             }
2250             if (tmpstring1 != NULL) {
2251                 g_free(tmpstring1);
2252                 tmpstring1 = NULL;
2253             }
2254             if (tmpstring2 != NULL) {
2255                 g_free(tmpstring2);
2256                 tmpstring2 = NULL;
2257             }
2258             if (tmpstring3 != NULL) {
2259                 g_free(tmpstring3);
2260                 tmpstring3 = NULL;
2261             }
2262             if (tmpstring4 != NULL) {
2263                 g_free(tmpstring4);
2264                 tmpstring4 = NULL;
2265             }
2266             tracks = tracks->next;
2267         }
2268     }
2269     // restore the current folder ID.
2270     if (Preferences.use_alt_access_method) {
2271         currentFolderID = tmpFolderID;
2272     }
2273     return list;
2274 }
2275 
2276 // ************************************************************************************************
2277 
buildFolderIDs(GSList ** list,LIBMTP_folder_t * folderptr)2278 void buildFolderIDs(GSList **list, LIBMTP_folder_t * folderptr) {
2279     while (folderptr != NULL) {
2280         *(list) = g_slist_append(*(list), &folderptr->folder_id);
2281         if (folderptr->child != NULL) {
2282             buildFolderIDs(list, folderptr->child);
2283         }
2284         folderptr = folderptr->sibling;
2285     }
2286 }
2287 
2288 // ************************************************************************************************
2289 
folderSearch(GPatternSpec * pspec,GSList ** list,LIBMTP_folder_t * folderptr)2290 void folderSearch(GPatternSpec *pspec, GSList **list, LIBMTP_folder_t * folderptr) {
2291     FileListStruc *filestruc = NULL;
2292     while (folderptr != NULL) {
2293         // Make search case insensitive.
2294         gchar *tmpstring = g_utf8_strup(folderptr->name, -1);
2295         if (g_pattern_match_string(pspec, tmpstring) == TRUE) {
2296             // We have found a matching string...
2297             filestruc = g_malloc(sizeof (FileListStruc));
2298             if (filestruc == NULL) {
2299                 if (tmpstring != NULL) {
2300                     g_free(tmpstring);
2301                     tmpstring = NULL;
2302                 }
2303                 g_fprintf(stderr, _("malloc in foldersearch failed\n"));
2304                 displayError(_("Failed searching? 'malloc in foldersearch'\n"));
2305                 return;
2306             }
2307             filestruc->filename = g_strdup(folderptr->name);
2308             filestruc->filesize = 0;
2309             filestruc->isFolder = TRUE;
2310             filestruc->itemid = folderptr->folder_id;
2311 #if defined(LIBMTP_FILETYPE_FOLDER)
2312             filestruc->filetype = LIBMTP_FILETYPE_FOLDER;
2313 #else
2314             filestruc->filetype = LIBMTP_FILETYPE_UNKNOWN;
2315 #endif
2316             filestruc->location = getFullFolderPath(folderptr->parent_id);
2317             *(list) = g_slist_append(*(list), filestruc);
2318         }
2319         if (tmpstring != NULL) {
2320             g_free(tmpstring);
2321             tmpstring = NULL;
2322         }
2323         // Search child if present;
2324         if (folderptr->child != NULL) {
2325             folderSearch(pspec, list, folderptr->child);
2326         }
2327         folderptr = folderptr->sibling;
2328     }
2329 }
2330 
2331 // ************************************************************************************************
2332 
setNewParentFolderID(uint32_t objectID,uint32_t folderID)2333 int setNewParentFolderID(uint32_t objectID, uint32_t folderID) {
2334     return LIBMTP_Set_Object_u32(DeviceMgr.device, objectID, LIBMTP_PROPERTY_ParentObject, folderID);
2335 }
2336