Subversion Repositories mdb

Rev

Rev 50 | Rev 56 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
2
 * Copyright (C) 2015 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * All rights reserved. No warranty, explicit or implicit, provided.
5
 *
6
 * NOTICE:  All information contained herein is, and remains
7
 * the property of Andreas Theofilu and his suppliers, if any.
8
 * The intellectual and technical concepts contained
9
 * herein are proprietary to Andreas Theofilu and its suppliers and
10
 * may be covered by European and Foreign Patents, patents in process,
11
 * and are protected by trade secret or copyright law.
12
 * Dissemination of this information or reproduction of this material
13
 * is strictly forbidden unless prior written permission is obtained
14
 * from Andreas Theofilu.
15
 */
16
#include <stdio.h>
17
#include <string.h>
4 andreas 18
#include <strings.h>
2 andreas 19
#include <unistd.h>
20
#include <stdlib.h>
21
#include <libgen.h>
5 andreas 22
#include <ctype.h>
2 andreas 23
#include <math.h>
24
#include <time.h>
25
#include <signal.h>
26
#include <syslog.h>
43 andreas 27
#include <iconv.h>
2 andreas 28
#include <errno.h>
29
#include <pthread.h>
30
#include <sys/stat.h>
31
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <arpa/inet.h>
34
#include <fcntl.h>
35
#include <netdb.h>
36
#include <dirent.h>
37
#include <netinet/in.h>
38
#include <sys/param.h>
39
#include <sys/ioctl.h>
40
#include <sqlite3.h>
45 andreas 41
#include <id3tag.h>
2 andreas 42
#include "config.h"
43
#include "helplib.h"
44
#include "mdb.h"
5 andreas 45
#include "list.h"
6 andreas 46
#include "play.h"
8 andreas 47
#include "user.h"
48
#include "delete.h"
9 andreas 49
#include "search.h"
2 andreas 50
 
45 andreas 51
#define ID3_NR_OF_V1_GENRES 148
52
 
53
static const char *ID3_v1_genre_description[ID3_NR_OF_V1_GENRES] =
54
{
55
	"Blues",             //0
56
	"Classic Rock",      //1
57
	"Country",           //2
58
	"Dance",             //3
59
	"Disco",             //4
60
	"Funk",              //5
61
	"Grunge",            //6
62
	"Hip-Hop",           //7
63
	"Jazz",              //8
64
	"Metal",             //9
65
	"New Age",           //10
66
	"Oldies",            //11
67
	"Other",             //12
68
	"Pop",               //13
69
	"R&B",               //14
70
	"Rap",               //15
71
	"Reggae",            //16
72
	"Rock",              //17
73
	"Techno",            //18
74
	"Industrial",        //19
75
	"Alternative",       //20
76
	"Ska",               //21
77
	"Death Metal",       //22
78
	"Pranks",            //23
79
	"Soundtrack",        //24
80
	"Euro-Techno",       //25
81
	"Ambient",           //26
82
	"Trip-Hop",          //27
83
	"Vocal",             //28
84
	"Jazz+Funk",         //29
85
	"Fusion",            //30
86
	"Trance",            //31
87
	"Classical",         //32
88
	"Instrumental",      //33
89
	"Acid",              //34
90
	"House",             //35
91
	"Game",              //36
92
	"Sound Clip",        //37
93
	"Gospel",            //38
94
	"Noise",             //39
95
	"AlternRock",        //40
96
	"Bass",              //41
97
	"Soul",              //42
98
	"Punk",              //43
99
	"Space",             //44
100
	"Meditative",        //45
101
	"Instrumental Pop",  //46
102
	"Instrumental Rock", //47
103
	"Ethnic",            //48
104
	"Gothic",            //49
105
	"Darkwave",          //50
106
	"Techno-Industrial", //51
107
	"Electronic",        //52
108
	"Pop-Folk",          //53
109
	"Eurodance",         //54
110
	"Dream",             //55
111
	"Southern Rock",     //56
112
	"Comedy",            //57
113
	"Cult",              //58
114
	"Gangsta",           //59
115
	"Top 40",            //60
116
	"Christian Rap",     //61
117
	"Pop/Funk",          //62
118
	"Jungle",            //63
119
	"Native American",   //64
120
	"Cabaret",           //65
121
	"New Wave",          //66
122
	"Psychedelic",       //67
123
	"Rave",              //68
124
	"Showtunes",         //69
125
	"Trailer",           //70
126
	"Lo-Fi",             //71
127
	"Tribal",            //72
128
	"Acid Punk",         //73
129
	"Acid Jazz",         //74
130
	"Polka",             //75
131
	"Retro",             //76
132
	"Musical",           //77
133
	"Rock & Roll",       //78
134
	"Hard Rock",         //79
135
	// following are winamp extentions
136
	"Folk",                  //80
137
	"Folk-Rock",             //81
138
	"National Folk",         //82
139
	"Swing",                 //83
140
	"Fast Fusion",           //84
141
	"Bebob",                 //85
142
	"Latin",                 //86
143
	"Revival",               //87
144
	"Celtic",                //88
145
	"Bluegrass",             //89
146
	"Avantgarde",            //90
147
	"Gothic Rock",           //91
148
	"Progressive Rock",      //92
149
	"Psychedelic Rock",      //93
150
	"Symphonic Rock",        //94
151
	"Slow Rock",             //95
152
	"Big Band",              //96
153
	"Chorus",                //97
154
	"Easy Listening",        //98
155
	"Acoustic",              //99
156
	"Humour",                //100
157
	"Speech",                //101
158
	"Chanson",               //102
159
	"Opera",                 //103
160
	"Chamber Music",         //104
161
	"Sonata",                //105
162
	"Symphony",              //106
163
	"Booty Bass",            //107
164
	"Primus",                //108
165
	"Porn Groove",           //109
166
	"Satire",                //110
167
	"Slow Jam",              //111
168
	"Club",                  //112
169
	"Tango",                 //113
170
	"Samba",                 //114
171
	"Folklore",              //115
172
	"Ballad",                //116
173
	"Power Ballad",          //117
174
	"Rhythmic Soul",         //118
175
	"Freestyle",             //119
176
	"Duet",                  //120
177
	"Punk Rock",             //121
178
	"Drum Solo",             //122
179
	"A capella",             //123
180
	"Euro-House",            //124
181
	"Dance Hall",            //125
182
	"Goa",                   //126
183
	"Drum & Bass",           //127
184
	"Club-House",            //128
185
	"Hardcore",              //129
186
	"Terror",                //130
187
	"Indie",                 //131
188
	"Britpop",               //132
189
	"Negerpunk",             //133
190
	"Polsk Punk",            //134
191
	"Beat",                  //135
192
	"Christian Gangsta Rap", //136
193
	"Heavy Metal",           //137
194
	"Black Metal",           //138
195
	"Crossover",             //139
196
	"Contemporary Christian",//140
197
	"Christian Rock ",       //141
198
	"Merengue",              //142
199
	"Salsa",                 //143
200
	"Thrash Metal",          //144
201
	"Anime",                 //145
202
	"JPop",                  //146
203
	"Synthpop"               //147
204
};
205
 
2 andreas 206
static pthread_mutex_t fastmutex_proc = PTHREAD_MUTEX_INITIALIZER;
207
int musicFilter(const struct dirent *dir);
12 andreas 208
int grabMusicFiles(int s1, char *dir);
2 andreas 209
void evaluateMusicFile(char *file);
8 andreas 210
int cleanArchieve(int s1, char *fname);
45 andreas 211
char *getID3_Field(union id3_field *field, enum id3_field_textencoding te, char *ret, int len);
212
int checkID3FieldType(enum id3_field_type ft);
2 andreas 213
 
4 andreas 214
/* Global variables */
2 andreas 215
int file_found = 0;
4 andreas 216
char cmd_error[512];
217
char cmd_message[512];
11 andreas 218
int currentPage = PAGE_NONE;
12 andreas 219
int grabFilesCount;						/* Temporary used to count the scanned files */
9 andreas 220
struct ST_PlayPars _playPars;
2 andreas 221
 
6 andreas 222
static pthread_t pthr_play;
3 andreas 223
/*
224
 * This is called from the main listening thread as a thread of its own.
225
 * The function gets the commands from the client, work with them and give
226
 * back the result.
227
 */
2 andreas 228
void *processCommands(void *pV_data)
229
{
4 andreas 230
	char ch, buf[512];
2 andreas 231
	int i, s1, s;
232
	struct SOCKETS *soc;
3 andreas 233
 
2 andreas 234
	soc = (struct SOCKETS *)pV_data;
235
	s1 = soc->newfd;
236
	s = soc->sockfd;
11 andreas 237
	i = 0;
238
	/* Report the actual status to the client */
19 andreas 239
/*	pthread_mutex_lock (&fastmutex_proc); */
11 andreas 240
	sprintf(buf, "# MDB v%s\n", VERSION);
241
	strcat (buf, "# (C) Copyright 2015 by Andreas Theofilu <andreas@theosys.at>\n");
242
	strcat (buf, "# All rights reserved. No warranty, explicit or implicit, provided.\n");
243
	write (s1, buf, strlen(buf));
244
 
245
	if (userchain != NULL)
246
	{
247
		sprintf(buf, "USER:%s;", userchain->uname);
248
		write (s1, buf, strlen(buf));
249
	}
250
 
251
	strcpy (buf, "PAGE:");
252
 
253
	switch (currentPage)
254
	{
255
		case PAGE_NONE:		strcat (buf, "NONE;"); break;
256
		case PAGE_TITLE:	strcat (buf, "TITLE;"); break;
257
		case PAGE_ARTIST:	strcat (buf, "ARTIST;"); break;
258
		case PAGE_ALBUM:	strcat (buf, "ALBUM;"); break;
259
		case PAGE_GENRE:	strcat (buf, "GENRE;"); break;
260
		case PAGE_QUEUE:	strcat (buf, "QUEUE;"); break;
261
		case PAGE_PLAYLIST:	strcat (buf, "PLAYLIST;"); break;
262
	}
263
 
264
	write (s1, buf, strlen(buf));
265
	sprintf(buf, "REPEAT:%s;", playerRepeat ? "TRUE" : "FALSE");
266
	write (s1, buf, strlen(buf));
267
	sprintf(buf, "RANDOM:%s;", playerRandom ? "TRUE" : "FALSE");
268
	write (s1, buf, strlen(buf));
269
	/* In case the player is playing, we send the data of the
270
	 * current song */
271
	if (playerActive)
272
	{
273
		char buffer[8192];
274
		char *title, *artist, *album, *genre;
275
 
276
		title = urlencode(playCurrent.title);
277
		artist = urlencode(playCurrent.artist);
278
		album = urlencode(playCurrent.album);
279
		genre = urlencode(playCurrent.genre);
12 andreas 280
		sprintf(buffer, "PLAYING:%d:%s:%s:%s:%s:%s;", playCurrent.id, title, artist, album, genre, playCurrent.cover);
11 andreas 281
		write (s1, buffer, strlen(buffer));
282
 
283
		if (title != NULL) free(title);
284
		if (artist != NULL) free(artist);
285
		if (album != NULL) free(album);
286
		if (genre != NULL) free(genre);
287
	}
288
	/* Signal client, that we are finished the initial report */
289
	strcpy (buf, "DONE;");
12 andreas 290
	write (s1, buf, strlen(buf));
11 andreas 291
 
19 andreas 292
/*	pthread_mutex_unlock(&fastmutex_proc); */
11 andreas 293
 
19 andreas 294
	memset(buf, 0, sizeof(buf));
4 andreas 295
	memset(cmd_message, 0, sizeof(cmd_message));
11 andreas 296
 
2 andreas 297
	while (read(s1,&ch,1) > 0)
298
	{
4 andreas 299
		if (i < (int)(sizeof(buf) - 1))
2 andreas 300
		{
301
			buf[i] = ch;
3 andreas 302
 
2 andreas 303
			if (ch == ';' || ch == 0x0d)
304
			{
305
				int pstat;
3 andreas 306
 
19 andreas 307
/*				pthread_mutex_lock (&fastmutex_proc); */
3 andreas 308
 
2 andreas 309
				if (!strncmp(buf, "quit", 4))
310
					break;
3 andreas 311
 
4 andreas 312
				if ((pstat = parseCommand(s1, buf)) == FALSE)
2 andreas 313
				{
314
					char hv0[128];
3 andreas 315
 
4 andreas 316
					char *p = urlencode(cmd_error);
317
 
318
					if (p != NULL)
319
					{
320
						sprintf(&hv0[0], "INVALID COMMAND: %s: %s;", buf, p);
321
						free(p);
322
					}
323
					else
324
						sprintf(&hv0[0], "INVALID COMMAND: %s;", buf);
325
 
326
					write(s1, hv0, strlen(hv0));
2 andreas 327
				}
328
				else if (pstat == 2)
329
					write(s1, "NAK;", 4);
330
				else
4 andreas 331
				{
332
					if (strlen(cmd_message) > 0)
5 andreas 333
						write(s1, cmd_message, strlen(cmd_message));
4 andreas 334
					else
335
						write(s1, "OK;", 3);
336
				}
337
 
2 andreas 338
				memset(&buf[0], 0, sizeof(buf));
12 andreas 339
				memset(cmd_message, 0, sizeof(cmd_message));
2 andreas 340
				i = 0;
19 andreas 341
/*				pthread_mutex_unlock(&fastmutex_proc); */
2 andreas 342
				continue;
343
			}
344
		}
3 andreas 345
 
2 andreas 346
		i++;
347
	}
3 andreas 348
 
2 andreas 349
	close(s1);
14 andreas 350
	return NULL;
2 andreas 351
}
352
 
353
/*
354
 * This function parses the commands given by a network client.
355
 */
356
int parseCommand(int s1, char *cmd)
357
{
4 andreas 358
	char bef[32],par[1024], *p;
359
	char hv0[256];
14 andreas 360
	int i;
4 andreas 361
 
362
	memset(bef, 0, sizeof(bef));
363
	memset(par, 0, sizeof(par));
364
	memset(cmd_error, 0, sizeof(cmd_error));
365
 
366
	if ((p = strchr(cmd, ':')) != NULL)			/* do we have a parameter? */
367
	{
368
		strncpy(bef, cmd, p - cmd);
369
		strncpy(par, p+1, strlen(p) - 2);		/* Cut off the trailing semi colon */
370
	}
371
	else
372
		strncpy(bef, cmd, strlen(cmd) - 1);
373
 
374
	cmd_error[0] = 0;
375
	cmd_message[0] = 0;
36 andreas 376
 
4 andreas 377
	if (!strcasecmp(bef, "RESCAN"))				/* Rescan all directories */
378
	{
379
		int fd;
5 andreas 380
		char fname[512];
4 andreas 381
 
382
		if (access(configs.Pathfile, R_OK))
383
		{
384
			syslog(LOG_WARNING, "Error accessing file %s", configs.Pathfile);
385
			sprintf(cmd_error, "Error accessing file >%s<", configs.Pathfile);
386
			return FALSE;
387
		}
388
 
389
		if ((fd = open(configs.Pathfile, O_RDONLY)) < 0)
390
		{
391
			syslog(LOG_WARNING, "Error opening file %s: %s", configs.Pathfile, strerror(errno));
392
			sprintf(cmd_error, "Error opening file >%s<", configs.Pathfile);
393
			return FALSE;
394
		}
395
 
396
		i = 0;
397
 
8 andreas 398
		/* Delete the database entries before we start to scan.
5 andreas 399
		 * This makes shure, that there is no double entry.
400
		 */
42 andreas 401
/*		strcpy(fname, configs.home);
9 andreas 402
		strcat(fname, MUSICDB);
5 andreas 403
 
404
		if (!access(fname, R_OK | W_OK))
8 andreas 405
			cleanArchieve(s1, fname);
42 andreas 406
*/
12 andreas 407
		grabFilesCount = 0;
5 andreas 408
		/* Scan all directories in the config file recursievly. */
4 andreas 409
		while (readLine(fd, &hv0[0], sizeof(hv0)) != NULL)
410
		{
12 andreas 411
			grabMusicFiles(s1, hv0);
4 andreas 412
			i++;
413
		}
414
 
12 andreas 415
		sprintf(cmd_message, "SCAN:%d:%d;", i, grabFilesCount);
4 andreas 416
		close(fd);
417
	}
418
 
5 andreas 419
	/*
420
	 * Syntax: LIST:<type>:<start>:<length>;
24 andreas 421
	 *         <type>   TITLE | ARTIST | ALBUM | GENRE | QUEUE | PLAYLIST | USERS
5 andreas 422
	 *         <start>  The line to start from
423
	 *         <length> The number of lines to report
424
	 * 
12 andreas 425
	 * Returns: LINE:<type>:<id>:<line>:<title>:<artist>:<album>:<genre>:<cover>;
5 andreas 426
	 *         <id>     The unique ID of the file. Needed to play the file!
427
	 *         <line>   The line number counting from 1
24 andreas 428
	 * 
429
	 * In case the type is USERS, the following is returned:
430
	 *          USERS:<id>:<line>:<name>;
431
	 *         <name>   The name of the user
5 andreas 432
	 */
433
	if (!strcasecmp(bef, "LIST"))				/* List content */
434
	{
435
		char p_type[16];
436
		int start, length;
437
 
438
		memset(p_type, 0, sizeof(p_type));
439
		remove_string(par, ":", &hv0[0]);
440
		start = strlen(hv0);
441
		hv0[start-1] = 0;
442
		strncpy(p_type, hv0, sizeof(p_type)-1);
443
		start = atoi(par);
444
		remove_string(par, ":", &hv0[0]);
445
		length = atoi(par);
446
		return listSongs(s1, p_type, start, length);
447
	}
448
 
449
	/*
9 andreas 450
	 * Syntax: PLIST:<user>:<playlist>:<start>:<length>;
451
	 *         <user>   The name of the user.
452
	 *         <playlist> The name of the playlist
453
	 *         <start>  The line to start from
454
	 *         <length> The number of lines to report
455
	 * 
13 andreas 456
	 * Returns: LINE:<type>:<id>:<line>:<title>:<artist>:<album>:<genre>:<cover>;
9 andreas 457
	 *         <id>     The unique ID of the file. Needed to play the file!
458
	 *         <line>   The line number counting from 1
459
	 */
460
	if (!strcasecmp(bef, "PLIST"))				/* List content */
461
	{
462
		char user[64], playlist[64], *t;
463
		int start, length, x;
464
 
465
		memset(user, 0, sizeof(user));
466
		memset(playlist, 0, sizeof(playlist));
467
		x = 0;
468
		t = strtok (par, ":");
469
 
470
		while (t)
471
		{
472
			switch(x)
473
			{
474
				case 0: strncpy (user, t, sizeof(user)-1); break;
475
				case 1: strncpy (playlist, t, sizeof(playlist)-1); break;
476
				case 2: start = atoi(t); break;
477
				case 3: length = atoi(t); break;
478
			}
479
 
480
			x++;
481
			t = strtok (NULL, ":");
482
		}
483
 
11 andreas 484
		t = urldecode(user);
485
 
486
		if (t)
487
		{
488
			strncpy(user, t, sizeof(user)-1);
489
			free(t);
490
		}
491
 
492
		t = urldecode(playlist);
493
 
494
		if (t)
495
		{
496
			strncpy(playlist, t, sizeof(playlist)-1);
497
			free(t);
498
		}
499
 
9 andreas 500
		return listUserPlaylist(s1, user, playlist, start, length);
501
	}
502
 
503
	/*
13 andreas 504
	 * Syntax: LISTFOLDER:<type>:<name>:<start>:<length>;
505
	 *         <type>   TITLE | ARTIST | ALBUM | GENRE
506
	 *         <start>  The line to start from
507
	 *         <length> The number of lines to report
508
	 * 
509
	 * Returns: LINE:<type>:<id>:<line>:<title>:<artist>:<album>:<genre>:<cover>;
510
	 *         <id>     The unique ID of the file. Needed to play the file!
511
	 *         <line>   The line number counting from 1
512
	 */
513
	if (!strcasecmp(bef, "LISTFOLDER"))			/* List the content of a folder */
514
	{
515
		char p_type[64], name[256], *t, *type, *nm;
516
		int x, start, length;
517
 
518
		x = 0;
519
		t = strtok(par, ":");
520
 
521
		while (t)
522
		{
523
			switch(x)
524
			{
525
				case 0: strncpy(p_type, t, sizeof(p_type)); break;
526
				case 1: strncpy(name, t, sizeof(name)); break;
527
				case 2: start = atoi(t); break;
528
				case 3: length = atoi(t); break;
529
			}
530
 
531
			x++;
532
			t = strtok(NULL, ":");
533
		}
534
 
535
		type = urldecode(p_type);
536
		nm = urldecode(name);
537
 
538
		if (type)
539
		{
540
			strncpy(p_type, type, sizeof(p_type)-1);
541
			free(type);
542
		}
543
 
544
		if (nm)
545
		{
546
			strncpy(name, nm, sizeof(name)-1);
547
			free(nm);
548
		}
549
 
550
		return listFolderContent(s1, p_type, name, start, length);
551
	}
552
 
553
	/*
5 andreas 554
	 * Syntax: FOLDER:<type>:<start>:<length>;
555
	 *         <type>   TITLE | ARTIST | ALBUM | GENRE
556
	 *         <start>  The line to start from
557
	 *         <length> The number of lines to report
558
	 * 
25 andreas 559
	 * Returns: FOLDER:<type>:<id>:<line>:<content>;
5 andreas 560
	 *         <id>       The unique ID of the file. Needed to play the file!
561
	 *         <line>     The line number counting from 1
562
	 *         <content>  The name of the folder
563
	 */
564
	if (!strcasecmp(bef, "FOLDER"))				/* List folders */
565
	{
566
		char p_type[16];
567
		int start, length;
568
 
569
		memset(p_type, 0, sizeof(p_type));
570
		remove_string(par, ":", &hv0[0]);
571
		start = strlen(hv0);
572
		hv0[start-1] = 0;
573
		strncpy(p_type, hv0, sizeof(p_type)-1);
574
		start = atoi(par);
575
		remove_string(par, ":", &hv0[0]);
576
		length = atoi(par);
577
		return listFolders(s1, p_type, start, length);
578
	}
579
 
6 andreas 580
	/*
14 andreas 581
	 * This command moves one or more files into the queue.
582
	 * If the queue already contains some files, the files are appended to
18 andreas 583
	 * the end of the queue. The command makes sure, that there are no
584
	 * duplicate entries in the queue.
14 andreas 585
	 * If the name of a folder is omitted, all files of the specified types
586
	 * are appended.
587
	 * If a folder name was specified, only the files of the folder are
588
	 * appended.
589
	 *
590
	 * Syntax: ADD:<type>:<folder>;
591
	 *          <type>     ID | TITLE | ARTIST | ALBUM | GENRE | PLAYLIST
592
	 *          <folder>   The name of a folder. This is optional.
593
	 */
594
	if (!strcasecmp(bef, "ADD"))
595
	{
596
		int x;
597
		char *t, p_type[32], folder[64], *type, *fld;
598
 
599
		memset(p_type, 0, sizeof(p_type));
600
		memset(folder, 0, sizeof(folder));
601
		x = 0;
602
		t = strtok(par, ":");
603
 
604
		while (t)
605
		{
606
			switch (x)
607
			{
608
				case 0: strncpy(p_type, t, sizeof(p_type)-1); break;
609
				case 1: strncpy(folder, t, sizeof(folder)-1); break;
610
			}
611
 
612
			x++;
613
			t = strtok(NULL, ":");
614
		}
615
 
616
		type = urldecode(p_type);
617
		fld = urldecode(folder);
618
 
619
		if (type)
620
		{
621
			strncpy(p_type, type, sizeof(p_type));
622
			free(type);
623
		}
624
 
625
		if (fld)
626
		{
627
			strncpy(folder, fld, sizeof(folder));
628
			free(fld);
629
		}
630
 
18 andreas 631
		if (strlen(p_type) && strlen(folder))
14 andreas 632
			appendToQueue(s1, p_type, folder);
633
		else
634
		{
18 andreas 635
			strcpy(cmd_message, "ERROR:ADD:Missing type or folder name;");
636
			return FALSE;
14 andreas 637
		}
638
	}
639
 
640
	/*
641
	 * This command moves one or more files into the queue and starts to play
642
	 * them.
643
	 * If the player is already playing, the file(s) are appended to the queue.
36 andreas 644
	 * If a play request for the queue is detected and the ID is 0, then the
645
	 * first or, if random is selected a random entry of the que is played. If
646
	 * the ID is grater than 0, the wanted ID is played even if random is
647
	 * selected.
49 andreas 648
	 * The type DIRECT means to play a particular file without change the current
649
	 * queue. If something is already playing, it's stopped and the file the
650
	 * parameter <what> points to is played. With DIRECT the parameter <what>
651
	 * has to contain a valid ID number.
14 andreas 652
	 *
6 andreas 653
	 * Syntax: PLAY:<type>:<what>;
49 andreas 654
	 *         <type>     ID | TITLE | ARTIST | ALBUM | GENRE | PLAYLIST | QUEUE | DIRECT
7 andreas 655
	 *         <what>     <id> or name of folder or name of playlist
6 andreas 656
	 * 
7 andreas 657
	 * Returns: PLAYING:<id>:<title>:<artist>:<album>:<genre>;
49 andreas 658
	 *          POSITION:<time>:<time left>:<total>;
6 andreas 659
	 */
660
	if (!strcasecmp(bef, "PLAY"))				/* Plays one or more files */
661
	{
662
		char p_type[16];
663
		char what[256];
664
		int i;
665
 
666
		memset(p_type, 0, sizeof(p_type));
36 andreas 667
		memset(hv0, 0, sizeof(hv0));
6 andreas 668
		remove_string(par, ":", &hv0[0]);
669
		i = strlen(hv0);
37 andreas 670
 
36 andreas 671
		if (i > 0)
672
		{
673
			hv0[i-1] = 0;
674
			strncpy(p_type, hv0, sizeof(p_type) - 1);
675
		}
676
		else
677
			strcpy(p_type, "QUEUE");
678
 
49 andreas 679
		if (strcasecmp(p_type, "ID") && strcasecmp(p_type, "DIRECT"))	/* If the type is not "ID" and not "DIRECT" then */
680
		{																/* decode the text */
9 andreas 681
			char *w;
7 andreas 682
 
9 andreas 683
			w = urldecode(par);
684
 
685
			if (w)
686
			{
687
				strncpy (what, w, sizeof(what));
688
				i = sizeof(what) - 1;
689
				what[i] = 0;
690
				free (w);
691
			}
692
			else
693
				strncpy(what, par, sizeof(what));
694
		}
36 andreas 695
		else if (strlen(par))
696
			strncpy(what, par, sizeof(what));
9 andreas 697
		else
36 andreas 698
			strcpy(what, "0");
37 andreas 699
 
49 andreas 700
		if (playerActive && playStatus == PLAY_STATUS_PAUSE && strcasecmp(p_type, "DIRECT"))
8 andreas 701
			nextCommand = PLAY_PLAY;
49 andreas 702
		else if (playerActive && strcasecmp(p_type, "DIRECT"))		/* Only if type is not DIRECT */
7 andreas 703
			appendToQueue(s1, p_type, what);
704
		else
6 andreas 705
		{
7 andreas 706
			_playPars.s1 = s1;
9 andreas 707
			strcpy(_playPars.type, p_type);
708
			strcpy(_playPars.what, what);
49 andreas 709
 
710
			if (!strcasecmp(p_type, "DIRECT") && playerActive)
711
			{
50 andreas 712
				qstackAdd(atoi(what));
713
				nextCommand = PLAY_STACK;
714
			}
51 andreas 715
			else if (!playerActive)
50 andreas 716
			{
717
				/* start a new thread to play the file(s) */
718
				if (pthread_create(&pthr_play, NULL, pthr_playfile, (void *)&_playPars) != 0)
49 andreas 719
				{
50 andreas 720
					syslog (LOG_DAEMON,"Creation of thread \"pthr_play\" failed!");
721
					strcpy(cmd_error, "Error playing a file!");
49 andreas 722
					return FALSE;
723
				}
724
			}
6 andreas 725
		}
726
	}
727
 
7 andreas 728
	if (!strcasecmp(bef, "STOP") && playerActive)				/* Stop the currently playing file */
729
		nextCommand = PLAY_STOP;
730
 
731
	if (!strcasecmp(bef, "PAUSE") && playerActive)				/* Pause the currently playing file */
732
		nextCommand = PLAY_PAUSE;
733
 
40 andreas 734
	if (!strcasecmp(bef, "PLAYPAUSE"))							/* Play/Pause the currently playing file, */
735
	{															/* or play one in the queue if there are any. */
736
		if (playerActive && (playStatus == PLAY_STATUS_PAUSE || playStatus == PLAY_STATUS_PLAY))
737
			nextCommand = PLAY_PLAYPAUSE;
738
		else if (playerActive && playStatus == PLAY_STATUS_STOP)
739
			nextCommand = PLAY_PLAY;
740
		else if (!playerActive)
741
		{
742
			_playPars.s1 = s1;
743
			strcpy(_playPars.type, "QUEUE");					/* Select the queue to play. */
744
			strcpy(_playPars.what, "0");						/* Play the first or a random file, if random is selected, in the queue. */
745
			/* start a new thread to play the file(s) */
746
			if (pthread_create(&pthr_play, NULL, pthr_playfile, (void *)&_playPars) != 0)
747
			{
748
				syslog (LOG_DAEMON,"Create of thread \"pthr_play\" failed!");
749
				strcpy(cmd_error, "Error playing a file!");
750
				return FALSE;
751
			}
752
		}
753
	}
7 andreas 754
 
755
	if (!strcasecmp(bef, "FORWARD") && playerActive)			/* Fast forward */
756
		nextCommand = PLAY_FWD;
757
 
758
	if (!strcasecmp(bef, "REWIND") && playerActive)				/* Fast rewind */
759
		nextCommand = PLAY_REW;
760
 
761
	if (!strcasecmp(bef, "SKIPFWD") && playerActive)			/* Skip to next file in queue */
762
		nextCommand = PLAY_SKIP_FWD;
763
 
764
	if (!strcasecmp(bef, "SKIPREW") && playerActive)			/* Skip to previous file in queue */
765
		nextCommand = PLAY_SKIP_REW;
766
 
11 andreas 767
	if (!strcasecmp(bef, "RANDOM"))								/* Toggle random play */
768
	{
769
		playerRandom = !playerRandom;
770
		sprintf(cmd_message, "RANDOM:%s;", playerRandom ? "TRUE" : "FALSE");
771
	}
772
 
773
	if (!strcasecmp(bef, "REPEAT"))								/* Toggle repeat */
774
	{
775
		playerRepeat = !playerRepeat;
776
		sprintf(cmd_message, "REPEAT:%s;", playerRepeat ? "TRUE" : "FALSE");
777
	}
778
 
7 andreas 779
	/*
14 andreas 780
	 * This command loads a user. If the user doesn't exist it creates
781
	 * the user. In this case the name of a playlist is needed.
782
	 * If the user already exist, the name of a playlist is optional.
783
	 * 
784
	 * If this command is called without the name of a playlist and the
785
	 * user doesn't exist, an error occurs.
786
	 *
787
	 * This command should only be called when a new playlist is to be
788
	 * saved. After this command the command "SAVEQUEUE" should be called.
789
	 *
8 andreas 790
	 * Syntax: USER:<name>:[<playlist>];
791
	 *         <name>     the name of the user.
792
	 *         <playlist> the name of the playlist; This is optional.
7 andreas 793
	 */
794
	if (!strcasecmp(bef, "USER"))								/* In case the user doesn't exist, create a new one. Activate this user */
795
	{
8 andreas 796
		char user[64], playlist[64], *t;
797
		int x;
7 andreas 798
 
8 andreas 799
		memset(user, 0, sizeof(user));
800
		memset(playlist, 0, sizeof(playlist));
801
		x = 0;
802
		t = strtok (par, ":");
7 andreas 803
 
8 andreas 804
		while (t)
805
		{
806
			char *hv;
807
 
808
			switch(x)
809
			{
810
				case 0:
811
					strncpy (user, t, sizeof(user));
812
					user[63] = 0;
813
					hv = urldecode(user);
814
 
815
					if (hv != NULL)
816
					{
817
						strcpy(user, hv);
818
						free(hv);
819
					}
820
				break;
821
 
822
				case 1:
823
					strncpy (playlist, t, sizeof(playlist));
824
					playlist[63] = 0;
825
					hv = urldecode(playlist);
826
 
827
					if (hv != NULL)
828
					{
829
						strcpy(playlist, hv);
830
						free(hv);
831
					}
832
				break;
833
			}
834
 
835
			x++;
836
			t = strtok(NULL, ":");
837
		}
838
 
839
		if (strlen(user) && strlen(playlist))
840
		{
841
			if (!createUser(s1, user, playlist))
842
				return FALSE;
843
 
844
			return selectUser(s1, user);
845
		}
846
		else if (strlen(user))
847
			return selectUser(s1, user);
848
		else
849
		{
850
			strcpy (cmd_error, "Missing the username and the name of the playlist");
851
			return FALSE;
852
		}
7 andreas 853
	}
854
 
8 andreas 855
	/*
856
	 * Syntax: SAVEQUEUE:<user>:<playlist>;
857
	 *         <user>     The name of the user. If this is empty, the actual
858
	 *                    user is taken, if any. If there's no user selected,
859
	 *                    an error occurs.
860
	 *         <playlist> The name of the playlist. If the playlist already
861
	 *                    exist, it'll be overwritten.
862
	 * 
863
	 * Return: TRANSFERED:<num>;
864
	 *         <num>      The number of entries transfered.
865
	 */
14 andreas 866
	if (!strcasecmp(bef, "SAVEQUEUE"))			/* Saves the content of the queue into a playlist */
8 andreas 867
	{
868
		char user[64], playlist[64];
869
		char *t;
870
		int x;
871
 
25 andreas 872
		if (!queueTotal)
873
		{
874
			readQueue();
875
 
876
			if (!queueTotal)
877
			{
878
				strcpy(cmd_error, "Queue is empty");
879
				return FALSE;
880
			}
881
		}
882
 
8 andreas 883
		x = 0;
884
		t = strtok(par, ":");
885
 
886
		while (t)
887
		{
888
			char *hv;
889
 
890
			switch(x)
891
			{
892
				case 0:
893
					strncpy (user, t, sizeof(user));
894
					user[63] = 0;
895
					hv = urldecode(user);
896
 
897
					if (hv != NULL)
898
					{
899
						strcpy(user, hv);
900
						free(hv);
901
					}
902
				break;
903
 
904
				case 1:
905
					strncpy (playlist, t, sizeof(playlist));
906
					playlist[63] = 0;
907
					hv = urldecode(playlist);
908
 
909
					if (hv != NULL)
910
					{
911
						strcpy(playlist, hv);
912
						free(hv);
913
					}
914
				break;
915
			}
916
 
917
			x++;
918
			t = strtok(NULL, ":");
919
		}
920
 
921
		if (!strlen(user) && userchain != NULL)
922
			strcpy(user, userchain->uname);
25 andreas 923
		else if (!selectUser(s1, user) && strlen(user) && strlen(playlist))
924
		{
925
			if (!createUser(s1, user, playlist))
926
				return FALSE;
927
 
928
			return QueueToPlaylist(s1, user, playlist);
929
		}
8 andreas 930
		else if (!selectUser(s1, user))
931
		{
932
			strcpy (cmd_error, "No or invalid user");
933
			return FALSE;
934
		}
935
 
936
		if (!strlen(playlist))
937
		{
938
			strcpy (cmd_error, "No or invalid playlist");
939
			return FALSE;
940
		}
941
 
942
		if (!QueueToPlaylist(s1, user, playlist))
943
			return FALSE;
944
	}
945
 
946
	/*
947
	 * Syntax: DELETE:<type>:<id>;
13 andreas 948
	 *      <type>     PTITLE | QUEUE | PLAYLIST
949
	 *                 PTITLE: Delete one title from a playlist
950
	 *                 QUEUE: If the given ID is -1, then the whole
951
	 *                        queue is deleted. Otherwise only a title
952
	 *                        in the queue.
953
	 *                 PLAYLIST Delete a whole playlist from a user
8 andreas 954
	 * 
13 andreas 955
	 *      <id>       -1 = Delete whole QUEUE or PLAYLIST
956
	 *                 >= 0 Delete only a particular entry
8 andreas 957
	 */
9 andreas 958
	if (!strcasecmp(bef, "DELETE"))
8 andreas 959
	{
960
		char p_type[32], *t;
961
		int id, x;
962
 
963
		x = 0;
964
		t = strtok(par, ":");
965
 
966
		while (t)
967
		{
968
			switch (x)
969
			{
970
				case 0:
971
					strncpy(p_type, t, sizeof(p_type));
972
					p_type[31] = 0;
973
				break;
974
 
975
				case 1: id = atoi(t); break;
976
			}
977
 
978
			x++;
979
			t = strtok(NULL, ":");
980
		}
981
 
982
		if (!strcasecmp(p_type, "QUEUE"))
983
			return deleteQueue(s1, id);
984
		else if (!strcasecmp(p_type, "PTITLE"))
985
			return deletePlaylistEntry(s1, id);
986
		else if (!strcasecmp(p_type, "PLAYLIST"))
987
			return deletePlaylist(s1, id);
988
		else
989
			return FALSE;
990
	}
991
 
992
	/*
9 andreas 993
	 * Syntax: SEARCH:<type>:<expression>:<start>:<lines>;
8 andreas 994
	 *            <type>   TITLE | ARTIST | ALBUM | GENRE
995
	 *            <expression> This is what to search for
9 andreas 996
	 *            <start>  the data to start to
997
	 *            <lines>  number of lines to return
998
	 * 
18 andreas 999
	 * Return: SEARCH:<type>:<id>:<line>:<title>:<artist>:<album>:<genre>;
8 andreas 1000
	 */
1001
	if (!strcasecmp(bef, "SEARCH"))
1002
	{
9 andreas 1003
		int start, lines, x;
1004
		char *t, p_type[32], expr[128];
1005
 
1006
		memset(p_type, 0, sizeof(p_type));
1007
		memset(expr, 0, sizeof(expr));
1008
		start = lines = 0;
1009
		x = 0;
1010
		t = strtok (par, ":");
1011
 
1012
		while (t)
1013
		{
11 andreas 1014
			char *hv;
1015
 
9 andreas 1016
			switch(x)
1017
			{
11 andreas 1018
				case 0: strncpy(p_type, t, sizeof(p_type)-1); break;
9 andreas 1019
 
1020
				case 1:
11 andreas 1021
					strncpy(expr, t, sizeof(expr)-1);
1022
					hv = urldecode(expr);
1023
 
1024
					if (hv != NULL)
1025
					{
1026
						strncpy(expr, hv, sizeof(expr) - 1);
1027
						free(hv);
1028
					}
9 andreas 1029
				break;
1030
 
1031
				case 2: start = atoi(t); break;
1032
				case 3: lines = atoi(t); break;
1033
			}
1034
 
1035
			x++;
1036
			t = strtok (NULL, ":");
1037
		}
13 andreas 1038
 
9 andreas 1039
		if (x != 4 || !strlen(p_type) || !strlen(expr) || !lines || !start)
1040
		{
1041
			strcpy (cmd_error, "Missing one ore more parameters");
1042
			return FALSE;
1043
		}
1044
 
1045
		return searchTerm(s1, p_type, expr, start, lines);
8 andreas 1046
	}
1047
 
28 andreas 1048
	/*
1049
	 * This command reread the config file.
1050
	 */
1051
	if (!strcasecmp(bef, "RESET"))
1052
	{
1053
		if (playerActive)
1054
			nextCommand = PLAY_STOP;
1055
 
1056
		readConf();
1057
	}
1058
 
4 andreas 1059
	return TRUE;		/* cmd was OK */
2 andreas 1060
}
1061
 
1062
/*
8 andreas 1063
 * This function opens the database and deletes the whole archive of scanned
1064
 * MP3 files.
1065
 * This is called when the command "RESCAN" was detected. When this function
1066
 * is finished, the database is ready for new data.
1067
 */
1068
int cleanArchieve(int s1, char *fname)
1069
{
1070
	char query[1024];
1071
	sqlite3 *db;
1072
	char *zErrMsg = 0;
1073
	int rc;
1074
 
1075
	rc = sqlite3_open(fname, &db);
1076
 
1077
	if (rc)
1078
	{
1079
		syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
1080
		strcpy(query, "ERROR:MDB:Error opening database;");
1081
		write (s1, query, strlen(query));
1082
		return FALSE;
1083
	}
1084
 
29 andreas 1085
	strcpy (query, "delete from \"main\".\"playlists\"");
1086
 
1087
	if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
1088
	{
1089
		syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1090
		sqlite3_free(zErrMsg);
1091
		sqlite3_close(db);
1092
		strcpy(query, "ERROR:MDB:SQL error;");
1093
		write (s1, query, strlen(query));
1094
		return FALSE;
1095
	}
1096
 
8 andreas 1097
	strcpy (query, "delete from \"main\".\"musicdb\"");
1098
 
1099
	if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
1100
	{
1101
		syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1102
		sqlite3_free(zErrMsg);
1103
		sqlite3_close(db);
1104
		strcpy(query, "ERROR:MDB:SQL error;");
1105
		write (s1, query, strlen(query));
1106
		return FALSE;
1107
	}
1108
 
1109
	sqlite3_close(db);
1110
	return TRUE;
1111
}
1112
 
1113
/*
2 andreas 1114
 * Callback function of directory scan.
1115
 * This function desides whether a directory entry will be treated as a
1116
 * music file or not.
1117
 */
1118
int musicFilter(const struct dirent *dir)
1119
{
4 andreas 1120
	if (dir == NULL)
1121
		return 0;
2 andreas 1122
 
4 andreas 1123
	if (dir->d_type == DT_REG)
1124
	{
32 andreas 1125
		char *p = getFileExtension(dir->d_name);
1126
 
1127
		if (p != NULL && (strcasecmp(p, "mp3") == 0 || strcasecmp(p, "flac") == 0))
1128
			return 1;
4 andreas 1129
	}
1130
	else if (dir->d_type == DT_DIR)
1131
	{
1132
		if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
1133
			return 1;
1134
	}
1135
 
2 andreas 1136
	return 0;
1137
}
1138
 
1139
/*
1140
 * This function scans a directory for music files. If it finds some file name
1141
 * who is a possible music file, it gives it to a function to evaluate and
1142
 * store it.
1143
 */
12 andreas 1144
int grabMusicFiles(int s1, char *dir)
2 andreas 1145
{
1146
	struct dirent **namelist;
1147
	int n;
1148
 
1149
	if (dir == NULL || strlen(dir) == 0)
1150
		return FALSE;
1151
 
1152
	n = scandir(dir, &namelist, musicFilter, alphasort);
1153
 
1154
	if (n < 0)
1155
	{
4 andreas 1156
		syslog(LOG_DAEMON, "Error scanning directory %s: %s", dir, strerror(errno));
2 andreas 1157
		return FALSE;
1158
	}
1159
	else
1160
	{ 
1161
		while(n--)
1162
		{
42 andreas 1163
			char hv0[1024];
1164
			int len;
1165
 
5 andreas 1166
			strcpy(hv0, dir);
1167
			strcat(hv0, "/");
42 andreas 1168
			len = sizeof(hv0) - strlen(hv0) - 1;
5 andreas 1169
 
42 andreas 1170
			if (len > 0)
1171
				strncat(hv0, namelist[n]->d_name, len);
1172
			else
1173
			{
1174
				free(namelist[n]);
1175
				continue;
1176
			}
1177
 
4 andreas 1178
			if (namelist[n]->d_type == DT_DIR)
12 andreas 1179
				grabMusicFiles(s1, hv0);
1180
			else
4 andreas 1181
			{
1182
				evaluateMusicFile(hv0);
1183
 
12 andreas 1184
				if (!(grabFilesCount % 100))
1185
				{
1186
					sprintf(hv0, "SCANNING:%d;", grabFilesCount);
1187
					write (s1, hv0, strlen(hv0));
1188
				}
1189
			}
1190
 
2 andreas 1191
			free(namelist[n]); 
1192
		} 
1193
 
1194
		free(namelist); 
14 andreas 1195
	}
1196
 
1197
	return TRUE;
2 andreas 1198
}
1199
 
1200
void evaluateMusicFile(char *file)
1201
{
42 andreas 1202
sqlite3 *db;
1203
sqlite3_stmt *res;
1204
char *zErrMsg = 0;
43 andreas 1205
int rc, fType, update, id;
42 andreas 1206
char fname[256], hv0[64];
1207
char query[8192];
45 andreas 1208
struct id3_tag *id3;
1209
struct id3_file *ifile;
1210
struct id3_frame *frame;
1211
union id3_field *field;
1212
id3_byte_t const *bt;
42 andreas 1213
char id3_title[256];
1214
char id3_singer[256];
1215
char id3_album[256];
1216
char id3_genre[256];
1217
char id3_cover[256];
1218
char *title, *singer, *album, *ext;
45 andreas 1219
enum id3_field_type enc;
3 andreas 1220
 
2 andreas 1221
	if (access(file, R_OK))
1222
		return;
1223
 
45 andreas 1224
	bt = NULL;
1225
 
2 andreas 1226
	strcpy(fname, configs.home);
9 andreas 1227
	strcat(fname, MUSICDB);
4 andreas 1228
 
5 andreas 1229
	if (!access(fname, R_OK | W_OK))
2 andreas 1230
		file_found = TRUE;
4 andreas 1231
	else						/* create the directory, if it doesn't exitst */
1232
	{
1233
		if (access(configs.home, R_OK | W_OK))
1234
		{
1235
			if (mkdir(configs.home, 0775) != 0)
1236
			{
1237
				syslog(LOG_WARNING, "Error creating directory %s: %s", configs.home, strerror(errno));
1238
				return;
1239
			}
1240
			else
1241
				syslog(LOG_INFO, "Directory %s was created.", configs.home);
1242
		}
5 andreas 1243
 
1244
		sprintf(query, "%s/Covers", configs.home);
1245
 
1246
		if (access(query, R_OK | W_OK))
1247
		{
1248
			if (mkdir(query, 0775) != 0)
1249
				syslog(LOG_WARNING, "Error creating directory %s: %s", query, strerror(errno));
1250
			else
1251
				syslog(LOG_INFO, "Directory %s was created.", query);
1252
		}
4 andreas 1253
	}
2 andreas 1254
 
1255
	rc = sqlite3_open(fname, &db);
1256
 
1257
	if (rc)
1258
	{
1259
		syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
1260
		return;
1261
	}
1262
 
1263
	if (!file_found)
1264
	{
32 andreas 1265
		/* id        autoincrement unique index
1266
		 * path      path to file containing an MP3 or FLAC file
1267
		 * type      1 = MP3, 2 = FLAC
1268
		 * title     title of song
1269
		 * interpret singer
1270
		 * album     the album the is from
1271
		 * genre     genre of the song
1272
		 * cover     name of file containing the cover
1273
		 */
2 andreas 1274
		strcpy(query, "create table \"main\".\"musicdb\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
32 andreas 1275
		strcat(query, "\"path\" TEXT NOT NULL, \"type\" INTEGER, \"title\" TEXT, \"interpret\" TEXT,");
5 andreas 1276
		strcat(query, "\"album\" TEXT, \"genre\" TEXT, \"cover\" TEXT)");
8 andreas 1277
		rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg);
2 andreas 1278
 
1279
		if (rc != SQLITE_OK)
1280
		{
5 andreas 1281
			syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
2 andreas 1282
			sqlite3_free(zErrMsg);
1283
			sqlite3_close(db);
1284
			return;
1285
		}
4 andreas 1286
		else
7 andreas 1287
			syslog(LOG_INFO, "Database \"musicdb\" was successfully created.");
1288
 
1289
		strcpy(query, "CREATE TABLE \"main\".\"users\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT,");
1290
		strcat(query, "\"uname\" TEXT NOT NULL, \"playlist\" TEXT)");
8 andreas 1291
		rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg);
7 andreas 1292
 
1293
		if (rc != SQLITE_OK)
1294
		{
1295
			syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1296
			sqlite3_free(zErrMsg);
1297
			sqlite3_close(db);
1298
			return;
1299
		}
1300
		else
1301
			syslog(LOG_INFO, "Database \"users\" was successfully created.");
8 andreas 1302
 
1303
		strcpy (query, "CREATE TABLE \"main\".\"playlists\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
1304
		strcat (query, "\"userid\" INTEGER NOT NULL, \"musicid\" INTEGER NOT NULL)");
1305
 
1306
		rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg);
1307
 
1308
		if (rc != SQLITE_OK)
1309
		{
1310
			syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1311
			sqlite3_free(zErrMsg);
1312
			sqlite3_close(db);
1313
			return;
1314
		}
1315
		else
1316
			syslog(LOG_INFO, "Database \"users\" was successfully created.");
2 andreas 1317
	}
1318
 
4 andreas 1319
	/* Make sure, the file is not already in the database */
45 andreas 1320
	sprintf(query, "select id, path, cover from musicdb where path = \"%s\"", file);
2 andreas 1321
 
8 andreas 1322
	if (sqlite3_prepare(db, query, -1, &res, NULL) != SQLITE_OK)
2 andreas 1323
	{
8 andreas 1324
		syslog(LOG_DAEMON, "Error preparing SQL statement [%s]: %s", query, sqlite3_errmsg(db));
2 andreas 1325
		sqlite3_close(db);
1326
		return;
1327
	}
42 andreas 1328
 
8 andreas 1329
	rc = sqlite3_step(res);
45 andreas 1330
	id3_cover[0] = 0;
42 andreas 1331
 
8 andreas 1332
	if (rc == SQLITE_ROW)			/* If we've a row, the path exists and we'll not add it again */
43 andreas 1333
	{								/* Instead we'll update the information */
1334
		update = 1;
1335
		id = sqlite3_column_int(res, 0);
45 andreas 1336
 
1337
		if ((ext = (char *)sqlite3_column_text(res, 2)) == NULL)
1338
		{
1339
			syslog(LOG_WARNING, "Error getting path of picture from database!");
1340
			id3_cover[0] = 0;
1341
		}
1342
		else
1343
			strncpy(&id3_cover[0], ext, sizeof(id3_cover));
2 andreas 1344
	}
43 andreas 1345
	else
1346
		update = 0;
2 andreas 1347
 
43 andreas 1348
	sqlite3_finalize(res);
32 andreas 1349
	/* Check the file extension and decide whether it's an MP3 or FLAC file. */
1350
	ext = getFileExtension(file);
1351
 
1352
	if (ext != NULL)
1353
	{
1354
		if (strcasecmp(ext, "flac") == 0)
1355
			fType = FILE_TYPE_FLAC;
1356
		else
1357
			fType = FILE_TYPE_MP3;
1358
	}
1359
	else
1360
		fType = FILE_TYPE_MP3;
1361
 
4 andreas 1362
	/* Open the file and get the ID3 tag. */
45 andreas 1363
	if ((ifile = id3_file_open(file, ID3_FILE_MODE_READONLY)) == NULL)
1364
	{
1365
		syslog(LOG_WARNING, "Error opening file %s!", file);
1366
		sqlite3_close(db);
1367
		return;
1368
	}
1369
 
1370
	if ((id3 = id3_file_tag(ifile)) == NULL)
1371
	{
1372
		syslog(LOG_WARNING, "Error initializing MP3 file %s", file);
1373
		sqlite3_close(db);
1374
		return;
1375
	}
1376
 
2 andreas 1377
	memset(&id3_title, 0, sizeof(id3_title));
1378
	memset(&id3_singer, 0, sizeof(id3_singer));
1379
	memset(&id3_album, 0, sizeof(id3_album));
1380
	memset(&id3_genre, 0, sizeof(id3_genre));
45 andreas 1381
 
1382
	if (!strlen(id3_cover))
1383
		memset(&id3_cover, 0, sizeof(id3_cover));
1384
 
4 andreas 1385
	/* Get the required frames */
45 andreas 1386
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_TITLE, 0)) != NULL)
2 andreas 1387
	{
45 andreas 1388
		int i;
1389
 
1390
		for (i = 0; i < (int)frame->nfields; i++)
1391
		{
1392
			field = id3_frame_field(frame, i);
1393
 
1394
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1395
				enc = id3_field_gettextencoding(field);
1396
 
1397
			if (field && checkID3FieldType(field->type))
1398
				break;
1399
		}
1400
 
1401
		getID3_Field(field, enc, &id3_title[0], sizeof(id3_title));
5 andreas 1402
		char_replace(id3_title, '"', '`');
1403
		char_replace(id3_title, '\\', ' ');
2 andreas 1404
	}
1405
 
45 andreas 1406
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_ARTIST, 0)) != NULL)
2 andreas 1407
	{
45 andreas 1408
		int i;
1409
 
1410
		for (i = 0; i < (int)frame->nfields; i++)
1411
		{
1412
			field = id3_frame_field(frame, i);
1413
 
1414
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1415
				enc = id3_field_gettextencoding(field);
1416
 
1417
			if (field && checkID3FieldType(field->type))
1418
				break;
1419
		}
1420
 
1421
		getID3_Field(field, enc, &id3_singer[0], sizeof(id3_singer));
5 andreas 1422
		char_replace(id3_singer, '"', '`');
1423
		char_replace(id3_singer, '\\', ' ');
2 andreas 1424
	}
1425
 
45 andreas 1426
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_ALBUM, 0)) != NULL)
2 andreas 1427
	{
45 andreas 1428
		int i;
1429
 
1430
		for (i = 0; i < (int)frame->nfields; i++)
1431
		{
1432
			field = id3_frame_field(frame, i);
1433
 
1434
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1435
				enc = id3_field_gettextencoding(field);
1436
 
1437
			if (field && checkID3FieldType(field->type))
1438
				break;
1439
		}
1440
 
1441
		getID3_Field(field, enc, &id3_album[0], sizeof(id3_album));
5 andreas 1442
		char_replace(id3_album, '"', '`');
1443
		char_replace(id3_album, '\\', ' ');
2 andreas 1444
	}
1445
 
45 andreas 1446
	if ((frame = id3_tag_findframe(id3, "APIC", 0)) != NULL)
12 andreas 1447
	{
1448
		char fpname[512], uid[128], hv0[256];
45 andreas 1449
		struct id3_frame *fpframe;
1450
		int i, fd, np;
1451
		long unsigned len;
12 andreas 1452
 
40 andreas 1453
		memset(uid, 0, sizeof(uid));
12 andreas 1454
		strcpy(fpname, configs.home);
1455
		strcat(fpname, "/Covers");
1456
 
1457
		if (access(fpname, R_OK | W_OK | X_OK))
1458
			mkdir(fpname, 0775);
1459
 
45 andreas 1460
		if (!strlen(id3_cover))
12 andreas 1461
		{
14 andreas 1462
			char *md5;
12 andreas 1463
 
22 andreas 1464
			if ((md5 = str2hash(file, (int)strlen(file))) != NULL)
14 andreas 1465
			{
1466
				sprintf(uid, "Picture-%s", md5);
1467
				free(md5);
1468
			}
1469
			else
1470
				sprintf(uid, "Picture-%ld", random());
1471
		}
1472
 
12 andreas 1473
		strcat(fpname, "/");
45 andreas 1474
		len = 0;
1475
		np = 0;			/* 1 = a new picture was found */
1476
		bt = NULL;
12 andreas 1477
		/* Get the picture and store it into a file */
45 andreas 1478
		for (i = 0; i < (int)frame->nfields; i++)
1479
		{
1480
			if ((field = id3_frame_field(frame, i)) != NULL)
1481
			{
1482
				id3_latin1_t const *lt1;
40 andreas 1483
 
45 andreas 1484
				switch (field->type)
1485
				{
1486
					case ID3_FIELD_TYPE_LATIN1:			// MIME type
1487
						if ((lt1 = id3_field_getlatin1(field)) != NULL)
1488
							strncpy (&hv0[0], (char *)lt1, sizeof(hv0)-1);
1489
					break;
1490
 
1491
					case ID3_FIELD_TYPE_LATIN1FULL:
1492
						if ((lt1 = id3_field_getfulllatin1(field)) != NULL)
1493
							strncpy (&hv0[0], (char *)lt1, sizeof(hv0)-1);
1494
					break;
1495
 
1496
					case ID3_FIELD_TYPE_BINARYDATA:		// The picture
1497
						bt = id3_field_getbinarydata(field, &len);
1498
						np = 1;
1499
					break;
1500
				}
1501
			}
1502
		}
1503
 
1504
		if (!strlen(id3_cover) && np)
12 andreas 1505
		{
45 andreas 1506
			if (strstr(hv0, "jpeg") != NULL)
1507
				strcat(uid, ".jpg");
1508
			else if (strstr(hv0, "png") != NULL)
1509
				strcat(uid, ".png");
1510
			else if (strstr(hv0, "gif") != NULL)
1511
				strcat(uid, ".gif");
1512
			else if (strstr(hv0, "tiff") != NULL)
1513
				strcat(uid, ".tiff");
1514
			else
1515
			{
1516
				char *pos;
12 andreas 1517
 
45 andreas 1518
				if ((pos = strrchr(hv0, '/')) != NULL)
1519
				{
1520
					strcat(uid, ".");
1521
					strcat(uid, pos+1);
1522
				}
1523
			}
1524
 
1525
			strcat(fpname, uid);
1526
			strcpy (id3_cover, uid);
1527
		}
1528
		else if (strlen(id3_cover) && !np)
1529
		{
1530
			strcat (fpname, id3_cover);
1531
			unlink(fpname);
1532
		}
1533
		else if (strlen(id3_cover))
1534
			strcat (fpname, id3_cover);
1535
 
1536
		if (np)
1537
		{
1538
			if ((fd = open(fpname, O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
1539
				syslog(LOG_WARNING, "Error opening file %s for saving a picture: %s", fpname, strerror(errno));
1540
			else
12 andreas 1541
			{
45 andreas 1542
				write(fd, bt, len);
1543
				close(fd);
12 andreas 1544
			}
1545
		}
1546
	}
1547
 
45 andreas 1548
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_GENRE, 0)) != NULL)
2 andreas 1549
	{
45 andreas 1550
		int i;
1551
 
1552
		for (i = 0; i < (int)frame->nfields; i++)
1553
		{
1554
			field = id3_frame_field(frame, i);
5 andreas 1555
 
45 andreas 1556
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1557
				enc = id3_field_gettextencoding(field);
1558
 
1559
			if (field && checkID3FieldType(field->type))
1560
				break;
1561
		}
1562
 
1563
		if (field != NULL)
1564
			getID3_Field(field, enc, &id3_genre[0], sizeof(id3_genre));
1565
		else
1566
			id3_genre[0] = 0;
1567
 
5 andreas 1568
		if (strchr(id3_genre, '(') && strchr(id3_genre, ')') && isdigit(id3_genre[1]))
1569
		{
45 andreas 1570
			int gen;
5 andreas 1571
 
45 andreas 1572
			gen = atoi(&id3_genre[1]);
5 andreas 1573
 
46 andreas 1574
			if (gen >= 0 && gen < ID3_NR_OF_V1_GENRES)
5 andreas 1575
				strncpy (id3_genre, ID3_v1_genre_description[gen], sizeof(id3_genre));
1576
			else
1577
				strcpy (id3_genre, "Pop");
1578
		}
1579
 
1580
		char_replace(id3_genre, '"', '`');
1581
		char_replace(id3_genre, '\\', ' ');
2 andreas 1582
	}
5 andreas 1583
 
45 andreas 1584
	id3_tag_delete(id3);
1585
	id3_file_close(ifile);
5 andreas 1586
 
12 andreas 1587
	if (!strlen(id3_title) && !strlen(id3_singer))		/* grab title and artist from file name */
1588
	{
1589
		char hv0[256], *p;
43 andreas 1590
		int x, flag;
12 andreas 1591
 
1592
		memset(hv0, 0, sizeof(hv0));
46 andreas 1593
		p = strrchr(file, '/');							/* find the last directory separator */
12 andreas 1594
 
46 andreas 1595
		if (p)											/* If there is a seperator ... */
1596
			strncpy(hv0, p+1, sizeof(hv0)-1);			/* Copy the part after it (this is the file name) */
1597
		else											/* There seems to be no path ... */
1598
			strncpy(hv0, file, sizeof(hv0)-1);			/* Copy the whole file name (this IS the file name) */
12 andreas 1599
 
46 andreas 1600
		if ((p = strchr(hv0, '-')) != NULL)				/* Do we have a dash as seperator? */
1601
		{												/* Yes, so look how many components the file name have */
1602
			char *p2;
1603
 
12 andreas 1604
			*p = 0;
1605
			p++;
1606
 
46 andreas 1607
			if ((p2 = strchr(p, '-')) != NULL)
1608
			{
1609
				*p2 = 0;
1610
				p2++;
1611
				strncpy(id3_album, hv0, sizeof(id3_album) - 1);
1612
				strncpy(id3_singer, p, sizeof(id3_singer) - 1);
1613
				strncpy(id3_title, p2, sizeof(id3_title) - 1);
1614
				trim(id3_album);
1615
			}
1616
			else
1617
			{
1618
				strncpy(id3_singer, hv0, sizeof(id3_singer) - 1);
1619
				strncpy(id3_title, p, sizeof(id3_title) - 1);
1620
			}
1621
 
12 andreas 1622
			if ((p = strrchr(id3_title, '.')) != NULL)
1623
				*p = 0;
1624
 
1625
			trim(id3_singer);
1626
			trim(id3_title);
43 andreas 1627
			/* Make upper / lower case */
46 andreas 1628
			flag = 1;
43 andreas 1629
 
1630
			for (x = 0; x < (int)strlen(id3_singer); x++)
1631
			{
1632
				if (id3_singer[x] == ' ')
1633
					flag = 1;
1634
 
1635
				if (flag && id3_singer[x] != ' ')
1636
				{
1637
					id3_singer[x] = (char)toupper((int)id3_singer[x]);
1638
					flag = 0;
1639
				}
1640
				else
1641
					id3_singer[x] = (char)tolower((int)id3_singer[x]);
1642
			}
1643
 
46 andreas 1644
			flag = 1;
43 andreas 1645
 
1646
			for (x = 0; x < (int)strlen(id3_title); x++)
1647
			{
1648
				if (id3_title[x] == ' ')
1649
					flag = 1;
1650
 
1651
				if (flag && id3_title[x] != ' ')
1652
				{
1653
					id3_title[x] = (char)toupper((int)id3_title[x]);
1654
					flag = 0;
1655
				}
1656
				else
1657
					id3_title[x] = (char)tolower((int)id3_title[x]);
1658
			}
46 andreas 1659
 
1660
			if (p2)
1661
			{
1662
				flag = 1;
1663
 
1664
				for (x = 0; x < (int)strlen(id3_album); x++)
1665
				{
1666
					if (id3_album[x] == ' ')
1667
						flag = 1;
1668
 
1669
					if (flag && id3_album[x] != ' ')
1670
					{
1671
						id3_album[x] = (char)toupper((int)id3_album[x]);
1672
						flag = 0;
1673
					}
1674
					else
1675
						id3_album[x] = (char)tolower((int)id3_album[x]);
1676
				}
1677
			}
12 andreas 1678
		}
1679
		else
1680
		{
1681
			strncpy(id3_title, hv0, sizeof(hv0) - 1);
1682
 
1683
			if ((p = strrchr(id3_title, '.')) != NULL)
1684
				*p = 0;
1685
 
1686
			trim(id3_title);
43 andreas 1687
			flag = 0;
1688
 
1689
			for (x = 0; x < (int)strlen(id3_title); x++)
1690
			{
1691
				if (id3_title[x] == ' ')
1692
					flag = 1;
1693
 
1694
				if (flag && id3_title[x] != ' ')
1695
				{
1696
					id3_title[x] = (char)toupper((int)id3_title[x]);
1697
					flag = 0;
1698
				}
1699
				else
1700
					id3_title[x] = (char)tolower((int)id3_title[x]);
1701
			}
12 andreas 1702
		}
1703
	}
1704
 
43 andreas 1705
	if (!update)
5 andreas 1706
	{
43 andreas 1707
		strcpy (query, "insert into musicdb (\"path\", \"type\", \"title\", \"interpret\", \"album\", \"genre\", \"cover\") values ");
1708
		strcat (query, "(\"");
1709
		strcat (query, file);
1710
		strcat (query, "\", ");
1711
		sprintf(hv0, "%d", fType);
1712
		strcat (query, hv0);
1713
		strcat (query, ", \"");
5 andreas 1714
		strcat (query, id3_title);
43 andreas 1715
		strcat (query, "\", \"");
1716
		strcat (query, id3_singer);
1717
		strcat (query, "\", \"");
1718
		strcat (query, id3_album);
1719
		strcat (query, "\", \"");
1720
		strcat (query, id3_genre);
1721
		strcat (query, "\", \"");
1722
		strcat (query, id3_cover);
1723
		strcat (query, "\")");
5 andreas 1724
	}
1725
	else
1726
	{
43 andreas 1727
		strcpy(query, "update musicdb set \"title\" = \"");
1728
		strcat(query, id3_title);
1729
		strcat(query, "\", \"interpret\" = \"");
1730
		strcat(query, id3_singer);
1731
		strcat(query, "\", \"album\" = \"");
1732
		strcat(query, id3_album);
1733
		strcat(query, "\", \"genre\" = \"");
1734
		strcat(query, id3_genre);
1735
		strcat(query, "\", \"cover\" = \"");
1736
		strcat(query, id3_cover);
1737
		strcat(query, "\" where id = ");
1738
		sprintf(hv0, "%d", id);
1739
		strcat(query, hv0);
5 andreas 1740
	}
1741
 
8 andreas 1742
	if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
2 andreas 1743
	{
5 andreas 1744
		syslog(LOG_DAEMON, "SQL Error  [%s]: %s", query, zErrMsg);
2 andreas 1745
		sqlite3_free(zErrMsg);
1746
		sqlite3_close(db);
1747
		return;
1748
	}
1749
 
1750
	sqlite3_close(db);
12 andreas 1751
	grabFilesCount++;
2 andreas 1752
}
43 andreas 1753
 
45 andreas 1754
int checkID3FieldType(enum id3_field_type ft)
43 andreas 1755
{
45 andreas 1756
	switch (ft)
1757
	{
1758
		case ID3_FIELD_TYPE_LATIN1:
1759
		case ID3_FIELD_TYPE_LATIN1FULL:
1760
		case ID3_FIELD_TYPE_LATIN1LIST:
1761
		case ID3_FIELD_TYPE_STRING:
1762
		case ID3_FIELD_TYPE_STRINGFULL:
1763
		case ID3_FIELD_TYPE_STRINGLIST:
1764
			return 1;
1765
 
1766
		case ID3_FIELD_TYPE_INT8:
1767
		case ID3_FIELD_TYPE_INT16:
1768
		case ID3_FIELD_TYPE_INT24:
1769
		case ID3_FIELD_TYPE_INT32:
1770
		case ID3_FIELD_TYPE_INT32PLUS:
1771
			return 1;
1772
	}
1773
 
1774
	return 0;
1775
}
1776
 
1777
char *getID3_Field(union id3_field *field, enum id3_field_textencoding te, char *ret, int len)
1778
{
44 andreas 1779
char *p, *pg;
45 andreas 1780
char wc[256];
1781
id3_utf8_t *uc;
1782
id3_ucs4_t const *ucs;
1783
id3_latin1_t const *lt1;
43 andreas 1784
iconv_t ic;
1785
int i;
45 andreas 1786
size_t length;
1787
long num;
43 andreas 1788
 
45 andreas 1789
	if (field == NULL)
1790
	{
1791
		if (configs.debug)
1792
			syslog(LOG_DEBUG, "Missing valid field pointer!");
1793
 
1794
		*ret = 0;
1795
		return NULL;
1796
	}
1797
 
43 andreas 1798
	*ret = 0;
1799
 
1800
	switch (te)
1801
	{
45 andreas 1802
		case ID3_FIELD_TEXTENCODING_ISO_8859_1:
1803
			if (field->type == ID3_FIELD_TYPE_LATIN1)
43 andreas 1804
			{
45 andreas 1805
				if ((lt1 = id3_field_getlatin1(field)) == NULL)
1806
				{
1807
					syslog(LOG_WARNING, "Couldn't get latin1 field!");
1808
					return NULL;
1809
				}
1810
			}
1811
			else if (field->type == ID3_FIELD_TYPE_LATIN1FULL)
1812
			{
1813
				if ((lt1 = id3_field_getfulllatin1(field)) == NULL)
1814
				{
1815
					syslog(LOG_WARNING, "Couldn't get full latin1 field!");
1816
					return NULL;
1817
				}
1818
			}
1819
			else if (field->type == ID3_FIELD_TYPE_LATIN1LIST)
1820
			{
1821
				int n;
43 andreas 1822
 
45 andreas 1823
				n = id3_field_getnstrings(field);
1824
 
1825
				for (i = 0; i < n; i++)
1826
				{
1827
					if ((ucs = id3_field_getstrings(field, i)) != NULL)
1828
						break;
1829
				}
1830
 
1831
				if (ucs == NULL)
1832
				{
1833
					syslog(LOG_WARNING, "Couldn't get Latin1 field out of a list of %d", n);
1834
					return NULL;
1835
				}
1836
 
1837
				uc = id3_ucs4_utf8duplicate(ucs);
1838
 
1839
				if (uc)
1840
				{
1841
					strncpy(ret, (char *)uc, len);
1842
					free (uc);
1843
					return ret;
1844
				}
1845
 
1846
				return NULL;
43 andreas 1847
			}
45 andreas 1848
			else
1849
			{
1850
				syslog(LOG_WARNING, "No parseable field type found!");
1851
				return NULL;
1852
			}
43 andreas 1853
 
1854
			if ((ic = iconv_open("UTF-8", "ISO-8859-1")) == (iconv_t)-1)
1855
			{
1856
				syslog(LOG_WARNING, "Error initializing ICONV to convert ASCII into UTF-8: %s", strerror(errno));
1857
				return ret;
1858
			}
1859
 
1860
			length = sizeof(wc);
1861
			p = wc;
45 andreas 1862
			pg = (char *)lt1;
1863
			i = strlen((char *)lt1);
43 andreas 1864
 
44 andreas 1865
			iconv(ic, &pg, (size_t *)&i, &p, &length);
43 andreas 1866
			iconv_close(ic);
1867
			strncpy (ret, wc, len);
1868
		break;
1869
 
45 andreas 1870
		case ID3_FIELD_TEXTENCODING_UTF_16:
1871
		case ID3_FIELD_TEXTENCODING_UTF_16BE:
1872
		case ID3_FIELD_TEXTENCODING_UTF_8:
1873
			if (field->type == ID3_FIELD_TYPE_STRINGFULL)
43 andreas 1874
			{
45 andreas 1875
				if ((ucs = id3_field_getfullstring(field)) == NULL)
1876
				{
1877
					syslog(LOG_WARNING, "Couldn't get full UTF-? field!");
1878
					return NULL;
1879
				}
43 andreas 1880
			}
45 andreas 1881
			else if (field->type == ID3_FIELD_TYPE_STRING)
43 andreas 1882
			{
45 andreas 1883
				if ((ucs = id3_field_getstring(field)) == NULL)
1884
				{
1885
					syslog(LOG_WARNING, "Couldn't get UTF-? field!");
1886
					return NULL;
1887
				}
43 andreas 1888
			}
45 andreas 1889
			else if (field->type == ID3_FIELD_TYPE_STRINGLIST)
43 andreas 1890
			{
45 andreas 1891
				int n;
43 andreas 1892
 
45 andreas 1893
				n = id3_field_getnstrings(field);
43 andreas 1894
 
45 andreas 1895
				for (i = 0; i < n; i++)
1896
				{
1897
					if ((ucs = id3_field_getstrings(field, i)) != NULL)
1898
						break;
1899
				}
43 andreas 1900
 
45 andreas 1901
				if (ucs == NULL)
1902
				{
1903
					syslog(LOG_WARNING, "Couldn't get UTF-? field out of a list of %d", n);
1904
					return NULL;
1905
				}
1906
			}
1907
			else
43 andreas 1908
			{
45 andreas 1909
				syslog(LOG_WARNING, "No parseable field type found!");
44 andreas 1910
				return NULL;
43 andreas 1911
			}
1912
 
45 andreas 1913
			uc = id3_ucs4_utf8duplicate(ucs);
43 andreas 1914
 
45 andreas 1915
			if (uc)
1916
			{
1917
				strncpy(ret, (char *)uc, len);
1918
				free (uc);
1919
			}
43 andreas 1920
		break;
1921
 
45 andreas 1922
		case ID3_FIELD_TYPE_INT8:
1923
		case ID3_FIELD_TYPE_INT16:
1924
		case ID3_FIELD_TYPE_INT24:
1925
		case ID3_FIELD_TYPE_INT32:
1926
		case ID3_FIELD_TYPE_INT32PLUS:
1927
			num = id3_field_getint(field);
1928
			sprintf(ret, "(%ld)", num);
44 andreas 1929
		break;
1930
 
43 andreas 1931
		default:
45 andreas 1932
			if (configs.debug)
1933
				syslog(LOG_DEBUG, "Unkown field encoding: %d", te);
1934
 
1935
			return NULL;
43 andreas 1936
	}
1937
 
1938
	return ret;
1939
}