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