Subversion Repositories mdb

Rev

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