mod_musicindex  1.4.1
config.c
Go to the documentation of this file.
1 /*
2  * config.c
3  * mod_musicindex
4  *
5  * $Id: config.c 1001 2012-07-30 18:45:20Z varenet $
6  *
7  * Created by Thibaut VARENE on Thu Mar 20 2003.
8  * Copyright (c) 2003-2006 Regis BOUDIN
9  * Copyright (c) 2003-2005,2007,2009,2012 Thibaut VARENE
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 2.1,
13  * as published by the Free Software Foundation.
14  *
15  */
16 
36 #include "config.h"
37 #include "sort.h"
38 
39 #ifdef ENABLE_CACHE_FILE
40 #include "cache-file.h"
41 #endif
42 #ifdef ENABLE_CACHE_MYSQL
43 #include "cache-mysql.h"
44 #endif
45 
46 #ifdef HAVE_STRING_H
47 #include <string.h>
48 #endif
49 #ifdef HAVE_STDLIB_H
50 #include <stdlib.h> /* atoi */
51 #endif
52 
53 typedef int (*cache_backend_setup)(cmd_parms *cmd, const char *setup_string, mu_config *const conf);
54 
56 static const cache_backend_setup const cache_setups[] = {
57 #ifdef ENABLE_CACHE_FILE
59 #endif
60 #ifdef ENABLE_CACHE_MYSQL
62 #endif
63  NULL
64 };
65 
67 static const unsigned char const default_order[] = {
68  SB_ALBUM,
69  SB_POSN,
70  SB_TRACK,
71  SB_ARTIST,
72  SB_TITLE,
73  SB_LENGTH,
74  SB_BITRATE,
75  SB_FREQ,
78  SB_URI,
79 };
80 
82 static const unsigned char const default_fields[] = {
83  SB_TITLE,
84  SB_ARTIST,
85  SB_ALBUM,
86  SB_LENGTH,
87  SB_BITRATE,
88 };
89 
90 static const char const default_directory[] = "/musicindex";
91 static const char const default_rootname[] = "Music";
92 static const char const default_css[] = "musicindex.css";
108 void *create_musicindex_config(apr_pool_t *p, char *dummy)
109 {
110  mu_config *const new = (mu_config *)apr_pcalloc(p, sizeof(mu_config));
111 
112  memcpy(new->fields, default_fields, sizeof(default_fields));
113  memcpy(new->order, default_order, sizeof(default_order));
114 
115  new->title = default_rootname;
116  new->directory = default_directory;
117  new->css = default_css;
118 
119  new->cookie_life = CONF_COOKIE_LIFE;
120  new->dir_per_line = CONF_DIRPERLINE;
121 
122  return (void *)new;
123 }
124 
161 void *merge_musicindex_configs(apr_pool_t *p, void *basev, void *addv)
162 {
163  mu_config *const restrict new = (mu_config *)apr_pcalloc(p, sizeof(mu_config));
164  mu_config *const restrict base = (mu_config *)basev;
165  mu_config *const restrict add = (mu_config *)addv;
166 
167  if (!base->sets) {
168  /* basev is empty we can ignore it */
169  memcpy(new->order, add->order, sizeof(add->order));
170  memcpy(new->fields, add->fields, sizeof(add->fields));
171  new->title = add->title;
172  new->css = add->css;
173  new->iceserver = add->iceserver;
174  new->cookie_life = add->cookie_life;
175  new->rss_items = add->rss_items;
176  new->dir_per_line = add->dir_per_line;
177  new->cache = add->cache;
178  new->cache_setup = add->cache_setup;
179  }
180  else {
181  /* we need to merge the configurations */
182  if (add->sets & CF_ORDER)
183  memcpy(new->order, add->order, sizeof(add->order));
184  else
185  memcpy(new->order, base->order, sizeof(base->order));
186 
187  if (add->sets & CF_FIELDS)
188  memcpy(new->fields, add->fields, sizeof(add->fields));
189  else
190  memcpy(new->fields, base->fields, sizeof(base->fields));
191 
192  new->title = (add->sets & CF_TITLE) ? add->title : base->title;
193  new->css = (add->sets & CF_CSS) ? add->css : base->css;
194  new->iceserver = (add->sets & CF_ICES) ? add->iceserver : base->iceserver;
195  new->cookie_life = (add->sets & CF_CKLF) ? add->cookie_life : base->cookie_life;
196  new->rss_items = (add->sets & CF_RSS) ? add->rss_items : base->rss_items;
197  new->dir_per_line = (add->sets & CF_DPL) ? add->dir_per_line : base->dir_per_line;
198 
199  if (add->sets & CF_CACHE) {
200  new->cache = add->cache;
201  new->cache_setup = add->cache_setup;
202  } else {
203  new->cache = base->cache;
204  new->cache_setup = base->cache_setup;
205  }
206  }
207 
208  new->options = base->options | add->options;
209  new->options &= ~(base->options_not | add->options_not);
210 
211  new->options_not = base->options_not | add->options_not;
212  new->options_not &= ~(base->options | add->options);
213 
214  /* directory is currently non-modifiable */
215  new->directory = default_directory;
216 
217  /* flag new as containing meaningful data */
218  new->sets |= CF_MERGED;
219 
220  return new;
221 }
222 
223 static const struct {
224  const char *const string;
225  const char value;
226 } const options[] = {
227  {"track", SB_TRACK},
228  {"disc", SB_POSN},
229  {"length", SB_LENGTH},
230  {"bitrate", SB_BITRATE},
231  {"freq", SB_FREQ},
232  {"artist", SB_ARTIST},
233  {"album", SB_ALBUM},
234  {"title", SB_TITLE},
235  {"filename", SB_FILENAME},
236  {"date", SB_DATE},
237  {"filetype", SB_FILETYPE},
238  {"genre", SB_GENRE},
239  {"uri", SB_URI},
240  {"size", SB_SIZE},
241  {NULL, 0}
242 };
243 
244 static unsigned short sort_or_fields(cmd_parms *cmd, unsigned char * restrict list, const char *optstr)
245 {
246  const char *r;
247  register unsigned short i = 0, j;
248 
249  while (optstr[0] && (i < SB_MAX)) {
250  r = ap_getword_conf(cmd->temp_pool, &optstr);
251  for (j=0; options[j].string; j++) {
252  if (!strcasecmp(r, options[j].string)) {
253  list[i++] = options[j].value;
254  break;
255  }
256  }
257  }
258  list[i] = 0;
259 
260  return i;
261 }
262 
263 static const char *sort_order(cmd_parms *cmd, void *d, const char *optstr)
264 {
265  mu_config *const d_cfg = (mu_config *)d;
266  unsigned short i = sort_or_fields(cmd, d_cfg->order, optstr);
267  d_cfg->order[i] = SB_URI; /* fallback on URI sort */
268  d_cfg->sets |= CF_ORDER;
269  return NULL;
270 }
271 
272 static const char *set_fields(cmd_parms *cmd, void *d, const char *optstr)
273 {
274  mu_config *const d_cfg = (mu_config *)d;
275  sort_or_fields(cmd, d_cfg->fields, optstr);
276  d_cfg->sets |= CF_FIELDS;
277  return NULL;
278 }
279 
291 static const char *basic_config(cmd_parms *cmd, void *d, const char *optstr)
292 {
293  const char *r;
294  mu_config *const cfg = (mu_config *)d;
295 
296  while (optstr[0] != '\0') {
297  int enable = 1;
298  unsigned short flag = 0;
299  r = ap_getword_conf(cmd->temp_pool, &optstr);
300 
301  /* Should we enable or disable ? Is there a +/- prefix ? */
302  if ( *r == '-' ) {
303  enable = 0;
304  r++;
305  } else if (*r == '+') {
306  r++;
307  }
308 
309  /* Which option are we talking about ? */
310  if (strcmp(r, "On") == 0) {
311  enable = 1;
312  flag = MI_ACTIVE;
313  } else if (strcmp(r, "Off") == 0) {
314  enable = 0;
315  flag = MI_ACTIVE;
316  } else if (strcmp(r, "Stream") == 0) {
317  flag = MI_ALLOWSTREAM;
318  } else if (strcmp(r, "Download") == 0) {
319  flag = MI_ALLOWDWNLD;
320  } else if (strcmp(r, "Search") == 0) {
321  flag = MI_ALLOWSEARCH;
322 #ifdef ENABLE_OUTPUT_ARCHIVE
323  } else if (strcmp(r, "Tarball") == 0) {
324  flag = MI_ALLOWTARBALL;
325 #endif
326  } else if (strcmp(r, "Rss") == 0) {
327  if (enable == 1)
328  cfg->rss_items = CONF_RSS_ITEMS;
329  else {
330  cfg->rss_items = -1;
331  }
332  }
333 
334  /* Have this done in one place instead of five */
335  if (flag != 0) {
336  if (enable == 1) {
337  cfg->options |= flag;
338  cfg->options_not &= ~flag;
339  } else {
340  cfg->options &= ~flag;
341  cfg->options_not |= flag;
342  }
343  }
344  }
345 
346  return NULL;
347 }
348 
360 static const char *set_cache_uri(cmd_parms *cmd, void *d, const char *optstr)
361 {
362  mu_config *const d_cfg = (mu_config *)d;
363  int i, ret = 1;
364 
365  for (i = 0; (ret != 0) && (cache_setups[i] != NULL); i++)
366  ret = cache_setups[i](cmd, optstr, d_cfg);
367 
368  d_cfg->sets |= CF_CACHE;
369  return NULL;
370 }
371 
383 static const char *set_page_title(cmd_parms *cmd, void *d, const char *optstr)
384 {
385  mu_config *const d_cfg = (mu_config *)d;
386  if ((optstr == NULL) || (optstr[0] == '\0'))
387  d_cfg->title = NULL;
388  else
389  d_cfg->title = apr_pstrdup(cmd->pool, optstr);
390  d_cfg->sets |= CF_TITLE;
391  return NULL;
392 }
393 
404 static const char *set_ice_server(cmd_parms *cmd, void *d, const char *optstr)
405 {
406  mu_config *const d_cfg = (mu_config *)d;
407  d_cfg->iceserver = apr_pstrdup(cmd->pool, optstr);
408  d_cfg->sets |= CF_ICES;
409  return NULL;
410 }
411 
422 static const char *set_css_default(cmd_parms *cmd, void *d, const char *optstr)
423 {
424  mu_config *const d_cfg = (mu_config *)d;
425  d_cfg->css = apr_pstrdup(cmd->pool, optstr);
426  d_cfg->sets |= CF_CSS;
427  return NULL;
428 }
429 
441 static const char *set_cookie_life(cmd_parms *cmd, void *d, const char *optstr)
442 {
443  mu_config *const d_cfg = (mu_config *)d;
444  d_cfg->cookie_life = atoi(optstr);
445  d_cfg->sets |= CF_CKLF;
446  return NULL;
447 }
448 
459 static const char *set_dirperline(cmd_parms *cmd, void *d, const char *optstr)
460 {
461  mu_config *const d_cfg = (mu_config *)d;
462  d_cfg->dir_per_line = (atoi(optstr) ? atoi(optstr) : CONF_DIRPERLINE);
463  d_cfg->sets |= CF_DPL;
464  return NULL;
465 }
466 
478 static const char *set_display(cmd_parms *cmd, void *d, const char *optstr)
479 {
480  mu_config *const cfg = (mu_config *)d;
481  if (strcmp(optstr, "RSS") == 0) {
482  cfg->options |= MI_RSS;
483  cfg->options &= ~MI_RECURSIVE;
484  cfg->order[0] = SB_MTIME;
485  cfg->order[1] = SB_URI;
486  cfg->rss_items = CONF_RSS_ITEMS; /* XXX necessary? */
487  cfg->sets |= (CF_ORDER | CF_RSS);
488  }
489  else if (strcmp(optstr, "HTML") == 0) {
490  cfg->options &= ~MI_RSS;
491  cfg->options_not |= MI_RSS;
492  memcpy(cfg->order, default_order, sizeof(default_order)); /* XXX necessary? */
493  /* cfg->sets |= CF_ORDER; */
494  }
495  return NULL;
496 }
497 
498 /* XXX if somebody puts a ACCESS_CONF setting in .htaccess, Apache triggers a 500 */
499 const command_rec musicindex_cmds[] = {
500  AP_INIT_RAW_ARGS("MusicIndex", basic_config, NULL, OR_INDEXES,
501  "can be : On/Off +/-Stream +/-Download +/-Search +/-Rss"),
502  AP_INIT_RAW_ARGS("MusicSortOrder", sort_order, NULL, OR_INDEXES,
503  "can be : title album artist track disc length bitrate filetype genre filename date uri"),
504  AP_INIT_RAW_ARGS("MusicFields", set_fields, NULL, OR_INDEXES,
505  "can be : title album artist track disc length bitrate filetype genre filename date"),
506  AP_INIT_RAW_ARGS("MusicIndexCache", set_cache_uri, NULL, ACCESS_CONF,
507  "Set the cache configuration string"),
508  AP_INIT_RAW_ARGS("MusicPageTitle", set_page_title, NULL, OR_INDEXES,
509  "Set the root title of the page."),
510  AP_INIT_TAKE1("MusicIceServer", set_ice_server, NULL, ACCESS_CONF,
511  "Set the icecast server address : [server.domain.org]:8000"),
512  AP_INIT_TAKE1("MusicDefaultCss", set_css_default, NULL, OR_INDEXES,
513  "Set the default CSS file"),
514  AP_INIT_TAKE1("MusicCookieLife", set_cookie_life, NULL, ACCESS_CONF,
515  "Set the lifetime (in seconds) of the cookie sent for custom playlists"),
516  AP_INIT_TAKE1("MusicDefaultDisplay", set_display, NULL, ACCESS_CONF,
517  "Set the default display returned by the module (HTML or RSS)"),
518  AP_INIT_TAKE1("MusicDirPerLine", set_dirperline, NULL, OR_INDEXES,
519  "Set the number of directories per line in the directory listing"),
520  {NULL}
521 };