451 lines
10 KiB
C++
451 lines
10 KiB
C++
/*
|
|
* cfgparser.c : GeeXboX uShare config file parser.
|
|
* Originally developped for the GeeXboX project.
|
|
* Copyright (C) 2005-2007 Alexis Saettler <asbin@asbin.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <stdbool.h>
|
|
#include <limits.h>
|
|
|
|
#include "config.h"
|
|
#include "gettext.h"
|
|
#include "cfgparser.h"
|
|
#include "ushare.h"
|
|
#include "trace.h"
|
|
#include "osdep.h"
|
|
|
|
#define USHARE_DIR_DELIM ","
|
|
|
|
static bool
|
|
ignore_line (const char *line)
|
|
{
|
|
int i;
|
|
size_t len;
|
|
|
|
/* commented line */
|
|
if (line[0] == '#' )
|
|
return true;
|
|
|
|
len = strlen (line);
|
|
|
|
for (i = 0 ; i < (int) len ; i++ )
|
|
if (line[i] != ' ' && line[i] != '\t' && line[i] != '\n')
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static char *
|
|
strdup_trim (const char *s)
|
|
{
|
|
size_t begin, end;
|
|
char *r = NULL;
|
|
|
|
if (!s)
|
|
return NULL;
|
|
|
|
end = strlen (s) - 1;
|
|
|
|
for (begin = 0 ; begin < end ; begin++)
|
|
if (s[begin] != ' ' && s[begin] != '\t' && s[begin] != '"')
|
|
break;
|
|
|
|
for (; begin < end ; end--)
|
|
if (s[end] != ' ' && s[end] != '\t' && s[end] != '"' && s[end] != '\n')
|
|
break;
|
|
|
|
r = strndup (s + begin, end - begin + 1);
|
|
|
|
return r;
|
|
}
|
|
|
|
static void
|
|
ushare_set_name (struct ushare_t *ut, const char *name)
|
|
{
|
|
if (!ut || !name)
|
|
return;
|
|
|
|
if (ut->name)
|
|
{
|
|
free (ut->name);
|
|
ut->name = NULL;
|
|
}
|
|
|
|
ut->name = strdup_trim (name);
|
|
}
|
|
|
|
static void
|
|
ushare_set_interface (struct ushare_t *ut, const char *iface)
|
|
{
|
|
if (!ut || !iface)
|
|
return;
|
|
|
|
if (ut->interface)
|
|
{
|
|
free (ut->interface);
|
|
ut->interface = NULL;
|
|
}
|
|
|
|
ut->interface = strdup_trim (iface);
|
|
}
|
|
|
|
static void
|
|
ushare_add_contentdir (struct ushare_t *ut, const char *dir)
|
|
{
|
|
if (!ut || !dir)
|
|
return;
|
|
|
|
ut->contentlist = content_add (ut->contentlist, dir);
|
|
}
|
|
|
|
static void
|
|
ushare_set_cfg_file (struct ushare_t *ut, const char *file)
|
|
{
|
|
if (!ut || !file)
|
|
return;
|
|
|
|
ut->cfg_file = strdup (file);
|
|
}
|
|
|
|
static void
|
|
ushare_set_dir (struct ushare_t *ut, const char *dirlist)
|
|
{
|
|
char *x = NULL, *token = NULL;
|
|
char *m_buffer = NULL, *buffer;
|
|
|
|
if (!ut || !dirlist)
|
|
return;
|
|
|
|
x = strdup_trim (dirlist);
|
|
if (x)
|
|
{
|
|
m_buffer = (char*) malloc (strlen (x) * sizeof (char));
|
|
if (m_buffer)
|
|
{
|
|
buffer = m_buffer;
|
|
token = strtok_r (x, USHARE_DIR_DELIM, &buffer);
|
|
while (token)
|
|
{
|
|
ushare_add_contentdir (ut, token);
|
|
token = strtok_r (NULL, USHARE_DIR_DELIM, &buffer);
|
|
}
|
|
free (m_buffer);
|
|
}
|
|
free (x);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ushare_set_port (struct ushare_t *ut, const char *port)
|
|
{
|
|
if (!ut || !port)
|
|
return;
|
|
|
|
ut->port = atoi (port);
|
|
if (ut->port < 49152)
|
|
{
|
|
fprintf (stderr,
|
|
_("Warning: port doesn't fit IANA port assignements.\n"));
|
|
|
|
fprintf (stderr, _("Warning: Only Dynamic or Private Ports can be used "
|
|
"(from 49152 through 65535)\n"));
|
|
ut->port = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ushare_set_telnet_port (struct ushare_t *ut, const char *port)
|
|
{
|
|
if (!ut || !port)
|
|
return;
|
|
|
|
ut->telnet_port = atoi (port);
|
|
}
|
|
|
|
static void
|
|
ushare_use_web (struct ushare_t *ut, const char *val)
|
|
{
|
|
if (!ut || !val)
|
|
return;
|
|
|
|
ut->use_presentation = (!strcmp (val, "yes")) ? true : false;
|
|
}
|
|
|
|
static void
|
|
ushare_use_telnet (struct ushare_t *ut, const char *val)
|
|
{
|
|
if (!ut || !val)
|
|
return;
|
|
|
|
ut->use_telnet = (!strcmp (val, "yes")) ? true : false;
|
|
}
|
|
|
|
static void
|
|
ushare_use_xbox (struct ushare_t *ut, const char *val)
|
|
{
|
|
if (!ut || !val)
|
|
return;
|
|
|
|
ut->xbox360 = (!strcmp (val, "yes")) ? true : false;
|
|
}
|
|
|
|
static void
|
|
ushare_use_dlna (struct ushare_t *ut, const char *val)
|
|
{
|
|
if (!ut || !val)
|
|
return;
|
|
|
|
#ifdef HAVE_DLNA
|
|
ut->dlna_enabled = (!strcmp (val, "yes")) ? true : false;
|
|
#endif /* HAVE_DLNA */
|
|
}
|
|
|
|
static void
|
|
ushare_set_override_iconv_err (struct ushare_t *ut, const char *arg)
|
|
{
|
|
if (!ut)
|
|
return;
|
|
|
|
ut->override_iconv_err = false;
|
|
|
|
if (!strcasecmp (arg, "yes")
|
|
|| !strcasecmp (arg, "true")
|
|
|| !strcmp (arg, "1"))
|
|
ut->override_iconv_err = true;
|
|
}
|
|
|
|
static u_configline_t configline[] = {
|
|
{ USHARE_NAME, ushare_set_name },
|
|
{ USHARE_IFACE, ushare_set_interface },
|
|
{ USHARE_PORT, ushare_set_port },
|
|
{ USHARE_TELNET_PORT, ushare_set_telnet_port },
|
|
{ USHARE_DIR, ushare_set_dir },
|
|
{ USHARE_OVERRIDE_ICONV_ERR, ushare_set_override_iconv_err },
|
|
{ USHARE_ENABLE_WEB, ushare_use_web },
|
|
{ USHARE_ENABLE_TELNET, ushare_use_telnet },
|
|
{ USHARE_ENABLE_XBOX, ushare_use_xbox },
|
|
{ USHARE_ENABLE_DLNA, ushare_use_dlna },
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
static void
|
|
parse_config_line (struct ushare_t *ut, const char *line,
|
|
u_configline_t *configline)
|
|
{
|
|
char *s = NULL;
|
|
|
|
s = strchr (line, '=');
|
|
if (s && s[1] != '\0')
|
|
{
|
|
int i;
|
|
for (i=0 ; configline[i].name ; i++)
|
|
{
|
|
if (!strncmp (line, configline[i].name, strlen (configline[i].name)))
|
|
{
|
|
configline[i].set_var (ut, s + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
parse_config_file (struct ushare_t *ut)
|
|
{
|
|
char filename[PATH_MAX];
|
|
FILE *conffile;
|
|
char *line = NULL;
|
|
size_t size = 0;
|
|
ssize_t read;
|
|
|
|
if (!ut)
|
|
return -1;
|
|
|
|
if (!ut->cfg_file)
|
|
snprintf (filename, PATH_MAX, "%s/%s", SYSCONFDIR, USHARE_CONFIG_FILE);
|
|
else
|
|
snprintf (filename, PATH_MAX, "%s", ut->cfg_file);
|
|
|
|
conffile = fopen (filename, "r");
|
|
if (!conffile)
|
|
return -1;
|
|
|
|
while ((read = getline (&line, &size, conffile)) != -1)
|
|
{
|
|
if (ignore_line (line))
|
|
continue;
|
|
|
|
if (line[read-1] == '\n')
|
|
line[read-1] = '\0';
|
|
|
|
while (line[0] == ' ' || line[0] == '\t')
|
|
line++;
|
|
|
|
parse_config_line (ut, line, configline);
|
|
}
|
|
|
|
fclose (conffile);
|
|
|
|
if (line)
|
|
free (line);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
display_usage (void)
|
|
{
|
|
display_headers ();
|
|
printf ("\n");
|
|
printf (_("Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c directory]...]\n"));
|
|
printf (_("Options:\n"));
|
|
printf (_(" -n, --name=NAME\tSet UPnP Friendly Name (default is '%s')\n"),
|
|
DEFAULT_USHARE_NAME);
|
|
printf (_(" -i, --interface=IFACE\tUse IFACE Network Interface (default is '%s')\n"),
|
|
DEFAULT_USHARE_IFACE);
|
|
printf (_(" -f, --cfg=FILE\t\tConfig file to be used\n"));
|
|
printf (_(" -p, --port=PORT\tForces the HTTP server to run on PORT\n"));
|
|
printf (_(" -q, --telnet-port=PORT\tForces the TELNET server to run on PORT\n"));
|
|
printf (_(" -c, --content=DIR\tShare the content of DIR directory\n"));
|
|
printf (_(" -w, --no-web\t\tDisable the control web page (enabled by default)\n"));
|
|
printf (_(" -t, --no-telnet\tDisable the TELNET control (enabled by default)\n"));
|
|
printf (_(" -o, --override-iconv-err\tIf iconv fails parsing name, still add to media contents (hoping the renderer can handle it)\n"));
|
|
printf (_(" -v, --verbose\t\tSet verbose display\n"));
|
|
printf (_(" -x, --xbox\t\tUse XboX 360 compliant profile\n"));
|
|
#ifdef HAVE_DLNA
|
|
printf (_(" -d, --dlna\t\tUse DLNA compliant profile (PlayStation3 needs this)\n"));
|
|
#endif /* HAVE_DLNA */
|
|
printf (_(" -D, --daemon\t\tRun as a daemon\n"));
|
|
printf (_(" -V, --version\t\tDisplay the version of uShare and exit\n"));
|
|
printf (_(" -h, --help\t\tDisplay this help\n"));
|
|
}
|
|
|
|
int
|
|
parse_command_line (struct ushare_t *ut, int argc, char **argv)
|
|
{
|
|
int c, index;
|
|
char short_options[] = "VhvDowtxdn:i:p:q:c:f:";
|
|
struct option long_options [] = {
|
|
{"version", no_argument, 0, 'V' },
|
|
{"help", no_argument, 0, 'h' },
|
|
{"verbose", no_argument, 0, 'v' },
|
|
{"daemon", no_argument, 0, 'D' },
|
|
{"override-iconv-err", no_argument, 0, 'o' },
|
|
{"name", required_argument, 0, 'n' },
|
|
{"interface", required_argument, 0, 'i' },
|
|
{"port", required_argument, 0, 'p' },
|
|
{"telnet-port", required_argument, 0, 'q' },
|
|
{"content", required_argument, 0, 'c' },
|
|
{"no-web", no_argument, 0, 'w' },
|
|
{"no-telnet", no_argument, 0, 't' },
|
|
{"xbox", no_argument, 0, 'x' },
|
|
#ifdef HAVE_DLNA
|
|
{"dlna", no_argument, 0, 'd' },
|
|
#endif /* HAVE_DLNA */
|
|
{"cfg", required_argument, 0, 'f' },
|
|
{0, 0, 0, 0 }
|
|
};
|
|
|
|
/* command line argument processing */
|
|
while (true)
|
|
{
|
|
c = getopt_long (argc, argv, short_options, long_options, &index);
|
|
|
|
if (c == EOF)
|
|
break;
|
|
|
|
switch (c)
|
|
{
|
|
case 0:
|
|
/* opt = long_options[index].name; */
|
|
break;
|
|
|
|
case '?':
|
|
case 'h':
|
|
display_usage ();
|
|
return -1;
|
|
|
|
case 'V':
|
|
display_headers ();
|
|
return -1;
|
|
|
|
case 'v':
|
|
ut->verbose = true;
|
|
break;
|
|
|
|
case 'D':
|
|
ut->daemon = true;
|
|
break;
|
|
|
|
case 'o':
|
|
ut->override_iconv_err = true;
|
|
break;
|
|
|
|
case 'n':
|
|
ushare_set_name (ut, optarg);
|
|
break;
|
|
|
|
case 'i':
|
|
ushare_set_interface (ut, optarg);
|
|
break;
|
|
|
|
case 'p':
|
|
ushare_set_port (ut, optarg);
|
|
break;
|
|
|
|
case 'q':
|
|
ushare_set_telnet_port (ut, optarg);
|
|
break;
|
|
|
|
case 'c':
|
|
ushare_add_contentdir (ut, optarg);
|
|
break;
|
|
|
|
case 'w':
|
|
ut->use_presentation = false;
|
|
break;
|
|
|
|
case 't':
|
|
ut->use_telnet = false;
|
|
break;
|
|
|
|
case 'x':
|
|
ut->xbox360 = true;
|
|
break;
|
|
|
|
#ifdef HAVE_DLNA
|
|
case 'd':
|
|
ut->dlna_enabled = true;
|
|
break;
|
|
#endif /* HAVE_DLNA */
|
|
|
|
case 'f':
|
|
ushare_set_cfg_file (ut, optarg);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|