Subversion Repositories mdb

Rev

Rev 58 | 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
{
59 andreas 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 */
45 andreas 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
 
50 andreas 722
				/* start a new thread to play the file(s) */
59 andreas 723
				if ((e = pthread_create(&pthr_play, &pattr, pthr_playfile, (void *)&_playPars)) != 0)
49 andreas 724
				{
57 andreas 725
					switch (e)
726
					{
727
						case EAGAIN: strcpy (hv0, "Insufficient resources to create another thread."); break;
728
						case EINVAL: strcpy (hv0, "Invalid settings in \"attr\"."); break;
729
						case EPERM:  strcpy (hv0, "No permission to set the scheduling policy and parameters specified in \"attr\"."); break;
730
						default:     sprintf (hv0, "Unknown error %d.", e);
731
					}
732
 
733
					syslog (LOG_DAEMON,"Creation of thread \"pthr_play\" failed: %s", hv0);
50 andreas 734
					strcpy(cmd_error, "Error playing a file!");
49 andreas 735
					return FALSE;
736
				}
737
			}
6 andreas 738
		}
739
	}
740
 
7 andreas 741
	if (!strcasecmp(bef, "STOP") && playerActive)				/* Stop the currently playing file */
742
		nextCommand = PLAY_STOP;
743
 
744
	if (!strcasecmp(bef, "PAUSE") && playerActive)				/* Pause the currently playing file */
745
		nextCommand = PLAY_PAUSE;
746
 
40 andreas 747
	if (!strcasecmp(bef, "PLAYPAUSE"))							/* Play/Pause the currently playing file, */
748
	{															/* or play one in the queue if there are any. */
749
		if (playerActive && (playStatus == PLAY_STATUS_PAUSE || playStatus == PLAY_STATUS_PLAY))
750
			nextCommand = PLAY_PLAYPAUSE;
751
		else if (playerActive && playStatus == PLAY_STATUS_STOP)
752
			nextCommand = PLAY_PLAY;
753
		else if (!playerActive)
754
		{
755
			_playPars.s1 = s1;
756
			strcpy(_playPars.type, "QUEUE");					/* Select the queue to play. */
757
			strcpy(_playPars.what, "0");						/* Play the first or a random file, if random is selected, in the queue. */
758
			/* start a new thread to play the file(s) */
59 andreas 759
			if (pthread_create(&pthr_play, &pattr, pthr_playfile, (void *)&_playPars) != 0)
40 andreas 760
			{
761
				syslog (LOG_DAEMON,"Create of thread \"pthr_play\" failed!");
762
				strcpy(cmd_error, "Error playing a file!");
763
				return FALSE;
764
			}
765
		}
766
	}
7 andreas 767
 
768
	if (!strcasecmp(bef, "FORWARD") && playerActive)			/* Fast forward */
769
		nextCommand = PLAY_FWD;
770
 
771
	if (!strcasecmp(bef, "REWIND") && playerActive)				/* Fast rewind */
772
		nextCommand = PLAY_REW;
773
 
774
	if (!strcasecmp(bef, "SKIPFWD") && playerActive)			/* Skip to next file in queue */
775
		nextCommand = PLAY_SKIP_FWD;
776
 
777
	if (!strcasecmp(bef, "SKIPREW") && playerActive)			/* Skip to previous file in queue */
778
		nextCommand = PLAY_SKIP_REW;
779
 
11 andreas 780
	if (!strcasecmp(bef, "RANDOM"))								/* Toggle random play */
781
	{
782
		playerRandom = !playerRandom;
783
		sprintf(cmd_message, "RANDOM:%s;", playerRandom ? "TRUE" : "FALSE");
784
	}
785
 
786
	if (!strcasecmp(bef, "REPEAT"))								/* Toggle repeat */
787
	{
788
		playerRepeat = !playerRepeat;
789
		sprintf(cmd_message, "REPEAT:%s;", playerRepeat ? "TRUE" : "FALSE");
790
	}
791
 
7 andreas 792
	/*
14 andreas 793
	 * This command loads a user. If the user doesn't exist it creates
794
	 * the user. In this case the name of a playlist is needed.
795
	 * If the user already exist, the name of a playlist is optional.
796
	 * 
797
	 * If this command is called without the name of a playlist and the
798
	 * user doesn't exist, an error occurs.
799
	 *
800
	 * This command should only be called when a new playlist is to be
801
	 * saved. After this command the command "SAVEQUEUE" should be called.
802
	 *
8 andreas 803
	 * Syntax: USER:<name>:[<playlist>];
804
	 *         <name>     the name of the user.
805
	 *         <playlist> the name of the playlist; This is optional.
7 andreas 806
	 */
807
	if (!strcasecmp(bef, "USER"))								/* In case the user doesn't exist, create a new one. Activate this user */
808
	{
8 andreas 809
		char user[64], playlist[64], *t;
810
		int x;
7 andreas 811
 
8 andreas 812
		memset(user, 0, sizeof(user));
813
		memset(playlist, 0, sizeof(playlist));
814
		x = 0;
815
		t = strtok (par, ":");
7 andreas 816
 
8 andreas 817
		while (t)
818
		{
819
			char *hv;
820
 
821
			switch(x)
822
			{
823
				case 0:
824
					strncpy (user, t, sizeof(user));
825
					user[63] = 0;
826
					hv = urldecode(user);
827
 
828
					if (hv != NULL)
829
					{
830
						strcpy(user, hv);
831
						free(hv);
832
					}
833
				break;
834
 
835
				case 1:
836
					strncpy (playlist, t, sizeof(playlist));
837
					playlist[63] = 0;
838
					hv = urldecode(playlist);
839
 
840
					if (hv != NULL)
841
					{
842
						strcpy(playlist, hv);
843
						free(hv);
844
					}
845
				break;
846
			}
847
 
848
			x++;
849
			t = strtok(NULL, ":");
850
		}
851
 
852
		if (strlen(user) && strlen(playlist))
853
		{
854
			if (!createUser(s1, user, playlist))
855
				return FALSE;
856
 
857
			return selectUser(s1, user);
858
		}
859
		else if (strlen(user))
860
			return selectUser(s1, user);
861
		else
862
		{
863
			strcpy (cmd_error, "Missing the username and the name of the playlist");
864
			return FALSE;
865
		}
7 andreas 866
	}
867
 
8 andreas 868
	/*
869
	 * Syntax: SAVEQUEUE:<user>:<playlist>;
870
	 *         <user>     The name of the user. If this is empty, the actual
871
	 *                    user is taken, if any. If there's no user selected,
872
	 *                    an error occurs.
873
	 *         <playlist> The name of the playlist. If the playlist already
874
	 *                    exist, it'll be overwritten.
875
	 * 
876
	 * Return: TRANSFERED:<num>;
877
	 *         <num>      The number of entries transfered.
878
	 */
14 andreas 879
	if (!strcasecmp(bef, "SAVEQUEUE"))			/* Saves the content of the queue into a playlist */
8 andreas 880
	{
881
		char user[64], playlist[64];
882
		char *t;
883
		int x;
884
 
25 andreas 885
		if (!queueTotal)
886
		{
887
			readQueue();
888
 
889
			if (!queueTotal)
890
			{
891
				strcpy(cmd_error, "Queue is empty");
892
				return FALSE;
893
			}
894
		}
895
 
8 andreas 896
		x = 0;
897
		t = strtok(par, ":");
898
 
899
		while (t)
900
		{
901
			char *hv;
902
 
903
			switch(x)
904
			{
905
				case 0:
906
					strncpy (user, t, sizeof(user));
907
					user[63] = 0;
908
					hv = urldecode(user);
909
 
910
					if (hv != NULL)
911
					{
912
						strcpy(user, hv);
913
						free(hv);
914
					}
915
				break;
916
 
917
				case 1:
918
					strncpy (playlist, t, sizeof(playlist));
919
					playlist[63] = 0;
920
					hv = urldecode(playlist);
921
 
922
					if (hv != NULL)
923
					{
924
						strcpy(playlist, hv);
925
						free(hv);
926
					}
927
				break;
928
			}
929
 
930
			x++;
931
			t = strtok(NULL, ":");
932
		}
933
 
934
		if (!strlen(user) && userchain != NULL)
935
			strcpy(user, userchain->uname);
25 andreas 936
		else if (!selectUser(s1, user) && strlen(user) && strlen(playlist))
937
		{
938
			if (!createUser(s1, user, playlist))
939
				return FALSE;
940
 
941
			return QueueToPlaylist(s1, user, playlist);
942
		}
8 andreas 943
		else if (!selectUser(s1, user))
944
		{
945
			strcpy (cmd_error, "No or invalid user");
946
			return FALSE;
947
		}
948
 
949
		if (!strlen(playlist))
950
		{
951
			strcpy (cmd_error, "No or invalid playlist");
952
			return FALSE;
953
		}
954
 
955
		if (!QueueToPlaylist(s1, user, playlist))
956
			return FALSE;
957
	}
958
 
959
	/*
960
	 * Syntax: DELETE:<type>:<id>;
13 andreas 961
	 *      <type>     PTITLE | QUEUE | PLAYLIST
962
	 *                 PTITLE: Delete one title from a playlist
963
	 *                 QUEUE: If the given ID is -1, then the whole
964
	 *                        queue is deleted. Otherwise only a title
965
	 *                        in the queue.
966
	 *                 PLAYLIST Delete a whole playlist from a user
8 andreas 967
	 * 
13 andreas 968
	 *      <id>       -1 = Delete whole QUEUE or PLAYLIST
969
	 *                 >= 0 Delete only a particular entry
8 andreas 970
	 */
9 andreas 971
	if (!strcasecmp(bef, "DELETE"))
8 andreas 972
	{
973
		char p_type[32], *t;
974
		int id, x;
975
 
976
		x = 0;
977
		t = strtok(par, ":");
978
 
979
		while (t)
980
		{
981
			switch (x)
982
			{
983
				case 0:
984
					strncpy(p_type, t, sizeof(p_type));
985
					p_type[31] = 0;
986
				break;
987
 
988
				case 1: id = atoi(t); break;
989
			}
990
 
991
			x++;
992
			t = strtok(NULL, ":");
993
		}
994
 
995
		if (!strcasecmp(p_type, "QUEUE"))
996
			return deleteQueue(s1, id);
997
		else if (!strcasecmp(p_type, "PTITLE"))
998
			return deletePlaylistEntry(s1, id);
999
		else if (!strcasecmp(p_type, "PLAYLIST"))
1000
			return deletePlaylist(s1, id);
1001
		else
1002
			return FALSE;
1003
	}
1004
 
1005
	/*
9 andreas 1006
	 * Syntax: SEARCH:<type>:<expression>:<start>:<lines>;
8 andreas 1007
	 *            <type>   TITLE | ARTIST | ALBUM | GENRE
1008
	 *            <expression> This is what to search for
9 andreas 1009
	 *            <start>  the data to start to
1010
	 *            <lines>  number of lines to return
1011
	 * 
18 andreas 1012
	 * Return: SEARCH:<type>:<id>:<line>:<title>:<artist>:<album>:<genre>;
8 andreas 1013
	 */
1014
	if (!strcasecmp(bef, "SEARCH"))
1015
	{
9 andreas 1016
		int start, lines, x;
1017
		char *t, p_type[32], expr[128];
1018
 
1019
		memset(p_type, 0, sizeof(p_type));
1020
		memset(expr, 0, sizeof(expr));
1021
		start = lines = 0;
1022
		x = 0;
1023
		t = strtok (par, ":");
1024
 
1025
		while (t)
1026
		{
11 andreas 1027
			char *hv;
1028
 
9 andreas 1029
			switch(x)
1030
			{
11 andreas 1031
				case 0: strncpy(p_type, t, sizeof(p_type)-1); break;
9 andreas 1032
 
1033
				case 1:
11 andreas 1034
					strncpy(expr, t, sizeof(expr)-1);
1035
					hv = urldecode(expr);
1036
 
1037
					if (hv != NULL)
1038
					{
1039
						strncpy(expr, hv, sizeof(expr) - 1);
1040
						free(hv);
1041
					}
9 andreas 1042
				break;
1043
 
1044
				case 2: start = atoi(t); break;
1045
				case 3: lines = atoi(t); break;
1046
			}
1047
 
1048
			x++;
1049
			t = strtok (NULL, ":");
1050
		}
13 andreas 1051
 
9 andreas 1052
		if (x != 4 || !strlen(p_type) || !strlen(expr) || !lines || !start)
1053
		{
1054
			strcpy (cmd_error, "Missing one ore more parameters");
1055
			return FALSE;
1056
		}
1057
 
1058
		return searchTerm(s1, p_type, expr, start, lines);
8 andreas 1059
	}
1060
 
28 andreas 1061
	/*
1062
	 * This command reread the config file.
1063
	 */
1064
	if (!strcasecmp(bef, "RESET"))
1065
	{
1066
		if (playerActive)
1067
			nextCommand = PLAY_STOP;
1068
 
1069
		readConf();
1070
	}
1071
 
4 andreas 1072
	return TRUE;		/* cmd was OK */
2 andreas 1073
}
1074
 
1075
/*
8 andreas 1076
 * This function opens the database and deletes the whole archive of scanned
1077
 * MP3 files.
1078
 * This is called when the command "RESCAN" was detected. When this function
1079
 * is finished, the database is ready for new data.
1080
 */
1081
int cleanArchieve(int s1, char *fname)
1082
{
1083
	char query[1024];
1084
	sqlite3 *db;
1085
	char *zErrMsg = 0;
1086
	int rc;
1087
 
1088
	rc = sqlite3_open(fname, &db);
1089
 
1090
	if (rc)
1091
	{
1092
		syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
1093
		strcpy(query, "ERROR:MDB:Error opening database;");
1094
		write (s1, query, strlen(query));
1095
		return FALSE;
1096
	}
1097
 
29 andreas 1098
	strcpy (query, "delete from \"main\".\"playlists\"");
1099
 
1100
	if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
1101
	{
1102
		syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1103
		sqlite3_free(zErrMsg);
1104
		sqlite3_close(db);
1105
		strcpy(query, "ERROR:MDB:SQL error;");
1106
		write (s1, query, strlen(query));
1107
		return FALSE;
1108
	}
1109
 
8 andreas 1110
	strcpy (query, "delete from \"main\".\"musicdb\"");
1111
 
1112
	if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
1113
	{
1114
		syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1115
		sqlite3_free(zErrMsg);
1116
		sqlite3_close(db);
1117
		strcpy(query, "ERROR:MDB:SQL error;");
1118
		write (s1, query, strlen(query));
1119
		return FALSE;
1120
	}
1121
 
1122
	sqlite3_close(db);
1123
	return TRUE;
1124
}
1125
 
1126
/*
2 andreas 1127
 * Callback function of directory scan.
1128
 * This function desides whether a directory entry will be treated as a
1129
 * music file or not.
1130
 */
1131
int musicFilter(const struct dirent *dir)
1132
{
4 andreas 1133
	if (dir == NULL)
1134
		return 0;
2 andreas 1135
 
4 andreas 1136
	if (dir->d_type == DT_REG)
1137
	{
32 andreas 1138
		char *p = getFileExtension(dir->d_name);
1139
 
1140
		if (p != NULL && (strcasecmp(p, "mp3") == 0 || strcasecmp(p, "flac") == 0))
1141
			return 1;
4 andreas 1142
	}
1143
	else if (dir->d_type == DT_DIR)
1144
	{
1145
		if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0)
1146
			return 1;
1147
	}
1148
 
2 andreas 1149
	return 0;
1150
}
1151
 
1152
/*
1153
 * This function scans a directory for music files. If it finds some file name
1154
 * who is a possible music file, it gives it to a function to evaluate and
1155
 * store it.
1156
 */
12 andreas 1157
int grabMusicFiles(int s1, char *dir)
2 andreas 1158
{
1159
	struct dirent **namelist;
1160
	int n;
1161
 
1162
	if (dir == NULL || strlen(dir) == 0)
1163
		return FALSE;
1164
 
1165
	n = scandir(dir, &namelist, musicFilter, alphasort);
1166
 
1167
	if (n < 0)
1168
	{
4 andreas 1169
		syslog(LOG_DAEMON, "Error scanning directory %s: %s", dir, strerror(errno));
2 andreas 1170
		return FALSE;
1171
	}
1172
	else
1173
	{ 
1174
		while(n--)
1175
		{
42 andreas 1176
			char hv0[1024];
1177
			int len;
1178
 
5 andreas 1179
			strcpy(hv0, dir);
1180
			strcat(hv0, "/");
42 andreas 1181
			len = sizeof(hv0) - strlen(hv0) - 1;
5 andreas 1182
 
42 andreas 1183
			if (len > 0)
1184
				strncat(hv0, namelist[n]->d_name, len);
1185
			else
1186
			{
1187
				free(namelist[n]);
1188
				continue;
1189
			}
1190
 
4 andreas 1191
			if (namelist[n]->d_type == DT_DIR)
12 andreas 1192
				grabMusicFiles(s1, hv0);
1193
			else
4 andreas 1194
			{
1195
				evaluateMusicFile(hv0);
1196
 
12 andreas 1197
				if (!(grabFilesCount % 100))
1198
				{
1199
					sprintf(hv0, "SCANNING:%d;", grabFilesCount);
1200
					write (s1, hv0, strlen(hv0));
1201
				}
1202
			}
1203
 
2 andreas 1204
			free(namelist[n]); 
1205
		} 
1206
 
1207
		free(namelist); 
14 andreas 1208
	}
1209
 
1210
	return TRUE;
2 andreas 1211
}
1212
 
1213
void evaluateMusicFile(char *file)
1214
{
42 andreas 1215
sqlite3 *db;
1216
sqlite3_stmt *res;
1217
char *zErrMsg = 0;
43 andreas 1218
int rc, fType, update, id;
42 andreas 1219
char fname[256], hv0[64];
1220
char query[8192];
45 andreas 1221
struct id3_tag *id3;
1222
struct id3_file *ifile;
1223
struct id3_frame *frame;
1224
union id3_field *field;
1225
id3_byte_t const *bt;
42 andreas 1226
char id3_title[256];
1227
char id3_singer[256];
1228
char id3_album[256];
1229
char id3_genre[256];
1230
char id3_cover[256];
56 andreas 1231
char /* *title, *singer, *album,*/ *ext;
45 andreas 1232
enum id3_field_type enc;
3 andreas 1233
 
2 andreas 1234
	if (access(file, R_OK))
1235
		return;
1236
 
45 andreas 1237
	bt = NULL;
1238
 
2 andreas 1239
	strcpy(fname, configs.home);
9 andreas 1240
	strcat(fname, MUSICDB);
4 andreas 1241
 
5 andreas 1242
	if (!access(fname, R_OK | W_OK))
2 andreas 1243
		file_found = TRUE;
4 andreas 1244
	else						/* create the directory, if it doesn't exitst */
1245
	{
1246
		if (access(configs.home, R_OK | W_OK))
1247
		{
1248
			if (mkdir(configs.home, 0775) != 0)
1249
			{
1250
				syslog(LOG_WARNING, "Error creating directory %s: %s", configs.home, strerror(errno));
1251
				return;
1252
			}
1253
			else
1254
				syslog(LOG_INFO, "Directory %s was created.", configs.home);
1255
		}
5 andreas 1256
 
1257
		sprintf(query, "%s/Covers", configs.home);
1258
 
1259
		if (access(query, R_OK | W_OK))
1260
		{
1261
			if (mkdir(query, 0775) != 0)
1262
				syslog(LOG_WARNING, "Error creating directory %s: %s", query, strerror(errno));
1263
			else
1264
				syslog(LOG_INFO, "Directory %s was created.", query);
1265
		}
4 andreas 1266
	}
2 andreas 1267
 
1268
	rc = sqlite3_open(fname, &db);
1269
 
1270
	if (rc)
1271
	{
1272
		syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
1273
		return;
1274
	}
1275
 
1276
	if (!file_found)
1277
	{
32 andreas 1278
		/* id        autoincrement unique index
1279
		 * path      path to file containing an MP3 or FLAC file
1280
		 * type      1 = MP3, 2 = FLAC
1281
		 * title     title of song
1282
		 * interpret singer
1283
		 * album     the album the is from
1284
		 * genre     genre of the song
1285
		 * cover     name of file containing the cover
1286
		 */
2 andreas 1287
		strcpy(query, "create table \"main\".\"musicdb\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
32 andreas 1288
		strcat(query, "\"path\" TEXT NOT NULL, \"type\" INTEGER, \"title\" TEXT, \"interpret\" TEXT,");
5 andreas 1289
		strcat(query, "\"album\" TEXT, \"genre\" TEXT, \"cover\" TEXT)");
8 andreas 1290
		rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg);
2 andreas 1291
 
1292
		if (rc != SQLITE_OK)
1293
		{
5 andreas 1294
			syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
2 andreas 1295
			sqlite3_free(zErrMsg);
1296
			sqlite3_close(db);
1297
			return;
1298
		}
4 andreas 1299
		else
7 andreas 1300
			syslog(LOG_INFO, "Database \"musicdb\" was successfully created.");
1301
 
1302
		strcpy(query, "CREATE TABLE \"main\".\"users\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT,");
1303
		strcat(query, "\"uname\" TEXT NOT NULL, \"playlist\" TEXT)");
8 andreas 1304
		rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg);
7 andreas 1305
 
1306
		if (rc != SQLITE_OK)
1307
		{
1308
			syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1309
			sqlite3_free(zErrMsg);
1310
			sqlite3_close(db);
1311
			return;
1312
		}
1313
		else
1314
			syslog(LOG_INFO, "Database \"users\" was successfully created.");
8 andreas 1315
 
1316
		strcpy (query, "CREATE TABLE \"main\".\"playlists\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
1317
		strcat (query, "\"userid\" INTEGER NOT NULL, \"musicid\" INTEGER NOT NULL)");
1318
 
1319
		rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg);
1320
 
1321
		if (rc != SQLITE_OK)
1322
		{
1323
			syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
1324
			sqlite3_free(zErrMsg);
1325
			sqlite3_close(db);
1326
			return;
1327
		}
1328
		else
1329
			syslog(LOG_INFO, "Database \"users\" was successfully created.");
2 andreas 1330
	}
1331
 
4 andreas 1332
	/* Make sure, the file is not already in the database */
45 andreas 1333
	sprintf(query, "select id, path, cover from musicdb where path = \"%s\"", file);
2 andreas 1334
 
8 andreas 1335
	if (sqlite3_prepare(db, query, -1, &res, NULL) != SQLITE_OK)
2 andreas 1336
	{
8 andreas 1337
		syslog(LOG_DAEMON, "Error preparing SQL statement [%s]: %s", query, sqlite3_errmsg(db));
2 andreas 1338
		sqlite3_close(db);
1339
		return;
1340
	}
42 andreas 1341
 
8 andreas 1342
	rc = sqlite3_step(res);
45 andreas 1343
	id3_cover[0] = 0;
42 andreas 1344
 
8 andreas 1345
	if (rc == SQLITE_ROW)			/* If we've a row, the path exists and we'll not add it again */
43 andreas 1346
	{								/* Instead we'll update the information */
1347
		update = 1;
1348
		id = sqlite3_column_int(res, 0);
45 andreas 1349
 
1350
		if ((ext = (char *)sqlite3_column_text(res, 2)) == NULL)
1351
		{
1352
			syslog(LOG_WARNING, "Error getting path of picture from database!");
1353
			id3_cover[0] = 0;
1354
		}
1355
		else
1356
			strncpy(&id3_cover[0], ext, sizeof(id3_cover));
2 andreas 1357
	}
43 andreas 1358
	else
1359
		update = 0;
2 andreas 1360
 
43 andreas 1361
	sqlite3_finalize(res);
32 andreas 1362
	/* Check the file extension and decide whether it's an MP3 or FLAC file. */
1363
	ext = getFileExtension(file);
1364
 
1365
	if (ext != NULL)
1366
	{
1367
		if (strcasecmp(ext, "flac") == 0)
1368
			fType = FILE_TYPE_FLAC;
1369
		else
1370
			fType = FILE_TYPE_MP3;
1371
	}
1372
	else
1373
		fType = FILE_TYPE_MP3;
1374
 
4 andreas 1375
	/* Open the file and get the ID3 tag. */
45 andreas 1376
	if ((ifile = id3_file_open(file, ID3_FILE_MODE_READONLY)) == NULL)
1377
	{
1378
		syslog(LOG_WARNING, "Error opening file %s!", file);
1379
		sqlite3_close(db);
1380
		return;
1381
	}
1382
 
1383
	if ((id3 = id3_file_tag(ifile)) == NULL)
1384
	{
1385
		syslog(LOG_WARNING, "Error initializing MP3 file %s", file);
1386
		sqlite3_close(db);
1387
		return;
1388
	}
1389
 
2 andreas 1390
	memset(&id3_title, 0, sizeof(id3_title));
1391
	memset(&id3_singer, 0, sizeof(id3_singer));
1392
	memset(&id3_album, 0, sizeof(id3_album));
1393
	memset(&id3_genre, 0, sizeof(id3_genre));
45 andreas 1394
 
1395
	if (!strlen(id3_cover))
1396
		memset(&id3_cover, 0, sizeof(id3_cover));
1397
 
4 andreas 1398
	/* Get the required frames */
45 andreas 1399
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_TITLE, 0)) != NULL)
2 andreas 1400
	{
45 andreas 1401
		int i;
1402
 
1403
		for (i = 0; i < (int)frame->nfields; i++)
1404
		{
1405
			field = id3_frame_field(frame, i);
1406
 
1407
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1408
				enc = id3_field_gettextencoding(field);
1409
 
1410
			if (field && checkID3FieldType(field->type))
1411
				break;
1412
		}
1413
 
1414
		getID3_Field(field, enc, &id3_title[0], sizeof(id3_title));
5 andreas 1415
		char_replace(id3_title, '"', '`');
1416
		char_replace(id3_title, '\\', ' ');
2 andreas 1417
	}
1418
 
45 andreas 1419
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_ARTIST, 0)) != NULL)
2 andreas 1420
	{
45 andreas 1421
		int i;
1422
 
1423
		for (i = 0; i < (int)frame->nfields; i++)
1424
		{
1425
			field = id3_frame_field(frame, i);
1426
 
1427
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1428
				enc = id3_field_gettextencoding(field);
1429
 
1430
			if (field && checkID3FieldType(field->type))
1431
				break;
1432
		}
1433
 
1434
		getID3_Field(field, enc, &id3_singer[0], sizeof(id3_singer));
5 andreas 1435
		char_replace(id3_singer, '"', '`');
1436
		char_replace(id3_singer, '\\', ' ');
2 andreas 1437
	}
1438
 
45 andreas 1439
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_ALBUM, 0)) != NULL)
2 andreas 1440
	{
45 andreas 1441
		int i;
1442
 
1443
		for (i = 0; i < (int)frame->nfields; i++)
1444
		{
1445
			field = id3_frame_field(frame, i);
1446
 
1447
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1448
				enc = id3_field_gettextencoding(field);
1449
 
1450
			if (field && checkID3FieldType(field->type))
1451
				break;
1452
		}
1453
 
1454
		getID3_Field(field, enc, &id3_album[0], sizeof(id3_album));
5 andreas 1455
		char_replace(id3_album, '"', '`');
1456
		char_replace(id3_album, '\\', ' ');
2 andreas 1457
	}
1458
 
45 andreas 1459
	if ((frame = id3_tag_findframe(id3, "APIC", 0)) != NULL)
12 andreas 1460
	{
1461
		char fpname[512], uid[128], hv0[256];
56 andreas 1462
/*		struct id3_frame *fpframe; */
45 andreas 1463
		int i, fd, np;
1464
		long unsigned len;
12 andreas 1465
 
40 andreas 1466
		memset(uid, 0, sizeof(uid));
12 andreas 1467
		strcpy(fpname, configs.home);
1468
		strcat(fpname, "/Covers");
1469
 
1470
		if (access(fpname, R_OK | W_OK | X_OK))
1471
			mkdir(fpname, 0775);
1472
 
45 andreas 1473
		if (!strlen(id3_cover))
12 andreas 1474
		{
14 andreas 1475
			char *md5;
12 andreas 1476
 
22 andreas 1477
			if ((md5 = str2hash(file, (int)strlen(file))) != NULL)
14 andreas 1478
			{
1479
				sprintf(uid, "Picture-%s", md5);
1480
				free(md5);
1481
			}
1482
			else
1483
				sprintf(uid, "Picture-%ld", random());
1484
		}
1485
 
12 andreas 1486
		strcat(fpname, "/");
45 andreas 1487
		len = 0;
1488
		np = 0;			/* 1 = a new picture was found */
1489
		bt = NULL;
12 andreas 1490
		/* Get the picture and store it into a file */
45 andreas 1491
		for (i = 0; i < (int)frame->nfields; i++)
1492
		{
1493
			if ((field = id3_frame_field(frame, i)) != NULL)
1494
			{
1495
				id3_latin1_t const *lt1;
40 andreas 1496
 
45 andreas 1497
				switch (field->type)
1498
				{
1499
					case ID3_FIELD_TYPE_LATIN1:			// MIME type
1500
						if ((lt1 = id3_field_getlatin1(field)) != NULL)
1501
							strncpy (&hv0[0], (char *)lt1, sizeof(hv0)-1);
1502
					break;
1503
 
1504
					case ID3_FIELD_TYPE_LATIN1FULL:
1505
						if ((lt1 = id3_field_getfulllatin1(field)) != NULL)
1506
							strncpy (&hv0[0], (char *)lt1, sizeof(hv0)-1);
1507
					break;
1508
 
1509
					case ID3_FIELD_TYPE_BINARYDATA:		// The picture
1510
						bt = id3_field_getbinarydata(field, &len);
1511
						np = 1;
1512
					break;
1513
				}
1514
			}
1515
		}
1516
 
1517
		if (!strlen(id3_cover) && np)
12 andreas 1518
		{
45 andreas 1519
			if (strstr(hv0, "jpeg") != NULL)
1520
				strcat(uid, ".jpg");
1521
			else if (strstr(hv0, "png") != NULL)
1522
				strcat(uid, ".png");
1523
			else if (strstr(hv0, "gif") != NULL)
1524
				strcat(uid, ".gif");
1525
			else if (strstr(hv0, "tiff") != NULL)
1526
				strcat(uid, ".tiff");
1527
			else
1528
			{
1529
				char *pos;
12 andreas 1530
 
45 andreas 1531
				if ((pos = strrchr(hv0, '/')) != NULL)
1532
				{
1533
					strcat(uid, ".");
1534
					strcat(uid, pos+1);
1535
				}
1536
			}
1537
 
1538
			strcat(fpname, uid);
1539
			strcpy (id3_cover, uid);
1540
		}
1541
		else if (strlen(id3_cover) && !np)
1542
		{
1543
			strcat (fpname, id3_cover);
1544
			unlink(fpname);
1545
		}
1546
		else if (strlen(id3_cover))
1547
			strcat (fpname, id3_cover);
1548
 
1549
		if (np)
1550
		{
1551
			if ((fd = open(fpname, O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
1552
				syslog(LOG_WARNING, "Error opening file %s for saving a picture: %s", fpname, strerror(errno));
1553
			else
12 andreas 1554
			{
45 andreas 1555
				write(fd, bt, len);
1556
				close(fd);
12 andreas 1557
			}
1558
		}
1559
	}
1560
 
45 andreas 1561
	if ((frame = id3_tag_findframe(id3, ID3_FRAME_GENRE, 0)) != NULL)
2 andreas 1562
	{
45 andreas 1563
		int i;
1564
 
1565
		for (i = 0; i < (int)frame->nfields; i++)
1566
		{
1567
			field = id3_frame_field(frame, i);
5 andreas 1568
 
45 andreas 1569
			if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
1570
				enc = id3_field_gettextencoding(field);
1571
 
1572
			if (field && checkID3FieldType(field->type))
1573
				break;
1574
		}
1575
 
1576
		if (field != NULL)
1577
			getID3_Field(field, enc, &id3_genre[0], sizeof(id3_genre));
1578
		else
1579
			id3_genre[0] = 0;
1580
 
5 andreas 1581
		if (strchr(id3_genre, '(') && strchr(id3_genre, ')') && isdigit(id3_genre[1]))
1582
		{
45 andreas 1583
			int gen;
5 andreas 1584
 
45 andreas 1585
			gen = atoi(&id3_genre[1]);
5 andreas 1586
 
46 andreas 1587
			if (gen >= 0 && gen < ID3_NR_OF_V1_GENRES)
5 andreas 1588
				strncpy (id3_genre, ID3_v1_genre_description[gen], sizeof(id3_genre));
1589
			else
1590
				strcpy (id3_genre, "Pop");
1591
		}
1592
 
1593
		char_replace(id3_genre, '"', '`');
1594
		char_replace(id3_genre, '\\', ' ');
2 andreas 1595
	}
5 andreas 1596
 
45 andreas 1597
	id3_tag_delete(id3);
1598
	id3_file_close(ifile);
5 andreas 1599
 
12 andreas 1600
	if (!strlen(id3_title) && !strlen(id3_singer))		/* grab title and artist from file name */
1601
	{
1602
		char hv0[256], *p;
43 andreas 1603
		int x, flag;
12 andreas 1604
 
1605
		memset(hv0, 0, sizeof(hv0));
46 andreas 1606
		p = strrchr(file, '/');							/* find the last directory separator */
12 andreas 1607
 
46 andreas 1608
		if (p)											/* If there is a seperator ... */
1609
			strncpy(hv0, p+1, sizeof(hv0)-1);			/* Copy the part after it (this is the file name) */
1610
		else											/* There seems to be no path ... */
1611
			strncpy(hv0, file, sizeof(hv0)-1);			/* Copy the whole file name (this IS the file name) */
12 andreas 1612
 
46 andreas 1613
		if ((p = strchr(hv0, '-')) != NULL)				/* Do we have a dash as seperator? */
1614
		{												/* Yes, so look how many components the file name have */
1615
			char *p2;
1616
 
12 andreas 1617
			*p = 0;
1618
			p++;
1619
 
46 andreas 1620
			if ((p2 = strchr(p, '-')) != NULL)
1621
			{
1622
				*p2 = 0;
1623
				p2++;
1624
				strncpy(id3_album, hv0, sizeof(id3_album) - 1);
1625
				strncpy(id3_singer, p, sizeof(id3_singer) - 1);
1626
				strncpy(id3_title, p2, sizeof(id3_title) - 1);
1627
				trim(id3_album);
1628
			}
1629
			else
1630
			{
1631
				strncpy(id3_singer, hv0, sizeof(id3_singer) - 1);
1632
				strncpy(id3_title, p, sizeof(id3_title) - 1);
1633
			}
1634
 
12 andreas 1635
			if ((p = strrchr(id3_title, '.')) != NULL)
1636
				*p = 0;
1637
 
1638
			trim(id3_singer);
1639
			trim(id3_title);
43 andreas 1640
			/* Make upper / lower case */
46 andreas 1641
			flag = 1;
43 andreas 1642
 
1643
			for (x = 0; x < (int)strlen(id3_singer); x++)
1644
			{
1645
				if (id3_singer[x] == ' ')
1646
					flag = 1;
1647
 
1648
				if (flag && id3_singer[x] != ' ')
1649
				{
1650
					id3_singer[x] = (char)toupper((int)id3_singer[x]);
1651
					flag = 0;
1652
				}
1653
				else
1654
					id3_singer[x] = (char)tolower((int)id3_singer[x]);
1655
			}
1656
 
46 andreas 1657
			flag = 1;
43 andreas 1658
 
1659
			for (x = 0; x < (int)strlen(id3_title); x++)
1660
			{
1661
				if (id3_title[x] == ' ')
1662
					flag = 1;
1663
 
1664
				if (flag && id3_title[x] != ' ')
1665
				{
1666
					id3_title[x] = (char)toupper((int)id3_title[x]);
1667
					flag = 0;
1668
				}
1669
				else
1670
					id3_title[x] = (char)tolower((int)id3_title[x]);
1671
			}
46 andreas 1672
 
1673
			if (p2)
1674
			{
1675
				flag = 1;
1676
 
1677
				for (x = 0; x < (int)strlen(id3_album); x++)
1678
				{
1679
					if (id3_album[x] == ' ')
1680
						flag = 1;
1681
 
1682
					if (flag && id3_album[x] != ' ')
1683
					{
1684
						id3_album[x] = (char)toupper((int)id3_album[x]);
1685
						flag = 0;
1686
					}
1687
					else
1688
						id3_album[x] = (char)tolower((int)id3_album[x]);
1689
				}
1690
			}
12 andreas 1691
		}
1692
		else
1693
		{
1694
			strncpy(id3_title, hv0, sizeof(hv0) - 1);
1695
 
1696
			if ((p = strrchr(id3_title, '.')) != NULL)
1697
				*p = 0;
1698
 
1699
			trim(id3_title);
43 andreas 1700
			flag = 0;
1701
 
1702
			for (x = 0; x < (int)strlen(id3_title); x++)
1703
			{
1704
				if (id3_title[x] == ' ')
1705
					flag = 1;
1706
 
1707
				if (flag && id3_title[x] != ' ')
1708
				{
1709
					id3_title[x] = (char)toupper((int)id3_title[x]);
1710
					flag = 0;
1711
				}
1712
				else
1713
					id3_title[x] = (char)tolower((int)id3_title[x]);
1714
			}
12 andreas 1715
		}
1716
	}
1717
 
43 andreas 1718
	if (!update)
5 andreas 1719
	{
43 andreas 1720
		strcpy (query, "insert into musicdb (\"path\", \"type\", \"title\", \"interpret\", \"album\", \"genre\", \"cover\") values ");
1721
		strcat (query, "(\"");
1722
		strcat (query, file);
1723
		strcat (query, "\", ");
1724
		sprintf(hv0, "%d", fType);
1725
		strcat (query, hv0);
1726
		strcat (query, ", \"");
5 andreas 1727
		strcat (query, id3_title);
43 andreas 1728
		strcat (query, "\", \"");
1729
		strcat (query, id3_singer);
1730
		strcat (query, "\", \"");
1731
		strcat (query, id3_album);
1732
		strcat (query, "\", \"");
1733
		strcat (query, id3_genre);
1734
		strcat (query, "\", \"");
1735
		strcat (query, id3_cover);
1736
		strcat (query, "\")");
5 andreas 1737
	}
1738
	else
1739
	{
43 andreas 1740
		strcpy(query, "update musicdb set \"title\" = \"");
1741
		strcat(query, id3_title);
1742
		strcat(query, "\", \"interpret\" = \"");
1743
		strcat(query, id3_singer);
1744
		strcat(query, "\", \"album\" = \"");
1745
		strcat(query, id3_album);
1746
		strcat(query, "\", \"genre\" = \"");
1747
		strcat(query, id3_genre);
1748
		strcat(query, "\", \"cover\" = \"");
1749
		strcat(query, id3_cover);
1750
		strcat(query, "\" where id = ");
1751
		sprintf(hv0, "%d", id);
1752
		strcat(query, hv0);
5 andreas 1753
	}
1754
 
8 andreas 1755
	if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
2 andreas 1756
	{
5 andreas 1757
		syslog(LOG_DAEMON, "SQL Error  [%s]: %s", query, zErrMsg);
2 andreas 1758
		sqlite3_free(zErrMsg);
1759
		sqlite3_close(db);
1760
		return;
1761
	}
1762
 
1763
	sqlite3_close(db);
12 andreas 1764
	grabFilesCount++;
2 andreas 1765
}
43 andreas 1766
 
45 andreas 1767
int checkID3FieldType(enum id3_field_type ft)
43 andreas 1768
{
45 andreas 1769
	switch (ft)
1770
	{
1771
		case ID3_FIELD_TYPE_LATIN1:
1772
		case ID3_FIELD_TYPE_LATIN1FULL:
1773
		case ID3_FIELD_TYPE_LATIN1LIST:
1774
		case ID3_FIELD_TYPE_STRING:
1775
		case ID3_FIELD_TYPE_STRINGFULL:
1776
		case ID3_FIELD_TYPE_STRINGLIST:
1777
			return 1;
1778
 
1779
		case ID3_FIELD_TYPE_INT8:
1780
		case ID3_FIELD_TYPE_INT16:
1781
		case ID3_FIELD_TYPE_INT24:
1782
		case ID3_FIELD_TYPE_INT32:
1783
		case ID3_FIELD_TYPE_INT32PLUS:
1784
			return 1;
1785
	}
1786
 
1787
	return 0;
1788
}
1789
 
1790
char *getID3_Field(union id3_field *field, enum id3_field_textencoding te, char *ret, int len)
1791
{
44 andreas 1792
char *p, *pg;
45 andreas 1793
char wc[256];
1794
id3_utf8_t *uc;
1795
id3_ucs4_t const *ucs;
1796
id3_latin1_t const *lt1;
43 andreas 1797
iconv_t ic;
1798
int i;
45 andreas 1799
size_t length;
1800
long num;
43 andreas 1801
 
45 andreas 1802
	if (field == NULL)
1803
	{
1804
		if (configs.debug)
1805
			syslog(LOG_DEBUG, "Missing valid field pointer!");
1806
 
1807
		*ret = 0;
1808
		return NULL;
1809
	}
1810
 
43 andreas 1811
	*ret = 0;
1812
 
1813
	switch (te)
1814
	{
45 andreas 1815
		case ID3_FIELD_TEXTENCODING_ISO_8859_1:
1816
			if (field->type == ID3_FIELD_TYPE_LATIN1)
43 andreas 1817
			{
45 andreas 1818
				if ((lt1 = id3_field_getlatin1(field)) == NULL)
1819
				{
1820
					syslog(LOG_WARNING, "Couldn't get latin1 field!");
1821
					return NULL;
1822
				}
1823
			}
1824
			else if (field->type == ID3_FIELD_TYPE_LATIN1FULL)
1825
			{
1826
				if ((lt1 = id3_field_getfulllatin1(field)) == NULL)
1827
				{
1828
					syslog(LOG_WARNING, "Couldn't get full latin1 field!");
1829
					return NULL;
1830
				}
1831
			}
1832
			else if (field->type == ID3_FIELD_TYPE_LATIN1LIST)
1833
			{
1834
				int n;
43 andreas 1835
 
45 andreas 1836
				n = id3_field_getnstrings(field);
1837
 
1838
				for (i = 0; i < n; i++)
1839
				{
1840
					if ((ucs = id3_field_getstrings(field, i)) != NULL)
1841
						break;
1842
				}
1843
 
1844
				if (ucs == NULL)
1845
				{
1846
					syslog(LOG_WARNING, "Couldn't get Latin1 field out of a list of %d", n);
1847
					return NULL;
1848
				}
1849
 
1850
				uc = id3_ucs4_utf8duplicate(ucs);
1851
 
1852
				if (uc)
1853
				{
1854
					strncpy(ret, (char *)uc, len);
1855
					free (uc);
1856
					return ret;
1857
				}
1858
 
1859
				return NULL;
43 andreas 1860
			}
45 andreas 1861
			else
1862
			{
1863
				syslog(LOG_WARNING, "No parseable field type found!");
1864
				return NULL;
1865
			}
43 andreas 1866
 
1867
			if ((ic = iconv_open("UTF-8", "ISO-8859-1")) == (iconv_t)-1)
1868
			{
1869
				syslog(LOG_WARNING, "Error initializing ICONV to convert ASCII into UTF-8: %s", strerror(errno));
1870
				return ret;
1871
			}
1872
 
1873
			length = sizeof(wc);
1874
			p = wc;
45 andreas 1875
			pg = (char *)lt1;
1876
			i = strlen((char *)lt1);
43 andreas 1877
 
44 andreas 1878
			iconv(ic, &pg, (size_t *)&i, &p, &length);
43 andreas 1879
			iconv_close(ic);
1880
			strncpy (ret, wc, len);
1881
		break;
1882
 
45 andreas 1883
		case ID3_FIELD_TEXTENCODING_UTF_16:
1884
		case ID3_FIELD_TEXTENCODING_UTF_16BE:
1885
		case ID3_FIELD_TEXTENCODING_UTF_8:
1886
			if (field->type == ID3_FIELD_TYPE_STRINGFULL)
43 andreas 1887
			{
45 andreas 1888
				if ((ucs = id3_field_getfullstring(field)) == NULL)
1889
				{
1890
					syslog(LOG_WARNING, "Couldn't get full UTF-? field!");
1891
					return NULL;
1892
				}
43 andreas 1893
			}
45 andreas 1894
			else if (field->type == ID3_FIELD_TYPE_STRING)
43 andreas 1895
			{
45 andreas 1896
				if ((ucs = id3_field_getstring(field)) == NULL)
1897
				{
1898
					syslog(LOG_WARNING, "Couldn't get UTF-? field!");
1899
					return NULL;
1900
				}
43 andreas 1901
			}
45 andreas 1902
			else if (field->type == ID3_FIELD_TYPE_STRINGLIST)
43 andreas 1903
			{
45 andreas 1904
				int n;
43 andreas 1905
 
45 andreas 1906
				n = id3_field_getnstrings(field);
43 andreas 1907
 
45 andreas 1908
				for (i = 0; i < n; i++)
1909
				{
1910
					if ((ucs = id3_field_getstrings(field, i)) != NULL)
1911
						break;
1912
				}
43 andreas 1913
 
45 andreas 1914
				if (ucs == NULL)
1915
				{
1916
					syslog(LOG_WARNING, "Couldn't get UTF-? field out of a list of %d", n);
1917
					return NULL;
1918
				}
1919
			}
1920
			else
43 andreas 1921
			{
45 andreas 1922
				syslog(LOG_WARNING, "No parseable field type found!");
44 andreas 1923
				return NULL;
43 andreas 1924
			}
1925
 
45 andreas 1926
			uc = id3_ucs4_utf8duplicate(ucs);
43 andreas 1927
 
45 andreas 1928
			if (uc)
1929
			{
1930
				strncpy(ret, (char *)uc, len);
1931
				free (uc);
1932
			}
43 andreas 1933
		break;
1934
 
45 andreas 1935
		case ID3_FIELD_TYPE_INT8:
1936
		case ID3_FIELD_TYPE_INT16:
1937
		case ID3_FIELD_TYPE_INT24:
1938
		case ID3_FIELD_TYPE_INT32:
1939
		case ID3_FIELD_TYPE_INT32PLUS:
1940
			num = id3_field_getint(field);
1941
			sprintf(ret, "(%ld)", num);
44 andreas 1942
		break;
1943
 
43 andreas 1944
		default:
45 andreas 1945
			if (configs.debug)
1946
				syslog(LOG_DEBUG, "Unkown field encoding: %d", te);
1947
 
1948
			return NULL;
43 andreas 1949
	}
1950
 
1951
	return ret;
1952
}
56 andreas 1953
 
1954
/*
1955
 * This are functions to handle all the handles for connected clients.
1956
 */
1957
void handleInit()
1958
{
1959
int i;
1960
 
1961
	for (i = 0; i < MAX_HANDLES; i++)
1962
		_s1[i] = -1;
1963
}
1964
 
1965
void handleAdd(int fd)
1966
{
1967
int i;
1968
 
1969
	for (i = 0; i < MAX_HANDLES; i++)
1970
	{
1971
		if (_s1[i] == fd)
1972
			return;
1973
	}
1974
 
1975
	for (i = 0; i < MAX_HANDLES; i++)
1976
	{
1977
		if (_s1[i] < 0)
1978
		{
1979
			_s1[i] = fd;
1980
			return;
1981
		}
1982
	}
1983
}
1984
 
1985
void handleDelete(int fd)
1986
{
1987
int i;
1988
 
1989
	for (i = 0; i < MAX_HANDLES; i++)
1990
	{
1991
		if (_s1[i] == fd)
1992
		{
1993
			_s1[i] = -1;
1994
			return;
1995
		}
1996
	}
1997
}
1998
 
1999
void handleWrite(char *txt)
2000
{
2001
	int i;
2002
 
2003
	for (i = 0; i < MAX_HANDLES; i++)
2004
	{
2005
		if (_s1[i] >= 0)
2006
			write(_s1[i], txt, strlen(txt));
2007
	}
2008
}