1/* MiniDLNA media server
2 * Copyright (C) 2014  NETGEAR
3 *
4 * This file is part of MiniDLNA.
5 *
6 * MiniDLNA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * MiniDLNA is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include <string.h>
19#include "clients.h"
20#include "minidlnatypes.h"
21#include "scanner.h"
22#include "upnpglobalvars.h"
23#include "containers.h"
24#include "log.h"
25
26#define NINETY_DAYS "7776000"
27
28const char *music_id = MUSIC_ID;
29const char *music_all_id = MUSIC_ALL_ID;
30const char *music_genre_id = MUSIC_GENRE_ID;
31const char *music_artist_id = MUSIC_ARTIST_ID;
32const char *music_album_id = MUSIC_ALBUM_ID;
33const char *music_plist_id = MUSIC_PLIST_ID;
34const char *music_dir_id = MUSIC_DIR_ID;
35const char *video_all_id = VIDEO_ALL_ID;
36const char *video_dir_id = VIDEO_DIR_ID;
37const char *image_all_id = IMAGE_ALL_ID;
38const char *image_date_id = IMAGE_DATE_ID;
39const char *image_camera_id = IMAGE_CAMERA_ID;
40const char *image_dir_id = IMAGE_DIR_ID;
41
42struct magic_container_s magic_containers[] =
43{
44	/* Alternate root container */
45	{ NULL,
46	  "0",
47	  &runtime_vars.root_container,
48	  NULL,
49	  "0",
50	  NULL,
51	  NULL,
52	  NULL,
53	  NULL,
54	  -1,
55	  0,
56	},
57
58	/* Recent 50 audio items */
59	{ "Recently Added",
60	  "1$FF0",
61	  NULL,
62	  "\"1$FF0$\" || OBJECT_ID",
63	  "\"1$FF0\"",
64	  "o.OBJECT_ID",
65	  "(select null from DETAILS where MIME glob 'a*' and timestamp > (strftime('%s','now') - "NINETY_DAYS") limit 50)",
66	  "MIME glob 'a*' and REF_ID is NULL and timestamp > (strftime('%s','now') - "NINETY_DAYS")",
67	  "order by TIMESTAMP DESC",
68	  50,
69	  0,
70	},
71
72	/* Recent 50 video items */
73	{ "Recently Added",
74	  "2$FF0",
75	  NULL,
76	  "\"2$FF0$\" || OBJECT_ID",
77	  "\"2$FF0\"",
78	  "o.OBJECT_ID",
79	  "(select null from DETAILS where MIME glob 'v*' and timestamp > (strftime('%s','now') - "NINETY_DAYS") limit 50)",
80	  "MIME glob 'v*' and REF_ID is NULL and timestamp > (strftime('%s','now') - "NINETY_DAYS")",
81	  "order by TIMESTAMP DESC",
82	  50,
83	  0,
84	},
85
86	/* Recent 50 image items */
87	{ "Recently Added",
88	  "3$FF0",
89	  NULL,
90	  "\"3$FF0$\" || OBJECT_ID",
91	  "\"3$FF0\"",
92	  "o.OBJECT_ID",
93	  "(select null from DETAILS where MIME glob 'i*' and timestamp > (strftime('%s','now') - "NINETY_DAYS") limit 50)",
94	  "MIME glob 'i*' and REF_ID is NULL and timestamp > (strftime('%s','now') - "NINETY_DAYS")",
95	  "order by TIMESTAMP DESC",
96	  50,
97	  0,
98	},
99
100	/* Microsoft PlaysForSure containers */
101	{ NULL, "4", &music_all_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
102	{ NULL, "5", &music_genre_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
103	{ NULL, "6", &music_artist_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
104	{ NULL, "7", &music_album_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
105	{ NULL, "8", &video_all_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
106	{ NULL, "B", &image_all_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
107	{ NULL, "C", &image_date_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
108	{ NULL, "F", &music_plist_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
109	{ NULL, "14", &music_dir_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
110	{ NULL, "15", &video_dir_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
111	{ NULL, "16", &image_dir_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
112	{ NULL, "D2", &image_camera_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS },
113
114	/* Jump straight to Music on audio-only devices */
115	{ NULL, "0", &music_id, NULL, "0", NULL, NULL, NULL, NULL, -1, FLAG_AUDIO_ONLY },
116
117	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0 }
118};
119
120struct magic_container_s *
121in_magic_container(const char *id, int flags, const char **real_id)
122{
123	size_t len;
124	int i;
125
126	for (i = 0; magic_containers[i].objectid_match; i++)
127	{
128		if (magic_containers[i].required_flags && !(flags & magic_containers[i].required_flags))
129			continue;
130		if (magic_containers[i].objectid && !(*magic_containers[i].objectid))
131			continue;
132		DPRINTF(E_MAXDEBUG, L_HTTP, "Checking magic container %d [%s]\n", i, magic_containers[i].objectid_match);
133		len = strlen(magic_containers[i].objectid_match);
134		if (strncmp(id, magic_containers[i].objectid_match, len) == 0)
135		{
136 			if (*(id+len) == '$')
137				*real_id = id+len+1;
138 			else if (*(id+len) == '\0')
139				*real_id = id;
140			else
141				continue;
142			DPRINTF(E_DEBUG, L_HTTP, "Found magic container %d [%s]\n", i, magic_containers[i].objectid_match);
143			return &magic_containers[i];
144		}
145	}
146
147	return NULL;
148}
149
150struct magic_container_s *
151check_magic_container(const char *id, int flags)
152{
153	int i;
154
155	for (i = 0; magic_containers[i].objectid_match; i++)
156	{
157		if (magic_containers[i].required_flags && !(flags & magic_containers[i].required_flags))
158			continue;
159		if (magic_containers[i].objectid && !(*magic_containers[i].objectid))
160			continue;
161		DPRINTF(E_MAXDEBUG, L_HTTP, "Checking magic container %d [%s]\n", i, magic_containers[i].objectid_match);
162		if (strcmp(id, magic_containers[i].objectid_match) == 0)
163		{
164			DPRINTF(E_DEBUG, L_HTTP, "Found magic container %d [%s]\n", i, magic_containers[i].objectid_match);
165			return &magic_containers[i];
166		}
167	}
168
169	return NULL;
170}
171