1/*
2 * Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <string.h>
24#include <stdint.h>
25
26#include <event.h>
27#include "evhttp/evhttp.h"
28
29#include "db.h"
30#include "misc.h"
31#include "logger.h"
32#include "dmap_common.h"
33
34
35/* gperf static hash, dmap_fields.gperf */
36#include "dmap_fields_hash.c"
37
38
39const struct dmap_field *
40dmap_get_fields_table(int *nfields)
41{
42  *nfields = sizeof(dmap_fields) / sizeof(dmap_fields[0]);
43
44  return dmap_fields;
45}
46
47
48void
49dmap_add_container(struct evbuffer *evbuf, char *tag, int len)
50{
51  unsigned char buf[4];
52
53  evbuffer_add(evbuf, tag, 4);
54
55  /* Container length */
56  buf[0] = (len >> 24) & 0xff;
57  buf[1] = (len >> 16) & 0xff;
58  buf[2] = (len >> 8) & 0xff;
59  buf[3] = len & 0xff;
60
61  evbuffer_add(evbuf, buf, sizeof(buf));
62}
63
64void
65dmap_add_long(struct evbuffer *evbuf, char *tag, int64_t val)
66{
67  unsigned char buf[12];
68
69  evbuffer_add(evbuf, tag, 4);
70
71  /* Length */
72  buf[0] = 0;
73  buf[1] = 0;
74  buf[2] = 0;
75  buf[3] = 8;
76
77  /* Value */
78  buf[4] = (val >> 56) & 0xff;
79  buf[5] = (val >> 48) & 0xff;
80  buf[6] = (val >> 40) & 0xff;
81  buf[7] = (val >> 32) & 0xff;
82  buf[8] = (val >> 24) & 0xff;
83  buf[9] = (val >> 16) & 0xff;
84  buf[10] = (val >> 8) & 0xff;
85  buf[11] = val & 0xff;
86
87  evbuffer_add(evbuf, buf, sizeof(buf));
88}
89
90void
91dmap_add_int(struct evbuffer *evbuf, char *tag, int val)
92{
93  unsigned char buf[8];
94
95  evbuffer_add(evbuf, tag, 4);
96
97  /* Length */
98  buf[0] = 0;
99  buf[1] = 0;
100  buf[2] = 0;
101  buf[3] = 4;
102
103  /* Value */
104  buf[4] = (val >> 24) & 0xff;
105  buf[5] = (val >> 16) & 0xff;
106  buf[6] = (val >> 8) & 0xff;
107  buf[7] = val & 0xff;
108
109  evbuffer_add(evbuf, buf, sizeof(buf));
110}
111
112void
113dmap_add_short(struct evbuffer *evbuf, char *tag, short val)
114{
115  unsigned char buf[6];
116
117  evbuffer_add(evbuf, tag, 4);
118
119  /* Length */
120  buf[0] = 0;
121  buf[1] = 0;
122  buf[2] = 0;
123  buf[3] = 2;
124
125  /* Value */
126  buf[4] = (val >> 8) & 0xff;
127  buf[5] = val & 0xff;
128
129  evbuffer_add(evbuf, buf, sizeof(buf));
130}
131
132void
133dmap_add_char(struct evbuffer *evbuf, char *tag, char val)
134{
135  unsigned char buf[5];
136
137  evbuffer_add(evbuf, tag, 4);
138
139  /* Length */
140  buf[0] = 0;
141  buf[1] = 0;
142  buf[2] = 0;
143  buf[3] = 1;
144
145  /* Value */
146  buf[4] = val;
147
148  evbuffer_add(evbuf, buf, sizeof(buf));
149}
150
151void
152dmap_add_literal(struct evbuffer *evbuf, char *tag, char *str, int len)
153{
154  char buf[4];
155
156  evbuffer_add(evbuf, tag, 4);
157
158  /* Length */
159  buf[0] = (len >> 24) & 0xff;
160  buf[1] = (len >> 16) & 0xff;
161  buf[2] = (len >> 8) & 0xff;
162  buf[3] = len & 0xff;
163
164  evbuffer_add(evbuf, buf, sizeof(buf));
165
166  if (str && (len > 0))
167    evbuffer_add(evbuf, str, len);
168}
169
170void
171dmap_add_string(struct evbuffer *evbuf, char *tag, const char *str)
172{
173  unsigned char buf[4];
174  int len;
175
176  if (str)
177    len = strlen(str);
178  else
179    len = 0;
180
181  evbuffer_add(evbuf, tag, 4);
182
183  /* String length */
184  buf[0] = (len >> 24) & 0xff;
185  buf[1] = (len >> 16) & 0xff;
186  buf[2] = (len >> 8) & 0xff;
187  buf[3] = len & 0xff;
188
189  evbuffer_add(evbuf, buf, sizeof(buf));
190
191  if (len)
192    evbuffer_add(evbuf, str, len);
193}
194
195void
196dmap_add_field(struct evbuffer *evbuf, const struct dmap_field *df, char *strval, int32_t intval)
197{
198  union {
199    int32_t v_i32;
200    uint32_t v_u32;
201    int64_t v_i64;
202    uint64_t v_u64;
203  } val;
204  int ret;
205
206  if (strval && (df->type != DMAP_TYPE_STRING))
207    {
208      switch (df->type)
209	{
210	  case DMAP_TYPE_DATE:
211	  case DMAP_TYPE_UBYTE:
212	  case DMAP_TYPE_USHORT:
213	  case DMAP_TYPE_UINT:
214	    ret = safe_atou32(strval, &val.v_u32);
215	    if (ret < 0)
216	      val.v_u32 = 0;
217	    break;
218
219	  case DMAP_TYPE_BYTE:
220	  case DMAP_TYPE_SHORT:
221	  case DMAP_TYPE_INT:
222	    ret = safe_atoi32(strval, &val.v_i32);
223	    if (ret < 0)
224	      val.v_i32 = 0;
225	    break;
226
227	  case DMAP_TYPE_ULONG:
228	    ret = safe_atou64(strval, &val.v_u64);
229	    if (ret < 0)
230	      val.v_u64 = 0;
231	    break;
232
233	  case DMAP_TYPE_LONG:
234	    ret = safe_atoi64(strval, &val.v_i64);
235	    if (ret < 0)
236	      val.v_i64 = 0;
237	    break;
238
239	  /* DMAP_TYPE_VERSION & DMAP_TYPE_LIST not handled here */
240	  default:
241	    DPRINTF(E_LOG, L_DAAP, "Unsupported DMAP type %d for DMAP field %s\n", df->type, df->desc);
242	    return;
243	}
244    }
245  else if (!strval && (df->type != DMAP_TYPE_STRING))
246    {
247      switch (df->type)
248	{
249	  case DMAP_TYPE_DATE:
250	  case DMAP_TYPE_UBYTE:
251	  case DMAP_TYPE_USHORT:
252	  case DMAP_TYPE_UINT:
253	    val.v_u32 = intval;
254	    break;
255
256	  case DMAP_TYPE_BYTE:
257	  case DMAP_TYPE_SHORT:
258	  case DMAP_TYPE_INT:
259	    val.v_i32 = intval;
260	    break;
261
262	  case DMAP_TYPE_ULONG:
263	    val.v_u64 = intval;
264	    break;
265
266	  case DMAP_TYPE_LONG:
267	    val.v_i64 = intval;
268	    break;
269
270	  /* DMAP_TYPE_VERSION & DMAP_TYPE_LIST not handled here */
271	  default:
272	    DPRINTF(E_LOG, L_DAAP, "Unsupported DMAP type %d for DMAP field %s\n", df->type, df->desc);
273	    return;
274	}
275    }
276
277  switch (df->type)
278    {
279      case DMAP_TYPE_UBYTE:
280	if (val.v_u32)
281	  dmap_add_char(evbuf, df->tag, val.v_u32);
282	break;
283
284      case DMAP_TYPE_BYTE:
285	if (val.v_i32)
286	  dmap_add_char(evbuf, df->tag, val.v_i32);
287	break;
288
289      case DMAP_TYPE_USHORT:
290	if (val.v_u32)
291	  dmap_add_short(evbuf, df->tag, val.v_u32);
292	break;
293
294      case DMAP_TYPE_SHORT:
295	if (val.v_i32)
296	  dmap_add_short(evbuf, df->tag, val.v_i32);
297	break;
298
299      case DMAP_TYPE_DATE:
300      case DMAP_TYPE_UINT:
301	if (val.v_u32)
302	  dmap_add_int(evbuf, df->tag, val.v_u32);
303	break;
304
305      case DMAP_TYPE_INT:
306	if (val.v_i32)
307	  dmap_add_int(evbuf, df->tag, val.v_i32);
308	break;
309
310      case DMAP_TYPE_ULONG:
311	if (val.v_u64)
312	  dmap_add_long(evbuf, df->tag, val.v_u64);
313	break;
314
315      case DMAP_TYPE_LONG:
316	if (val.v_i64)
317	  dmap_add_long(evbuf, df->tag, val.v_i64);
318	break;
319
320      case DMAP_TYPE_STRING:
321	if (strval)
322	  dmap_add_string(evbuf, df->tag, strval);
323	break;
324
325      case DMAP_TYPE_VERSION:
326      case DMAP_TYPE_LIST:
327	return;
328    }
329}
330
331
332void
333dmap_send_error(struct evhttp_request *req, char *container, char *errmsg)
334{
335  struct evbuffer *evbuf;
336  int len;
337  int ret;
338
339  evbuf = evbuffer_new();
340  if (!evbuf)
341    {
342      DPRINTF(E_LOG, L_DMAP, "Could not allocate evbuffer for DMAP error\n");
343
344      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
345      return;
346    }
347
348  len = 12 + 8 + 8 + strlen(errmsg);
349
350  ret = evbuffer_expand(evbuf, len);
351  if (ret < 0)
352    {
353      DPRINTF(E_LOG, L_DMAP, "Could not expand evbuffer for DMAP error\n");
354
355      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
356
357      evbuffer_free(evbuf);
358      return;
359    }
360
361  dmap_add_container(evbuf, container, len - 8);
362  dmap_add_int(evbuf, "mstt", 500);
363  dmap_add_string(evbuf, "msts", errmsg);
364
365  evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
366
367  evbuffer_free(evbuf);
368}
369
370
371int
372dmap_encode_file_metadata(struct evbuffer *songlist, struct evbuffer *song, struct db_media_file_info *dbmfi, const struct dmap_field **meta, int nmeta, int sort_tags, int force_wav)
373{
374  const struct dmap_field_map *dfm;
375  const struct dmap_field *df;
376  char **strval;
377  char *ptr;
378  int32_t val;
379  int want_mikd;
380  int want_asdk;
381  int i;
382  int ret;
383
384  want_mikd = 0;
385  want_asdk = 0;
386
387  i = -1;
388  while (1)
389    {
390      i++;
391
392      /* Specific meta tags requested (or default list) */
393      if (nmeta > 0)
394	{
395	  if (i == nmeta)
396	    break;
397
398	  df = meta[i];
399	  dfm = df->dfm;
400	}
401      /* No specific meta tags requested, send out everything */
402      else
403	{
404	  /* End of list */
405	  if (i == (sizeof(dmap_fields) / sizeof(dmap_fields[0])))
406	    break;
407
408	  df = &dmap_fields[i];
409	  dfm = dmap_fields[i].dfm;
410	}
411
412      /* Not in struct media_file_info */
413      if (dfm->mfi_offset < 0)
414	continue;
415
416      /* Will be prepended to the list */
417      if (dfm == &dfm_dmap_mikd)
418	{
419	  /* item kind */
420	  want_mikd = 1;
421	  continue;
422	}
423      else if (dfm == &dfm_dmap_asdk)
424	{
425	  /* data kind */
426	  want_asdk = 1;
427	  continue;
428	}
429
430      DPRINTF(E_DBG, L_DAAP, "Investigating %s\n", df->desc);
431
432      strval = (char **) ((char *)dbmfi + dfm->mfi_offset);
433
434      if (!(*strval) || (**strval == '\0'))
435	continue;
436
437      /* Here's one exception ... codectype (ascd) is actually an integer */
438      if (dfm == &dfm_dmap_ascd)
439	{
440	  dmap_add_literal(song, df->tag, *strval, 4);
441	  continue;
442	}
443
444      val = 0;
445
446      if (force_wav)
447	{
448	  switch (dfm->mfi_offset)
449	    {
450	      case dbmfi_offsetof(type):
451		ptr = "wav";
452		strval = &ptr;
453		break;
454
455	      case dbmfi_offsetof(bitrate):
456		val = 0;
457		ret = safe_atoi32(dbmfi->samplerate, &val);
458		if ((ret < 0) || (val == 0))
459		  val = 1411;
460		else
461		  val = (val * 8) / 250;
462
463		ptr = NULL;
464		strval = &ptr;
465		break;
466
467	      case dbmfi_offsetof(description):
468		ptr = "wav audio file";
469		strval = &ptr;
470		break;
471
472	      default:
473		break;
474	    }
475	}
476
477      dmap_add_field(song, df, *strval, val);
478
479      DPRINTF(E_DBG, L_DAAP, "Done with meta tag %s (%s)\n", df->desc, *strval);
480    }
481
482  if (sort_tags)
483    {
484      dmap_add_string(song, "assn", dbmfi->title_sort);
485      dmap_add_string(song, "assa", dbmfi->artist_sort);
486      dmap_add_string(song, "assu", dbmfi->album_sort);
487      dmap_add_string(song, "assl", dbmfi->album_artist_sort);
488
489      if (dbmfi->composer_sort)
490	dmap_add_string(song, "assc", dbmfi->composer_sort);
491    }
492
493  val = 0;
494  if (want_mikd)
495    val += 9;
496  if (want_asdk)
497    val += 9;
498
499  dmap_add_container(songlist, "mlit", EVBUFFER_LENGTH(song) + val);
500
501  /* Prepend mikd & asdk if needed */
502  if (want_mikd)
503    {
504      /* dmap.itemkind must come first */
505      ret = safe_atoi32(dbmfi->item_kind, &val);
506      if (ret < 0)
507	val = 2; /* music by default */
508      dmap_add_char(songlist, "mikd", val);
509    }
510  if (want_asdk)
511    {
512      ret = safe_atoi32(dbmfi->data_kind, &val);
513      if (ret < 0)
514	val = 0;
515      dmap_add_char(songlist, "asdk", val);
516    }
517
518  ret = evbuffer_add_buffer(songlist, song);
519  if (ret < 0)
520    {
521      DPRINTF(E_LOG, L_DAAP, "Could not add song to song list\n");
522
523      return -1;
524    }
525
526  return 0;
527}
528