ushare-1.1a/0000755000175000017500000000000010726763650011111 5ustar benbenushare-1.1a/AUTHORS0000644000175000017500000000155410726763650012166 0ustar benbenAuthor ====== Benjamin Zores With many contributions from : - Alexis Saettler - Amir Shalem - Rémi Turboult for some UPnP standard compliance check. - Bernd Loske for some buffer overrun fix. - Eric Tanguy for Fedora RPM build and startup scripts. - Julien Lincy for a better UPnP CDS respect and commercial UPnP players compliance. - Jonathan (no_dice at users.sourceforge.net) for large files support. - Mostafa Hosseini for XboX 360 compliance, several UPnP compliance fixes and basic 'Search' support. - Phil Chandler for RedBlack balanced tree sorting algorithm and some memory optimizations. - Navaho Gunleg for MacOSX build fix. - Sven Almgren for Telnet Control interface. Please send remarks, questions, bug reports to . ushare-1.1a/ChangeLog0000644000175000017500000001427310726763650012672 0ustar benben2007-12-09 Benjamin Zores * new public release (Version 1.1a). 2007-12-04 Benjamin Zores * new public release (Version 1.1). 2007-11-04 Benjamin Zores * much complete DLNA support through libdlna. 2007-07-30 Benjamin Zores * MacOSX build fix. 2007-07-05 Alexis Saettler * new public release (Version 1.0). 2007-06-26 Benjamin Zores * fix for XboX 360 file discovery (patch by Keith Brindley). 2007-06-25 Benjamin Zores * added support for DLNA (Digital Living Network Alliance), the wonderful closed-source marketing UPnP++ specification. uShare is now compliant with PlayStation 3 UPnP/DLNA Media Renderer. 2007-02-26 Alexis Saettler * new public release (Version 0.9.10). * fixed http 404 error which prevented ushare 0.9.9 release to work. 2007-02-25 Alexis Saettler * new public release (Version 0.9.9). * fixed bug with localization, use now --localedir configure's option to set location of .mo files. 2007-01-23 Benjamin Zores * make libupnp >= 1.4.2 a requirement. 2007-01-20 Benjamin Zores * added support for FreeBSD. 2007-01-19 Benjamin Zores * use a RedBlack balanced tree searching and sorting algorithm instead of the recursive one. It avoids recursive calls, takes less memory (perfect for embedded systems) and executes in more "constant time" than the logarithmic style. Original patch by Phil Chandler. * massive memory optimization (uShare now takes 75% less RAM ;-) only not using fixed size URL allocation buffer (a 16000+ files collection now only takes 5MB where it used to take 19MB). * improved search parsing and matching mechanism (patch by Mostafa Hosseini). XboX360 support is now complete. Please note that to stream video to the XboX, the console should be running dashboard version 2.0.4552.0 and only unprotected .wmv files are supported. 2007-01-14 Benjamin Zores * make libupnp >= 1.4.1 a requirement. * fixed support for 2GB+ files (see http://sourceforge.net/tracker/index.php?func=detail&aid=1634927&group_id=151880&atid=782410) * fixed support for XboX 360 (thanks to Mostafa Hosseini). * added basic support for 'Search' action. 2006-12-10 Alexis Saettler * new public release (Version 0.9.8). 2006-10-19 Alexis Saettler * add German translation (thanks to Robin H.). * fix filtering and browse capabilities : now uShare is conform to ContentDirectory:1 Service Template Standard. 2006-09-17 Alexis Saettler * add iso and bin mime types. * convert special xml characters to xml (like & => &) (reported by Frank Scholz). 2006-09-10 Alexis Saettler * Use sysconfdir (from configure) to set /etc destination * update init script to use lsb functions 2006-03-12 Benjamin Zores * new public release (Version 0.9.7) 2006-03-07 Benjamin Zores * modify configure.ac to check for functions in libupnp that only comes with releases >= 1.3.1 (previous versions of the library are buggy and should not be used). * added new Microsoft Registrar service which fakes the authorization required to be able to stream to MS compliant Media Renderers (i.e now usable with XboX 360 and probably others). 2006-02-27 Benjamin Zores * applied suggestions from Julien Lincy * UPnP CDS compliance fix when request count and index are 0. * removed the ':' characters from UDN anming convention (devices like the Roku SoundBridge M2000 Network Music Player do not support it). 2006-02-19 Benjamin Zores * new public release (Version 0.9.6) 2006-01-06 Benjamin Zores * added Fedora RPM build file (ushare.spec) and startup script. (patch by Eric Tanguy ) 2005-12-28 Benjamin Zores * can now specify on which port the HTTP server has to run. (useful for security and firewall issues). 2005-12-27 Benjamin Zores * fixed a potential buffer overrun when building DIDL messages. (patch by Bernd Loske ). 2005-12-19 Benjamin Zores * new public release (Version 0.9.5) 2005-12-17 Benjamin Zores * added UPnP presentation URL support. (you can now update or add contents through a web interface). 2005-12-10 Benjamin Zores * added support for subtitle file formats. * added support for DVD specific file formats. 2005-12-08 Benjamin Zores * new public bug-fix release (Version 0.9.4) * fixed some memleaks. * avoid having empty shared directory name (crash with djmount, thanks to Remi Turboult for reporting it). * fixed handling of non-absolute content directories paths. 2005-11-23 Alexis Saettler * add logging with syslog support, in daemon mode. 2005-11-20 Benjamin Zores * new public bug-fix release (Version 0.9.3) * Added verbose mode. * Read configuration from /etc/ushare.conf configuration file. * Support for daemon mode. * Better MIME types handling. * Support for new multimedia files extensions. * Rewrite of some string buffer and integer manipulation tools. 2005-11-16 Alexis Saettler * modify -c parameter habdle, to allow multiple shared directories. 2005-11-13 Benjamin Zores * new public bug-fix release (Version 0.9.2) 2005-11-13 Benjamin Zores * improved UPnP compliance with Browse RequestedCount flag. * fixed some UPnP Object ID sent in Browse messages. 2005-11-10 Benjamin Zores * new public release (Version 0.9.1) 2005-11-08 Alexis Saettler * Prepare uShare for internationalization * Add French localization * Add support of iconv, for UTF-8 filenames conversions 2005-10-29 Alexis Saettler * Added Debian package building scripts 2005-10-25 Benjamin Zores * First public release (Version 0.9.0) ushare-1.1a/configure0000755000175000017500000004271710726763650013033 0ustar benben#!/bin/sh # # uShare configure script - (c) 2007 Benjamin Zores # # (fully inspirated from ffmpeg configure script, thanks to Fabrice Bellard) # # make sure we are running under a compatible shell unset foo (: ${foo%%bar}) 2>/dev/null && ! (: ${foo?}) 2>/dev/null if test "$?" != 0; then if test "x$USHARE_CONFIGURE_EXEC" = x; then USHARE_CONFIGURE_EXEC=1 export USHARE_CONFIGURE_EXEC exec bash "$0" "$@" exec ksh "$0" "$@" exec /usr/xpg4/bin/sh "$0" "$@" fi echo "No compatible shell script interpreter found." exit 1 fi show_help(){ echo "Usage: configure [options]" echo "Options: [defaults in brackets after descriptions]" echo echo "Standard options:" echo " --help print this message" echo " --log[=FILE|yes|no] log tests and output to FILE [config.log]" echo " --prefix=PREFIX install in PREFIX [$PREFIX]" echo " --bindir=DIR install binaries in DIR [PREFIX/bin]" echo " --sysconfdir=DIR configuration files DIR [PREFIX/etc]" echo " --localedir=DIR use locales from DIR [PREFIX/share/locale]" echo "" echo "Extended options:" echo " --enable-dlna enable DLNA support through libldna" echo " --disable-dlna disable DLNA support" echo " --disable-nls do not use Native Language Support" echo "" echo "Search paths:" echo " --with-libupnp-dir=DIR check for libupnp installed in DIR" echo " --with-libdlna-dir=DIR check for libdlna installed in DIR" echo "" echo "Advanced options (experts only):" echo " --enable-debug enable debugging symbols" echo " --disable-debug disable debugging symbols" echo " --disable-strip disable stripping of executables at installation" echo " --disable-optimize disable compiler optimization" echo " --cross-prefix=PREFIX use PREFIX for compilation tools [$cross_prefix]" echo " --cross-compile assume a cross-compiler is used" exit 1 } log(){ echo "$@" >>$logfile } log_file(){ log BEGIN $1 cat -n $1 >>$logfile log END $1 } echolog(){ log "$@" echo "$@" } clean(){ rm -f $TMPC $TMPO $TMPE $TMPS } die(){ echolog "$@" if enabled logging; then echo "See file \"$logfile\" produced by configure for more details." else echo "Rerun configure with logging enabled (do not use --log=no) for more details." fi clean exit 1 } enabled(){ eval test "x\$$1" = "xyes" } flags_saved(){ (: ${SAVE_CFLAGS?}) 2>/dev/null } save_flags(){ flags_saved && return SAVE_CFLAGS="$CFLAGS" SAVE_LDFLAGS="$LDFLAGS" SAVE_extralibs="$extralibs" } restore_flags(){ CFLAGS="$SAVE_CFLAGS" LDFLAGS="$SAVE_LDFLAGS" extralibs="$SAVE_extralibs" unset SAVE_CFLAGS unset SAVE_LDFLAGS unset SAVE_extralibs } temp_cflags(){ temp_append CFLAGS "$@" } temp_ldflags(){ temp_append LDFLAGS "$@" } temp_extralibs(){ temp_append extralibs "$@" } temp_append(){ local var var=$1 shift save_flags append_var "$var" "$@" } append_var(){ local var f var=$1 shift for f in $@; do if eval echo \$$var | grep -qv -e "$f"; then eval "$var=\"\$$var $f\"" fi done } append(){ local var var=$1 shift flags_saved && append_var "SAVE_$var" "$@" append_var "$var" "$@" } add_cflags(){ append CFLAGS "$@" } add_ldflags(){ append LDFLAGS "$@" } add_extralibs(){ append extralibs "$@" } add_clog(){ echo "#define $1 $2" >> $CONFIG_H } add_clog_str(){ echo "#define $1 \"$2\"" >> $CONFIG_H } check_cmd(){ log "$@" "$@" >>$logfile 2>&1 } check_cc(){ log check_cc "$@" cat >$TMPC log_file $TMPC check_cmd $cc $CFLAGS "$@" -c -o $TMPO $TMPC } check_cpp(){ log check_cpp "$@" cat >$TMPC log_file $TMPC check_cmd $cc $CFLAGS "$@" -E -o $TMPO $TMPC } check_ld(){ log check_ld "$@" check_cc || return check_cmd $cc $LDFLAGS "$@" -o $TMPE $TMPO $extralibs } check_exec(){ check_ld "$@" && { enabled cross_compile || $TMPE >>$logfile 2>&1; } } check_cflags(){ log check_cflags "$@" check_cc "$@" < int x; EOF } check_func(){ local func log check_func "$@" func=$1 shift check_ld "$@" <> $CONFIGFILE } expand_var(){ v="$1" while true; do eval t="$v" test "$t" = "$v" && break v="$t" done echo "$v" } # set temporary file name if test ! -z "$TMPDIR" ; then TMPDIR1="${TMPDIR}" elif test ! -z "$TEMPDIR" ; then TMPDIR1="${TEMPDIR}" else TMPDIR1="/tmp" fi TMPC="${TMPDIR1}/ushare-${RANDOM}-$$-${RANDOM}.c" TMPO="${TMPDIR1}/ushare-${RANDOM}-$$-${RANDOM}.o" TMPE="${TMPDIR1}/ushare-${RANDOM}-$$-${RANDOM}" TMPS="${TMPDIR1}/ushare-${RANDOM}-$$-${RANDOM}.S" CONFIGFILE="config.mak" CONFIG_H="config.h" ################################################# # set default parameters ################################################# logging="yes" logfile="config.log" PREFIX="/usr/local" bindir='${PREFIX}/bin' sysconfdir='${PREFIX}/etc' localedir='${PREFIX}/share/locale' dlna="no" nls="yes" cc="gcc" make="make" strip="strip" cpu=`uname -m` optimize="yes" debug="no" dostrip="yes" extralibs="" installstrip="-s" cross_compile="no" INSTALL="/usr/bin/install -c" VERSION="1.1a" system_name=`uname -s 2>&1` ################################################# # set cpu variable and specific cpu flags ################################################# case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="x86" ;; x86_64|amd64) cpu="x86" canon_arch="`$cc -dumpmachine | sed -e 's,\([^-]*\)-.*,\1,'`" if [ x"$canon_arch" = x"x86_64" -o x"$canon_arch" = x"amd64" ]; then if [ -z "`echo $CFLAGS | grep -- -m32`" ]; then cpu="x86_64" fi fi ;; # armv4l is a subset of armv5tel arm|armv4l|armv5tel) cpu="armv4l" ;; alpha) cpu="alpha" ;; "Power Macintosh"|ppc|ppc64|powerpc) cpu="powerpc" ;; mips|mipsel|IP*) cpu="mips" ;; sun4u|sparc64) cpu="sparc64" ;; sparc) cpu="sparc" ;; sh4) cpu="sh4" ;; parisc|parisc64) cpu="parisc" ;; s390|s390x) cpu="s390" ;; m68k) cpu="m68k" ;; ia64) cpu="ia64" ;; bfin) cpu="bfin" ;; *) cpu="unknown" ;; esac # OS test booleans functions issystem() { test "`echo $system_name | tr A-Z a-z`" = "`echo $1 | tr A-Z a-z`" } linux() { issystem "Linux" || issystem "uClinux" ; return "$?" ; } sunos() { issystem "SunOS" ; return "$?" ; } hpux() { issystem "HP-UX" ; return "$?" ; } irix() { issystem "IRIX" ; return "$?" ; } aix() { issystem "AIX" ; return "$?" ; } cygwin() { issystem "CYGWIN" ; return "$?" ; } freebsd() { issystem "FreeBSD" || issystem "GNU/kFreeBSD"; return "$?" ; } netbsd() { issystem "NetBSD" ; return "$?" ; } bsdos() { issystem "BSD/OS" ; return "$?" ; } openbsd() { issystem "OpenBSD" ; return "$?" ; } bsd() { freebsd || netbsd || bsdos || openbsd ; return "$?" ; } qnx() { issystem "QNX" ; return "$?" ; } darwin() { issystem "Darwin" ; return "$?" ; } gnu() { issystem "GNU" ; return "$?" ; } mingw32() { issystem "MINGW32" ; return "$?" ; } morphos() { issystem "MorphOS" ; return "$?" ; } amigaos() { issystem "AmigaOS" ; return "$?" ; } win32() { cygwin || mingw32 ; return "$?" ; } beos() { issystem "BEOS" ; return "$?" ; } ################################################# # check options ################################################# for opt do optval="${opt#*=}" case "$opt" in --log) ;; --log=*) logging="$optval" ;; --prefix=*) PREFIX="$optval"; force_prefix=yes ;; --bindir=*) bindir="$optval"; ;; --sysconfdir=*) sysconfdir="$optval"; ;; --localedir=*) localedir="$optval"; ;; --with-libupnp-dir=*) libupnpdir="$optval"; ;; --with-libdlna-dir=*) libdlnadir="$optval"; ;; --disable-nls) nls="no" ;; --enable-dlna) dlna="yes" ;; --disable-dlna) dlna="no" ;; --enable-debug) debug="yes" ;; --disable-debug) debug="no" ;; --disable-strip) dostrip="no" ;; --disable-optimize) optimize="no" ;; --cross-prefix=*) cross_prefix="$optval" ;; --cross-compile) cross_compile="yes" ;; --help) show_help ;; *) echo "Unknown option \"$opt\"." echo "See $0 --help for available options." exit 1 ;; esac done if [ -n "$cross_prefix" ]; then cross_compile="yes" cc="${cross_prefix}${cc}" strip="${cross_prefix}${strip}" else [ -n "$CC" ] && cc="$CC" [ -n "$STRIP" ] && strip="$STRIP" fi [ -n "$MAKE" ] && make="$MAKE" ################################################# # create logging file ################################################# if test "$logging" != no; then enabled logging || logfile="$logging" echo "# $0 $@" >$logfile set >>$logfile else logfile=/dev/null fi ################################################# # compiler sanity check ################################################# echolog "Checking for compiler available..." check_exec <&1 | grep version | grep Apple`"; then add_cflags "-faltivec" else add_cflags "-maltivec -mabi=altivec" fi fi fi check_header altivec.h && _altivec_h=yes || _altivec_h=no # check if our compiler supports Motorola AltiVec C API if enabled altivec; then if enabled _altivec_h; then inc_altivec_h="#include " else inc_altivec_h= fi check_cc < int main(void) { #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) return 0; #else #error no vector builtins #endif } EOF # test for mm3dnow.h test "$cpu" = "x86_64" && march=k8 || march=athlon check_cc -march=$march < int main(void) { __m64 b1; b1 = _m_pswapd(b1); _m_femms(); return 0; } EOF # --- # big/little-endian test if test "$cross_compile" = "no"; then check_ld < int main(int argc, char ** argv){ volatile uint32_t i=0x01234567; return (*((uint8_t*)(&i))) == 0x67; } EOF else # programs cannot be launched if cross compiling, so make a static guess if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then bigendian="yes" fi fi # add some useful compiler flags if supported add_cflags -I.. check_cflags -W check_cflags -Wall check_cflags -D_LARGEFILE_SOURCE check_cflags -D_FILE_OFFSET_BITS=64 check_cflags -D_REENTRANT linux && add_cflags -D_GNU_SOURCE ################################################# # check for debug symbols ################################################# if enabled debug; then add_cflags -g3 add_cflags -DHAVE_DEBUG dostrip=no fi if enabled optimize; then if test -n "`$cc -v 2>&1 | grep xlc`"; then add_cflags "-O5" add_ldflags "-O5" else add_cflags "-O3" fi fi ################################################# # check for locales (optional) ################################################# echolog "Checking for locales ..." check_header locale.h && add_cflags -DHAVE_LOCALE_H check_lib locale.h setlocale "" && add_cflags -DHAVE_SETLOCALE ################################################# # check for ifaddr (optional) ################################################# echolog "Checking for ifaddrs ..." check_lib ifaddrs.h getifaddrs "" && add_cflags -DHAVE_IFADDRS_H ################################################# # check for langinfo (optional) ################################################# echolog "Checking for langinfo ..." check_header langinfo.h && add_cflags -DHAVE_LANGINFO_H check_lib langinfo.h nl_langinfo "" && add_cflags -DHAVE_LANGINFO_CODESET ################################################# # check for iconv (optional) ################################################# echolog "Checking for iconv ..." check_lib iconv.h iconv "" && add_cflags -DHAVE_ICONV ################################################# # check for libupnp and friends (mandatory) ################################################# if [ -n "$libupnpdir" ]; then check_cflags -I$libupnpdir check_ldflags -L$libupnpdir fi echolog "Checking for libixml ..." check_lib upnp/ixml.h ixmlRelaxParser -lixml || die "Error, can't find libixml !" echolog "Checking for libthreadutil ..." check_lib upnp/ThreadPool.h ThreadPoolAdd "-lthreadutil -lpthread" || die "Error, can't find libthreadutil !" add_extralibs -lpthread libupnp_min_version="1.4.2" echolog "Checking for libupnp >= $libupnp_min_version ..." check_lib upnp/upnp.h UpnpSetMaxContentLength -lupnp || die "Error, can't find libupnp !" check_lib_version libupnp $libupnp_min_version || die "Error, libupnp < $libupnp_min_version !" add_cflags `pkg-config libupnp --cflags` add_extralibs `pkg-config libupnp --libs` ################################################# # check for libdlna (mandatory if enabled) ################################################# if test "$dlna" = "yes"; then libdlna_min_version="0.2.1" echolog "Checking for libdlna >= $libdlna_min_version ..." if [ -n "$libdlnadir" ]; then check_cflags -I$libdlnadir check_ldflags -L$libdlnadir fi check_lib dlna.h dlna_register_all_media_profiles -ldlna || die "Error, can't find libdlna (install it or use --disable-dlna) !" check_lib_version libdlna $libdlna_min_version || die "Error, libdlna < $libdlna_min_version !" add_cflags -DHAVE_DLNA add_cflags `pkg-config libdlna --cflags` add_extralibs `pkg-config libdlna --libs` fi ################################################# # logging result ################################################# echolog "" echolog "uShare: configure is OK" echolog " version $VERSION" echolog " using libupnp `pkg-config libupnp --modversion`" test $dlna = yes && echolog " using libdlna `pkg-config libdlna --modversion`" echolog "configuration:" echolog " install prefix $PREFIX" echolog " configuration dir $sysconfdir" echolog " locales dir $localedir" echolog " NLS support $nls" echolog " DLNA support $dlna" echolog " C compiler $cc" echolog " STRIP $strip" echolog " make $make" echolog " CPU $cpu ($tune)" echolog " debug symbols $debug" echolog " strip symbols $dostrip" echolog " optimize $optimize" echolog "" echolog " CFLAGS $CFLAGS" echolog " LDFLAGS $LDFLAGS" echolog " extralibs $extralibs" echolog "" ################################################# # save configs attributes ################################################# echolog "Creating $CONFIGFILE ..." echo "# Automatically generated by configure - do not modify!" > $CONFIGFILE append_config "VERSION=$VERSION" append_config "PREFIX=$PREFIX" append_config "prefix=\$(DESTDIR)\$(PREFIX)" append_config "bindir=\$(DESTDIR)$bindir" append_config "sysconfdir=\$(DESTDIR)$sysconfdir" append_config "localedir=\$(DESTDIR)$localedir" append_config "MAKE=$make" append_config "CC=$cc" append_config "LN=ln" if enabled dostrip; then append_config "STRIP=$strip" append_config "INSTALLSTRIP=$installstrip" else append_config "STRIP=echo ignoring strip" append_config "INSTALLSTRIP=" fi append_config "EXTRALIBS=$extralibs" append_config "OPTFLAGS=$CFLAGS" append_config "LDFLAGS=$LDFLAGS" append_config "INSTALL=$INSTALL" append_config "DEBUG=$debug" echolog "Creating $CONFIG_H ..." echo "/* Automatically generated by configure - do not modify! */" > $CONFIG_H add_clog_str VERSION "$VERSION" add_clog_str PACKAGE "ushare" add_clog_str PACKAGE_NAME "uShare" add_clog_str SYSCONFDIR `expand_var "${sysconfdir}"` add_clog_str LOCALEDIR `expand_var "${localedir}"` test $nls = yes && add_clog CONFIG_NLS 1 clean exit 0 ushare-1.1a/COPYING0000644000175000017500000004312210726763650012146 0ustar benben GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ushare-1.1a/NEWS0000644000175000017500000001106610726763650011614 0ustar benben2007-12-09: GeeXboX uShare 1.1a released. Support for XboX 360 dashboard Fall Update (.avi and .divx now are supported) DLNA support is not enabled by default, as not mandatory. Some configure script fixes and better support for cross-compilation. Fixed network interface discovery on MacOSX. 2007-12-04: GeeXboX uShare 1.1 released. Much more complete DLNA support through external libdlna. Telnet Control interface. Support for FLAC and HDMOV files. FreeBSD 64bit and MacOSX build fix. Newly written configure script. 2007-07-05 : GeeXboX uShare 1.0 released. Fixed XboX 360 file discovery (it finally should work). Support for Sony PlayStation 3. DLNA compliance. 2007-02-26 : GeeXboX uShare 0.9.10 released. Fixed http 404 error which prevented ushare 0.9.9 release to work. 2007-02-25 : GeeXboX uShare 0.9.9 released. Added support for FreeBSD. Use a RedBlack balanced tree searching and sorting algorithm instead of the recursive one. It avoids recursive calls, takes less memory (perfect for embedded systems) and executes in more "constant time" than the logarithmic style. Original patch by Phil Chandler. Massive memory optimization (uShare now takes 75% less RAM ;-) only not using fixed size URL allocation buffer (a 16000+ files collection now only takes 5MB where it used to take 19MB). Improved search parsing and matching mechanism (patch by Mostafa Hosseini). XboX360 support is now complete. Please note that to stream video to the XboX, the console should be running dashboard version 2.0.4552.0 and only unprotected .wmv files are supported. Fixed support for 2GB+ files (see http://sourceforge.net/tracker/index.php?func=detail&aid=1634927&group_id=151880&atid=782410) Fixed support for XboX 360 (thanks to Mostafa Hosseini). Added basic support for 'Search' action. Fixed bug with localization, use now --localedir configure's option to set location of .mo files. Make libupnp >= 1.4.2 a requirement. 2006-12-10 : GeeXboX uShare 0.9.8 released. Added German translation. Convert special xml characters to xml (like & => &). Added iso and bin mime types. Better filtering and browse capabilities: now uShare is conform to ContentDirectory:1 Service Template Standard. Updated init script to use lsb functions. 2006-03-12 : GeeXboX uShare 0.9.7 released. Added new Microsoft Registrar service which fakes the authorization required to be able to stream to MS compliant Media Renderers. Updated AVI file MIME type for better compliance with UPnP devices. Better UPnP CDS compliance when request count and index are 0. Removed the nasty characters from UDN naming for compatibility issues. Force usage of libupnp >= 1.3.1 (previous versions of the library are buggy and should not be used). Support for XboX 360, D-Link DSM-320 and Roku SoundBridge M2000 Network Music Player devices. 2006-02-19 : GeeXboX uShare 0.9.6 released. Added Fedora RPM build and startup init scripts. Support for for large files (2GB+ files). Can now specify on which port the HTTP server has to run. Fixed a potential buffer overrun when building DIDL messages. 2006-01-31 : uShare has been included in the Fedora Project. See http://fedoraproject.org/extras/4/i386/repodata/repoview/ushare-0-0.9.5-4.fc4.html 2005-12-19 : GeeXboX uShare 0.9.5 released. Added UPnP presentation URL support (you can now update or add/remove contents through a web interface). Added support for subtitle file formats. Added support for DVD specific file formats. 2005-12-07 : GeeXboX uShare 0.9.4 released. Fixed some memleaks. Avoid having empty shared directory name. Fixed handling of non-absolute content directories paths. Added logging with syslog support, in daemon mode. 2005-11-20: GeeXboX uShare 0.9.3 released. Support for multiple directories to be shared. Added start/stop script. Added verbose mode. Read configuration from /etc/ushare.conf configuration file. Support for daemon mode. Better MIME types handling. Support for new multimedia files extensions. Rewrite of some string buffer and integer manipulation tools. 2005-11-13: GeeXboX uShare 0.9.2 released. Improved UPnP compliance with Browse RequestedCount flag. Fixed some UPnP Object ID sent in Browse messages (terrible mistake). 2005-11-10: GeeXboX uShare 0.9.1 released. uShare ready for internationalization. Added French localization. Support of iconv, for UTF-8 filenames conversions. Added Debian package building scripts. 2005-10-25: GeeXboX uShare 0.9.0 released. First public release. Tested with : - Intel Digital Media Adaptor - Intel UPnP AV Media Controller ushare-1.1a/README0000644000175000017500000001607310726763650012000 0ustar benbenGeeXboX uShare - Introduction ============================= GeeXboX uShare is a UPnP (TM) A/V Media Server. It implements the server component that provides UPnP media devices with information on available multimedia files. uShare uses the built-in http server of libupnp to stream the files to clients. GeeXboX uShare is able to provide access to both images, videos, music or playlists files (see below for a complete file format support list). It does not act as an UPnP Media Adaptor and thus, can't transcode streams to fit the client requirements. uShare is written in C for the GeeXboX project (see http://www.geexbox.org/). It is designed to provide access to multimedia contents to GeeXboX but can of course be used by any other UPnP client device. It should compile and run on any modern POSIX compatible system such as Linux. GeeXboX uShare is free software - it is licensed under the terms of the GNU General Public License (GPL). Copyright and License ===================== GeeXboX uShare is copyright (C) 2005-2007 Benjamin Zores. 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 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. Note that uShare links with libupnp, which is licensed under the terms of a modified BSD license (i.e. the original BSD license without the advertising clause). This license is compatible with the GNU GPL. Homepage ======== Web site and file area for uShare is hosted on GeeXboX server : http://ushare.geexbox.org/ The latest version of uShare should always be available on this site. Requirements ============ The following programs are required to build uShare: * GNU C Compiler (gcc), 2.95 or later. The GNU C Compiler is part of the GNU Compiler Collection which can be downloaded from http://gcc.gnu.org/. * pkg-config. pkg-config is a helper tool used when compiling applications and libraries. It helps you insert the correct compiler options on the command line. (see http://pkg-config.freedesktop.org/wiki/ ). The following UPnP library is required to build and run uShare : * Linux SDK for UPnP Devices (libupnp), 1.4.2 or later The libupnp library is used to communicate using the UPnP protocol. libupnp can be downloaded from http://pupnp.sourceforge.net/. The following DLNA library is required for proper DLNA support : * libdlna, 0.2.1 or later The libdlna library is used to provides DLNA profiles informations. libdlna can be downloaded from http://libdlna.geexbox.org/. Building and Installation ========================= Compile uShare by running configure and then make. This should produce an executable ushare in the src subdirectory, which can be used right away. No extra files need to be installed. You can pass the CFLAGS you want to configure including -DDEBUG in order to activate support for debug messages in uShare. Example : CFLAGS="-Os" ./configure --prefix=/usr make You can enable DLNA support by doing a: ./configure --enable-dlna If you want to install uShare on your system, run : make install-strip This will copy the executable and manual page into their appropriate directories (/usr/bin and /usr/man/man1 in this example). For more information regarding configure and make, see the INSTALL document. Usage ===== uShare runs from the console only. It supports the usual --help option which displays usage and option information. Usage: ushare [-n name] [-i interface] [-c directory] [[-c directory] ...] Options: -n, --name=NAME Set UPnP Friendly Name (default is 'uShare') -i, --interface=IFACE Use IFACE Network Interface (default is 'eth0') -f, --cfg=FILE Config file to be used -p, --port=PORT Forces the HTTP server to run on PORT -q, --telnet-port=PORT Forces the TELNET server to run on PORT -c, --content=DIR Share the content of DIR directory. -w, --no-web Disable the control web page (enabled by default) -t, --no-telnet Disable the TELNET control (enabled by default) -o, --override-iconv-err If iconv fails parsing name, still add to media contents (hoping the renderer can handle it) -v, --verbose Set verbose display -x, --xbox Use XboX 360 compliant profile -d, --dlna Use DLNA compliant profile (PlayStation3 needs this) -D, --daemon Run as a daemon. -V, --version Display the version of uShare and exit -h, --help Display this help uShare gets its configuration from the /etc/ushare.conf file. You can force configuration options through command line. uShare expects one or several directory argument (-c argument), specifying where multimedia files are stored. You should probably also use the -i option to specify which interface uShare should listen on. ushare -c /shares ushare -c /shares1 --content=/shares2 You can also perform remote control of uShare UPnP Media Server through its web interface. This let you define new content locations at runtime or update the currently shared one in case the filesystem has changed. Just go to : http://ip_address:port/web/ushare.html See the manual page for more details : man ushare Supported File Formats List =========================== - Video files : asf, avi, dv, divx, wmv, mjpg, mjpeg, mpeg, mpg, mpe, mp2p, vob, mp2t, m1v, m2v, m4v, m4p, mp4ps, ts, ogm, mkv, rmvb, mov, qt - Audio files : aac, ac3, aif, aiff, at3p, au, snd, dts, rmi, mp1, mp2, mp3, mp4, mpa, ogg, wav, pcm, lpcm, l16, wma, mka, ra, rm, ram - Images files : bmp, ico, gif, jpeg, jpg, jpe, pcd, png, pnm, ppm, qti, qtf, qtif, tif, tiff - Playlist files : pls, m3u, asx If you want uShare to support more file formats, simply add its properties in the src/mime.c table. Do not forget to send a patch to update uShare. Feedback ======== Please send bug reports, suggestions, ideas, comments or patches to : ushare@geexbox.org Known bugs and limitations ========================== If you need to listen on more than one interface, you will have to start multiple instances of the media server. uShare keeps some information on files in memory. If your multimedia collection is huge, this might be a problem. Thanks ====== Many thanks to Oskar Liljeblad for its original work on GMediaServer (which is much more functionnal in terms of UPnP A/V features that uShare will ever be). References ========== Note that this list of references is not complete. * UPnP(TM) Standards (http://www.upnp.org/standardizeddcps/default.asp) Trademarks ========== UPnP(TM) is a trademark of the UPnP(TM) Implementers Corporation. - ushare-1.1a/THANKS0000644000175000017500000000047710726763650012034 0ustar benbenMany thanks to Oskar Liljeblad for its original work on GMediaServer (which is much more functionnal in terms of UPnP A/V features that uShare will ever be). Special Thanks to Rémi Turboult for some UPnP standard compliance check. Thanks to Jason Woodward for making me aware of most of DLNA specification internals. ushare-1.1a/TODO0000644000175000017500000000023010726763650011574 0ustar benben- change daemon running user (currently root) - add static libupnp in sources for easier maintaining and fixes - add authentication to web interface ?? ushare-1.1a/Makefile0000644000175000017500000000205210726763650012550 0ustar benbenifeq (,$(wildcard config.mak)) $(error "config.mak is not present, run configure !") endif include config.mak DISTFILE = ushare-$(VERSION).tar.bz2 EXTRADIST = AUTHORS \ ChangeLog \ configure \ COPYING \ NEWS \ README \ THANKS \ TODO \ SUBDIRS = po \ scripts \ src \ all: for subdir in $(SUBDIRS); do \ $(MAKE) -C $$subdir $@; \ done clean: for subdir in $(SUBDIRS); do \ $(MAKE) -C $$subdir $@; \ done distclean: clean for subdir in $(SUBDIRS); do \ $(MAKE) -C $$subdir $@; \ done -$(RM) -f config.log -$(RM) -f config.mak -$(RM) -f config.h install: for subdir in $(SUBDIRS); do \ $(MAKE) -C $$subdir $@; \ done .PHONY: clean distclean install dist: -$(RM) $(DISTFILE) dist=$(shell pwd)/ushare-$(VERSION) && \ for subdir in . $(SUBDIRS); do \ mkdir -p "$$dist/$$subdir"; \ $(MAKE) -C $$subdir dist-all DIST="$$dist/$$subdir"; \ done && \ tar cjf $(DISTFILE) ushare-$(VERSION) -$(RM) -rf ushare-$(VERSION) dist-all: cp $(EXTRADIST) $(SRCS) Makefile $(DIST) .PHONY: dist dist-all ushare-1.1a/po/0000755000175000017500000000000010726763650011527 5ustar benbenushare-1.1a/po/fr.po0000644000175000017500000002154210726763650012502 0ustar benben# French translations for uShare package. # Copyright (C) 2005-2007 http://ushare.geexbox.org # This file is distributed under the same license as the ushare package. # Alexis Saettler , 2005-2007. # msgid "" msgstr "" "Project-Id-Version: uShare 1.0\n" "Report-Msgid-Bugs-To: ushare@geexbox.org\n" "POT-Creation-Date: 2007-11-18 16:25+0100\n" "PO-Revision-Date: 2007-07-05 20:55+0200\n" "Last-Translator: Alexis Saettler \n" "Language-Team: uShare French trad \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: src/ushare.c:263 msgid "Stopping UPnP Service ...\n" msgstr "Arrêt du service UPnP ...\n" #: src/ushare.c:316 msgid "Initializing UPnP subsystem ...\n" msgstr "Initialisation du système UPnP ...\n" #: src/ushare.c:320 msgid "Cannot initialize UPnP subsystem\n" msgstr "Impossible d'initialiser le système UPnP ...\n" #: src/ushare.c:325 msgid "Could not set Max content UPnP\n" msgstr "Impossible de configurer la taille max pour UPnP\n" #: src/ushare.c:328 msgid "Starting in XboX 360 compliant profile ...\n" msgstr "Démarre en mode compatibilité pour XboX 360 ...\n" #: src/ushare.c:333 msgid "Starting in DLNA compliant profile ...\n" msgstr "Démarre en mode compatibilité DLNA ...\n" #: src/ushare.c:342 #, c-format msgid "UPnP MediaServer listening on %s:%d\n" msgstr "Serveur Multimédia UPnP en écoute sur %s:%d\n" #: src/ushare.c:350 msgid "Cannot set virtual directory callbacks\n" msgstr "Impossible de créer les retours des dossiers virtuels\n" #: src/ushare.c:358 msgid "Cannot add virtual directory for web server\n" msgstr "Impossible d'ajouter le dossier virtuel du serveur web\n" #: src/ushare.c:368 src/ushare.c:386 msgid "Cannot register UPnP device\n" msgstr "Impossible d'enregistrer le périphérique UPnP\n" #: src/ushare.c:376 msgid "Cannot unregister UPnP device\n" msgstr "Impossible de supprimer le périphérique UPnP\n" #: src/ushare.c:391 msgid "Sending UPnP advertisement for device ...\n" msgstr "Envoit des informations UPnP du périphérique ...\n" #: src/ushare.c:394 msgid "Listening for control point connections ...\n" msgstr "Attente de connexions ...\n" #: src/ushare.c:450 #, c-format msgid "Interface %s is down.\n" msgstr "L'interface %s est arrêtée.\n" #: src/ushare.c:451 src/ushare.c:462 msgid "Recheck uShare's configuration and try again !\n" msgstr "Revérifiez la configuration de uShare et recommencez !\n" #: src/ushare.c:461 #, c-format msgid "Can't find interface %s.\n" msgstr "Impossible de trouver l'interface %s.\n" #: src/ushare.c:622 msgid "Reloading configuration...\n" msgstr "Rechargement de la configuration...\n" #: src/ushare.c:683 src/ushare.c:771 msgid "Error: no content directory to be shared.\n" msgstr "Erreur : aucun répertoire de contenus à partager.\n" #: src/ushare.c:691 #, c-format msgid "%s (version %s), a lightweight UPnP Media Server.\n" msgstr "%s (version %s), un serveur mutlimédia UPnP léger.\n" #: src/ushare.c:693 #, c-format msgid "Benjamin Zores (C) 2005-2007, for GeeXboX Team.\n" msgstr "Benjamin Zores (C) 2005-2007, pour l'équipe GeeXboX.\n" #: src/ushare.c:694 #, c-format msgid "See http://ushare.geexbox.org/ for updates.\n" msgstr "Voir http://ushare.geexbox.org/ pour les mises à jour.\n" #: src/ushare.c:711 msgid "" "Server is shutting down: other clients will be notified soon, Bye bye ...\n" msgstr "" "Arrêt du serveur en cours : les autres clients seront notifié bientôt. Au " "revoir !\n" #: src/ushare.c:746 #, c-format msgid "Warning: can't parse file \"%s\".\n" msgstr "Attention : impossible de lire le fichier \"%s\".\n" #: src/ushare.c:802 #, c-format msgid "Error: failed to daemonize program : %s\n" msgstr "Erreur : impossible de démoniser le programme : %s\n" #: src/ushare.c:825 msgid "Terminates the uShare server" msgstr "Arrêt du serveur uShare" #: src/metadata.c:402 msgid "Failed to add the RB lookup tree\n" msgstr "Impossible d'ajouter l'arbre de recherche RB\n" #: src/metadata.c:530 msgid "Cannot create RB tree for lookups\n" msgstr "Impossible de créer l'arbre RB pour les recherches\n" #: src/metadata.c:537 msgid "Building Metadata List ...\n" msgstr "Création de la liste de données\n" #: src/metadata.c:550 #, c-format msgid "Looking for files in content directory : %s\n" msgstr "Recherche des fichiers dans le répertoire de contenus : %s\n" #: src/metadata.c:574 #, c-format msgid "Found %d files and subdirectories.\n" msgstr "%d fichiers et sous-répertoires trouvés.\n" #: src/cfgparser.c:166 #, c-format msgid "Warning: port doesn't fit IANA port assignements.\n" msgstr "Attention : ce port ne suit pas les recommendations IANA.\n" #: src/cfgparser.c:168 #, c-format msgid "" "Warning: Only Dynamic or Private Ports can be used (from 49152 through " "65535)\n" msgstr "" "Attention : seuls les ports dynamiques ou privés peuvent être utilisés (de " "49152 à 65535)\n" #: src/cfgparser.c:318 #, c-format msgid "" "Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c " "directory]...]\n" msgstr "" "Usage : ushare [-n nom] [-i interface] [-p port] [-c répertoire] [[-c " "répertoire]...]\n" #: src/cfgparser.c:319 #, c-format msgid "Options:\n" msgstr "Options :\n" #: src/cfgparser.c:320 #, c-format msgid " -n, --name=NAME\tSet UPnP Friendly Name (default is '%s')\n" msgstr " -n, --name=NOM\t\tDéfini le nom UPnP ('%s' par défaut)\n" #: src/cfgparser.c:322 #, c-format msgid " -i, --interface=IFACE\tUse IFACE Network Interface (default is '%s')\n" msgstr "" " -i, --interface=IFACE\tUtiliser l'interface réseau IFACE ('%s' par défaut)\n" #: src/cfgparser.c:324 #, c-format msgid " -f, --cfg=FILE\t\tConfig file to be used\n" msgstr " -f, --cfg=FICHIER\tFichier de configuration à utiliser\n" #: src/cfgparser.c:325 #, c-format msgid " -p, --port=PORT\tForces the HTTP server to run on PORT\n" msgstr " -p, --port=PORT\tForce le serveur HTTP à utiliser ce PORT\n" #: src/cfgparser.c:326 #, c-format msgid " -q, --telnet-port=PORT\tForces the TELNET server to run on PORT\n" msgstr " -q, --telnet-port=PORT\tForce le server TELNET à utiliser ce PORT\n" #: src/cfgparser.c:327 #, c-format msgid " -c, --content=DIR\tShare the content of DIR directory\n" msgstr " -c, --content=REP\tPartage le contenu du répertoire REP\n" #: src/cfgparser.c:328 #, c-format msgid " -w, --no-web\t\tDisable the control web page (enabled by default)\n" msgstr "" " -w, --no-web\t\tDésactive la page de contrôle web (activée par défaut)\n" #: src/cfgparser.c:329 #, c-format msgid " -t, --no-telnet\tDisable the TELNET control (enabled by default)\n" msgstr "" " -t, --no-telnet\tDésactiver le contrôle par TELNET (activé par défaut)\n" #: src/cfgparser.c:330 #, c-format msgid "" " -o, --override-iconv-err\tIf iconv fails parsing name, still add to media " "contents (hoping the renderer can handle it)\n" msgstr "" " -o, --override-iconv-err\tSi iconv n'arrive pas à traduire le nom du " "fichier, ajouter tout de même le contenu (en espérant que le lecteur puisse " "le lire)\n" #: src/cfgparser.c:331 #, c-format msgid " -v, --verbose\t\tSet verbose display\n" msgstr " -v, --verbose\t\tMode bavard\n" #: src/cfgparser.c:332 #, c-format msgid " -x, --xbox\t\tUse XboX 360 compliant profile\n" msgstr " -x, --xbox\t\tUtiliser le mode de compatibilité XboX 360\n" #: src/cfgparser.c:334 #, c-format msgid " -d, --dlna\t\tUse DLNA compliant profile (PlayStation3 needs this)\n" msgstr "" " -d, --dlna\t\tUtiliser le mode de compatibilité DLNA pour PlayStation3\n" #: src/cfgparser.c:336 #, c-format msgid " -D, --daemon\t\tRun as a daemon\n" msgstr " -D, --daemon\t\tDémarrer en mode démon\n" #: src/cfgparser.c:337 #, c-format msgid " -V, --version\t\tDisplay the version of uShare and exit\n" msgstr "" " -V, --version\t\tAffiche la version de uShare et quitte le programme\n" #: src/cfgparser.c:338 #, c-format msgid " -h, --help\t\tDisplay this help\n" msgstr " -h, --help\t\tAffiche cette aide\n" #: src/presentation.c:108 src/presentation.c:143 msgid "uShare Information Page" msgstr "Page d'information de uShare" #: src/presentation.c:155 msgid "uShare UPnP A/V Media Server" msgstr "uShare - Serveur Multimédia A/V UPnP" #: src/presentation.c:156 msgid "Information Page" msgstr "Page d'information" #: src/presentation.c:163 msgid "Version" msgstr "Version" #: src/presentation.c:166 msgid "Device UDN" msgstr "Périphérique UDN" #: src/presentation.c:168 msgid "Number of shared files and directories" msgstr "Nombre de fichiers et sous-répertoires partagés" #: src/presentation.c:178 msgid "Share" msgstr "Partage" #: src/presentation.c:184 msgid "unShare!" msgstr "Départager !" #: src/presentation.c:190 msgid "Add a new share : " msgstr "Ajouter un partage : " #: src/presentation.c:196 msgid "Share!" msgstr "Partager !" #: src/presentation.c:207 msgid "Refresh Shares ..." msgstr "Rafraîchir les partages ..." ushare-1.1a/po/de.po0000644000175000017500000002021510726763650012457 0ustar benben# German translations for uShare package. # Copyright (C) 2006 http://ushare.geexbox.org # This file is distributed under the same license as the uShare package. # uShare Team , 2006. # msgid "" msgstr "" "Project-Id-Version: uShare 0.9.8\n" "Report-Msgid-Bugs-To: ushare@geexbox.org\n" "POT-Creation-Date: 2007-11-18 16:25+0100\n" "PO-Revision-Date: 2006-09-20 22:12+0200\n" "Last-Translator: German uShare Team \n" "Language-Team: German uShare Team \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/ushare.c:263 msgid "Stopping UPnP Service ...\n" msgstr "UPnP Service wird gestoppt ...\n" #: src/ushare.c:316 msgid "Initializing UPnP subsystem ...\n" msgstr "Initialisiere UPnP Subsystem ...\n" #: src/ushare.c:320 msgid "Cannot initialize UPnP subsystem\n" msgstr "Kann UPnP Subsystem nicht initialisieren\n" #: src/ushare.c:325 msgid "Could not set Max content UPnP\n" msgstr "" #: src/ushare.c:328 msgid "Starting in XboX 360 compliant profile ...\n" msgstr "" #: src/ushare.c:333 msgid "Starting in DLNA compliant profile ...\n" msgstr "" #: src/ushare.c:342 #, c-format msgid "UPnP MediaServer listening on %s:%d\n" msgstr "UPnP MediaServer lauscht auf %s:%d\n" #: src/ushare.c:350 msgid "Cannot set virtual directory callbacks\n" msgstr "Kann virtuelle Verzeichnis-Callbacks nicht setzen\n" #: src/ushare.c:358 msgid "Cannot add virtual directory for web server\n" msgstr "Kann virtuelles Verzeichnis für den Webserver nicht zurücksetzen\n" #: src/ushare.c:368 src/ushare.c:386 msgid "Cannot register UPnP device\n" msgstr "Kann Upnp Gerät nicht registrieren\n" #: src/ushare.c:376 msgid "Cannot unregister UPnP device\n" msgstr "Kann UpnP Gerät nicht deregistrieren\n" #: src/ushare.c:391 msgid "Sending UPnP advertisement for device ...\n" msgstr "Sende UpnP Advertisement für Gerät...\n" #: src/ushare.c:394 msgid "Listening for control point connections ...\n" msgstr "Lausche auf Control Point Verbindungen...\n" #: src/ushare.c:450 #, c-format msgid "Interface %s is down.\n" msgstr "Interface %s ist down.\n" #: src/ushare.c:451 src/ushare.c:462 msgid "Recheck uShare's configuration and try again !\n" msgstr "Überprüfe uShare's Konfiguration und versuche es erneut!\n" #: src/ushare.c:461 #, c-format msgid "Can't find interface %s.\n" msgstr "Kann Interface %s nicht finden.\n" #: src/ushare.c:622 msgid "Reloading configuration...\n" msgstr "Lade Konfiguration erneut...\n" #: src/ushare.c:683 src/ushare.c:771 msgid "Error: no content directory to be shared.\n" msgstr "Fehler: Kein Content Verzeichnis zum sharen.\n" #: src/ushare.c:691 #, c-format msgid "%s (version %s), a lightweight UPnP Media Server.\n" msgstr "%s (Version %s), ein leichtgewichtiger UPnP Media Server.\n" #: src/ushare.c:693 #, c-format msgid "Benjamin Zores (C) 2005-2007, for GeeXboX Team.\n" msgstr "Benjamin Zores (C) 2005-2007, für das GeeXboX Team.\n" #: src/ushare.c:694 #, c-format msgid "See http://ushare.geexbox.org/ for updates.\n" msgstr "Für Updates gehe auf http://ushare.geexbox.org/.\n" #: src/ushare.c:711 msgid "" "Server is shutting down: other clients will be notified soon, Bye bye ...\n" msgstr "" #: src/ushare.c:746 #, c-format msgid "Warning: can't parse file \"%s\".\n" msgstr "Warnung: Kann Datei nicht parsen \"%s\".\n" #: src/ushare.c:802 #, c-format msgid "Error: failed to daemonize program : %s\n" msgstr "Fehler: Daemonisierung des Programms nicht möglich: %s\n" #: src/ushare.c:825 msgid "Terminates the uShare server" msgstr "" #: src/metadata.c:402 msgid "Failed to add the RB lookup tree\n" msgstr "" #: src/metadata.c:530 msgid "Cannot create RB tree for lookups\n" msgstr "" #: src/metadata.c:537 msgid "Building Metadata List ...\n" msgstr "Erzeuge Metadata List ...\n" #: src/metadata.c:550 #, c-format msgid "Looking for files in content directory : %s\n" msgstr "Suche nach Dateien im Content Verzeichnis : %s\n" #: src/metadata.c:574 #, c-format msgid "Found %d files and subdirectories.\n" msgstr "Fand %d Dateien und Unterverzeichnisse.\n" #: src/cfgparser.c:166 #, c-format msgid "Warning: port doesn't fit IANA port assignements.\n" msgstr "Warnung: Port passt nicht zur IANA Port Zuordnung.\n" #: src/cfgparser.c:168 #, c-format msgid "" "Warning: Only Dynamic or Private Ports can be used (from 49152 through " "65535)\n" msgstr "" "Warnung: Nur dynamische und private Ports können benutzt werden (von 49152 " "bis 65535)\n" #: src/cfgparser.c:318 #, c-format msgid "" "Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c " "directory]...]\n" msgstr "" "Usage: ushare [-n Name] [-i Interface] [-p Port] [-c Verzeichnis] [[-c " "Verzeichnis]...]\n" #: src/cfgparser.c:319 #, c-format msgid "Options:\n" msgstr "Optionen:\n" #: src/cfgparser.c:320 #, c-format msgid " -n, --name=NAME\tSet UPnP Friendly Name (default is '%s')\n" msgstr " -n, --name=NAME\tSet UPnP-freundlicher Name (vorgegeben ist '%s')\n" #: src/cfgparser.c:322 #, c-format msgid " -i, --interface=IFACE\tUse IFACE Network Interface (default is '%s')\n" msgstr "" " -i, --interface=IFACE\tBenutze IFACE Netzwerk Interface (vorgegeben ist '%" "s')\n" #: src/cfgparser.c:324 #, c-format msgid " -f, --cfg=FILE\t\tConfig file to be used\n" msgstr "" #: src/cfgparser.c:325 #, c-format msgid " -p, --port=PORT\tForces the HTTP server to run on PORT\n" msgstr "" " -p, --port=PORT\tLegt das PORT fest, auf dem der HTTP Server laufen soll\n" #: src/cfgparser.c:326 #, fuzzy, c-format msgid " -q, --telnet-port=PORT\tForces the TELNET server to run on PORT\n" msgstr "" " -p, --port=PORT\tLegt das PORT fest, auf dem der HTTP Server laufen soll\n" #: src/cfgparser.c:327 #, c-format msgid " -c, --content=DIR\tShare the content of DIR directory\n" msgstr "" " -c, --content=DIR\tShare den Inhalt des folgenden Content Verzeichnisses" "(DIR)\n" #: src/cfgparser.c:328 #, c-format msgid " -w, --no-web\t\tDisable the control web page (enabled by default)\n" msgstr "" " -w, --no-web\t\tDeaktiviere die Kontrollwebseite (Vorgabe: Webseite ist " "aktiviert)\n" #: src/cfgparser.c:329 #, fuzzy, c-format msgid " -t, --no-telnet\tDisable the TELNET control (enabled by default)\n" msgstr "" " -w, --no-web\t\tDeaktiviere die Kontrollwebseite (Vorgabe: Webseite ist " "aktiviert)\n" #: src/cfgparser.c:330 #, c-format msgid "" " -o, --override-iconv-err\tIf iconv fails parsing name, still add to media " "contents (hoping the renderer can handle it)\n" msgstr "" #: src/cfgparser.c:331 #, c-format msgid " -v, --verbose\t\tSet verbose display\n" msgstr " -v, --verbose\t\tSetze Verbose Display\n" #: src/cfgparser.c:332 #, c-format msgid " -x, --xbox\t\tUse XboX 360 compliant profile\n" msgstr "" #: src/cfgparser.c:334 #, c-format msgid " -d, --dlna\t\tUse DLNA compliant profile (PlayStation3 needs this)\n" msgstr "" #: src/cfgparser.c:336 #, c-format msgid " -D, --daemon\t\tRun as a daemon\n" msgstr " -D, --daemon\t\tAusführen des Porgramms in Daemon Mode\n" #: src/cfgparser.c:337 #, c-format msgid " -V, --version\t\tDisplay the version of uShare and exit\n" msgstr "" " -V, --version\t\tZeigt die uShare Version an und beendet uShare danach\n" #: src/cfgparser.c:338 #, c-format msgid " -h, --help\t\tDisplay this help\n" msgstr " -h, --help\t\tZeigt diese Hilfe an\n" #: src/presentation.c:108 src/presentation.c:143 msgid "uShare Information Page" msgstr "uShare Informationsseite" #: src/presentation.c:155 msgid "uShare UPnP A/V Media Server" msgstr "uShare UPnP A/V Media Server" #: src/presentation.c:156 msgid "Information Page" msgstr "Informationsseite" #: src/presentation.c:163 msgid "Version" msgstr "Version" #: src/presentation.c:166 msgid "Device UDN" msgstr "Gerät UDN" #: src/presentation.c:168 msgid "Number of shared files and directories" msgstr "Anzahl der geshareten Dateien und Verzeichnisse" #: src/presentation.c:178 msgid "Share" msgstr "Share" #: src/presentation.c:184 msgid "unShare!" msgstr "unShare!" #: src/presentation.c:190 msgid "Add a new share : " msgstr "Füge neues Share hinzu : " #: src/presentation.c:196 msgid "Share!" msgstr "Share!" #: src/presentation.c:207 msgid "Refresh Shares ..." msgstr "Erneuere Shares ..." ushare-1.1a/po/fr.gmo0000644000175000017500000001564410726763650012654 0ustar benbenÞ•=Sì897Y6‘BÈ( 4ET:šwÕ7M@…AÆ$A-,o2œÏ0ã 0 ,J "w !š ¼ 'Ù   @ (K *t !Ÿ #Á å ö  ,. ,[ &ˆ ¯ /¹ é ü , *E Jp » Á 'È +ð  7 $T Ty Î NÖ %2Fy‘®‡·(?Dh9­Gç8/ hM‰8×;®CêK.zJ—9â5R6i" &Ã7ê4".W0†7·/ï1Q4d4™-Î+ü($;`<š1× 8M$j83ÈVüS [)f2Ãß.øX'€^ˆ0ç:S%p –=)*#' &<-82 ;"6%7$9 3.( :45+ / 01!, -D, --daemon Run as a daemon -V, --version Display the version of uShare and exit -c, --content=DIR Share the content of DIR directory -d, --dlna Use DLNA compliant profile (PlayStation3 needs this) -f, --cfg=FILE Config file to be used -h, --help Display this help -i, --interface=IFACE Use IFACE Network Interface (default is '%s') -n, --name=NAME Set UPnP Friendly Name (default is '%s') -o, --override-iconv-err If iconv fails parsing name, still add to media contents (hoping the renderer can handle it) -p, --port=PORT Forces the HTTP server to run on PORT -q, --telnet-port=PORT Forces the TELNET server to run on PORT -t, --no-telnet Disable the TELNET control (enabled by default) -v, --verbose Set verbose display -w, --no-web Disable the control web page (enabled by default) -x, --xbox Use XboX 360 compliant profile %s (version %s), a lightweight UPnP Media Server. Add a new share : Benjamin Zores (C) 2005-2007, for GeeXboX Team. Building Metadata List ... Can't find interface %s. Cannot add virtual directory for web server Cannot create RB tree for lookups Cannot initialize UPnP subsystem Cannot register UPnP device Cannot set virtual directory callbacks Cannot unregister UPnP device Could not set Max content UPnP Device UDNError: failed to daemonize program : %s Error: no content directory to be shared. Failed to add the RB lookup tree Found %d files and subdirectories. Information PageInitializing UPnP subsystem ... Interface %s is down. Listening for control point connections ... Looking for files in content directory : %s Number of shared files and directoriesOptions: Recheck uShare's configuration and try again ! Refresh Shares ...Reloading configuration... See http://ushare.geexbox.org/ for updates. Sending UPnP advertisement for device ... Server is shutting down: other clients will be notified soon, Bye bye ... ShareShare!Starting in DLNA compliant profile ... Starting in XboX 360 compliant profile ... Stopping UPnP Service ... Terminates the uShare serverUPnP MediaServer listening on %s:%d Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c directory]...] VersionWarning: Only Dynamic or Private Ports can be used (from 49152 through 65535) Warning: can't parse file "%s". Warning: port doesn't fit IANA port assignements. uShare Information PageuShare UPnP A/V Media ServerunShare!Project-Id-Version: uShare 1.0 Report-Msgid-Bugs-To: ushare@geexbox.org POT-Creation-Date: 2007-11-18 16:25+0100 PO-Revision-Date: 2007-07-05 20:55+0200 Last-Translator: Alexis Saettler Language-Team: uShare French trad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); -D, --daemon Démarrer en mode démon -V, --version Affiche la version de uShare et quitte le programme -c, --content=REP Partage le contenu du répertoire REP -d, --dlna Utiliser le mode de compatibilité DLNA pour PlayStation3 -f, --cfg=FICHIER Fichier de configuration à utiliser -h, --help Affiche cette aide -i, --interface=IFACE Utiliser l'interface réseau IFACE ('%s' par défaut) -n, --name=NOM Défini le nom UPnP ('%s' par défaut) -o, --override-iconv-err Si iconv n'arrive pas à traduire le nom du fichier, ajouter tout de même le contenu (en espérant que le lecteur puisse le lire) -p, --port=PORT Force le serveur HTTP à utiliser ce PORT -q, --telnet-port=PORT Force le server TELNET à utiliser ce PORT -t, --no-telnet Désactiver le contrôle par TELNET (activé par défaut) -v, --verbose Mode bavard -w, --no-web Désactive la page de contrôle web (activée par défaut) -x, --xbox Utiliser le mode de compatibilité XboX 360 %s (version %s), un serveur mutlimédia UPnP léger. Ajouter un partage : Benjamin Zores (C) 2005-2007, pour l'équipe GeeXboX. Création de la liste de données Impossible de trouver l'interface %s. Impossible d'ajouter le dossier virtuel du serveur web Impossible de créer l'arbre RB pour les recherches Impossible d'initialiser le système UPnP ... Impossible d'enregistrer le périphérique UPnP Impossible de créer les retours des dossiers virtuels Impossible de supprimer le périphérique UPnP Impossible de configurer la taille max pour UPnP Périphérique UDNErreur : impossible de démoniser le programme : %s Erreur : aucun répertoire de contenus à partager. Impossible d'ajouter l'arbre de recherche RB %d fichiers et sous-répertoires trouvés. Page d'informationInitialisation du système UPnP ... L'interface %s est arrêtée. Attente de connexions ... Recherche des fichiers dans le répertoire de contenus : %s Nombre de fichiers et sous-répertoires partagésOptions : Revérifiez la configuration de uShare et recommencez ! Rafraîchir les partages ...Rechargement de la configuration... Voir http://ushare.geexbox.org/ pour les mises à jour. Envoit des informations UPnP du périphérique ... Arrêt du serveur en cours : les autres clients seront notifié bientôt. Au revoir ! PartagePartager !Démarre en mode compatibilité DLNA ... Démarre en mode compatibilité pour XboX 360 ... Arrêt du service UPnP ... Arrêt du serveur uShareServeur Multimédia UPnP en écoute sur %s:%d Usage : ushare [-n nom] [-i interface] [-p port] [-c répertoire] [[-c répertoire]...] VersionAttention : seuls les ports dynamiques ou privés peuvent être utilisés (de 49152 à 65535) Attention : impossible de lire le fichier "%s". Attention : ce port ne suit pas les recommendations IANA. Page d'information de uShareuShare - Serveur Multimédia A/V UPnPDépartager !ushare-1.1a/po/de.gmo0000644000175000017500000001215410726763650012626 0ustar benbenÞ•0œC()7I6¸EØ:7Y$‘A¶2ø+0?pŒ,¦!Óõ': Y(d*#¸Ü í,%,R& ¦/°àó, *< g m t $ T´  N ` 2 ´ Ì é ò 7ƒ F» N "Q Nt Bà I&PRw:Ê5!W rC“)×$2&&Y €8‹-Ä(ò!-O*g/’/ ò;ý9M2k(žÇÍÔ#ôXqWy'Ñ3ù-Fc %0* ',(+$# &.- ! /)"  -D, --daemon Run as a daemon -V, --version Display the version of uShare and exit -c, --content=DIR Share the content of DIR directory -h, --help Display this help -i, --interface=IFACE Use IFACE Network Interface (default is '%s') -n, --name=NAME Set UPnP Friendly Name (default is '%s') -p, --port=PORT Forces the HTTP server to run on PORT -v, --verbose Set verbose display -w, --no-web Disable the control web page (enabled by default) %s (version %s), a lightweight UPnP Media Server. Add a new share : Benjamin Zores (C) 2005-2007, for GeeXboX Team. Building Metadata List ... Can't find interface %s. Cannot add virtual directory for web server Cannot initialize UPnP subsystem Cannot register UPnP device Cannot set virtual directory callbacks Cannot unregister UPnP device Device UDNError: failed to daemonize program : %s Error: no content directory to be shared. Found %d files and subdirectories. Information PageInitializing UPnP subsystem ... Interface %s is down. Listening for control point connections ... Looking for files in content directory : %s Number of shared files and directoriesOptions: Recheck uShare's configuration and try again ! Refresh Shares ...Reloading configuration... See http://ushare.geexbox.org/ for updates. Sending UPnP advertisement for device ... ShareShare!Stopping UPnP Service ... UPnP MediaServer listening on %s:%d Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c directory]...] VersionWarning: Only Dynamic or Private Ports can be used (from 49152 through 65535) Warning: can't parse file "%s". Warning: port doesn't fit IANA port assignements. uShare Information PageuShare UPnP A/V Media ServerunShare!Project-Id-Version: uShare 0.9.8 Report-Msgid-Bugs-To: ushare@geexbox.org POT-Creation-Date: 2007-11-18 16:25+0100 PO-Revision-Date: 2006-09-20 22:12+0200 Last-Translator: German uShare Team Language-Team: German uShare Team MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); -D, --daemon Ausführen des Porgramms in Daemon Mode -V, --version Zeigt die uShare Version an und beendet uShare danach -c, --content=DIR Share den Inhalt des folgenden Content Verzeichnisses(DIR) -h, --help Zeigt diese Hilfe an -i, --interface=IFACE Benutze IFACE Netzwerk Interface (vorgegeben ist '%s') -n, --name=NAME Set UPnP-freundlicher Name (vorgegeben ist '%s') -p, --port=PORT Legt das PORT fest, auf dem der HTTP Server laufen soll -v, --verbose Setze Verbose Display -w, --no-web Deaktiviere die Kontrollwebseite (Vorgabe: Webseite ist aktiviert) %s (Version %s), ein leichtgewichtiger UPnP Media Server. Füge neues Share hinzu : Benjamin Zores (C) 2005-2007, für das GeeXboX Team. Erzeuge Metadata List ... Kann Interface %s nicht finden. Kann virtuelles Verzeichnis für den Webserver nicht zurücksetzen Kann UPnP Subsystem nicht initialisieren Kann Upnp Gerät nicht registrieren Kann virtuelle Verzeichnis-Callbacks nicht setzen Kann UpnP Gerät nicht deregistrieren Gerät UDNFehler: Daemonisierung des Programms nicht möglich: %s Fehler: Kein Content Verzeichnis zum sharen. Fand %d Dateien und Unterverzeichnisse. InformationsseiteInitialisiere UPnP Subsystem ... Interface %s ist down. Lausche auf Control Point Verbindungen... Suche nach Dateien im Content Verzeichnis : %s Anzahl der geshareten Dateien und VerzeichnisseOptionen: Überprüfe uShare's Konfiguration und versuche es erneut! Erneuere Shares ...Lade Konfiguration erneut... Für Updates gehe auf http://ushare.geexbox.org/. Sende UpnP Advertisement für Gerät... ShareShare!UPnP Service wird gestoppt ... UPnP MediaServer lauscht auf %s:%d Usage: ushare [-n Name] [-i Interface] [-p Port] [-c Verzeichnis] [[-c Verzeichnis]...] VersionWarnung: Nur dynamische und private Ports können benutzt werden (von 49152 bis 65535) Warnung: Kann Datei nicht parsen "%s". Warnung: Port passt nicht zur IANA Port Zuordnung. uShare InformationsseiteuShare UPnP A/V Media ServerunShare!ushare-1.1a/po/POTFILES0000644000175000017500000000007710726763650012703 0ustar benbensrc/ushare.c src/metadata.c src/cfgparser.c src/presentation.c ushare-1.1a/po/ushare.pot0000644000175000017500000001355710726763650013555 0ustar benben# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR http://ushare.geexbox.org # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: ushare@geexbox.org\n" "POT-Creation-Date: 2007-11-18 17:38+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/ushare.c:263 msgid "Stopping UPnP Service ...\n" msgstr "" #: src/ushare.c:316 msgid "Initializing UPnP subsystem ...\n" msgstr "" #: src/ushare.c:320 msgid "Cannot initialize UPnP subsystem\n" msgstr "" #: src/ushare.c:325 msgid "Could not set Max content UPnP\n" msgstr "" #: src/ushare.c:328 msgid "Starting in XboX 360 compliant profile ...\n" msgstr "" #: src/ushare.c:333 msgid "Starting in DLNA compliant profile ...\n" msgstr "" #: src/ushare.c:342 #, c-format msgid "UPnP MediaServer listening on %s:%d\n" msgstr "" #: src/ushare.c:350 msgid "Cannot set virtual directory callbacks\n" msgstr "" #: src/ushare.c:358 msgid "Cannot add virtual directory for web server\n" msgstr "" #: src/ushare.c:368 src/ushare.c:386 msgid "Cannot register UPnP device\n" msgstr "" #: src/ushare.c:376 msgid "Cannot unregister UPnP device\n" msgstr "" #: src/ushare.c:391 msgid "Sending UPnP advertisement for device ...\n" msgstr "" #: src/ushare.c:394 msgid "Listening for control point connections ...\n" msgstr "" #: src/ushare.c:450 #, c-format msgid "Interface %s is down.\n" msgstr "" #: src/ushare.c:451 src/ushare.c:462 msgid "Recheck uShare's configuration and try again !\n" msgstr "" #: src/ushare.c:461 #, c-format msgid "Can't find interface %s.\n" msgstr "" #: src/ushare.c:622 msgid "Reloading configuration...\n" msgstr "" #: src/ushare.c:683 src/ushare.c:771 msgid "Error: no content directory to be shared.\n" msgstr "" #: src/ushare.c:691 #, c-format msgid "%s (version %s), a lightweight UPnP Media Server.\n" msgstr "" #: src/ushare.c:693 #, c-format msgid "Benjamin Zores (C) 2005-2007, for GeeXboX Team.\n" msgstr "" #: src/ushare.c:694 #, c-format msgid "See http://ushare.geexbox.org/ for updates.\n" msgstr "" #: src/ushare.c:711 msgid "" "Server is shutting down: other clients will be notified soon, Bye bye ...\n" msgstr "" #: src/ushare.c:746 #, c-format msgid "Warning: can't parse file \"%s\".\n" msgstr "" #: src/ushare.c:802 #, c-format msgid "Error: failed to daemonize program : %s\n" msgstr "" #: src/ushare.c:825 msgid "Terminates the uShare server" msgstr "" #: src/metadata.c:402 msgid "Failed to add the RB lookup tree\n" msgstr "" #: src/metadata.c:530 msgid "Cannot create RB tree for lookups\n" msgstr "" #: src/metadata.c:537 msgid "Building Metadata List ...\n" msgstr "" #: src/metadata.c:550 #, c-format msgid "Looking for files in content directory : %s\n" msgstr "" #: src/metadata.c:574 #, c-format msgid "Found %d files and subdirectories.\n" msgstr "" #: src/cfgparser.c:166 #, c-format msgid "Warning: port doesn't fit IANA port assignements.\n" msgstr "" #: src/cfgparser.c:168 #, c-format msgid "" "Warning: Only Dynamic or Private Ports can be used (from 49152 through " "65535)\n" msgstr "" #: src/cfgparser.c:318 #, c-format msgid "" "Usage: ushare [-n name] [-i interface] [-p port] [-c directory] [[-c " "directory]...]\n" msgstr "" #: src/cfgparser.c:319 #, c-format msgid "Options:\n" msgstr "" #: src/cfgparser.c:320 #, c-format msgid " -n, --name=NAME\tSet UPnP Friendly Name (default is '%s')\n" msgstr "" #: src/cfgparser.c:322 #, c-format msgid " -i, --interface=IFACE\tUse IFACE Network Interface (default is '%s')\n" msgstr "" #: src/cfgparser.c:324 #, c-format msgid " -f, --cfg=FILE\t\tConfig file to be used\n" msgstr "" #: src/cfgparser.c:325 #, c-format msgid " -p, --port=PORT\tForces the HTTP server to run on PORT\n" msgstr "" #: src/cfgparser.c:326 #, c-format msgid " -q, --telnet-port=PORT\tForces the TELNET server to run on PORT\n" msgstr "" #: src/cfgparser.c:327 #, c-format msgid " -c, --content=DIR\tShare the content of DIR directory\n" msgstr "" #: src/cfgparser.c:328 #, c-format msgid " -w, --no-web\t\tDisable the control web page (enabled by default)\n" msgstr "" #: src/cfgparser.c:329 #, c-format msgid " -t, --no-telnet\tDisable the TELNET control (enabled by default)\n" msgstr "" #: src/cfgparser.c:330 #, c-format msgid "" " -o, --override-iconv-err\tIf iconv fails parsing name, still add to media " "contents (hoping the renderer can handle it)\n" msgstr "" #: src/cfgparser.c:331 #, c-format msgid " -v, --verbose\t\tSet verbose display\n" msgstr "" #: src/cfgparser.c:332 #, c-format msgid " -x, --xbox\t\tUse XboX 360 compliant profile\n" msgstr "" #: src/cfgparser.c:334 #, c-format msgid " -d, --dlna\t\tUse DLNA compliant profile (PlayStation3 needs this)\n" msgstr "" #: src/cfgparser.c:336 #, c-format msgid " -D, --daemon\t\tRun as a daemon\n" msgstr "" #: src/cfgparser.c:337 #, c-format msgid " -V, --version\t\tDisplay the version of uShare and exit\n" msgstr "" #: src/cfgparser.c:338 #, c-format msgid " -h, --help\t\tDisplay this help\n" msgstr "" #: src/presentation.c:108 src/presentation.c:143 msgid "uShare Information Page" msgstr "" #: src/presentation.c:155 msgid "uShare UPnP A/V Media Server" msgstr "" #: src/presentation.c:156 msgid "Information Page" msgstr "" #: src/presentation.c:163 msgid "Version" msgstr "" #: src/presentation.c:166 msgid "Device UDN" msgstr "" #: src/presentation.c:168 msgid "Number of shared files and directories" msgstr "" #: src/presentation.c:178 msgid "Share" msgstr "" #: src/presentation.c:184 msgid "unShare!" msgstr "" #: src/presentation.c:190 msgid "Add a new share : " msgstr "" #: src/presentation.c:196 msgid "Share!" msgstr "" #: src/presentation.c:207 msgid "Refresh Shares ..." msgstr "" ushare-1.1a/po/Makefile0000644000175000017500000000401110726763650013163 0ustar benbenifeq (,$(wildcard ../config.mak)) $(error "../config.mak is not present, run configure !") endif include ../config.mak top_srcdir = .. DOMAIN = ushare # Languages to generate LANGS = fr de GMSGFMT = /usr/bin/msgfmt XGETTEXT = /usr/bin/xgettext MSGMERGE = msgmerge MSGMERGE_UPDATE = /usr/bin/msgmerge --update MSGINIT = msginit MSGCONV = msgconv MSGFILTER = msgfilter EXTRADIST = $(POFILES) $(GMOFILES) \ POTFILES \ $(DOMAIN).pot \ GMOFILES = $(addsuffix .gmo,$(LANGS)) POFILES = $(addsuffix .po,$(LANGS)) POTFILES = $(shell for f in `cat POTFILES`; do echo -n "$(top_srcdir)/$$f "; done) all: stamp-po stamp-po: $(DOMAIN).pot $(MAKE) $(GMOFILES) touch $@ .po.gmo: $(GMSGFMT) -c --statistics -o $@ $< .SUFFIXES: .po .gmo $(POFILES): $(DOMAIN).pot $(MSGMERGE_UPDATE) $@ $(DOMAIN).pot; update-po: $(MAKE) $(DOMAIN).pot-update $(MAKE) update-gmo update-gmo: $(GMOFILES) @: .PHONY: update-po update-gmo # This target rebuilds $(DOMAIN).pot; it is an expensive operation. # Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. $(DOMAIN).pot-update: $(POTFILES) POTFILES $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ --add-comments=TRANSLATORS: \ --keyword=_ --keyword=N_ \ --files-from=POTFILES \ --copyright-holder='http://ushare.geexbox.org' \ --msgid-bugs-address="ushare@geexbox.org" \ -o $(DOMAIN).pot # This rule has no dependencies: we don't need to update $(DOMAIN).pot at # every "make" invocation, only create it when it is missing. # Only "make $(DOMAIN).pot-update" or "make dist" will force an update. $(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update clean: -$(RM) -f stamp-po distclean: clean -$(RM) -f $(GMOFILES) install: $(GMOFILES) for gmo in $(GMOFILES); do \ lang=`echo $$gmo | sed -e 's/\.gmo$$//'`; \ $(INSTALL) -d $(localedir)/$$lang/LC_MESSAGES; \ $(INSTALL) -m 644 $$lang.gmo $(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo; \ done dist-all: $(GMOFILES) cp $(EXTRADIST) $(SRCS) Makefile $(DIST) .PHONY: dist-all install clean distclean ushare-1.1a/scripts/0000755000175000017500000000000010726763650012600 5ustar benbenushare-1.1a/scripts/ushare.conf0000644000175000017500000000235710726763650014745 0ustar benben# /etc/ushare.conf # Configuration file for uShare # uShare UPnP Friendly Name (default is 'uShare'). USHARE_NAME= # Interface to listen to (default is eth0). # Ex : USHARE_IFACE=eth1 USHARE_IFACE= # Port to listen to (default is random from IANA Dynamic Ports range) # Ex : USHARE_PORT=49200 USHARE_PORT= # Port to listen for Telnet connections # Ex : USHARE_TELNET_PORT=1337 USHARE_TELNET_PORT= # Directories to be shared (space or CSV list). # Ex: USHARE_DIR=/dir1,/dir2 USHARE_DIR= # Use to override what happens when iconv fails to parse a file name. # The default uShare behaviour is to not add the entry in the media list # This option overrides that behaviour and adds the non-iconv'ed string into # the media list, with the assumption that the renderer will be able to # handle it. Devices like Noxon 2 have no problem with strings being passed # as is. (Umlauts for all!) # # Options are TRUE/YES/1 for override and anything else for default behaviour USHARE_OVERRIDE_ICONV_ERR= # Enable Web interface (yes/no) ENABLE_WEB= # Enable Telnet control interface (yes/no) ENABLE_TELNET= # Use XboX 360 compatibility mode (yes/no) ENABLE_XBOX= # Use DLNA profile (yes/no) # This is needed for PlayStation3 to work (among other devices) ENABLE_DLNA= ushare-1.1a/scripts/ushare0000755000175000017500000000357310726763650014025 0ustar benben#!/bin/sh -e # # uShare init script # ### BEGIN INIT INFO # Provides: ushare # Required-Start: $local_fs $syslog $network # Should-Start: # Required-Stop: # Should-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: uShare # Description: uShare UPnP (TM) A/V & DLNA Media Server # You should edit configuration in /etc/ushare.conf file # See http://ushare.geexbox.org for details ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/bin/ushare NAME=ushare DESC="uShare UPnP A/V & DLNA Media Server" PIDFILE=/var/run/ushare.pid CONFIGFILE=/etc/ushare.conf # abort if no executable exists [ -x $DAEMON ] || exit 0 # Get lsb functions . /lib/lsb/init-functions . /etc/default/rcS [ -f /etc/default/ushare ] && . /etc/default/ushare checkpid() { [ -e $PIDFILE ] || touch $PIDFILE } check_shares() { if [ -r "$CONFIGFILE" ]; then . $CONFIGFILE [ -n "$USHARE_DIR" ] && return 0 fi return 1 } case "$1" in start) log_daemon_msg "Starting $DESC: $NAME" if ! $(check_shares); then log_warning_msg "No shares avalaible ..." log_end_msg 0 else checkpid start-stop-daemon --start --quiet --background --oknodo \ --make-pidfile --pidfile $PIDFILE \ --exec $DAEMON -- $USHARE_OPTIONS log_end_msg $? fi ;; stop) log_daemon_msg "Stopping $DESC: $NAME" start-stop-daemon --stop --signal 2 --quiet --oknodo --pidfile $PIDFILE log_end_msg $? ;; reload|force-reload) log_daemon_msg "Reloading $DESC: $NAME" start-stop-daemon --stop --signal 1 --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON log_end_msg $? ;; restart) $0 stop $0 start ;; *) N=/etc/init.d/$NAME log_success_msg "Usage: $N {start|stop|restart|reload|force-reload}" exit 1 ;; esac exit 0 ushare-1.1a/scripts/Makefile0000644000175000017500000000076610726763650014251 0ustar benbenifeq (,$(wildcard ../config.mak)) $(error "config.mak is not present, run configure !") endif include ../config.mak CONF_FILE = "ushare.conf" INITD_FILE = "ushare" EXTRADIST = $(CONF_FILE) $(INITD_FILE) all: clean: distclean: install: $(INSTALL) -d $(sysconfdir) $(INSTALL) -m 644 $(CONF_FILE) $(sysconfdir) $(INSTALL) -d $(sysconfdir)/init.d $(INSTALL) -m 755 $(INITD_FILE) $(sysconfdir)/init.d dist-all: cp $(EXTRADIST) $(SRCS) Makefile $(DIST) .PHONY: clean disctlean install dist-all ushare-1.1a/src/0000755000175000017500000000000010726763650011700 5ustar benbenushare-1.1a/src/ushare.10000644000175000017500000000761610726763650013263 0ustar benben.\" -*- nroff -*- .\" ushare.1 - Manual page for uShare. .\" .\" Copyright (C) 2005-2007 Benjamin Zores .\" .\" 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. .\" .TH USHARE 1 "July 05, 2007" .SH NAME uShare \(hy a lightweight UPnP A/V and DLNA Media Server .SH SYNOPSIS .B ushare [\f-\-v\fR] [\f-\-n name\fR] [\f-\-i interface\fR] [\f-\-p port\fR] [\f-\-w\fR] [\f-\-c directory\fR] [[\f-\-c directory\fR]...] .SH DESCRIPTION \fBuShare\fP is a free UPnP / DLNA multimedia files Media Server. It implements the server component that provides UPnP media devices with information on available multimedia files. uShare uses the built-in http server of libupnp to stream the files to clients. .SH OPTIONS This program follow the usual GNU command line syntax. .TP \fB\-\-name (\-n)\fR \fINAME\fR Set UPnP Friendly Name (display name of the media server). Default is 'uShare'. .TP \fB\-\-interface (\-i)\fR \fIINTERFACE\fR Set Network interface to listen on. Default is 'uShare'. .TP \fB\-\-cfg (\-f)\fR \fIFILE\fR Config file to be used. .TP \fB\-\-port (\-p)\fR \fIPORT\fR Set Network port to listen on. Default is random above 49152. .TP \fB\-\-telnet_port (\-q)\fR \fIPORT\fR Set Network port to listen on for telnet control connections. Default is 1337. .TP \fB\-\-content (\-c)\fR \fIDIRECTORY\fR Set directory to scan for multimedia files. .TP \fB\-\-no\-web (\-w)\fR Disable the control web page (enabled by default). .TP \fB\-\-no\-telnet (\-t)\fR Disable the telnet control (enabled by default). .TP \fB\-\-override-iconv-err (\-o)\fR If iconv fails parsing name, still add to media contents (hoping the renderer can handle it). .TP \fB\-\-verbose (\-v)\fR Set verbose display. .TP \fB\-\-xbox (\-x)\fR Use XboX 360 compliant profile. .TP \fB\-\-dlna (\-d)\fR Use DLNA compliant profile (required for PlayStation3). .TP \fB\-\-daemon (\-D)\fR Run as a daemon. .TP \fB\-\-version (\-V)\fR Display uShare version number. .TP \fB\-\-help (\-h)\fR Display help message. .SH "REMOTE CONTROL" You can also perform remote control of uShare UPnP Media Server through its web interface. This let you define new content locations at runtime or update the currently shared one in case the filesystem has changed. To disable this feature, use the \-\-no\-web option (see bellow). .TP Just go to : .TP .B http://ip_address:port/web/ushare.html .SH "FILE TYPES" The following file formats (extensions) are supported : .TP .B Video asf, avi, dv, divx, wmv, mjpg, mjpeg, mpeg, mpg, mpe, mp2p, vob, mp2t, m1v, m2v, m4v, m4p, mp4ps, ts, ogm, mkv, rmvb, mov, qt .TP .B Audio aac, ac3, aif, aiff, at3p, au, snd, dts, rmi, mp1, mp2, mp3, mp4, mpa, ogg, wav, pcm, lpcm, l16, wma, mka, ra, rm, ram .TP .B Images bmp, ico, gif, jpeg, jpg, jpe, pcd, png, pnm, ppm, qti, qtf, qtif, tif, tiff .TP .B Playlist pls, m3u, asx .TP .B Subtitles dks, idx, mpl, pjs, psb, scr, srt, ssa, stl, sub, tts, vsf, zeg .TP .B Miscellaneous files bup, ifo .SH "REPORTING BUGS" Report bugs to <\fIushare@geexbox.org\fP>. .SH AUTHOR uShare was written by Benjamin Zores . .SH COPYRIGHT Copyright \(co 2005-2007 Benjamin Zores This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ushare-1.1a/src/cds.h0000644000175000017500000001705410726763650012631 0ustar benben/* * cds.h : GeeXboX uShare Content Directory Service header. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef CDS_H_ #define CDS_H_ #define CDS_DESCRIPTION \ "" \ "" \ " " \ " 1" \ " 0" \ " " \ " " \ " " \ " Browse" \ " " \ " " \ " ObjectID" \ " in" \ " A_ARG_TYPE_ObjectID" \ " " \ " " \ " BrowseFlag" \ " in" \ " A_ARG_TYPE_BrowseFlag" \ " " \ " " \ " Filter" \ " in" \ " A_ARG_TYPE_Filter" \ " " \ " " \ " StartingIndex" \ " in" \ " A_ARG_TYPE_Index" \ " " \ " " \ " RequestedCount" \ " in" \ " A_ARG_TYPE_Count" \ " " \ " " \ " SortCriteria" \ " in" \ " A_ARG_TYPE_SortCriteria" \ " " \ " " \ " Result" \ " out" \ " A_ARG_TYPE_Result" \ " " \ " " \ " NumberReturned" \ " out" \ " A_ARG_TYPE_Count" \ " " \ " " \ " TotalMatches" \ " out" \ " A_ARG_TYPE_Count" \ " " \ " " \ " UpdateID" \ " out" \ " A_ARG_TYPE_UpdateID" \ " " \ " " \ " " \ " " \ " DestroyObject" \ " " \ " " \ " ObjectID" \ " in" \ " A_ARG_TYPE_ObjectID" \ " " \ " " \ " " \ " " \ " GetSystemUpdateID" \ " " \ " " \ " Id" \ " out" \ " SystemUpdateID" \ " " \ " " \ " " \ " " \ " GetSearchCapabilities" \ " " \ " " \ " SearchCaps" \ " out" \ " SearchCapabilities" \ " " \ " " \ " " \ " " \ " GetSortCapabilities" \ " " \ " " \ " SortCaps" \ " out" \ " SortCapabilities" \ " " \ " " \ " " \ " " \ " UpdateObject" \ " " \ " " \ " ObjectID" \ " in" \ " A_ARG_TYPE_ObjectID" \ " " \ " " \ " CurrentTagValue" \ " in" \ " A_ARG_TYPE_TagValueList" \ " " \ " " \ " NewTagValue" \ " in" \ " A_ARG_TYPE_TagValueList" \ " " \ " " \ " " \ " " \ " " \ " " \ " A_ARG_TYPE_BrowseFlag" \ " string" \ " " \ " BrowseMetadata" \ " BrowseDirectChildren" \ " " \ " " \ " " \ " SystemUpdateID" \ " ui4" \ " " \ " " \ " A_ARG_TYPE_Count" \ " ui4" \ " " \ " " \ " A_ARG_TYPE_SortCriteria" \ " string" \ " " \ " " \ " SortCapabilities" \ " string" \ " " \ " " \ " A_ARG_TYPE_Index" \ " ui4" \ " " \ " " \ " A_ARG_TYPE_ObjectID" \ " string" \ " " \ " " \ " A_ARG_TYPE_UpdateID" \ " ui4" \ " " \ " " \ " A_ARG_TYPE_TagValueList" \ " string" \ " " \ " " \ " A_ARG_TYPE_Result" \ " string" \ " " \ " " \ " SearchCapabilities" \ " string" \ " " \ " " \ " A_ARG_TYPE_Filter" \ " string" \ " " \ " " \ "" #define CDS_DESCRIPTION_LEN strlen (CDS_DESCRIPTION) #define CDS_LOCATION "/web/cds.xml" #define CDS_SERVICE_ID "urn:upnp-org:serviceId:ContentDirectory" #define CDS_SERVICE_TYPE "urn:schemas-upnp-org:service:ContentDirectory:1" #endif /* CDS_H_ */ ushare-1.1a/src/cms.h0000644000175000017500000001416510726763650012642 0ustar benben/* * cms.h : GeeXboX uShare Connection Management Service header. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef CMS_H_ #define CMS_H_ #define CMS_DESCRIPTION \ "" \ "" \ " " \ " 1" \ " 0" \ " " \ " " \ " " \ " GetCurrentConnectionInfo" \ " " \ " " \ " ConnectionID" \ " in" \ " A_ARG_TYPE_ConnectionID" \ " " \ " " \ " RcsID" \ " out" \ " A_ARG_TYPE_RcsID" \ " " \ " " \ " AVTransportID" \ " out" \ " A_ARG_TYPE_AVTransportID" \ " " \ " " \ " ProtocolInfo" \ " out" \ " A_ARG_TYPE_ProtocolInfo" \ " " \ " " \ " PeerConnectionManager" \ " out" \ " A_ARG_TYPE_ConnectionManager" \ " " \ " " \ " PeerConnectionID" \ " out" \ " A_ARG_TYPE_ConnectionID" \ " " \ " " \ " Direction" \ " out" \ " A_ARG_TYPE_Direction" \ " " \ " " \ " Status" \ " out" \ " A_ARG_TYPE_ConnectionStatus" \ " " \ " " \ " " \ " " \ " GetProtocolInfo" \ " " \ " " \ " Source" \ " out" \ " SourceProtocolInfo" \ " " \ " " \ " Sink" \ " out" \ " SinkProtocolInfo" \ " " \ " " \ " " \ " " \ " GetCurrentConnectionIDs" \ " " \ " " \ " ConnectionIDs" \ " out" \ " CurrentConnectionIDs" \ " " \ " " \ " " \ " " \ " " \ " " \ " A_ARG_TYPE_ProtocolInfo" \ " string" \ " " \ " " \ " A_ARG_TYPE_ConnectionStatus" \ " string" \ " " \ " OK" \ " ContentFormatMismatch" \ " InsufficientBandwidth" \ " UnreliableChannel" \ " Unknown" \ " " \ " " \ " " \ " A_ARG_TYPE_AVTransportID" \ " i4" \ " " \ " " \ " A_ARG_TYPE_RcsID" \ " i4" \ " " \ " " \ " A_ARG_TYPE_ConnectionID" \ " i4" \ " " \ " " \ " A_ARG_TYPE_ConnectionManager" \ " string" \ " " \ " " \ " SourceProtocolInfo" \ " string" \ " " \ " " \ " SinkProtocolInfo" \ " string" \ " " \ " " \ " A_ARG_TYPE_Direction" \ " string" \ " " \ " Input" \ " Output" \ " " \ " " \ " " \ " CurrentConnectionIDs" \ " string" \ " " \ " " \ "" #define CMS_DESCRIPTION_LEN strlen (CMS_DESCRIPTION) #define CMS_LOCATION "/web/cms.xml" #define CMS_SERVICE_ID "urn:upnp-org:serviceId:ConnectionManager" #define CMS_SERVICE_TYPE "urn:schemas-upnp-org:service:ConnectionManager:1" #endif /* CMS_H_ */ ushare-1.1a/src/msr.h0000644000175000017500000001015510726763650012654 0ustar benben/* * msr.h : GeeXboX uShare Microsoft Registrar Service header. * Originally developped for the GeeXboX project. * Copyright (C) 2006 Benjamin Zores * * 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. */ #ifndef MSR_H_ #define MSR_H_ #define MSR_DESCRIPTION \ "" \ "" \ "" \ " 1" \ " 0" \ "" \ "" \ " " \ " IsAuthorized" \ " " \ " " \ " DeviceID" \ " in" \ " A_ARG_TYPE_DeviceID" \ " " \ " " \ " Result" \ " out" \ " A_ARG_TYPE_Result" \ " " \ " " \ " " \ " " \ " RegisterDevice" \ " " \ " " \ " RegistrationReqMsg" \ " in" \ " A_ARG_TYPE_RegistrationReqMsg" \ " " \ " " \ " RegistrationRespMsg" \ " out" \ " A_ARG_TYPE_RegistrationRespMsg" \ " " \ " " \ " " \ " " \ " IsValidated" \ " " \ " " \ " DeviceID" \ " in" \ " A_ARG_TYPE_DeviceID" \ " " \ " " \ " Result" \ " out" \ " A_ARG_TYPE_Result" \ " " \ " " \ " " \ "" \ "" \ " " \ " A_ARG_TYPE_DeviceID" \ " string" \ " " \ " " \ " A_ARG_TYPE_Result" \ " int" \ " " \ " " \ " A_ARG_TYPE_RegistrationReqMsg" \ " bin.base64" \ " " \ " " \ " A_ARG_TYPE_RegistrationRespMsg" \ " bin.base64" \ " " \ " " \ " AuthorizationGrantedUpdateID" \ " ui4" \ " " \ " " \ " AuthorizationDeniedUpdateID" \ " ui4" \ " " \ " " \ " ValidationSucceededUpdateID" \ " ui4" \ " " \ " " \ " ValidationRevokedUpdateID" \ " ui4" \ " " \ "" \ "" #define MSR_DESCRIPTION_LEN strlen (MSR_DESCRIPTION) #define MSR_LOCATION "/web/msr.xml" #define MSR_SERVICE_ID "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar" #define MSR_SERVICE_TYPE "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1" #endif /* MSR_H_ */ ushare-1.1a/src/http.h0000644000175000017500000000216510726763650013034 0ustar benben/* * http.h : GeeXboX uShare Web Server handler header. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _HTTP_H_ #define _HTTP_H_ #include #include struct UpnpVirtualDirCallbacks virtual_dir_callbacks; #endif /* _HTTP_H_ */ ushare-1.1a/src/presentation.h0000644000175000017500000000233210726763650014564 0ustar benben/* * presentation.h : GeeXboX uShare UPnP Presentation Page headers. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _PRESENTATION_H_ #define _PRESENTATION_H_ #define USHARE_PRESENTATION_PAGE "/web/ushare.html" #define PRESENTATION_PAGE_CONTENT_TYPE "text/html" #define USHARE_CGI "/web/ushare.cgi" int process_cgi (struct ushare_t *ut, char *cgiargs); int build_presentation_page (struct ushare_t *ut); #endif /* _PRESENTATION_H_ */ ushare-1.1a/src/metadata.h0000644000175000017500000000341110726763650013630 0ustar benben/* * metadata.h : GeeXboX uShare CDS Metadata DB header. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _METADATA_H_ #define _METADATA_H_ #include #include #include #include #include "ushare.h" #include "http.h" #include "content.h" struct upnp_entry_t { int id; char *fullpath; #ifdef HAVE_DLNA dlna_profile_t *dlna_profile; #endif /* HAVE_DLNA */ struct upnp_entry_t *parent; int child_count; struct upnp_entry_t **childs; struct mime_type_t *mime_type; char *title; char *url; off_t size; int fd; }; typedef struct xml_convert_s { char charac; char *xml; } xml_convert_t; void free_metadata_list (struct ushare_t *ut); void build_metadata_list (struct ushare_t *ut); struct upnp_entry_t *upnp_get_entry (struct ushare_t *ut, int id); void upnp_entry_free (struct ushare_t *ut, struct upnp_entry_t *entry); int rb_compare (const void *pa, const void *pb, const void *config); #endif /* _METADATA_H_ */ ushare-1.1a/src/mime.h0000644000175000017500000000212710726763650013002 0ustar benben/* * mime.h : GeeXboX uShare media file MIME-type association header. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _MIME_H_ #define _MIME_H_ struct mime_type_t { char *extension; char *mime_class; char *mime_protocol; }; char *mime_get_protocol (struct mime_type_t *mime); #endif /* _MIME_H */ ushare-1.1a/src/services.h0000644000175000017500000000337010726763650013677 0ustar benben/* * services.h : GeeXboX uShare UPnP services handler header. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _SERVICES_H_ #define _SERVICES_H_ #include #include #include "ushare.h" struct service_action_t { char *name; bool (*function) (struct action_event_t *); }; struct service_t { char *id; char *type; struct service_action_t *actions; }; #define SERVICE_CONTENT_TYPE "text/xml" bool find_service_action (struct Upnp_Action_Request *request, struct service_t **service, struct service_action_t **action); bool upnp_add_response (struct action_event_t *event, char *key, const char *value); char * upnp_get_string (struct Upnp_Action_Request *request, const char *key); int upnp_get_ui4 (struct Upnp_Action_Request *request, const char *key); #endif /* _SERVICES_H_ */ ushare-1.1a/src/buffer.h0000644000175000017500000000250110726763650013320 0ustar benben/* buffer.h - String buffer manipulation tools header. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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. * */ #ifndef _STRING_BUFFER_H_ #define _STRING_BUFFER_H_ struct buffer_t { char *buf; size_t len; size_t capacity; }; struct buffer_t *buffer_new (void) __attribute__ ((malloc)); void buffer_free (struct buffer_t *buffer); void buffer_append (struct buffer_t *buffer, const char *str); void buffer_appendf (struct buffer_t *buffer, const char *format, ...) __attribute__ ((format (printf , 2, 3))); #endif /* _STRING_BUFFER_H_ */ ushare-1.1a/src/util_iconv.h0000644000175000017500000000217110726763650014225 0ustar benben/* * util_iconv.h : GeeXboX uShare iconv string encoding utilities headers. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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. */ #ifndef _UTIL_ICONV_H_ #define _UTIL_ICONV_H_ void setup_iconv (void); void finish_iconv (void); char *iconv_convert (const char *inbuf) __attribute__ ((malloc, nonnull, format_arg (1))); #define UTF8 "UTF-8" #endif ushare-1.1a/src/content.h0000644000175000017500000000237010726763650013525 0ustar benben/* * content.h : GeeXboX uShare content list header * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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. */ #ifndef _CONTENT_H_ #define _CONTENT_H_ typedef struct content_list { char **content; int count; } content_list; content_list *content_add(content_list *list, const char *item) __attribute__ ((malloc)); content_list *content_del(content_list *list, int n) __attribute__ ((nonnull)); void content_free(content_list *list) __attribute__ ((nonnull)); #endif ushare-1.1a/src/cfgparser.h0000644000175000017500000000402310726763650014024 0ustar benben/* * cfgparser.c : GeeXboX uShare config file parser headers. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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. */ #ifndef _CONFIG_PARSER_H_ #define _CONFIG_PARSER_H_ #include "ushare.h" #define USHARE_NAME "USHARE_NAME" #define USHARE_IFACE "USHARE_IFACE" #define USHARE_PORT "USHARE_PORT" #define USHARE_TELNET_PORT "USHARE_TELNET_PORT" #define USHARE_DIR "USHARE_DIR" #define USHARE_OVERRIDE_ICONV_ERR "USHARE_OVERRIDE_ICONV_ERR" #define USHARE_ENABLE_WEB "USHARE_ENABLE_WEB" #define USHARE_ENABLE_TELNET "USHARE_ENABLE_TELNET" #define USHARE_ENABLE_XBOX "USHARE_ENABLE_XBOX" #define USHARE_ENABLE_DLNA "USHARE_ENABLE_DLNA" #define USHARE_CONFIG_FILE "ushare.conf" #define DEFAULT_USHARE_NAME "uShare" #if (defined(BSD) || defined(__FreeBSD__)) #define DEFAULT_USHARE_IFACE "lnc0" #else /* Linux */ #define DEFAULT_USHARE_IFACE "eth0" #endif int parse_config_file (struct ushare_t *ut) __attribute__ ((nonnull)); int parse_command_line (struct ushare_t *ut, int argc, char **argv) __attribute__ ((nonnull (1))); typedef struct { char *name; void (*set_var) (struct ushare_t*, const char*); } u_configline_t; #endif /* _CONFIG_PARSER_H_ */ ushare-1.1a/src/trace.h0000644000175000017500000000306710726763650013155 0ustar benben/* * trace.h : GeeXboX uShare log facility headers. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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. */ #ifndef _TRACE_H_ #define _TRACE_H_ typedef enum { ULOG_NORMAL = 1, ULOG_ERROR = 2, ULOG_VERBOSE = 3, } log_level; void print_log (log_level level, const char *format, ...) __attribute__ ((format (printf, 2, 3))); inline void start_log (void); /* log_info * Normal print, to replace printf */ #define log_info(s, str...) { \ print_log (ULOG_NORMAL, (s), ##str); \ } /* log_error * Error messages, output to stderr */ #define log_error(s, str...) { \ print_log (ULOG_ERROR, (s), ##str); \ } /* log_verbose * Output only in verbose mode */ #define log_verbose(s, str...) { \ print_log (ULOG_VERBOSE, (s), ##str); \ } #endif /* _TRACE_H_ */ ushare-1.1a/src/redblack.h0000644000175000017500000001364210726763650013626 0ustar benben/* * RCS $Id: redblack.h,v 1.9 2003/10/24 01:31:21 damo Exp $ */ /* Redblack balanced tree algorithm Copyright (C) Damian Ivereigh 2000 This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See the file COPYING for details. 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 General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Header file for redblack.c, should be included by any code that ** uses redblack.c since it defines the functions */ /* Stop multiple includes */ #ifndef _REDBLACK_H #ifndef RB_CUSTOMIZE /* * Without customization, the data member in the tree nodes is a void * pointer, and you need to pass in a comparison function to be * applied at runtime. With customization, you specify the data type * as the macro RB_ENTRY(data_t) (has to be a macro because compilers * gag on typdef void) and the name of the compare function as the * value of the macro RB_CMP. Because the comparison function is * compiled in, RB_CMP only needs to take two arguments. If your * content type is not a pointer, define INLINE to get direct access. */ #define rbdata_t void #define RB_CMP(s, t, e) (*rbinfo->rb_cmp)(s, t, e) #undef RB_INLINE #define RB_ENTRY(name) rb##name #endif /* RB_CUSTOMIZE */ #ifndef RB_STATIC #define RB_STATIC #endif /* Modes for rblookup */ #define RB_NONE -1 /* None of those below */ #define RB_LUEQUAL 0 /* Only exact match */ #define RB_LUGTEQ 1 /* Exact match or greater */ #define RB_LULTEQ 2 /* Exact match or less */ #define RB_LULESS 3 /* Less than key (not equal to) */ #define RB_LUGREAT 4 /* Greater than key (not equal to) */ #define RB_LUNEXT 5 /* Next key after current */ #define RB_LUPREV 6 /* Prev key before current */ #define RB_LUFIRST 7 /* First key in index */ #define RB_LULAST 8 /* Last key in index */ /* For rbwalk - pinched from search.h */ typedef enum { preorder, postorder, endorder, leaf } VISIT; struct RB_ENTRY(lists) { const struct RB_ENTRY(node) *rootp; const struct RB_ENTRY(node) *nextp; }; #define RBLIST struct RB_ENTRY(lists) struct RB_ENTRY(tree) { #ifndef RB_CUSTOMIZE /* comparison routine */ int (*rb_cmp)(const void *, const void *, const void *); /* config data to be passed to rb_cmp */ const void *rb_config; /* root of tree */ #endif /* RB_CUSTOMIZE */ struct RB_ENTRY(node) *rb_root; }; #ifndef RB_CUSTOMIZE RB_STATIC struct RB_ENTRY(tree) *rbinit(int (*)(const void *, const void *, const void *), const void *); #else RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void); #endif /* RB_CUSTOMIZE */ #ifndef no_delete RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(delete)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); #endif #ifndef no_find RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(find)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); #endif #ifndef no_lookup RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(lookup)(int, const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); #endif #ifndef no_search RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(search)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); #endif #ifndef no_destroy RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *); #endif #ifndef no_walk RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *, void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *); #endif #ifndef no_readlist RB_STATIC RBLIST *RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *); RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(readlist)(RBLIST *); RB_STATIC void RB_ENTRY(closelist)(RBLIST *); #endif /* Some useful macros */ #define rbmin(rbinfo) RB_ENTRY(lookup)(RB_LUFIRST, NULL, (rbinfo)) #define rbmax(rbinfo) RB_ENTRY(lookup)(RB_LULAST, NULL, (rbinfo)) #define _REDBLACK_H #endif /* _REDBLACK_H */ /* * * $Log: redblack.h,v $ * Revision 1.9 2003/10/24 01:31:21 damo * Patches from Eric Raymond: %prefix is implemented.  Various other small * changes avoid stepping on global namespaces and improve the documentation. * * Revision 1.8 2003/10/23 04:18:47 damo * Fixed up the rbgen stuff ready for the 1.3 release * * Revision 1.7 2002/08/26 03:11:40 damo * Fixed up a bunch of compiler warnings when compiling example4 * * Tidies up the Makefile.am & Specfile. * * Renamed redblack to rbgen * * Revision 1.6 2002/08/26 01:03:35 damo * Patch from Eric Raymond to change the way the library is used:- * * Eric's idea is to convert libredblack into a piece of in-line code * generated by another program. This should be faster, smaller and easier * to use. * * This is the first check-in of his code before I start futzing with it! * * Revision 1.5 2002/01/30 07:54:53 damo * Fixed up the libtool versioning stuff (finally) * Fixed bug 500600 (not detecting a NULL return from malloc) * Fixed bug 509485 (no longer needs search.h) * Cleaned up debugging section * Allow multiple inclusions of redblack.h * Thanks to Matthias Andree for reporting (and fixing) these * * Revision 1.4 2000/06/06 14:43:43 damo * Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk. * Added two new examples * * Revision 1.3 2000/05/24 06:45:27 damo * Converted everything over to using const * Added a new example1.c file to demonstrate the worst case scenario * Minor fixups of the spec file * * Revision 1.2 2000/05/24 06:17:10 damo * Fixed up the License (now the LGPL) * * Revision 1.1 2000/05/24 04:15:53 damo * Initial import of files. Versions are now all over the place. Oh well * */ ushare-1.1a/src/osdep.h0000644000175000017500000000216510726763650013167 0ustar benben/* * osdep.h : GeeXboX uShare OS independant helpers headers. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _OS_DEP_H_ #define _OS_DEP_H_ #if (defined(BSD) || defined(__FreeBSD__)) #include char *strndup (const char *s, size_t n); ssize_t getline (char **lineptr, size_t *n, FILE *stream); #endif #endif /* _OS_DEP_H_ */ ushare-1.1a/src/ctrl_telnet.h0000644000175000017500000000507710726763650014401 0ustar benben/* ctrltelnet.h - Header for the Telnet controler * Copyright (C) 2005-2007 Sven Almgren * * 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. * */ #ifndef _CTRL_TELNET_H_ #define _CTRL_TELNET_H_ #define CTRL_TELNET_PORT 1337 #define CTRL_TELNET_BACKLOG 10 #define CTRL_TELNET_SHARED_BUFFER_SIZE 256 #define CTRL_CLIENT_RECV_BUFFER_SIZE 256 #include /** * @brief Structure doubling as both a connected client data holder * and as a linked list */ typedef struct ctrl_telnet_client_t { /* Recv buffer used to read single lines from more then one packet ... Not garanteed to be NULL terminated */ char buffer_recv[CTRL_CLIENT_RECV_BUFFER_SIZE]; int buffer_recv_current; int socket; int ready; /* True if this client has a complete line, ready to be parsed */ int exiting; struct sockaddr_in remote_address; struct ctrl_telnet_client_t* next; } ctrl_telnet_client; typedef void (* ctrl_telnet_command_ptr) (ctrl_telnet_client *, int, char **); /** * @brief Starts a Telnet bound control interface * * @return 0 on success, -1 on error */ int ctrl_telnet_start (int port); /** * @brief Stops all telnet bound control interfaces */ void ctrl_telnet_stop (void); /* FIXME: You can register a function name multiple times, but the last one added is the one getting called... not a problem a.t.m. */ void ctrl_telnet_register (const char *funcname, ctrl_telnet_command_ptr funcptr, const char* description); int ctrl_telnet_client_send (const ctrl_telnet_client *, const char* string); int ctrl_telnet_client_sendf (const ctrl_telnet_client *client, const char* format, ...); int ctrl_telnet_client_sendsf (const ctrl_telnet_client *client, char* buffer, int buffersize, const char* format, ...); #endif /* _CTRL_TELNET_H_ */ ushare-1.1a/src/ushare.h0000644000175000017500000001032410726763650013340 0ustar benben/* * ushare.h : GeeXboX uShare UPnP Media Server header. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #ifndef _USHARE_H_ #define _USHARE_H_ #include #include #include #include #ifdef HAVE_DLNA #include #endif /* HAVE_DLNA */ #include "content.h" #include "buffer.h" #include "redblack.h" #define VIRTUAL_DIR "/web" #define XBOX_MODEL_NAME "Windows Media Connect Compatible" #define DEFAULT_UUID "898f9738-d930-4db4-a3cf" #define UPNP_MAX_CONTENT_LENGTH 4096 #define STARTING_ENTRY_ID_DEFAULT 0 #define STARTING_ENTRY_ID_XBOX360 100000 #define UPNP_DESCRIPTION \ "" \ "" \ " " \ " 1" \ " 0" \ " " \ " " \ " urn:schemas-upnp-org:device:MediaServer:1" \ " %s: 1" \ " GeeXboX Team" \ " http://ushare.geexbox.org/" \ " GeeXboX uShare : UPnP Media Server" \ " %s" \ " 001" \ " http://ushare.geexbox.org/" \ " GEEXBOX-USHARE-01" \ " uuid:%s" \ " " \ " " \ " urn:schemas-upnp-org:service:ConnectionManager:1" \ " urn:upnp-org:serviceId:ConnectionManager" \ " /web/cms.xml" \ " /web/cms_control" \ " /web/cms_event" \ " " \ " " \ " urn:schemas-upnp-org:service:ContentDirectory:1" \ " urn:upnp-org:serviceId:ContentDirectory" \ " /web/cds.xml" \ " /web/cds_control" \ " /web/cds_event" \ " " \ " " \ " urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1\n" \ " urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar\n" \ " /web/msr.xml" \ " /web/msr_control" \ " /web/msr_event" \ " \n" \ " " \ " /web/ushare.html" \ " " \ "" struct ushare_t { char *name; char *interface; char *model_name; content_list *contentlist; struct rbtree *rb; struct upnp_entry_t *root_entry; int nr_entries; int starting_id; int init; UpnpDevice_Handle dev; char *udn; char *ip; unsigned short port; unsigned short telnet_port; struct buffer_t *presentation; bool use_presentation; bool use_telnet; #ifdef HAVE_DLNA bool dlna_enabled; dlna_t *dlna; dlna_org_flags_t dlna_flags; #endif /* HAVE_DLNA */ bool xbox360; bool verbose; bool daemon; bool override_iconv_err; char *cfg_file; pthread_mutex_t termination_mutex; pthread_cond_t termination_cond; }; struct action_event_t { struct Upnp_Action_Request *request; bool status; struct service_t *service; }; inline void display_headers (void); #endif /* _USHARE_H_ */ ushare-1.1a/src/gettext.h0000644000175000017500000000663710726763650013551 0ustar benben/* Convenience header for conditional use of GNU . Copyright (C) 1995-1998, 2000-2002, 2004 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2, 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 Library 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. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 #define _(string) gettext (string) /* NLS can be disabled through the configure --disable-nls option. */ #ifdef CONFIG_NLS /* Get declarations of GNU message catalog functions. */ # include #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. We don't include as well because people using "gettext.h" will not include , and also including would fail on SunOS 4, whereas is OK. */ #if defined(__sun) # include #endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. */ #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) # include # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H # include # endif #endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ # define gettext(Msgid) ((const char *) (Msgid)) # define dgettext(Domainname, Msgid) ((const char *) (Msgid)) # define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) # define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define dngettext(Domainname, Msgid1, Msgid2, N) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define textdomain(Domainname) ((const char *) (Domainname)) # define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) # define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) #endif /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. The argument, String, should be a literal string. Concatenated strings and other string expressions won't work. The macro's expansion is not parenthesized, so that it is suitable as initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String #endif /* _LIBGETTEXT_H */ ushare-1.1a/src/minmax.h0000644000175000017500000000200310726763650013335 0ustar benben/* MIN, MAX macros. * Copyright (C) 1995, 1998, 2001, 2003, 2005 Free Software Foundation, Inc. * * 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, 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 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. */ #ifndef _MINMAX_H_ #define _MINMAX_H_ #include #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #endif /* _MINMAX_H_ */ ushare-1.1a/src/cds.c0000644000175000017500000006413710726763650012630 0ustar benben/* * cds.c : GeeXboX uShare Content Directory Service * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include "ushare.h" #include "services.h" #include "ushare.h" #include "services.h" #include "metadata.h" #include "mime.h" #include "buffer.h" #include "minmax.h" /* Represent the CDS GetSearchCapabilities action. */ #define SERVICE_CDS_ACTION_SEARCH_CAPS "GetSearchCapabilities" /* Represent the CDS GetSortCapabilities action. */ #define SERVICE_CDS_ACTION_SORT_CAPS "GetSortCapabilities" /* Represent the CDS GetSystemUpdateID action. */ #define SERVICE_CDS_ACTION_UPDATE_ID "GetSystemUpdateID" /* Represent the CDS Browse action. */ #define SERVICE_CDS_ACTION_BROWSE "Browse" /* Represent the CDS Search action. */ #define SERVICE_CDS_ACTION_SEARCH "Search" /* Represent the CDS SearchCaps argument. */ #define SERVICE_CDS_ARG_SEARCH_CAPS "SearchCaps" /* Represent the CDS SortCaps argument. */ #define SERVICE_CDS_ARG_SORT_CAPS "SortCaps" /* Represent the CDS UpdateId argument. */ #define SERVICE_CDS_ARG_UPDATE_ID "Id" /* Represent the CDS StartingIndex argument. */ #define SERVICE_CDS_ARG_START_INDEX "StartingIndex" /* Represent the CDS RequestedCount argument. */ #define SERVICE_CDS_ARG_REQUEST_COUNT "RequestedCount" /* Represent the CDS ObjectID argument. */ #define SERVICE_CDS_ARG_OBJECT_ID "ObjectID" /* Represent the CDS Filter argument. */ #define SERVICE_CDS_ARG_FILTER "Filter" /* Represent the CDS BrowseFlag argument. */ #define SERVICE_CDS_ARG_BROWSE_FLAG "BrowseFlag" /* Represent the CDS SortCriteria argument. */ #define SERVICE_CDS_ARG_SORT_CRIT "SortCriteria" /* Represent the CDS SearchCriteria argument. */ #define SERVICE_CDS_ARG_SEARCH_CRIT "SearchCriteria" /* Represent the CDS Root Object ID argument. */ #define SERVICE_CDS_ROOT_OBJECT_ID "0" /* Represent the CDS DIDL Message Metadata Browse flag argument. */ #define SERVICE_CDS_BROWSE_METADATA "BrowseMetadata" /* Represent the CDS DIDL Message DirectChildren Browse flag argument. */ #define SERVICE_CDS_BROWSE_CHILDREN "BrowseDirectChildren" /* Represent the CDS DIDL Message Result argument. */ #define SERVICE_CDS_DIDL_RESULT "Result" /* Represent the CDS DIDL Message NumberReturned argument. */ #define SERVICE_CDS_DIDL_NUM_RETURNED "NumberReturned" /* Represent the CDS DIDL Message TotalMatches argument. */ #define SERVICE_CDS_DIDL_TOTAL_MATCH "TotalMatches" /* Represent the CDS DIDL Message UpdateID argument. */ #define SERVICE_CDS_DIDL_UPDATE_ID "UpdateID" /* DIDL parameters */ /* Represent the CDS DIDL Message Header Namespace. */ #define DIDL_NAMESPACE \ "xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" " \ "xmlns:dc=\"http://purl.org/dc/elements/1.1/\" " \ "xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\"" /* Represent the CDS DIDL Message Header Tag. */ #define DIDL_LITE "DIDL-Lite" /* Represent the CDS DIDL Message Item value. */ #define DIDL_ITEM "item" /* Represent the CDS DIDL Message Item ID value. */ #define DIDL_ITEM_ID "id" /* Represent the CDS DIDL Message Item Parent ID value. */ #define DIDL_ITEM_PARENT_ID "parentID" /* Represent the CDS DIDL Message Item Restricted value. */ #define DIDL_ITEM_RESTRICTED "restricted" /* Represent the CDS DIDL Message Item UPnP Class value. */ #define DIDL_ITEM_CLASS "upnp:class" /* Represent the CDS DIDL Message Item Title value. */ #define DIDL_ITEM_TITLE "dc:title" /* Represent the CDS DIDL Message Item Resource value. */ #define DIDL_RES "res" /* Represent the CDS DIDL Message Item Protocol Info value. */ #define DIDL_RES_INFO "protocolInfo" /* Represent the CDS DIDL Message Item Resource Size value. */ #define DIDL_RES_SIZE "size" /* Represent the CDS DIDL Message Container value. */ #define DIDL_CONTAINER "container" /* Represent the CDS DIDL Message Container ID value. */ #define DIDL_CONTAINER_ID "id" /* Represent the CDS DIDL Message Container Parent ID value. */ #define DIDL_CONTAINER_PARENT_ID "parentID" /* Represent the CDS DIDL Message Container number of children value. */ #define DIDL_CONTAINER_CHILDS "childCount" /* Represent the CDS DIDL Message Container Restricted value. */ #define DIDL_CONTAINER_RESTRICTED "restricted" /* Represent the CDS DIDL Message Container Searchable value. */ #define DIDL_CONTAINER_SEARCH "searchable" /* Represent the CDS DIDL Message Container UPnP Class value. */ #define DIDL_CONTAINER_CLASS "upnp:class" /* Represent the CDS DIDL Message Container Title value. */ #define DIDL_CONTAINER_TITLE "dc:title" /* Represent the "upnp:class" reserved keyword for Search action */ #define SEARCH_CLASS_MATCH_KEYWORD "(upnp:class = \"" /* Represent the "upnp:class derived from" reserved keyword */ #define SEARCH_CLASS_DERIVED_KEYWORD "(upnp:class derivedfrom \"" /* Represent the "res@protocolInfo contains" reserved keyword */ #define SEARCH_PROTOCOL_CONTAINS_KEYWORD "(res@protocolInfo contains \"" /* Represent the Search default keyword */ #define SEARCH_OBJECT_KEYWORD "object" /* Represent the Search 'AND' connector keyword */ #define SEARCH_AND ") and (" static bool filter_has_val (const char *filter, const char *val) { char *x = NULL, *token = NULL; char *m_buffer = NULL, *buffer; int len = strlen (val); bool ret = false; if (!strcmp (filter, "*")) return true; x = strdup (filter); if (x) { m_buffer = (char*) malloc (strlen (x)); if (m_buffer) { buffer = m_buffer; token = strtok_r (x, ",", &buffer); while (token) { if (*val == '@') token = strchr (token, '@'); if (token && !strncmp (token, val, len)) { ret = true; break; } token = strtok_r (NULL, ",", &buffer); } free (m_buffer); } free (x); } return ret; } /* UPnP ContentDirectory Service actions */ static bool cds_get_search_capabilities (struct action_event_t *event) { upnp_add_response (event, SERVICE_CDS_ARG_SEARCH_CAPS, ""); return event->status; } static bool cds_get_sort_capabilities (struct action_event_t *event) { upnp_add_response (event, SERVICE_CDS_ARG_SORT_CAPS, ""); return event->status; } static bool cds_get_system_update_id (struct action_event_t *event) { upnp_add_response (event, SERVICE_CDS_ARG_UPDATE_ID, SERVICE_CDS_ROOT_OBJECT_ID); return event->status; } static void didl_add_header (struct buffer_t *out) { buffer_appendf (out, "<%s %s>", DIDL_LITE, DIDL_NAMESPACE); } static void didl_add_footer (struct buffer_t *out) { buffer_appendf (out, "", DIDL_LITE); } static void didl_add_tag (struct buffer_t *out, char *tag, char *value) { if (value) buffer_appendf (out, "<%s>%s", tag, value, tag); } static void didl_add_param (struct buffer_t *out, char *param, char *value) { if (value) buffer_appendf (out, " %s=\"%s\"", param, value); } static void didl_add_value (struct buffer_t *out, char *param, off_t value) { buffer_appendf (out, " %s=\"%lld\"", param, value); } static void didl_add_item (struct buffer_t *out, int item_id, int parent_id, char *restricted, char *class, char *title, char *protocol_info, off_t size, char *url, char *filter) { buffer_appendf (out, "<%s", DIDL_ITEM); didl_add_value (out, DIDL_ITEM_ID, item_id); didl_add_value (out, DIDL_ITEM_PARENT_ID, parent_id); didl_add_param (out, DIDL_ITEM_RESTRICTED, restricted); buffer_append (out, ">"); didl_add_tag (out, DIDL_ITEM_CLASS, class); didl_add_tag (out, DIDL_ITEM_TITLE, title); if (filter_has_val (filter, DIDL_RES)) { buffer_appendf (out, "<%s", DIDL_RES); // protocolInfo is required : didl_add_param (out, DIDL_RES_INFO, protocol_info); if (filter_has_val (filter, "@"DIDL_RES_SIZE)) didl_add_value (out, DIDL_RES_SIZE, size); buffer_append (out, ">"); if (url) { extern struct ushare_t *ut; buffer_appendf (out, "http://%s:%d%s/%s", UpnpGetServerIpAddress (), ut->port, VIRTUAL_DIR, url); } buffer_appendf (out, "", DIDL_RES); } buffer_appendf (out, "", DIDL_ITEM); } static void didl_add_container (struct buffer_t *out, int id, int parent_id, int child_count, char *restricted, char *searchable, char *title, char *class) { buffer_appendf (out, "<%s", DIDL_CONTAINER); didl_add_value (out, DIDL_CONTAINER_ID, id); didl_add_value (out, DIDL_CONTAINER_PARENT_ID, parent_id); if (child_count >= 0) didl_add_value (out, DIDL_CONTAINER_CHILDS, child_count); didl_add_param (out, DIDL_CONTAINER_RESTRICTED, restricted); didl_add_param (out, DIDL_CONTAINER_SEARCH, searchable); buffer_append (out, ">"); didl_add_tag (out, DIDL_CONTAINER_CLASS, class); didl_add_tag (out, DIDL_CONTAINER_TITLE, title); buffer_appendf (out, "", DIDL_CONTAINER); } static int cds_browse_metadata (struct action_event_t *event, struct buffer_t *out, int index, int count, struct upnp_entry_t *entry, char *filter) { int result_count = 0, c = 0; if (!entry) return -1; if (entry->child_count == -1) /* item : file */ { #ifdef HAVE_DLNA extern struct ushare_t *ut; #endif /* HAVE_DLNA */ char *protocol = #ifdef HAVE_DLNA entry->dlna_profile ? dlna_write_protocol_info (DLNA_PROTOCOL_INFO_TYPE_HTTP, DLNA_ORG_PLAY_SPEED_NORMAL, DLNA_ORG_CONVERSION_NONE, DLNA_ORG_OPERATION_RANGE, ut->dlna_flags, entry->dlna_profile) : #endif /* HAVE_DLNA */ mime_get_protocol (entry->mime_type); didl_add_header (out); #ifdef HAVE_DLNA entry->dlna_profile ? didl_add_item (out, entry->id, entry->parent ? entry->parent->id : -1, "false", dlna_profile_upnp_object_item (entry->dlna_profile), entry->title, protocol, entry->size, entry->url, filter) : #endif /* HAVE_DLNA */ didl_add_item (out, entry->id, entry->parent ? entry->parent->id : -1, "false", entry->mime_type->mime_class, entry->title, protocol, entry->size, entry->url, filter); didl_add_footer (out); free (protocol); for (c = index; c < MIN (index + count, entry->child_count); c++) result_count++; } else /* container : directory */ { didl_add_header (out); didl_add_container (out, entry->id, entry->parent ? entry->parent->id : -1, entry->child_count, "true", "true", entry->title, entry->mime_type->mime_class); didl_add_footer (out); result_count = 1; } upnp_add_response (event, SERVICE_CDS_DIDL_RESULT, out->buf); upnp_add_response (event, SERVICE_CDS_DIDL_NUM_RETURNED, "1"); upnp_add_response (event, SERVICE_CDS_DIDL_TOTAL_MATCH, "1"); return result_count; } static int cds_browse_directchildren (struct action_event_t *event, struct buffer_t *out, int index, int count, struct upnp_entry_t *entry, char *filter) { struct upnp_entry_t **childs; int s, result_count = 0; char tmp[32]; if (entry->child_count == -1) /* item : file */ return -1; didl_add_header (out); /* go to the child pointed out by index */ childs = entry->childs; for (s = 0; s < index; s++) if (*childs) childs++; /* UPnP CDS compliance : If starting index = 0 and requested count = 0 then all children must be returned */ if (index == 0 && count == 0) count = entry->child_count; for (; *childs; childs++) { if (count == 0 || result_count < count) /* only fetch the requested count number or all entries if count = 0 */ { if ((*childs)->child_count >= 0) /* container */ didl_add_container (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, (*childs)->child_count, "true", NULL, (*childs)->title, (*childs)->mime_type->mime_class); else /* item */ { #ifdef HAVE_DLNA extern struct ushare_t *ut; #endif /* HAVE_DLNA */ char *protocol = #ifdef HAVE_DLNA (*childs)->dlna_profile ? dlna_write_protocol_info (DLNA_PROTOCOL_INFO_TYPE_HTTP, DLNA_ORG_PLAY_SPEED_NORMAL, DLNA_ORG_CONVERSION_NONE, DLNA_ORG_OPERATION_RANGE, ut->dlna_flags, (*childs)->dlna_profile) : #endif /* HAVE_DLNA */ mime_get_protocol ((*childs)->mime_type); #ifdef HAVE_DLNA (*childs)->dlna_profile ? didl_add_item (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, "true", dlna_profile_upnp_object_item ((*childs)->dlna_profile), (*childs)->title, protocol, (*childs)->size, (*childs)->url, filter) : #endif /* HAVE_DLNA */ didl_add_item (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, "true", (*childs)->mime_type->mime_class, (*childs)->title, protocol, (*childs)->size, (*childs)->url, filter); free (protocol); } result_count++; } } didl_add_footer (out); upnp_add_response (event, SERVICE_CDS_DIDL_RESULT, out->buf); sprintf (tmp, "%d", result_count); upnp_add_response (event, SERVICE_CDS_DIDL_NUM_RETURNED, tmp); sprintf (tmp, "%d", entry->child_count); upnp_add_response (event, SERVICE_CDS_DIDL_TOTAL_MATCH, tmp); return result_count; } static bool cds_browse (struct action_event_t *event) { extern struct ushare_t *ut; struct upnp_entry_t *entry = NULL; int result_count = 0, index, count, id, sort_criteria; char *flag = NULL; char *filter = NULL; struct buffer_t *out = NULL; bool metadata; if (!event) return false; /* Check for status */ if (!event->status) return false; /* check if metadatas have been well inited */ if (!ut->init) return false; /* Retrieve Browse arguments */ index = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_START_INDEX); count = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_REQUEST_COUNT); id = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_OBJECT_ID); flag = upnp_get_string (event->request, SERVICE_CDS_ARG_BROWSE_FLAG); filter = upnp_get_string (event->request, SERVICE_CDS_ARG_FILTER); sort_criteria = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_SORT_CRIT); if (!flag || !filter) return false; /* Check arguments validity */ if (!strcmp (flag, SERVICE_CDS_BROWSE_METADATA)) { if (index) { free (flag); return false; } metadata = true; } else if (!strcmp (flag, SERVICE_CDS_BROWSE_CHILDREN)) metadata = false; else { free (flag); return false; } free (flag); entry = upnp_get_entry (ut, id); if (!entry && (id < ut->starting_id)) entry = upnp_get_entry (ut, ut->starting_id); if (!entry) { free (filter); return false; } out = buffer_new (); if (!out) { free (filter); return false; } if (metadata) result_count = cds_browse_metadata (event, out, index, count, entry, filter); else result_count = cds_browse_directchildren (event, out, index, count, entry, filter); free (filter); if (result_count < 0) { buffer_free (out); return false; } buffer_free (out); upnp_add_response (event, SERVICE_CDS_DIDL_UPDATE_ID, SERVICE_CDS_ROOT_OBJECT_ID); return event->status; } static bool matches_search (char *search_criteria, struct upnp_entry_t *entry) { char keyword[256] = SEARCH_OBJECT_KEYWORD; bool derived_from = false, protocol_contains = false, result = false; char *quote_closed = NULL, *and_clause = NULL; #ifdef HAVE_DLNA extern struct ushare_t *ut; #endif /* HAVE_DLNA */ char *protocol = #ifdef HAVE_DLNA entry->dlna_profile ? dlna_write_protocol_info (DLNA_PROTOCOL_INFO_TYPE_HTTP, DLNA_ORG_PLAY_SPEED_NORMAL, DLNA_ORG_CONVERSION_NONE, DLNA_ORG_OPERATION_RANGE, ut->dlna_flags, entry->dlna_profile) : #endif /* HAVE_DLNA */ mime_get_protocol (entry->mime_type); if (!strncmp (search_criteria, SEARCH_CLASS_MATCH_KEYWORD, strlen (SEARCH_CLASS_MATCH_KEYWORD))) { strncpy (keyword, search_criteria + strlen (SEARCH_CLASS_MATCH_KEYWORD), sizeof (keyword)); quote_closed = strchr (keyword, '"'); if (quote_closed) *quote_closed = '\0'; } else if (!strncmp (search_criteria, SEARCH_CLASS_DERIVED_KEYWORD, strlen (SEARCH_CLASS_DERIVED_KEYWORD))) { derived_from = true; strncpy (keyword, search_criteria + strlen (SEARCH_CLASS_DERIVED_KEYWORD), sizeof (keyword)); quote_closed = strchr (keyword, '"'); if (quote_closed) *quote_closed = '\0'; } else if (!strncmp (search_criteria, SEARCH_PROTOCOL_CONTAINS_KEYWORD, strlen (SEARCH_PROTOCOL_CONTAINS_KEYWORD))) { protocol_contains = true; strncpy (keyword, search_criteria + strlen (SEARCH_PROTOCOL_CONTAINS_KEYWORD), sizeof (keyword)); quote_closed = strchr (keyword, '"'); if (quote_closed) *quote_closed = '\0'; } if (derived_from && entry->mime_type && !strncmp (entry->mime_type->mime_class, keyword, strlen (keyword))) result = true; else if (protocol_contains && strstr (protocol, keyword)) result = true; else if (entry->mime_type && !strcmp (entry->mime_type->mime_class, keyword)) result = true; free (protocol); and_clause = strstr (search_criteria, SEARCH_AND); if (and_clause) return (result && matches_search (and_clause + strlen (SEARCH_AND) -1, entry)); return true; } static int cds_search_directchildren_recursive (struct buffer_t *out, int count, struct upnp_entry_t *entry, char *filter, char *search_criteria) { struct upnp_entry_t **childs; int result_count = 0; if (entry->child_count == -1) /* item : file */ return -1; /* go to the first child */ childs = entry->childs; for (; *childs; childs++) { if (count == 0 || result_count < count) /* only fetch the requested count number or all entries if count = 0 */ { if ((*childs)->child_count >= 0) /* container */ { int new_count; new_count = cds_search_directchildren_recursive (out, (count == 0) ? 0 : (count - result_count), (*childs), filter, search_criteria); result_count += new_count; } else /* item */ { if (matches_search (search_criteria, *childs)) { #ifdef HAVE_DLNA extern struct ushare_t *ut; #endif /* HAVE_DLNA */ char *protocol = #ifdef HAVE_DLNA (*childs)->dlna_profile ? dlna_write_protocol_info(DLNA_PROTOCOL_INFO_TYPE_HTTP, DLNA_ORG_PLAY_SPEED_NORMAL, DLNA_ORG_CONVERSION_NONE, DLNA_ORG_OPERATION_RANGE, ut->dlna_flags, (*childs)->dlna_profile): #endif /* HAVE_DLNA */ mime_get_protocol ((*childs)->mime_type); #ifdef HAVE_DLNA (*childs)->dlna_profile ? didl_add_item (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, "true", dlna_profile_upnp_object_item ((*childs)->dlna_profile), (*childs)->title, protocol, (*childs)->size, (*childs)->url, filter) : #endif /* HAVE_DLNA */ didl_add_item (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, "true", (*childs)->mime_type->mime_class, (*childs)->title, protocol, (*childs)->size, (*childs)->url, filter); free (protocol); result_count++; } } } } return result_count; } static int cds_search_directchildren (struct action_event_t *event, struct buffer_t *out, int index, int count, struct upnp_entry_t *entry, char *filter, char *search_criteria) { struct upnp_entry_t **childs; int s, result_count = 0; char tmp[32]; index = 0; if (entry->child_count == -1) /* item : file */ return -1; didl_add_header (out); /* go to the child pointed out by index */ childs = entry->childs; for (s = 0; s < index; s++) if (*childs) childs++; /* UPnP CDS compliance : If starting index = 0 and requested count = 0 then all children must be returned */ if (index == 0 && count == 0) count = entry->child_count; for (; *childs; childs++) { if (count == 0 || result_count < count) /* only fetch the requested count number or all entries if count = 0 */ { if ((*childs)->child_count >= 0) /* container */ { int new_count; new_count = cds_search_directchildren_recursive (out, (count == 0) ? 0 : (count - result_count), (*childs), filter, search_criteria); result_count += new_count; } else /* item */ { if (matches_search (search_criteria, *childs)) { #ifdef HAVE_DLNA extern struct ushare_t *ut; #endif /* HAVE_DLNA */ char *protocol = #ifdef HAVE_DLNA (*childs)->dlna_profile ? dlna_write_protocol_info(DLNA_PROTOCOL_INFO_TYPE_HTTP, DLNA_ORG_PLAY_SPEED_NORMAL, DLNA_ORG_CONVERSION_NONE, DLNA_ORG_OPERATION_RANGE, ut->dlna_flags, (*childs)->dlna_profile): #endif /* HAVE_DLNA */ mime_get_protocol ((*childs)->mime_type); #ifdef HAVE_DLNA (*childs)->dlna_profile ? didl_add_item (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, "true", dlna_profile_upnp_object_item ((*childs)->dlna_profile), (*childs)->title, protocol, (*childs)->size, (*childs)->url, filter) : #endif /* HAVE_DLNA */ didl_add_item (out, (*childs)->id, (*childs)->parent ? (*childs)->parent->id : -1, "true", (*childs)->mime_type->mime_class, (*childs)->title, protocol, (*childs)->size, (*childs)->url, filter); free (protocol); result_count++; } } } } didl_add_footer (out); upnp_add_response (event, SERVICE_CDS_DIDL_RESULT, out->buf); sprintf (tmp, "%d", result_count); upnp_add_response (event, SERVICE_CDS_DIDL_NUM_RETURNED, tmp); sprintf (tmp, "%d", result_count); upnp_add_response (event, SERVICE_CDS_DIDL_TOTAL_MATCH, tmp); return result_count; } static bool cds_search (struct action_event_t *event) { extern struct ushare_t *ut; struct upnp_entry_t *entry = NULL; int result_count = 0, index, count, id, sort_criteria; char *search_criteria = NULL; char *filter = NULL; struct buffer_t *out = NULL; if (!event) return false; /* Check for status */ if (!event->status) return false; /* check if metadatas have been well inited */ if (!ut->init) return false; /* Retrieve Browse arguments */ index = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_START_INDEX); count = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_REQUEST_COUNT); id = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_OBJECT_ID); search_criteria = upnp_get_string (event->request, SERVICE_CDS_ARG_SEARCH_CRIT); filter = upnp_get_string (event->request, SERVICE_CDS_ARG_FILTER); sort_criteria = upnp_get_ui4 (event->request, SERVICE_CDS_ARG_SORT_CRIT); if (!search_criteria || !filter) return false; entry = upnp_get_entry (ut, id); if (!entry && (id < ut->starting_id)) entry = upnp_get_entry (ut, ut->starting_id); if (!entry) return false; out = buffer_new (); if (!out) return false; result_count = cds_search_directchildren (event, out, index, count, entry, filter, search_criteria); if (result_count < 0) { buffer_free (out); return false; } buffer_free (out); upnp_add_response (event, SERVICE_CDS_DIDL_UPDATE_ID, SERVICE_CDS_ROOT_OBJECT_ID); free (search_criteria); free (filter); return event->status; } /* List of UPnP ContentDirectory Service actions */ struct service_action_t cds_service_actions[] = { { SERVICE_CDS_ACTION_SEARCH_CAPS, cds_get_search_capabilities }, { SERVICE_CDS_ACTION_SORT_CAPS, cds_get_sort_capabilities }, { SERVICE_CDS_ACTION_UPDATE_ID, cds_get_system_update_id }, { SERVICE_CDS_ACTION_BROWSE, cds_browse }, { SERVICE_CDS_ACTION_SEARCH, cds_search }, { NULL, NULL } }; ushare-1.1a/src/cms.c0000644000175000017500000001244310726763650012632 0ustar benben/* * cms.c : GeeXboX uShare Connection Management Service. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include "ushare.h" #include "services.h" #include "mime.h" /* Represent the CMS GetProtocolInfo action. */ #define SERVICE_CMS_ACTION_PROT_INFO "GetProtocolInfo" /* Represent the CMS GetCurrentConnectionIDs action. */ #define SERVICE_CMS_ACTION_CON_ID "GetCurrentConnectionIDs" /* Represent the CMS GetCurrentConnectionInfo action. */ #define SERVICE_CMS_ACTION_CON_INFO "GetCurrentConnectionInfo" /* Represent the CMS SOURCE argument. */ #define SERVICE_CMS_ARG_SOURCE "Source" /* Represent the CMS SINK argument. */ #define SERVICE_CMS_ARG_SINK "Sink" /* Represent the CMS ConnectionIDs argument. */ #define SERVICE_CMS_ARG_CONNECTION_IDS "ConnectionIDs" /* Represent the CMS ConnectionID argument. */ #define SERVICE_CMS_ARG_CONNECTION_ID "ConnectionID" /* Represent the CMS RcsID argument. */ #define SERVICE_CMS_ARG_RCS_ID "RcsID" /* Represent the CMS AVTransportID argument. */ #define SERVICE_CMS_ARG_TRANSPORT_ID "AVTransportID" /* Represent the CMS ProtocolInfo argument. */ #define SERVICE_CMS_ARG_PROT_INFO "ProtocolInfo" /* Represent the CMS PeerConnectionManager argument. */ #define SERVICE_CMS_ARG_PEER_CON_MANAGER "PeerConnectionManager" /* Represent the CMS PeerConnectionID argument. */ #define SERVICE_CMS_ARG_PEER_CON_ID "PeerConnectionID" /* Represent the CMS Direction argument. */ #define SERVICE_CMS_ARG_DIRECTION "Direction" /* Represent the CMS Status argument. */ #define SERVICE_CMS_ARG_STATUS "Status" /* Represent the CMS default connection ID value. */ #define SERVICE_CMS_DEFAULT_CON_ID "0" /* Represent the CMS unknown connection ID value. */ #define SERVICE_CMS_UNKNOW_ID "-1" /* Represent the CMS Output value. */ #define SERVICE_CMS_OUTPUT "Output" /* Represent the CMS Success Status. */ #define SERVICE_CMS_STATUS_OK "OK" static bool cms_get_protocol_info (struct action_event_t *event) { extern struct mime_type_t MIME_Type_List[]; struct mime_type_t *list; char *respText = NULL, *respPtr; size_t respLen = 0, len; if (!event) return false; // calculating length of response list = MIME_Type_List; while (list->extension) { char *protocol = mime_get_protocol (list); respLen += strlen (protocol) + 1; free (protocol); list++; } respText = (char*) malloc (respLen * sizeof (char)); if (!respText) return event->status; list = MIME_Type_List; respPtr = respText; while (list->extension) { char *protocol = mime_get_protocol (list); len = strlen (protocol); strncpy (respPtr, protocol, len); free (protocol); respPtr += len; list++; if (list->extension) strcpy (respPtr++, ","); } *respPtr = '\0'; upnp_add_response (event, SERVICE_CMS_ARG_SOURCE, respText); upnp_add_response (event, SERVICE_CMS_ARG_SINK, ""); free (respText); return event->status; } static bool cms_get_current_connection_ids (struct action_event_t *event) { if (!event) return false; upnp_add_response (event, SERVICE_CMS_ARG_CONNECTION_IDS, ""); return event->status; } static bool cms_get_current_connection_info (struct action_event_t *event) { extern struct mime_type_t MIME_Type_List[]; struct mime_type_t *list = MIME_Type_List; if (!event) return false; upnp_add_response (event, SERVICE_CMS_ARG_CONNECTION_ID, SERVICE_CMS_DEFAULT_CON_ID); upnp_add_response (event, SERVICE_CMS_ARG_RCS_ID, SERVICE_CMS_UNKNOW_ID); upnp_add_response (event, SERVICE_CMS_ARG_TRANSPORT_ID, SERVICE_CMS_UNKNOW_ID); while (list->extension) { char *protocol = mime_get_protocol (list); upnp_add_response (event, SERVICE_CMS_ARG_PROT_INFO, protocol); free (protocol); list++; } upnp_add_response (event, SERVICE_CMS_ARG_PEER_CON_MANAGER, ""); upnp_add_response (event, SERVICE_CMS_ARG_PEER_CON_ID, SERVICE_CMS_UNKNOW_ID); upnp_add_response (event, SERVICE_CMS_ARG_DIRECTION, SERVICE_CMS_OUTPUT); upnp_add_response (event, SERVICE_CMS_ARG_STATUS, SERVICE_CMS_STATUS_OK); return event->status; } /* List of UPnP ConnectionManager Service actions */ struct service_action_t cms_service_actions[] = { { SERVICE_CMS_ACTION_PROT_INFO, cms_get_protocol_info }, { SERVICE_CMS_ACTION_CON_ID, cms_get_current_connection_ids }, { SERVICE_CMS_ACTION_CON_INFO, cms_get_current_connection_info }, { NULL, NULL } }; ushare-1.1a/src/msr.c0000644000175000017500000000534610726763650012655 0ustar benben/* * msr.c : GeeXboX uShare Microsoft Registrar Service. * Originally developped for the GeeXboX project. * Copyright (C) 2006 Benjamin Zores * * 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 #include #include "ushare.h" #include "services.h" /* Represent the MSR IsAuthorized action. */ #define SERVICE_MSR_ACTION_IS_AUTHORIZED "IsAuthorized" /* Represent the MSR RegisterDevice action. */ #define SERVICE_MSR_ACTION_REGISTER_DEVICE "RegisterDevice" /* Represent the MSR IsValidated action. */ #define SERVICE_MSR_ACTION_IS_VALIDATED "IsValidated" /* Represent the MSR DeviceID argument. */ #define SERVICE_MSR_ARG_DEVICE_ID "DeviceID" /* Represent the MSR Result argument. */ #define SERVICE_MSR_ARG_RESULT "Result" /* Represent the MSR RegistrationReqMsg argument. */ #define SERVICE_MSR_ARG_REGISTRATION_REQUEST_MSG "RegistrationReqMsg" /* Represent the MSR RegistrationRespMsg argument. */ #define SERVICE_MSR_ARG_REGISTRATION_RESPONSE_MSG "RegistrationRespMsg" /* Represent the MSR Registered/Activated ID value. */ #define SERVICE_MSR_STATUS_OK "1" static bool msr_is_authorized (struct action_event_t *event) { if (!event) return false; /* send a fake authorization to these stupid MS players ;-) */ upnp_add_response (event, SERVICE_MSR_ARG_RESULT, SERVICE_MSR_STATUS_OK); return event->status; } static bool msr_register_device (struct action_event_t *event) { if (!event) return false; /* dummy action */ return event->status; } static bool msr_is_validated (struct action_event_t *event) { if (!event) return false; /* send a fake validation to these stupid MS players ;-) */ upnp_add_response (event, SERVICE_MSR_ARG_RESULT, SERVICE_MSR_STATUS_OK); return event->status; } /* List of UPnP Microsoft Registrar Service actions */ struct service_action_t msr_service_actions[] = { { SERVICE_MSR_ACTION_IS_AUTHORIZED, msr_is_authorized }, { SERVICE_MSR_ACTION_REGISTER_DEVICE, msr_register_device }, { SERVICE_MSR_ACTION_IS_VALIDATED, msr_is_validated }, { NULL, NULL } }; ushare-1.1a/src/http.c0000644000175000017500000002370310726763650013030 0ustar benben/* * http.c : GeeXboX uShare Web Server handler. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include #include #include #include #include #include #include #include "services.h" #include "cds.h" #include "cms.h" #include "msr.h" #include "metadata.h" #include "http.h" #include "minmax.h" #include "trace.h" #include "presentation.h" #include "osdep.h" #include "mime.h" #define PROTOCOL_TYPE_PRE_SZ 11 /* for the str length of "http-get:*:" */ #define PROTOCOL_TYPE_SUFF_SZ 2 /* for the str length of ":*" */ struct web_file_t { char *fullpath; off_t pos; enum { FILE_LOCAL, FILE_MEMORY } type; union { struct { int fd; struct upnp_entry_t *entry; } local; struct { char *contents; off_t len; } memory; } detail; }; static inline void set_info_file (struct File_Info *info, const size_t length, const char *content_type) { info->file_length = length; info->last_modified = 0; info->is_directory = 0; info->is_readable = 1; info->content_type = ixmlCloneDOMString (content_type); } static int http_get_info (const char *filename, struct File_Info *info) { extern struct ushare_t *ut; struct upnp_entry_t *entry = NULL; struct stat st; int upnp_id = 0; char *content_type = NULL; char *protocol = NULL; if (!filename || !info) return -1; log_verbose ("http_get_info, filename : %s\n", filename); if (!strcmp (filename, CDS_LOCATION)) { set_info_file (info, CDS_DESCRIPTION_LEN, SERVICE_CONTENT_TYPE); return 0; } if (!strcmp (filename, CMS_LOCATION)) { set_info_file (info, CMS_DESCRIPTION_LEN, SERVICE_CONTENT_TYPE); return 0; } if (!strcmp (filename, MSR_LOCATION)) { set_info_file (info, MSR_DESCRIPTION_LEN, SERVICE_CONTENT_TYPE); return 0; } if (ut->use_presentation && !strcmp (filename, USHARE_PRESENTATION_PAGE)) { if (build_presentation_page (ut) < 0) return -1; set_info_file (info, ut->presentation->len, PRESENTATION_PAGE_CONTENT_TYPE); return 0; } if (ut->use_presentation && !strncmp (filename, USHARE_CGI, strlen (USHARE_CGI))) { if (process_cgi (ut, (char *) (filename + strlen (USHARE_CGI) + 1)) < 0) return -1; set_info_file (info, ut->presentation->len, PRESENTATION_PAGE_CONTENT_TYPE); return 0; } upnp_id = atoi (strrchr (filename, '/') + 1); entry = upnp_get_entry (ut, upnp_id); if (!entry) return -1; if (!entry->fullpath) return -1; if (stat (entry->fullpath, &st) < 0) return -1; if (access (entry->fullpath, R_OK) < 0) { if (errno != EACCES) return -1; info->is_readable = 0; } else info->is_readable = 1; /* file exist and can be read */ info->file_length = st.st_size; info->last_modified = st.st_mtime; info->is_directory = S_ISDIR (st.st_mode); protocol = #ifdef HAVE_DLNA entry->dlna_profile ? dlna_write_protocol_info (DLNA_PROTOCOL_INFO_TYPE_HTTP, DLNA_ORG_PLAY_SPEED_NORMAL, DLNA_ORG_CONVERSION_NONE, DLNA_ORG_OPERATION_RANGE, ut->dlna_flags, entry->dlna_profile) : #endif /* HAVE_DLNA */ mime_get_protocol (entry->mime_type); content_type = strndup ((protocol + PROTOCOL_TYPE_PRE_SZ), strlen (protocol + PROTOCOL_TYPE_PRE_SZ) - PROTOCOL_TYPE_SUFF_SZ); free (protocol); if (content_type) { info->content_type = ixmlCloneDOMString (content_type); free (content_type); } else info->content_type = ixmlCloneDOMString (""); return 0; } static UpnpWebFileHandle get_file_memory (const char *fullpath, const char *description, const size_t length) { struct web_file_t *file; file = malloc (sizeof (struct web_file_t)); file->fullpath = strdup (fullpath); file->pos = 0; file->type = FILE_MEMORY; file->detail.memory.contents = strdup (description); file->detail.memory.len = length; return ((UpnpWebFileHandle) file); } static UpnpWebFileHandle http_open (const char *filename, enum UpnpOpenFileMode mode) { extern struct ushare_t *ut; struct upnp_entry_t *entry = NULL; struct web_file_t *file; int fd, upnp_id = 0; if (!filename) return NULL; log_verbose ("http_open, filename : %s\n", filename); if (mode != UPNP_READ) return NULL; if (!strcmp (filename, CDS_LOCATION)) return get_file_memory (CDS_LOCATION, CDS_DESCRIPTION, CDS_DESCRIPTION_LEN); if (!strcmp (filename, CMS_LOCATION)) return get_file_memory (CMS_LOCATION, CMS_DESCRIPTION, CMS_DESCRIPTION_LEN); if (!strcmp (filename, MSR_LOCATION)) return get_file_memory (MSR_LOCATION, MSR_DESCRIPTION, MSR_DESCRIPTION_LEN); if (ut->use_presentation && ( !strcmp (filename, USHARE_PRESENTATION_PAGE) || !strncmp (filename, USHARE_CGI, strlen (USHARE_CGI)))) return get_file_memory (USHARE_PRESENTATION_PAGE, ut->presentation->buf, ut->presentation->len); upnp_id = atoi (strrchr (filename, '/') + 1); entry = upnp_get_entry (ut, upnp_id); if (!entry) return NULL; if (!entry->fullpath) return NULL; log_verbose ("Fullpath : %s\n", entry->fullpath); fd = open (entry->fullpath, O_RDONLY | O_NONBLOCK | O_SYNC | O_NDELAY); if (fd < 0) return NULL; file = malloc (sizeof (struct web_file_t)); file->fullpath = strdup (entry->fullpath); file->pos = 0; file->type = FILE_LOCAL; file->detail.local.entry = entry; file->detail.local.fd = fd; return ((UpnpWebFileHandle) file); } static int http_read (UpnpWebFileHandle fh, char *buf, size_t buflen) { struct web_file_t *file = (struct web_file_t *) fh; ssize_t len = -1; log_verbose ("http_read\n"); if (!file) return -1; switch (file->type) { case FILE_LOCAL: log_verbose ("Read local file.\n"); len = read (file->detail.local.fd, buf, buflen); break; case FILE_MEMORY: log_verbose ("Read file from memory.\n"); len = (size_t) MIN (buflen, file->detail.memory.len - file->pos); memcpy (buf, file->detail.memory.contents + file->pos, (size_t) len); break; default: log_verbose ("Unknown file type.\n"); break; } if (len >= 0) file->pos += len; log_verbose ("Read %zd bytes.\n", len); return len; } static int http_write (UpnpWebFileHandle fh __attribute__((unused)), char *buf __attribute__((unused)), size_t buflen __attribute__((unused))) { log_verbose ("http write\n"); return 0; } static int http_seek (UpnpWebFileHandle fh, off_t offset, int origin) { struct web_file_t *file = (struct web_file_t *) fh; off_t newpos = -1; log_verbose ("http_seek\n"); if (!file) return -1; switch (origin) { case SEEK_SET: log_verbose ("Attempting to seek to %lld (was at %lld) in %s\n", offset, file->pos, file->fullpath); newpos = offset; break; case SEEK_CUR: log_verbose ("Attempting to seek by %lld from %lld in %s\n", offset, file->pos, file->fullpath); newpos = file->pos + offset; break; case SEEK_END: log_verbose ("Attempting to seek by %lld from end (was at %lld) in %s\n", offset, file->pos, file->fullpath); if (file->type == FILE_LOCAL) { struct stat sb; if (stat (file->fullpath, &sb) < 0) { log_verbose ("%s: cannot stat: %s\n", file->fullpath, strerror (errno)); return -1; } newpos = sb.st_size + offset; } else if (file->type == FILE_MEMORY) newpos = file->detail.memory.len + offset; break; } switch (file->type) { case FILE_LOCAL: /* Just make sure we cannot seek before start of file. */ if (newpos < 0) { log_verbose ("%s: cannot seek: %s\n", file->fullpath, strerror (EINVAL)); return -1; } /* Don't seek with origin as specified above, as file may have changed in size since our last stat. */ if (lseek (file->detail.local.fd, newpos, SEEK_SET) == -1) { log_verbose ("%s: cannot seek: %s\n", file->fullpath, strerror (errno)); return -1; } break; case FILE_MEMORY: if (newpos < 0 || newpos > file->detail.memory.len) { log_verbose ("%s: cannot seek: %s\n", file->fullpath, strerror (EINVAL)); return -1; } break; } file->pos = newpos; return 0; } static int http_close (UpnpWebFileHandle fh) { struct web_file_t *file = (struct web_file_t *) fh; log_verbose ("http_close\n"); if (!file) return -1; switch (file->type) { case FILE_LOCAL: close (file->detail.local.fd); break; case FILE_MEMORY: /* no close operation */ if (file->detail.memory.contents) free (file->detail.memory.contents); break; default: log_verbose ("Unknown file type.\n"); break; } if (file->fullpath) free (file->fullpath); free (file); return 0; } struct UpnpVirtualDirCallbacks virtual_dir_callbacks = { http_get_info, http_open, http_read, http_write, http_seek, http_close }; ushare-1.1a/src/presentation.c0000644000175000017500000001633210726763650014564 0ustar benben/* * presentation.c : GeeXboX uShare UPnP Presentation Page. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #if HAVE_LANGINFO_CODESET # include #endif #include "config.h" #include "metadata.h" #include "content.h" #include "buffer.h" #include "presentation.h" #include "gettext.h" #include "util_iconv.h" #define CGI_ACTION "action=" #define CGI_ACTION_ADD "add" #define CGI_ACTION_DEL "del" #define CGI_ACTION_REFRESH "refresh" #define CGI_PATH "path" #define CGI_SHARE "share" int process_cgi (struct ushare_t *ut, char *cgiargs) { char *action = NULL; int refresh = 0; if (!ut || !cgiargs) return -1; if (strncmp (cgiargs, CGI_ACTION, strlen (CGI_ACTION))) return -1; action = cgiargs + strlen (CGI_ACTION); if (!strncmp (action, CGI_ACTION_ADD, strlen (CGI_ACTION_ADD))) { char *path = NULL; path = action + strlen (CGI_ACTION_ADD) + 1; if (path && !strncmp (path, CGI_PATH"=", strlen (CGI_PATH) + 1)) { ut->contentlist = content_add (ut->contentlist, path + strlen (CGI_PATH) + 1); refresh = 1; } } else if (!strncmp (action, CGI_ACTION_DEL, strlen (CGI_ACTION_DEL))) { char *shares,*share; char *m_buffer = NULL, *buffer; int num, shift=0; shares = strdup (action + strlen (CGI_ACTION_DEL) + 1); m_buffer = (char*) malloc (strlen (shares) * sizeof (char)); if (m_buffer) { buffer = m_buffer; for (share = strtok_r (shares, "&", &buffer) ; share ; share = strtok_r (NULL, "&", &buffer)) { if (sscanf (share, CGI_SHARE"[%d]=on", &num) < 0) continue; ut->contentlist = content_del (ut->contentlist, num - shift++); } free (m_buffer); } refresh = 1; free (shares); } else if (!strncmp (action, CGI_ACTION_REFRESH, strlen (CGI_ACTION_REFRESH))) refresh = 1; if (refresh && ut->contentlist) { free_metadata_list (ut); build_metadata_list (ut); } if (ut->presentation) buffer_free (ut->presentation); ut->presentation = buffer_new (); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_appendf (ut->presentation, "%s", _("uShare Information Page")); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); return 0; } int build_presentation_page (struct ushare_t *ut) { int i; char *mycodeset = NULL; if (!ut) return -1; if (ut->presentation) buffer_free (ut->presentation); ut->presentation = buffer_new (); #if HAVE_LANGINFO_CODESET mycodeset = nl_langinfo (CODESET); #endif if (!mycodeset) mycodeset = UTF8; buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_appendf (ut->presentation, "%s", _("uShare Information Page")); buffer_appendf (ut->presentation, "", mycodeset); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, "

"); buffer_appendf (ut->presentation, "%s
", _("uShare UPnP A/V Media Server")); buffer_append (ut->presentation, _("Information Page")); buffer_append (ut->presentation, "

"); buffer_append (ut->presentation, "
"); buffer_append (ut->presentation, "
"); buffer_append (ut->presentation, ""); buffer_appendf (ut->presentation, "%s : %s
", _("Version"), VERSION); buffer_append (ut->presentation, ""); buffer_appendf (ut->presentation, "%s : %s
", _("Device UDN"), ut->udn); buffer_appendf (ut->presentation, "%s : %d
", _("Number of shared files and directories"), ut->nr_entries); buffer_append (ut->presentation, "

"); buffer_appendf (ut->presentation, "
", USHARE_CGI); buffer_appendf (ut->presentation, "", CGI_ACTION_DEL); for (i = 0 ; i < ut->contentlist->count ; i++) { buffer_appendf (ut->presentation, "%s #%d :", _("Share"), i + 1); buffer_appendf (ut->presentation, "", i); buffer_appendf (ut->presentation, "%s
", ut->contentlist->content[i]); } buffer_appendf (ut->presentation, "", _("unShare!")); buffer_append (ut->presentation, "
"); buffer_append (ut->presentation, "
"); buffer_appendf (ut->presentation, "
", USHARE_CGI); buffer_append (ut->presentation, _("Add a new share : ")); buffer_appendf (ut->presentation, "", CGI_ACTION_ADD); buffer_append (ut->presentation, ""); buffer_appendf (ut->presentation, "", _("Share!")); buffer_append (ut->presentation, "
"); buffer_append (ut->presentation, "
"); buffer_appendf (ut->presentation, "
", USHARE_CGI); buffer_appendf (ut->presentation, "", CGI_ACTION_REFRESH); buffer_appendf (ut->presentation, "", _("Refresh Shares ...")); buffer_append (ut->presentation, "
"); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); buffer_append (ut->presentation, ""); return 0; } ushare-1.1a/src/metadata.c0000644000175000017500000003202210726763650013623 0ustar benben/* * metadata.c : GeeXboX uShare CDS Metadata DB. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include #include #include #include #include #include #include #include "mime.h" #include "metadata.h" #include "util_iconv.h" #include "content.h" #include "gettext.h" #include "trace.h" #define TITLE_UNKNOWN "unknown" #define MAX_URL_SIZE 32 struct upnp_entry_lookup_t { int id; struct upnp_entry_t *entry_ptr; }; static char * getExtension (const char *filename) { char *str = NULL; str = strrchr (filename, '.'); if (str) str++; return str; } static struct mime_type_t * getMimeType (const char *extension) { extern struct mime_type_t MIME_Type_List[]; struct mime_type_t *list; if (!extension) return NULL; list = MIME_Type_List; while (list->extension) { if (!strcasecmp (list->extension, extension)) return list; list++; } return NULL; } static bool is_valid_extension (const char *extension) { if (!extension) return false; if (getMimeType (extension)) return true; return false; } static int get_list_length (void *list) { void **l = list; int n = 0; while (*(l++)) n++; return n; } static xml_convert_t xml_convert[] = { {'"' , """}, {'&' , "&"}, {'\'', "'"}, {'<' , "<"}, {'>' , ">"}, {'\n', " "}, {'\r', " "}, {'\t', " "}, {0, NULL}, }; static char * get_xmlconvert (int c) { int j; for (j = 0; xml_convert[j].xml; j++) { if (c == xml_convert[j].charac) return xml_convert[j].xml; } return NULL; } static char * convert_xml (const char *title) { char *newtitle, *s, *t, *xml; int nbconvert = 0; /* calculate extra size needed */ for (t = (char*) title; *t; t++) { xml = get_xmlconvert (*t); if (xml) nbconvert += strlen (xml) - 1; } if (!nbconvert) return NULL; newtitle = s = (char*) malloc (strlen (title) + nbconvert + 1); for (t = (char*) title; *t; t++) { xml = get_xmlconvert (*t); if (xml) { strcpy (s, xml); s += strlen (xml); } else *s++ = *t; } *s = '\0'; return newtitle; } static struct mime_type_t Container_MIME_Type = { NULL, "object.container.storageFolder", NULL}; static struct upnp_entry_t * upnp_entry_new (struct ushare_t *ut, const char *name, const char *fullpath, struct upnp_entry_t *parent, off_t size, int dir) { struct upnp_entry_t *entry = NULL; char *title = NULL, *x = NULL; char url_tmp[MAX_URL_SIZE] = { '\0' }; char *title_or_name = NULL; if (!name) return NULL; entry = (struct upnp_entry_t *) malloc (sizeof (struct upnp_entry_t)); #ifdef HAVE_DLNA entry->dlna_profile = NULL; entry->url = NULL; if (ut->dlna_enabled && fullpath && !dir) { dlna_profile_t *p = dlna_guess_media_profile (ut->dlna, fullpath); if (!p) { free (entry); return NULL; } entry->dlna_profile = p; } #endif /* HAVE_DLNA */ if (ut->xbox360) { if (ut->root_entry) entry->id = ut->starting_id + ut->nr_entries++; else entry->id = 0; /* Creating the root node so don't use the usual IDs */ } else entry->id = ut->starting_id + ut->nr_entries++; entry->fullpath = fullpath ? strdup (fullpath) : NULL; entry->parent = parent; entry->child_count = dir ? 0 : -1; entry->title = NULL; entry->childs = (struct upnp_entry_t **) malloc (sizeof (struct upnp_entry_t *)); *(entry->childs) = NULL; if (!dir) /* item */ { #ifdef HAVE_DLNA if (ut->dlna_enabled) entry->mime_type = NULL; else { #endif /* HAVE_DLNA */ struct mime_type_t *mime = getMimeType (getExtension (name)); if (!mime) { --ut->nr_entries; upnp_entry_free (ut, entry); log_error ("Invalid Mime type for %s, entry ignored", name); return NULL; } entry->mime_type = mime; #ifdef HAVE_DLNA } #endif /* HAVE_DLNA */ if (snprintf (url_tmp, MAX_URL_SIZE, "%d.%s", entry->id, getExtension (name)) >= MAX_URL_SIZE) log_error ("URL string too long for id %d, truncated!!", entry->id); /* Only malloc() what we really need */ entry->url = strdup (url_tmp); } else /* container */ { entry->mime_type = &Container_MIME_Type; entry->url = NULL; } /* Try Iconv'ing the name but if it fails the end device may still be able to handle it */ title = iconv_convert (name); if (title) title_or_name = title; else { if (ut->override_iconv_err) { title_or_name = strdup (name); log_error ("Entry invalid name id=%d [%s]\n", entry->id, name); } else { upnp_entry_free (ut, entry); log_error ("Freeing entry invalid name id=%d [%s]\n", entry->id, name); return NULL; } } if (!dir) { x = strrchr (title_or_name, '.'); if (x) /* avoid displaying file extension */ *x = '\0'; } x = convert_xml (title_or_name); if (x) { free (title_or_name); title_or_name = x; } entry->title = title_or_name; if (!strcmp (title_or_name, "")) /* DIDL dc:title can't be empty */ { free (title_or_name); entry->title = strdup (TITLE_UNKNOWN); } entry->size = size; entry->fd = -1; if (entry->id && entry->url) log_verbose ("Entry->URL (%d): %s\n", entry->id, entry->url); return entry; } /* Seperate recursive free() function in order to avoid freeing off * the parents child list within the freeing of the first child, as * the only entry which is not part of a childs list is the root entry */ static void _upnp_entry_free (struct upnp_entry_t *entry) { struct upnp_entry_t **childs; if (!entry) return; if (entry->fullpath) free (entry->fullpath); if (entry->title) free (entry->title); if (entry->url) free (entry->url); #ifdef HAVE_DLNA if (entry->dlna_profile) entry->dlna_profile = NULL; #endif /* HAVE_DLNA */ for (childs = entry->childs; *childs; childs++) _upnp_entry_free (*childs); free (entry->childs); } void upnp_entry_free (struct ushare_t *ut, struct upnp_entry_t *entry) { if (!ut || !entry) return; /* Free all entries (i.e. children) */ if (entry == ut->root_entry) { struct upnp_entry_t *entry_found = NULL; struct upnp_entry_lookup_t *lk = NULL; RBLIST *rblist; int i = 0; rblist = rbopenlist (ut->rb); lk = (struct upnp_entry_lookup_t *) rbreadlist (rblist); while (lk) { entry_found = lk->entry_ptr; if (entry_found) { if (entry_found->fullpath) free (entry_found->fullpath); if (entry_found->title) free (entry_found->title); if (entry_found->url) free (entry_found->url); free (entry_found); i++; } free (lk); /* delete the lookup */ lk = (struct upnp_entry_lookup_t *) rbreadlist (rblist); } rbcloselist (rblist); rbdestroy (ut->rb); ut->rb = NULL; log_verbose ("Freed [%d] entries\n", i); } else _upnp_entry_free (entry); free (entry); } static void upnp_entry_add_child (struct ushare_t *ut, struct upnp_entry_t *entry, struct upnp_entry_t *child) { struct upnp_entry_lookup_t *entry_lookup_ptr = NULL; struct upnp_entry_t **childs; int n; if (!entry || !child) return; for (childs = entry->childs; *childs; childs++) if (*childs == child) return; n = get_list_length ((void *) entry->childs) + 1; entry->childs = (struct upnp_entry_t **) realloc (entry->childs, (n + 1) * sizeof (*(entry->childs))); entry->childs[n] = NULL; entry->childs[n - 1] = child; entry->child_count++; entry_lookup_ptr = (struct upnp_entry_lookup_t *) malloc (sizeof (struct upnp_entry_lookup_t)); entry_lookup_ptr->id = child->id; entry_lookup_ptr->entry_ptr = child; if (rbsearch ((void *) entry_lookup_ptr, ut->rb) == NULL) log_info (_("Failed to add the RB lookup tree\n")); } struct upnp_entry_t * upnp_get_entry (struct ushare_t *ut, int id) { struct upnp_entry_lookup_t *res, entry_lookup; log_verbose ("Looking for entry id %d\n", id); if (id == 0) /* We do not store the root (id 0) as it is not a child */ return ut->root_entry; entry_lookup.id = id; res = (struct upnp_entry_lookup_t *) rbfind ((void *) &entry_lookup, ut->rb); if (res) { log_verbose ("Found at %p\n", ((struct upnp_entry_lookup_t *) res)->entry_ptr); return ((struct upnp_entry_lookup_t *) res)->entry_ptr; } log_verbose ("Not Found\n"); return NULL; } static void metadata_add_file (struct ushare_t *ut, struct upnp_entry_t *entry, const char *file, const char *name, struct stat *st_ptr) { if (!entry || !file || !name) return; #ifdef HAVE_DLNA if (ut->dlna_enabled || is_valid_extension (getExtension (file))) #else if (is_valid_extension (getExtension (file))) #endif { struct upnp_entry_t *child = NULL; child = upnp_entry_new (ut, name, file, entry, st_ptr->st_size, false); if (child) upnp_entry_add_child (ut, entry, child); } } static void metadata_add_container (struct ushare_t *ut, struct upnp_entry_t *entry, const char *container) { struct dirent **namelist; int n,i; if (!entry || !container) return; n = scandir (container, &namelist, 0, alphasort); if (n < 0) { perror ("scandir"); return; } for (i = 0; i < n; i++) { struct stat st; char *fullpath = NULL; if (namelist[i]->d_name[0] == '.') { free (namelist[i]); continue; } fullpath = (char *) malloc (strlen (container) + strlen (namelist[i]->d_name) + 2); sprintf (fullpath, "%s/%s", container, namelist[i]->d_name); log_verbose ("%s\n", fullpath); if (stat (fullpath, &st) < 0) { free (namelist[i]); free (fullpath); continue; } if (S_ISDIR (st.st_mode)) { struct upnp_entry_t *child = NULL; child = upnp_entry_new (ut, namelist[i]->d_name, fullpath, entry, 0, true); if (child) { metadata_add_container (ut, child, fullpath); upnp_entry_add_child (ut, entry, child); } } else metadata_add_file (ut, entry, fullpath, namelist[i]->d_name, &st); free (namelist[i]); free (fullpath); } free (namelist); } void free_metadata_list (struct ushare_t *ut) { ut->init = 0; if (ut->root_entry) upnp_entry_free (ut, ut->root_entry); ut->root_entry = NULL; ut->nr_entries = 0; if (ut->rb) { rbdestroy (ut->rb); ut->rb = NULL; } ut->rb = rbinit (rb_compare, NULL); if (!ut->rb) log_error (_("Cannot create RB tree for lookups\n")); } void build_metadata_list (struct ushare_t *ut) { int i; log_info (_("Building Metadata List ...\n")); /* build root entry */ if (!ut->root_entry) ut->root_entry = upnp_entry_new (ut, "root", NULL, NULL, -1, true); /* add files from content directory */ for (i=0 ; i < ut->contentlist->count ; i++) { struct upnp_entry_t *entry = NULL; char *title = NULL; int size = 0; log_info (_("Looking for files in content directory : %s\n"), ut->contentlist->content[i]); size = strlen (ut->contentlist->content[i]); if (ut->contentlist->content[i][size - 1] == '/') ut->contentlist->content[i][size - 1] = '\0'; title = strrchr (ut->contentlist->content[i], '/'); if (title) title++; else { /* directly use content directory name if no '/' before basename */ title = ut->contentlist->content[i]; } entry = upnp_entry_new (ut, title, ut->contentlist->content[i], ut->root_entry, -1, true); if (!entry) continue; upnp_entry_add_child (ut, ut->root_entry, entry); metadata_add_container (ut, entry, ut->contentlist->content[i]); } log_info (_("Found %d files and subdirectories.\n"), ut->nr_entries); ut->init = 1; } int rb_compare (const void *pa, const void *pb, const void *config __attribute__ ((unused))) { struct upnp_entry_lookup_t *a, *b; a = (struct upnp_entry_lookup_t *) pa; b = (struct upnp_entry_lookup_t *) pb; if (a->id < b->id) return -1; if (a->id > b->id) return 1; return 0; } ushare-1.1a/src/mime.c0000644000175000017500000001503110726763650012773 0ustar benben/* * mime.c : GeeXboX uShare media file MIME-type association. * Originally developped for the GeeXboX project. * Ref : http://freedesktop.org/wiki/Standards_2fshared_2dmime_2dinfo_2dspec * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include "mime.h" #include "ushare.h" #define UPNP_VIDEO "object.item.videoItem" #define UPNP_AUDIO "object.item.audioItem.musicTrack" #define UPNP_PHOTO "object.item.imageItem.photo" #define UPNP_PLAYLIST "object.item.playlistItem" #define UPNP_TEXT "object.item.textItem" const struct mime_type_t MIME_Type_List[] = { /* Video files */ { "asf", UPNP_VIDEO, "http-get:*:video/x-ms-asf:"}, { "avc", UPNP_VIDEO, "http-get:*:video/avi:"}, { "avi", UPNP_VIDEO, "http-get:*:video/avi:"}, { "dv", UPNP_VIDEO, "http-get:*:video/x-dv:"}, { "divx", UPNP_VIDEO, "http-get:*:video/avi:"}, { "wmv", UPNP_VIDEO, "http-get:*:video/x-ms-wmv:"}, { "mjpg", UPNP_VIDEO, "http-get:*:video/x-motion-jpeg:"}, { "mjpeg", UPNP_VIDEO, "http-get:*:video/x-motion-jpeg:"}, { "mpeg", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "mpg", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "mpe", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "mp2p", UPNP_VIDEO, "http-get:*:video/mp2p:"}, { "vob", UPNP_VIDEO, "http-get:*:video/mp2p:"}, { "mp2t", UPNP_VIDEO, "http-get:*:video/mp2t:"}, { "m1v", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "m2v", UPNP_VIDEO, "http-get:*:video/mpeg2:"}, { "mpg2", UPNP_VIDEO, "http-get:*:video/mpeg2:"}, { "mpeg2", UPNP_VIDEO, "http-get:*:video/mpeg2:"}, { "m4v", UPNP_VIDEO, "http-get:*:video/mp4:"}, { "m4p", UPNP_VIDEO, "http-get:*:video/mp4:"}, { "mp4ps", UPNP_VIDEO, "http-get:*:video/x-nerodigital-ps:"}, { "ts", UPNP_VIDEO, "http-get:*:video/mpeg2:"}, { "ogm", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "mkv", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "rmvb", UPNP_VIDEO, "http-get:*:video/mpeg:"}, { "mov", UPNP_VIDEO, "http-get:*:video/quicktime:"}, { "hdmov", UPNP_VIDEO, "http-get:*:video/quicktime:"}, { "qt", UPNP_VIDEO, "http-get:*:video/quicktime:"}, { "bin", UPNP_VIDEO, "http-get:*:video/mpeg2:"}, { "iso", UPNP_VIDEO, "http-get:*:video/mpeg2:"}, /* Audio files */ { "3gp", UPNP_AUDIO, "http-get:*:audio/3gpp:"}, { "aac", UPNP_AUDIO, "http-get:*:audio/x-aac:"}, { "ac3", UPNP_AUDIO, "http-get:*:audio/x-ac3:"}, { "aif", UPNP_AUDIO, "http-get:*:audio/aiff:"}, { "aiff", UPNP_AUDIO, "http-get:*:audio/aiff:"}, { "at3p", UPNP_AUDIO, "http-get:*:audio/x-atrac3:"}, { "au", UPNP_AUDIO, "http-get:*:audio/basic:"}, { "snd", UPNP_AUDIO, "http-get:*:audio/basic:"}, { "dts", UPNP_AUDIO, "http-get:*:audio/x-dts:"}, { "rmi", UPNP_AUDIO, "http-get:*:audio/midi:"}, { "mid", UPNP_AUDIO, "http-get:*:audio/midi:"}, { "mp1", UPNP_AUDIO, "http-get:*:audio/mp1:"}, { "mp2", UPNP_AUDIO, "http-get:*:audio/mp2:"}, { "mp3", UPNP_AUDIO, "http-get:*:audio/mpeg:"}, { "mp4", UPNP_AUDIO, "http-get:*:audio/mp4:"}, { "m4a", UPNP_AUDIO, "http-get:*:audio/mp4:"}, { "ogg", UPNP_AUDIO, "http-get:*:audio/x-ogg:"}, { "wav", UPNP_AUDIO, "http-get:*:audio/wav:"}, { "pcm", UPNP_AUDIO, "http-get:*:audio/l16:"}, { "lpcm", UPNP_AUDIO, "http-get:*:audio/l16:"}, { "l16", UPNP_AUDIO, "http-get:*:audio/l16:"}, { "wma", UPNP_AUDIO, "http-get:*:audio/x-ms-wma:"}, { "mka", UPNP_AUDIO, "http-get:*:audio/mpeg:"}, { "ra", UPNP_AUDIO, "http-get:*:audio/x-pn-realaudio:"}, { "rm", UPNP_AUDIO, "http-get:*:audio/x-pn-realaudio:"}, { "ram", UPNP_AUDIO, "http-get:*:audio/x-pn-realaudio:"}, { "flac", UPNP_AUDIO, "http-get:*:audio/x-flac:"}, /* Images files */ { "bmp", UPNP_PHOTO, "http-get:*:image/bmp:"}, { "ico", UPNP_PHOTO, "http-get:*:image/x-icon:"}, { "gif", UPNP_PHOTO, "http-get:*:image/gif:"}, { "jpeg", UPNP_PHOTO, "http-get:*:image/jpeg:"}, { "jpg", UPNP_PHOTO, "http-get:*:image/jpeg:"}, { "jpe", UPNP_PHOTO, "http-get:*:image/jpeg:"}, { "pcd", UPNP_PHOTO, "http-get:*:image/x-ms-bmp:"}, { "png", UPNP_PHOTO, "http-get:*:image/png:"}, { "pnm", UPNP_PHOTO, "http-get:*:image/x-portable-anymap:"}, { "ppm", UPNP_PHOTO, "http-get:*:image/x-portable-pixmap:"}, { "qti", UPNP_PHOTO, "http-get:*:image/x-quicktime:"}, { "qtf", UPNP_PHOTO, "http-get:*:image/x-quicktime:"}, { "qtif", UPNP_PHOTO, "http-get:*:image/x-quicktime:"}, { "tif", UPNP_PHOTO, "http-get:*:image/tiff:"}, { "tiff", UPNP_PHOTO, "http-get:*:image/tiff:"}, /* Playlist files */ { "pls", UPNP_PLAYLIST, "http-get:*:audio/x-scpls:"}, { "m3u", UPNP_PLAYLIST, "http-get:*:audio/mpegurl:"}, { "asx", UPNP_PLAYLIST, "http-get:*:video/x-ms-asf:"}, /* Subtitle Text files */ { "srt", UPNP_TEXT, "http-get:*:text/srt:"}, /* SubRip */ { "ssa", UPNP_TEXT, "http-get:*:text/ssa:"}, /* SubStation Alpha */ { "stl", UPNP_TEXT, "http-get:*:text/srt:"}, /* Spruce */ { "psb", UPNP_TEXT, "http-get:*:text/psb:"}, /* PowerDivX */ { "pjs", UPNP_TEXT, "http-get:*:text/pjs:"}, /* Phoenix Japanim */ { "sub", UPNP_TEXT, "http-get:*:text/sub:"}, /* MicroDVD */ { "idx", UPNP_TEXT, "http-get:*:text/idx:"}, /* VOBsub */ { "dks", UPNP_TEXT, "http-get:*:text/dks:"}, /* DKS */ { "scr", UPNP_TEXT, "http-get:*:text/scr:"}, /* MACsub */ { "tts", UPNP_TEXT, "http-get:*:text/tts:"}, /* TurboTitler */ { "vsf", UPNP_TEXT, "http-get:*:text/vsf:"}, /* ViPlay */ { "zeg", UPNP_TEXT, "http-get:*:text/zeg:"}, /* ZeroG */ { "mpl", UPNP_TEXT, "http-get:*:text/mpl:"}, /* MPL */ /* Miscellaneous text files */ { "bup", UPNP_TEXT, "http-get:*:text/bup:"}, /* DVD backup */ { "ifo", UPNP_TEXT, "http-get:*:text/ifo:"}, /* DVD information */ { NULL, NULL, NULL} }; char *mime_get_protocol (struct mime_type_t *mime) { char protocol[512]; if (!mime) return NULL; sprintf (protocol, mime->mime_protocol); strcat (protocol, "*"); return strdup (protocol); } ushare-1.1a/src/services.c0000644000175000017500000001015010726763650013664 0ustar benben/* * services.c : GeeXboX uShare UPnP services handler. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include "ushare.h" #include "services.h" #include "cms.h" #include "cds.h" #include "msr.h" #include "trace.h" /* Represent the ObjectID argument. */ #define ARG_OBJECT_ID "ObjectID" /* Represent the ContainerID argument. */ #define ARG_CONTAINER_ID "ContainerID" extern struct service_action_t cds_service_actions[]; extern struct service_action_t cms_service_actions[]; extern struct service_action_t msr_service_actions[]; static struct service_t services[] = { { CDS_SERVICE_ID, CDS_SERVICE_TYPE, cds_service_actions }, { CMS_SERVICE_ID, CMS_SERVICE_TYPE, cms_service_actions }, { MSR_SERVICE_ID, MSR_SERVICE_TYPE, msr_service_actions }, { NULL, NULL, NULL } }; bool find_service_action (struct Upnp_Action_Request *request, struct service_t **service, struct service_action_t **action) { int c, d; *service = NULL; *action = NULL; if (!request || !request->ActionName) return false; for (c = 0; services[c].id != NULL; c++) if (!strcmp (services[c].id, request->ServiceID)) { *service = &services[c]; for (d = 0; services[c].actions[d].name; d++) { if (!strcmp (services[c].actions[d].name, request->ActionName)) { *action = &services[c].actions[d]; return true; } } return false; } return false; } bool upnp_add_response (struct action_event_t *event, char *key, const char *value) { char *val; int res; if (!event || !event->status || !key || !value) return false; val = strdup (value); if (!val) return false; res = UpnpAddToActionResponse (&event->request->ActionResult, event->request->ActionName, event->service->type, key, val); if (res != UPNP_E_SUCCESS) { free (val); return false; } free (val); return true; } char * upnp_get_string (struct Upnp_Action_Request *request, const char *key) { IXML_Node *node = NULL; if (!request || !request->ActionRequest || !key) return NULL; node = (IXML_Node *) request->ActionRequest; if (!node) { log_verbose ("Invalid action request document\n"); return NULL; } node = ixmlNode_getFirstChild (node); if (!node) { log_verbose ("Invalid action request document\n"); return NULL; } node = ixmlNode_getFirstChild (node); for (; node; node = ixmlNode_getNextSibling (node)) if (!strcmp (ixmlNode_getNodeName (node), key)) { node = ixmlNode_getFirstChild (node); if (!node) return strdup (""); return strdup (ixmlNode_getNodeValue (node)); } log_verbose ("Missing action request argument (%s)\n", key); return NULL; } int upnp_get_ui4 (struct Upnp_Action_Request *request, const char *key) { char *value; int val; if (!request || !key) return 0; value = upnp_get_string (request, key); if (!value && !strcmp (key, ARG_OBJECT_ID)) value = upnp_get_string (request, ARG_CONTAINER_ID); if (!value) return 0; val = atoi (value); free (value); return val; } ushare-1.1a/src/buffer.c0000644000175000017500000000474710726763650013331 0ustar benben/* buffer.c - String buffer manipulation tools. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include #include "buffer.h" #include "minmax.h" #define BUFFER_DEFAULT_CAPACITY 32768 struct buffer_t * buffer_new (void) { struct buffer_t *buffer = NULL; buffer = (struct buffer_t *) malloc (sizeof (struct buffer_t)); if (!buffer) return NULL; buffer->buf = NULL; buffer->len = 0; buffer->capacity = 0; return buffer; } void buffer_append (struct buffer_t *buffer, const char *str) { size_t len; if (!buffer || !str) return; if (!buffer->buf) { buffer->capacity = BUFFER_DEFAULT_CAPACITY; buffer->buf = (char *) malloc (buffer->capacity * sizeof (char)); memset (buffer->buf, '\0', buffer->capacity); } len = buffer->len + strlen (str); if (len >= buffer->capacity) { buffer->capacity = MAX (len + 1, 2 * buffer->capacity); buffer->buf = realloc (buffer->buf, buffer->capacity); } strcat (buffer->buf, str); buffer->len += strlen (str); } void buffer_appendf (struct buffer_t *buffer, const char *format, ...) { char str[BUFFER_DEFAULT_CAPACITY]; int size; va_list va; if (!buffer || !format) return; va_start (va, format); size = vsnprintf (str, BUFFER_DEFAULT_CAPACITY, format, va); if (size >= BUFFER_DEFAULT_CAPACITY) { char* dynstr = (char *) malloc (size + 1); vsnprintf (dynstr, size + 1, format, va); buffer_append (buffer, dynstr); free (dynstr); } else buffer_append (buffer, str); va_end (va); } void buffer_free (struct buffer_t *buffer) { if (!buffer) return; if (buffer->buf) free (buffer->buf); free (buffer); } ushare-1.1a/src/util_iconv.c0000644000175000017500000000742710726763650014231 0ustar benben/* * util_iconv.c : GeeXboX uShare iconv string encoding utlities. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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 #include #include #include #include "util_iconv.h" #if HAVE_ICONV #include static iconv_t cd = 0; #endif #if HAVE_LANGINFO_CODESET #include #endif void setup_iconv (void) { #if HAVE_ICONV && HAVE_LANGINFO_CODESET char *mycodeset = NULL; mycodeset = nl_langinfo (CODESET); if (!mycodeset) return; /** * Setup conversion descriptor if user's console is non-UTF-8. Otherwise * we can just leave cd as NULL */ if (strcmp (mycodeset, UTF8)) { cd = iconv_open (UTF8, mycodeset); if (cd == (iconv_t) (-1)) { perror ("iconv_open"); cd = 0; } } #endif } void finish_iconv (void) { #if HAVE_ICONV if (!cd) return; if (iconv_close (cd) < 0) perror ("iconv_close"); cd = 0; #endif } /** * iconv_convert : convert a string, using the current codeset * return: a malloc'd string with the converted result */ char * iconv_convert (const char *input) { #if HAVE_ICONV size_t inputsize = strlen (input) + 1; size_t dummy = 0; size_t length = 0; char *result; char *inptr, *outptr; size_t insize, outsize; /* conversion not necessary. save our time. */ if (!cd) return strdup (input); /* Determine the length we need. */ iconv (cd, NULL, NULL, NULL, &dummy); { static char tmpbuf[BUFSIZ]; inptr = (char*) input; insize = inputsize; while (insize > 0) { outptr = tmpbuf; outsize = BUFSIZ; if (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) (-1)) { /** * if error is EINVAL or EILSEQ, conversion must be stoped, * but if it is E2BIG (not enough space in buffer), we just loop again */ if( errno != E2BIG) { perror ("error iconv"); return NULL; } } length += outptr - tmpbuf; } outptr = tmpbuf; outsize = BUFSIZ; if (iconv (cd, NULL, NULL, &outptr, &outsize) == (size_t) (-1)) { perror ("error iconv"); return NULL; } length += outptr - tmpbuf; } /* length determined, allocate result space */ if ((result = (char*) malloc (length * sizeof (char))) == NULL) { perror ("error malloc"); return NULL; } /* Do the conversion for real. */ iconv (cd, NULL, NULL, NULL, &dummy); { inptr = (char*) input; insize = inputsize; outptr = result; outsize = length; while (insize > 0) { if (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) (-1)) { if (errno != E2BIG) { perror ("error iconv"); free (result); return NULL; } } } if (iconv (cd, NULL, NULL, &outptr, &outsize) == (size_t) (-1)) { perror ("error iconv"); free (result); return NULL; } if (outsize != 0) abort (); } return result; #else return strdup (input); #endif } ushare-1.1a/src/content.c0000644000175000017500000000412510726763650013520 0ustar benben/* * content.c : GeeXboX uShare content list * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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 #include #include #include "content.h" content_list * content_add(content_list *list, const char *item) { if (!list) { list = (content_list*) malloc (sizeof(content_list)); list->content = NULL; list->count = 0; } if (item) { list->count++; list->content = (char**) realloc (list->content, list->count * sizeof(char*)); if (!list->content) { perror ("error realloc"); exit (2); } list->content[list->count-1] = strdup (item); } return list; } /* * Remove the n'th content (start from 0) */ content_list * content_del(content_list *list, int n) { int i; if (!list || n >= list->count) return NULL; if (n >= list->count) return list; if (list->content[n]) { free (list->content[n]); for (i = n ; i < list->count - 1 ; i++) list->content[i] = list->content[i+1]; list->count--; list->content[list->count] = NULL; } return list; } void content_free(content_list *list) { int i; if (!list) return; if (list->content) { for (i=0 ; i < list->count ; i++) { if (list->content[i]) free (list->content[i]); } free (list->content); } free (list); } ushare-1.1a/src/cfgparser.c0000644000175000017500000002411710726763650014025 0ustar benben/* * cfgparser.c : GeeXboX uShare config file parser. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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 #include #include #include #include #include #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; } inline 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; } ushare-1.1a/src/trace.c0000644000175000017500000000322410726763650013143 0ustar benben/* * trace.c : GeeXboX uShare log facility. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Alexis Saettler * * 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 #include #include #include #include "config.h" #include "trace.h" #include "ushare.h" extern struct ushare_t *ut; void print_log (log_level level, const char *format, ...) { va_list va; bool is_daemon = ut ? ut->daemon : false; bool is_verbose = ut ? ut->verbose : false; if (!format) return; if (!is_verbose && level >= ULOG_VERBOSE) return; va_start (va, format); if (is_daemon) { int flags = LOG_DAEMON; flags |= level == ULOG_ERROR ? LOG_ERR : LOG_NOTICE; vsyslog (flags, format, va); } else { FILE *output = level == ULOG_ERROR ? stderr : stdout; vfprintf (output, format, va); } va_end (va); } inline void start_log (void) { openlog (PACKAGE_NAME, LOG_PID, LOG_DAEMON); } ushare-1.1a/src/redblack.c0000644000175000017500000006015210726763650013617 0ustar benbenstatic char rcsid[]="$Id: redblack.c,v 1.9 2003/10/24 01:31:21 damo Exp $"; /* Redblack balanced tree algorithm Copyright (C) Damian Ivereigh 2000 This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See the file COPYING for details. 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 General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Implement the red/black tree structure. It is designed to emulate ** the standard tsearch() stuff. i.e. the calling conventions are ** exactly the same */ #include #include #include #include "redblack.h" #define assert(expr) /* Uncomment this if you would rather use a raw sbrk to get memory ** (however the memory is never released again (only re-used). Can't ** see any point in using this these days. */ /* #define USE_SBRK */ enum nodecolour { BLACK, RED }; struct RB_ENTRY(node) { struct RB_ENTRY(node) *left; /* Left down */ struct RB_ENTRY(node) *right; /* Right down */ struct RB_ENTRY(node) *up; /* Up */ enum nodecolour colour; /* Node colour */ #ifdef RB_INLINE RB_ENTRY(data_t) key; /* User's key (and data) */ #define RB_GET(x,y) &x->y #define RB_SET(x,y,v) x->y = *(v) #else const RB_ENTRY(data_t) *key; /* Pointer to user's key (and data) */ #define RB_GET(x,y) x->y #define RB_SET(x,y,v) x->y = v #endif /* RB_INLINE */ }; /* Dummy (sentinel) node, so that we can make X->left->up = X ** We then use this instead of NULL to mean the top or bottom ** end of the rb tree. It is a black node. ** ** Initialization of the last field in this initializer is left implicit ** because it could be of any type. We count on the compiler to zero it. */ struct RB_ENTRY(node) RB_ENTRY(_null)={&RB_ENTRY(_null), &RB_ENTRY(_null), &RB_ENTRY(_null), BLACK, &RB_ENTRY(_null)}; #define RBNULL (&RB_ENTRY(_null)) #if defined(USE_SBRK) static struct RB_ENTRY(node) *RB_ENTRY(_alloc)(); static void RB_ENTRY(_free)(struct RB_ENTRY(node) *); #else static struct RB_ENTRY(node) *RB_ENTRY(_alloc)() {return (struct RB_ENTRY(node) *) malloc(sizeof(struct RB_ENTRY(node)));} static void RB_ENTRY(_free)(struct RB_ENTRY(node) *x) {free(x);} #endif /* These functions are always needed */ static void RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); static void RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); static struct RB_ENTRY(node) *RB_ENTRY(_successor)(const struct RB_ENTRY(node) *); static struct RB_ENTRY(node) *RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *); static struct RB_ENTRY(node) *RB_ENTRY(_traverse)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *); /* These functions may not be needed */ #ifndef no_lookup static struct RB_ENTRY(node) *RB_ENTRY(_lookup)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *); #endif #ifndef no_destroy static void RB_ENTRY(_destroy)(struct RB_ENTRY(node) *); #endif #ifndef no_delete static void RB_ENTRY(_delete)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); static void RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); #endif #ifndef no_walk static void RB_ENTRY(_walk)(const struct RB_ENTRY(node) *, void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *, int); #endif #ifndef no_readlist static RBLIST *RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *); static const RB_ENTRY(data_t) * RB_ENTRY(_readlist)(RBLIST *); static void RB_ENTRY(_closelist)(RBLIST *); #endif /* ** OK here we go, the balanced tree stuff. The algorithm is the ** fairly standard red/black taken from "Introduction to Algorithms" ** by Cormen, Leiserson & Rivest. Maybe one of these days I will ** fully understand all this stuff. ** ** Basically a red/black balanced tree has the following properties:- ** 1) Every node is either red or black (colour is RED or BLACK) ** 2) A leaf (RBNULL pointer) is considered black ** 3) If a node is red then its children are black ** 4) Every path from a node to a leaf contains the same no ** of black nodes ** ** 3) & 4) above guarantee that the longest path (alternating ** red and black nodes) is only twice as long as the shortest ** path (all black nodes). Thus the tree remains fairly balanced. */ /* * Initialise a tree. Identifies the comparison routine and any config * data that must be sent to it when called. * Returns a pointer to the top of the tree. */ #ifndef RB_CUSTOMIZE RB_STATIC struct RB_ENTRY(tree) * rbinit(int (*cmp)(const void *, const void *, const void *), const void *config) #else RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void) #endif /* RB_CUSTOMIZE */ { struct RB_ENTRY(tree) *retval; char c; c=rcsid[0]; /* This does nothing but shutup the -Wall */ if ((retval=(struct RB_ENTRY(tree) *) malloc(sizeof(struct RB_ENTRY(tree))))==NULL) return(NULL); #ifndef RB_CUSTOMIZE retval->rb_cmp=cmp; retval->rb_config=config; #endif /* RB_CUSTOMIZE */ retval->rb_root=RBNULL; return(retval); } #ifndef no_destroy RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *rbinfo) { if (rbinfo==NULL) return; if (rbinfo->rb_root!=RBNULL) RB_ENTRY(_destroy)(rbinfo->rb_root); free(rbinfo); } #endif /* no_destroy */ #ifndef no_search RB_STATIC const RB_ENTRY(data_t) * RB_ENTRY(search)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) { struct RB_ENTRY(node) *x; if (rbinfo==NULL) return(NULL); x=RB_ENTRY(_traverse)(1, key, rbinfo); return((x==RBNULL) ? NULL : RB_GET(x, key)); } #endif /* no_search */ #ifndef no_find RB_STATIC const RB_ENTRY(data_t) * RB_ENTRY(find)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) { struct RB_ENTRY(node) *x; if (rbinfo==NULL) return(NULL); /* If we have a NULL root (empty tree) then just return */ if (rbinfo->rb_root==RBNULL) return(NULL); x=RB_ENTRY(_traverse)(0, key, rbinfo); return((x==RBNULL) ? NULL : RB_GET(x, key)); } #endif /* no_find */ #ifndef no_delete RB_STATIC const RB_ENTRY(data_t) * RB_ENTRY(delete)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) { struct RB_ENTRY(node) *x; const RB_ENTRY(data_t) * y; if (rbinfo==NULL) return(NULL); x=RB_ENTRY(_traverse)(0, key, rbinfo); if (x==RBNULL) { return(NULL); } else { y=RB_GET(x, key); RB_ENTRY(_delete)(&rbinfo->rb_root, x); return(y); } } #endif /* no_delete */ #ifndef no_walk RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *rbinfo, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg) { if (rbinfo==NULL) return; RB_ENTRY(_walk)(rbinfo->rb_root, action, arg, 0); } #endif /* no_walk */ #ifndef no_readlist RB_STATIC RBLIST * RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *rbinfo) { if (rbinfo==NULL) return(NULL); return(RB_ENTRY(_openlist)(rbinfo->rb_root)); } RB_STATIC const RB_ENTRY(data_t) * RB_ENTRY(readlist)(RBLIST *rblistp) { if (rblistp==NULL) return(NULL); return(RB_ENTRY(_readlist)(rblistp)); } RB_STATIC void RB_ENTRY(closelist)(RBLIST *rblistp) { if (rblistp==NULL) return; RB_ENTRY(_closelist)(rblistp); } #endif /* no_readlist */ #ifndef no_lookup RB_STATIC const RB_ENTRY(data_t) * RB_ENTRY(lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) { struct RB_ENTRY(node) *x; /* If we have a NULL root (empty tree) then just return NULL */ if (rbinfo==NULL || rbinfo->rb_root==NULL) return(NULL); x=RB_ENTRY(_lookup)(mode, key, rbinfo); return((x==RBNULL) ? NULL : RB_GET(x, key)); } #endif /* no_lookup */ /* --------------------------------------------------------------------- */ /* Search for and if not found and insert is true, will add a new ** node in. Returns a pointer to the new node, or the node found */ static struct RB_ENTRY(node) * RB_ENTRY(_traverse)(int insert, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) { struct RB_ENTRY(node) *x,*y,*z; int cmp; int found=0; int cmpmods(); y=RBNULL; /* points to the parent of x */ x=rbinfo->rb_root; /* walk x down the tree */ while(x!=RBNULL && found==0) { y=x; /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ #ifndef RB_CUSTOMIZE cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config); #else cmp=RB_CMP(key, RB_GET(x, key)); #endif /* RB_CUSTOMIZE */ if (cmp<0) x=x->left; else if (cmp>0) x=x->right; else found=1; } if (found || !insert) return(x); if ((z=RB_ENTRY(_alloc)())==NULL) { /* Whoops, no memory */ return(RBNULL); } RB_SET(z, key, key); z->up=y; if (y==RBNULL) { rbinfo->rb_root=z; } else { #ifndef RB_CUSTOMIZE cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key), rbinfo->rb_config); #else cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key)); #endif /* RB_CUSTOMIZE */ if (cmp<0) y->left=z; else y->right=z; } z->left=RBNULL; z->right=RBNULL; /* colour this new node red */ z->colour=RED; /* Having added a red node, we must now walk back up the tree balancing ** it, by a series of rotations and changing of colours */ x=z; /* While we are not at the top and our parent node is red ** N.B. Since the root node is garanteed black, then we ** are also going to stop if we are the child of the root */ while(x != rbinfo->rb_root && (x->up->colour == RED)) { /* if our parent is on the left side of our grandparent */ if (x->up == x->up->up->left) { /* get the right side of our grandparent (uncle?) */ y=x->up->up->right; if (y->colour == RED) { /* make our parent black */ x->up->colour = BLACK; /* make our uncle black */ y->colour = BLACK; /* make our grandparent red */ x->up->up->colour = RED; /* now consider our grandparent */ x=x->up->up; } else { /* if we are on the right side of our parent */ if (x == x->up->right) { /* Move up to our parent */ x=x->up; RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x); } /* make our parent black */ x->up->colour = BLACK; /* make our grandparent red */ x->up->up->colour = RED; /* right rotate our grandparent */ RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x->up->up); } } else { /* everything here is the same as above, but ** exchanging left for right */ y=x->up->up->left; if (y->colour == RED) { x->up->colour = BLACK; y->colour = BLACK; x->up->up->colour = RED; x=x->up->up; } else { if (x == x->up->left) { x=x->up; RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x); } x->up->colour = BLACK; x->up->up->colour = RED; RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x->up->up); } } } /* Set the root node black */ (rbinfo->rb_root)->colour = BLACK; return(z); } #ifndef no_lookup /* Search for a key according to mode (see redblack.h) */ static struct RB_ENTRY(node) * RB_ENTRY(_lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) { struct RB_ENTRY(node) *x,*y; int cmp=0; int found=0; y=RBNULL; /* points to the parent of x */ x=rbinfo->rb_root; if (mode==RB_LUFIRST) { /* Keep going left until we hit a NULL */ while(x!=RBNULL) { y=x; x=x->left; } return(y); } else if (mode==RB_LULAST) { /* Keep going right until we hit a NULL */ while(x!=RBNULL) { y=x; x=x->right; } return(y); } /* walk x down the tree */ while(x!=RBNULL && found==0) { y=x; /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ #ifndef RB_CUSTOMIZE cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config); #else cmp=RB_CMP(key, RB_GET(x, key)); #endif /* RB_CUSTOMIZE */ if (cmp<0) x=x->left; else if (cmp>0) x=x->right; else found=1; } if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ)) return(x); if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV)) return(RBNULL); if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT)) { if (cmp>0) return(RB_ENTRY(_successor)(y)); else return(y); } if (mode==RB_LULTEQ || (!found && mode==RB_LULESS)) { if (cmp<0) return(RB_ENTRY(_predecessor)(y)); else return(y); } if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT)) return(RB_ENTRY(_successor)(x)); if (mode==RB_LUPREV || (found && mode==RB_LULESS)) return(RB_ENTRY(_predecessor)(x)); /* Shouldn't get here */ return(RBNULL); } #endif /* no_lookup */ #ifndef no_destroy /* * Destroy all the elements blow us in the tree * only useful as part of a complete tree destroy. */ static void RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x) { if (x!=RBNULL) { if (x->left!=RBNULL) RB_ENTRY(_destroy)(x->left); if (x->right!=RBNULL) RB_ENTRY(_destroy)(x->right); RB_ENTRY(_free)(x); } } #endif /* no_destroy */ /* ** Rotate our tree thus:- ** ** X rb_left_rotate(X)---> Y ** / \ / \ ** A Y <---rb_right_rotate(Y) X C ** / \ / \ ** B C A B ** ** N.B. This does not change the ordering. ** ** We assume that neither X or Y is NULL */ static void RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x) { struct RB_ENTRY(node) *y; assert(x!=RBNULL); assert(x->right!=RBNULL); y=x->right; /* set Y */ /* Turn Y's left subtree into X's right subtree (move B)*/ x->right = y->left; /* If B is not null, set it's parent to be X */ if (y->left != RBNULL) y->left->up = x; /* Set Y's parent to be what X's parent was */ y->up = x->up; /* if X was the root */ if (x->up == RBNULL) { *rootp=y; } else { /* Set X's parent's left or right pointer to be Y */ if (x == x->up->left) { x->up->left=y; } else { x->up->right=y; } } /* Put X on Y's left */ y->left=x; /* Set X's parent to be Y */ x->up = y; } static void RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *y) { struct RB_ENTRY(node) *x; assert(y!=RBNULL); assert(y->left!=RBNULL); x=y->left; /* set X */ /* Turn X's right subtree into Y's left subtree (move B) */ y->left = x->right; /* If B is not null, set it's parent to be Y */ if (x->right != RBNULL) x->right->up = y; /* Set X's parent to be what Y's parent was */ x->up = y->up; /* if Y was the root */ if (y->up == RBNULL) { *rootp=x; } else { /* Set Y's parent's left or right pointer to be X */ if (y == y->up->left) { y->up->left=x; } else { y->up->right=x; } } /* Put Y on X's right */ x->right=y; /* Set Y's parent to be X */ y->up = x; } /* Return a pointer to the smallest key greater than x */ static struct RB_ENTRY(node) * RB_ENTRY(_successor)(const struct RB_ENTRY(node) *x) { struct RB_ENTRY(node) *y; if (x->right!=RBNULL) { /* If right is not NULL then go right one and ** then keep going left until we find a node with ** no left pointer. */ for (y=x->right; y->left!=RBNULL; y=y->left); } else { /* Go up the tree until we get to a node that is on the ** left of its parent (or the root) and then return the ** parent. */ y=x->up; while(y!=RBNULL && x==y->right) { x=y; y=y->up; } } return(y); } /* Return a pointer to the largest key smaller than x */ static struct RB_ENTRY(node) * RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *x) { struct RB_ENTRY(node) *y; if (x->left!=RBNULL) { /* If left is not NULL then go left one and ** then keep going right until we find a node with ** no right pointer. */ for (y=x->left; y->right!=RBNULL; y=y->right); } else { /* Go up the tree until we get to a node that is on the ** right of its parent (or the root) and then return the ** parent. */ y=x->up; while(y!=RBNULL && x==y->left) { x=y; y=y->up; } } return(y); } #ifndef no_delete /* Delete the node z, and free up the space */ static void RB_ENTRY(_delete)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *z) { struct RB_ENTRY(node) *x, *y; if (z->left == RBNULL || z->right == RBNULL) y=z; else y=RB_ENTRY(_successor)(z); if (y->left != RBNULL) x=y->left; else x=y->right; x->up = y->up; if (y->up == RBNULL) { *rootp=x; } else { if (y==y->up->left) y->up->left = x; else y->up->right = x; } if (y!=z) { RB_SET(z, key, RB_GET(y, key)); } if (y->colour == BLACK) RB_ENTRY(_delete_fix)(rootp, x); RB_ENTRY(_free)(y); } /* Restore the reb-black properties after a delete */ static void RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x) { struct RB_ENTRY(node) *w; while (x!=*rootp && x->colour==BLACK) { if (x==x->up->left) { w=x->up->right; if (w->colour==RED) { w->colour=BLACK; x->up->colour=RED; rb_left_rotate(rootp, x->up); w=x->up->right; } if (w->left->colour==BLACK && w->right->colour==BLACK) { w->colour=RED; x=x->up; } else { if (w->right->colour == BLACK) { w->left->colour=BLACK; w->colour=RED; RB_ENTRY(_right_rotate)(rootp, w); w=x->up->right; } w->colour=x->up->colour; x->up->colour = BLACK; w->right->colour = BLACK; RB_ENTRY(_left_rotate)(rootp, x->up); x=*rootp; } } else { w=x->up->left; if (w->colour==RED) { w->colour=BLACK; x->up->colour=RED; RB_ENTRY(_right_rotate)(rootp, x->up); w=x->up->left; } if (w->right->colour==BLACK && w->left->colour==BLACK) { w->colour=RED; x=x->up; } else { if (w->left->colour == BLACK) { w->right->colour=BLACK; w->colour=RED; RB_ENTRY(_left_rotate)(rootp, w); w=x->up->left; } w->colour=x->up->colour; x->up->colour = BLACK; w->left->colour = BLACK; RB_ENTRY(_right_rotate)(rootp, x->up); x=*rootp; } } } x->colour=BLACK; } #endif /* no_delete */ #ifndef no_walk static void RB_ENTRY(_walk)(const struct RB_ENTRY(node) *x, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg, int level) { if (x==RBNULL) return; if (x->left==RBNULL && x->right==RBNULL) { /* leaf */ (*action)(RB_GET(x, key), leaf, level, arg); } else { (*action)(RB_GET(x, key), preorder, level, arg); RB_ENTRY(_walk)(x->left, action, arg, level+1); (*action)(RB_GET(x, key), postorder, level, arg); RB_ENTRY(_walk)(x->right, action, arg, level+1); (*action)(RB_GET(x, key), endorder, level, arg); } } #endif /* no_walk */ #ifndef no_readlist static RBLIST * RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *rootp) { RBLIST *rblistp; rblistp=(RBLIST *) malloc(sizeof(RBLIST)); if (!rblistp) return(NULL); rblistp->rootp=rootp; rblistp->nextp=rootp; if (rootp!=RBNULL) { while(rblistp->nextp->left!=RBNULL) { rblistp->nextp=rblistp->nextp->left; } } return(rblistp); } static const RB_ENTRY(data_t) * RB_ENTRY(_readlist)(RBLIST *rblistp) { const RB_ENTRY(data_t) *key=NULL; if (rblistp!=NULL && rblistp->nextp!=RBNULL) { key=RB_GET(rblistp->nextp, key); rblistp->nextp=RB_ENTRY(_successor)(rblistp->nextp); } return(key); } static void rb_closelist(RBLIST *rblistp) { if (rblistp) free(rblistp); } #endif /* no_readlist */ #if defined(RB_USE_SBRK) /* Allocate space for our nodes, allowing us to get space from ** sbrk in larger chucks. */ static struct RB_ENTRY(node) *rbfreep=NULL; #define RB_ENTRY(NODE)ALLOC_CHUNK_SIZE 1000 static struct RB_ENTRY(node) * RB_ENTRY(_alloc)() { struct RB_ENTRY(node) *x; int i; if (rbfreep==NULL) { /* must grab some more space */ rbfreep=(struct RB_ENTRY(node) *) sbrk(sizeof(struct RB_ENTRY(node)) * RB_ENTRY(NODE)ALLOC_CHUNK_SIZE); if (rbfreep==(struct RB_ENTRY(node) *) -1) { return(NULL); } /* tie them together in a linked list (use the up pointer) */ for (i=0, x=rbfreep; iup = (x+1); } x->up=NULL; } x=rbfreep; rbfreep = rbfreep->up; #ifdef RB_ALLOC RB_ALLOC(ACCESS(x, key)); #endif /* RB_ALLOC */ return(x); } /* free (dealloc) an RB_ENTRY(node) structure - add it onto the front of the list ** N.B. RB_ENTRY(node) need not have been allocated through rb_alloc() */ static void RB_ENTRY(_free)(struct RB_ENTRY(node) *x) { #ifdef RB_FREE RB_FREE(ACCESS(x, key)); #endif /* RB_FREE */ x->up=rbfreep; rbfreep=x; } #endif #if 0 int RB_ENTRY(_check)(struct RB_ENTRY(node) *rootp) { if (rootp==NULL || rootp==RBNULL) return(0); if (rootp->up!=RBNULL) { fprintf(stderr, "Root up pointer not RBNULL"); dumptree(rootp, 0); return(1); } if (RB_ENTRY(_check)1(rootp)) { RB_ENTRY(dumptree)(rootp, 0); return(1); } if (RB_ENTRY(count_black)(rootp)==-1) { RB_ENTRY(dumptree)(rootp, 0); return(-1); } return(0); } int RB_ENTRY(_check1)(struct RB_ENTRY(node) *x) { if (x->left==NULL || x->right==NULL) { fprintf(stderr, "Left or right is NULL"); return(1); } if (x->colour==RED) { if (x->left->colour!=BLACK && x->right->colour!=BLACK) { fprintf(stderr, "Children of red node not both black, x=%ld", x); return(1); } } if (x->left != RBNULL) { if (x->left->up != x) { fprintf(stderr, "x->left->up != x, x=%ld", x); return(1); } if (rb_check1(x->left)) return(1); } if (x->right != RBNULL) { if (x->right->up != x) { fprintf(stderr, "x->right->up != x, x=%ld", x); return(1); } if (rb_check1(x->right)) return(1); } return(0); } RB_ENTRY(count_black)(struct RB_ENTRY(node) *x) { int nleft, nright; if (x==RBNULL) return(1); nleft=RB_ENTRY(count_black)(x->left); nright=RB_ENTRY(count_black)(x->right); if (nleft==-1 || nright==-1) return(-1); if (nleft != nright) { fprintf(stderr, "Black count not equal on left & right, x=%ld", x); return(-1); } if (x->colour == BLACK) { nleft++; } return(nleft); } RB_ENTRY(dumptree)(struct RB_ENTRY(node) *x, int n) { char *prkey(); if (x!=NULL && x!=RBNULL) { n++; fprintf(stderr, "Tree: %*s %ld: left=%ld, right=%ld, colour=%s, key=%s", n, "", x, x->left, x->right, (x->colour==BLACK) ? "BLACK" : "RED", prkey(RB_GET(x, key))); RB_ENTRY(dumptree)(x->left, n); RB_ENTRY(dumptree)(x->right, n); } } #endif /* * $Log: redblack.c,v $ * Revision 1.9 2003/10/24 01:31:21 damo * Patches from Eric Raymond: %prefix is implemented.  Various other small * changes avoid stepping on global namespaces and improve the documentation. * * Revision 1.8 2002/08/26 05:33:47 damo * Some minor fixes:- * Stopped ./configure warning about stuff being in the wrong order * Fixed compiler warning about const (not sure about this) * Changed directory of redblack.c in documentation * * Revision 1.7 2002/08/26 03:11:40 damo * Fixed up a bunch of compiler warnings when compiling example4 * * Tidies up the Makefile.am & Specfile. * * Renamed redblack to rbgen * * Revision 1.6 2002/08/26 01:03:35 damo * Patch from Eric Raymond to change the way the library is used:- * * Eric's idea is to convert libredblack into a piece of in-line code * generated by another program. This should be faster, smaller and easier * to use. * * This is the first check-in of his code before I start futzing with it! * * Revision 1.5 2002/01/30 07:54:53 damo * Fixed up the libtool versioning stuff (finally) * Fixed bug 500600 (not detecting a NULL return from malloc) * Fixed bug 509485 (no longer needs search.h) * Cleaned up debugging section * Allow multiple inclusions of redblack.h * Thanks to Matthias Andree for reporting (and fixing) these * * Revision 1.4 2000/06/06 14:43:43 damo * Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk. * Added two new examples * * Revision 1.3 2000/05/24 06:45:27 damo * Converted everything over to using const * Added a new example1.c file to demonstrate the worst case scenario * Minor fixups of the spec file * * Revision 1.2 2000/05/24 06:17:10 damo * Fixed up the License (now the LGPL) * * Revision 1.1 2000/05/24 04:15:53 damo * Initial import of files. Versions are now all over the place. Oh well * */ ushare-1.1a/src/osdep.c0000644000175000017500000000374510726763650013167 0ustar benben/* * osdep.c : GeeXboX uShare OS independant helpers. * Originally developped for the GeeXboX project. * Copyright (C) 2005-2007 Benjamin Zores * * 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. */ #if (defined(__unix__) || defined(unix)) && !defined(USG) #include #endif #include #include #include #include #include "osdep.h" #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) char * strndup (const char *s, size_t n) { size_t len; char *sdup = NULL; if (!s) return NULL; len = strlen (s); len = n < len ? n : len; sdup = (char *) malloc (len + 1); if (sdup) { memcpy (sdup, s, len); sdup[len] = '\0'; } return sdup; } ssize_t getline (char **lineptr, size_t *n, FILE *stream) { static char line[256]; char *ptr; ssize_t len; if (!lineptr || !n) return -1; if (ferror (stream)) return -1; if (feof (stream)) return -1; fgets (line, 256, stream); ptr = strchr (line, '\n'); if (ptr) *ptr = '\0'; len = strlen (line); if ((len + 1) < 256) { ptr = realloc (*lineptr, 256); if (!ptr) return -1; *lineptr = ptr; *n = 256; } strcpy (*lineptr, line); return len; } #endif /* (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) */ ushare-1.1a/src/ctrl_telnet.c0000644000175000017500000005422610726763650014374 0ustar benben/* ctrltelnet.c - Telnet controler * Copyright (C) 2005-2007 Sven Almgren * * 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. * */ #define STR(x) _STR(x) #define _STR(x) __STR(x) #define __STR(x) #x #include "config.h" #include "ctrl_telnet.h" #include "minmax.h" #include "trace.h" #include #include #include #include /* For select */ #include #include /* For pipe */ #include #include #include #include #include #if (defined(____DISABLE_MUTEX) || 0) #define pthread_mutex_lock(x) printf(">>>> Locking " __FILE__ ":" STR(__LINE__) " \t" #x "\n"); #define pthread_mutex_unlock(x) printf("<<<< Unlocking " __FILE__ ":" STR(__LINE__) " \t" #x "\n"); #endif /** * @brief Structure holding data between the staring rutine and the thread */ typedef struct telnet_thread_data_t { pthread_t thread; /* Litening socket */ int listener; /* Socket used to terminate loop: 0 is reading and 1 is sending, kill by sending to 1 */ int killer[2]; /* Our socket address */ struct sockaddr_in local_address; /* Shared data buffer that can be used by others... */ char shared_buffer[CTRL_TELNET_SHARED_BUFFER_SIZE]; ctrl_telnet_client *clients; } telnet_thread_data; /** * @brief Struct for registerd commands */ typedef struct telnet_function_list_t { /* Function name, or keyword, if you like */ char *name; char *description; ctrl_telnet_command_ptr function; struct telnet_function_list_t *next; } telnet_function_list; /* Static yes used to set socketoptions */ static int yes = 1; static telnet_thread_data ttd; static telnet_function_list* functions = NULL; static pthread_mutex_t functions_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t startstop_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t shared_lock = PTHREAD_MUTEX_INITIALIZER; static int started = 0; /* Threadfunction, core in telnet controler */ /** * @brief Thread function * * @param data Not used, leave as NULL */ static void *ctrl_telnet_thread (void *data); /** * @brief Adds a new client to our list of new ones * * @param client to add */ static void ctrl_telnet_client_add (ctrl_telnet_client *client); /** * @brief Removes "client" from our list of clients */ static void ctrl_telnet_client_remove (ctrl_telnet_client *client); /** * @brief Updates an fd_set to contain the current set of clients * * @return max fd found in list */ static int ctrl_telnet_fix_fdset (fd_set* readable); static void ctrl_telnet_tokenize (char *raw, int *argc, char ***argv); static int ctrl_telnet_client_recv (ctrl_telnet_client *client); static int ctrl_telnet_client_execute (ctrl_telnet_client *client); static int ctrl_telnet_client_execute_line (ctrl_telnet_client *client, char *line); static int ctrl_telnet_client_execute_line_safe (ctrl_telnet_client *client, char *line); static void ctrl_telnet_register_internals(); /** * @brief Starts a Telnet bound control interface * * @return 0 on success, -1 on error */ int ctrl_telnet_start (int port) { /* Start by making us threadsafe... */ pthread_mutex_lock (&startstop_lock); /* Create listener socket */ ttd.listener = socket (PF_INET, SOCK_STREAM, 0); if (ttd.listener == -1) { perror ("socket"); pthread_mutex_unlock (&startstop_lock); return -1; } /* Clears us from "address already in use" errors */ if (setsockopt (ttd.listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == -1) perror ("setsockopt"); ttd.local_address.sin_family = AF_INET; ttd.local_address.sin_addr.s_addr = INADDR_ANY; ttd.local_address.sin_port = htons (port); memset (&ttd.local_address.sin_zero, '\0', sizeof (ttd.local_address.sin_zero)); if (bind (ttd.listener, (struct sockaddr *) &ttd.local_address, sizeof (ttd.local_address)) == -1) { perror ("bind"); pthread_mutex_unlock (&startstop_lock); return -1; } if (listen (ttd.listener, CTRL_TELNET_BACKLOG) == -1) { perror ("listen"); pthread_mutex_unlock (&startstop_lock); return -1; } print_log (ULOG_NORMAL, "Listening on telnet port %u\n", port); /* Create killer pipes */ if (pipe (ttd.killer)) { perror ("Failed to create killer pipe"); pthread_mutex_unlock (&startstop_lock); return -1; /* FIXME. Kill all sockets... not critical,, but still */ } if (pthread_create (&ttd.thread, NULL, ctrl_telnet_thread, NULL)) { /* FIXME: Killall sockets... */ perror ("Failed to create thread"); pthread_mutex_unlock (&startstop_lock); return -1; } started = 1; ctrl_telnet_register_internals (); pthread_mutex_unlock (&startstop_lock); return 0; } /** * @brief Stops all telnet bound control interfaces */ void ctrl_telnet_stop (void) { pthread_mutex_lock (&startstop_lock); if (!started) { pthread_mutex_unlock (&startstop_lock); return; } /* yes is int, which is bigger then char, so this should be safe */ write (ttd.killer[1], &yes, sizeof (char)); pthread_mutex_unlock (&startstop_lock); pthread_join (ttd.thread, NULL); } /** * @brief Telnet thread function */ static void * ctrl_telnet_thread (void *a __attribute__ ((unused))) { /* fd_set with readable clients */ fd_set fd_readable; /* Pointer to a client object */ ctrl_telnet_client *client; int fd_max; while (1) { /* Get fds */ fd_max = ctrl_telnet_fix_fdset (&fd_readable); if (select (fd_max + 1, &fd_readable, NULL, NULL, NULL) == -1) { perror ("select"); /* FIXME: Close sockets */ return NULL; } /* Check killer */ if (FD_ISSET (ttd.killer[0], &fd_readable)) { /* FIXME: TODO: Shut down sockets... */ /* Close listener and killer */ close (ttd.listener); close (ttd.killer[0]); close (ttd.killer[1]); /* Check which fds that had anyhting to say... */ client = ttd.clients; /* Say goodby to clients */ while (client) { ctrl_telnet_client *current = client; ctrl_telnet_client_send (current, "\nServer is going down, Bye bye\n"); client = client->next; ctrl_telnet_client_remove (current); } pthread_mutex_lock (&functions_lock); while (functions) { telnet_function_list *head = functions; functions = functions->next; free (head->name); if (head->description) free (head->description); free (head); } pthread_mutex_unlock (&functions_lock); return NULL; } /* Check for new connection */ if (FD_ISSET (ttd.listener, &fd_readable)) { socklen_t sl_addr; /* Create client object */ client = malloc (sizeof (ctrl_telnet_client)); if (!client) { perror ("Failed to create new client"); return NULL; } memset (client, '\0', sizeof (ctrl_telnet_client)); sl_addr = sizeof (client->remote_address); client->socket = accept (ttd.listener, (struct sockaddr *) &client->remote_address, &sl_addr); if (client->socket == -1) { perror ("accept"); free (client); } else { ctrl_telnet_client_add (client); ctrl_telnet_client_execute_line_safe (client, "banner"); ctrl_telnet_client_sendf (client, "For a list of registered commands type \"help\"\n"); ctrl_telnet_client_send (client, "\n> "); } } /* Check which fds that had anyhting to say... */ client = ttd.clients; /* Run through all clients and check if there's data avalible with FD_ISSET(current->socket) */ while (client) { ctrl_telnet_client *current = client; client = client->next; if (FD_ISSET (current->socket, &fd_readable)) { if (ctrl_telnet_client_recv (current) <= 0) { ctrl_telnet_client_remove (current); continue; } if (current->ready) { ctrl_telnet_client_execute (current); if (!current->exiting) ctrl_telnet_client_send (current, "\n> "); else ctrl_telnet_client_remove (current); } } } } } /** * @brief Adds a new client to our list of new ones * * @note This funtion is only called from a single thread, * as such it won't need to be threadsafe * @param client to add */ static void ctrl_telnet_client_add (ctrl_telnet_client *client) { client->next = ttd.clients; ttd.clients = client; } /** * @brief Removes "client" from our list of clients * * @note This funtion is only called from a single thread, * as such it won't need to be threadsafe * @param client to remove */ static void ctrl_telnet_client_remove (ctrl_telnet_client *client) { ctrl_telnet_client *tmp; /* Start by dealing with our head */ if (client == ttd.clients) ttd.clients = client->next; else { for (tmp = ttd.clients; tmp->next; tmp = tmp->next) { if (tmp->next == client) { tmp->next = tmp->next->next; break; } } } close (client->socket); free (client); } /** * @brief Clears readable fd_set and adds every client to it, * returns max fd found * * @param readable fd_set to update * @return Biggest fd */ static int ctrl_telnet_fix_fdset (fd_set *readable) { int maxfd; ctrl_telnet_client *client; maxfd = MAX (ttd.killer[0], ttd.listener); FD_ZERO (readable); FD_SET (ttd.listener, readable); FD_SET (ttd.killer[0], readable); client = ttd.clients; while (client) { if (client->socket > maxfd) maxfd = client->socket; FD_SET (client->socket, readable); client = client->next; } return maxfd; } static int ctrl_telnet_client_recv (ctrl_telnet_client *client) { int i; int nbytes; int buffer_free = CTRL_CLIENT_RECV_BUFFER_SIZE - client->buffer_recv_current - 1; nbytes = recv (client->socket, client->buffer_recv + client->buffer_recv_current, buffer_free, 0); if (nbytes <= 0) { close (client->socket); return nbytes; } client->buffer_recv_current += nbytes; client->buffer_recv[client->buffer_recv_current] = '\0'; for (i = 0; i < client->buffer_recv_current; i++) if (client->buffer_recv[i] == '\n') client->ready = 1; return nbytes; } int ctrl_telnet_client_send (const ctrl_telnet_client *client, const char *string) { const char* cc = string; int len = strlen (cc); int sent = 0; int senttotal = 0; while ((cc - string) < len) { /* Use nonblocking just as a precation... and a failed write won't _really_ kill us */ sent = send (client->socket, string, len - (cc - string), MSG_DONTWAIT); /* This will mark the socket as dead... just to be safe.. and its only a telnet interface... reconnect and do it again */ if (sent == -1) return -1; senttotal += sent; cc += sent; } return senttotal; } int ctrl_telnet_client_sendf (const ctrl_telnet_client *client, const char *format, ...) { int retval; va_list ap; int len; pthread_mutex_lock (&shared_lock); va_start (ap, format); len = vsnprintf (ttd.shared_buffer, CTRL_TELNET_SHARED_BUFFER_SIZE, format, ap); va_end (ap); /* Check if the message fitted inside the buffer, if not, either exit or adjust len to be buffersize, I choose exit for now */ if (len >= CTRL_TELNET_SHARED_BUFFER_SIZE) { pthread_mutex_unlock (&shared_lock); /* FIXME: Return error or send what we've got? */ return -1; /* Buffer was to small */ } /* TODO: Might be good to have the option to specify str length so send doesn't have to recompute it... */ retval = ctrl_telnet_client_send (client, ttd.shared_buffer); pthread_mutex_unlock (&shared_lock); return retval; } int ctrl_telnet_client_sendsf (const ctrl_telnet_client *client, char *buffer, int buffersize, const char *format, ...) { va_list ap; int len; va_start (ap, format); len = vsnprintf (buffer, buffersize, format, ap); va_end (ap); /* Check if the message fitted inside the buffer, if not, either exit or adjust len to be buffersize, I choose exit for now */ if (len >= buffersize) return -1; /* Buffer was to small */ /* TODO: Might be good to have the option to specify str length so send doesn't have to recompute it... */ return ctrl_telnet_client_send (client, buffer); } /* FIXME: Ulgy non optimised version */ static int ctrl_telnet_client_execute (ctrl_telnet_client *client) { int i = 0; /* Check buffer for complete lines and execute them,,, */ for (i = 0; i < client->buffer_recv_current; i++) { if (client->buffer_recv[i] == '\n' || client->buffer_recv[i] == '\r') { /* Replace newline with null (or \r) */ client->buffer_recv[i] = '\0'; /* Send line to execution */ ctrl_telnet_client_execute_line_safe (client, client->buffer_recv); /* Check if next is either newline or CR, strip that too, if needed */ if ((i + 1 < CTRL_CLIENT_RECV_BUFFER_SIZE) && (client->buffer_recv[i+1]=='\n' || client->buffer_recv[i+1]=='\r')) client->buffer_recv[++i] = '\0'; /* Remove processed line */ memmove (client->buffer_recv, client->buffer_recv + i, client->buffer_recv_current - 1); client->buffer_recv_current -= (i + 1); i = -1; } } return 0; /* No syntax error checking yet */ } static int ctrl_telnet_client_execute_line_safe (ctrl_telnet_client *client, char *line) { int retval; pthread_mutex_lock (&functions_lock); retval = ctrl_telnet_client_execute_line (client, line); pthread_mutex_unlock (&functions_lock); return retval; } static int ctrl_telnet_client_execute_line (ctrl_telnet_client *client, char *line) { int argc = 0; char **argv = NULL; telnet_function_list *node; char *line2 = strdup (line); /* To make it safer */ ctrl_telnet_tokenize (line2, &argc, &argv); node = functions; if (*argv[0] == '\0') { free (argv); free (line2); return 0; } while (node) { if (!strcmp (node->name, argv[0])) { node->function (client, argc, argv); break; } node = node->next; } if (!node) ctrl_telnet_client_sendf (client, "%s: Command not found\n", argv[0]); free (argv); free (line2); return strlen (line); } void ctrl_telnet_register (const char *funcname, ctrl_telnet_command_ptr funcptr, const char *description) { telnet_function_list *function; function = malloc (sizeof (telnet_function_list)); function->name = strdup (funcname); /* Mayby use strndup...? */ function->description = description ? strdup (description) : NULL; function->function = funcptr; pthread_mutex_lock (&functions_lock); function->next = functions; functions = function; pthread_mutex_unlock (&functions_lock); } /* Warning: This WILL edit the input string... use strdup or something if needed, also remember to free() argv as the first array is dynamic */ /* If *argv != NULL it'll first be free()ed... or realloc, make sure to clear *argv to null on initialization */ static void ctrl_telnet_tokenize (char *raw, int *argc, char ***argv) { int i; int has_backslash = 0; int has_quote = 0; char *pc = raw; if (!raw || !argc || !argv) { perror ("NULL in " __FILE__ " at line " STR (__LINE__)); return; } /* (1/3) First run is just to count our arguments... */ *argc = (raw[0] == '\0') ? 0 : 1; pc = raw; while (*pc) { switch (*pc) { case '\\': if (!has_backslash) has_backslash = 2; /* FULHACK */ break; case ' ': if (!has_backslash && !has_quote) (*argc)++; break; case '"': if (!has_backslash) has_quote = !has_quote; break; } /* When we get a BS we set it to two, this makes it one, next run it will still be 1, then one after that is zero... FULHACK */ if (has_backslash) has_backslash--; pc++; } /* Create argv */ *argv = malloc (sizeof (char **) * ((*argc) + 1)); /* (2/3) Parse throu one more time, this time filling argv (Pass 2 / 3) */ i = 0; pc = raw; has_backslash = 0; has_quote = 0; (*argv)[0] = raw; while (*pc) { switch (*pc) { case '\\': if (!has_backslash) has_backslash = 2; /* FULHACK */ break; case ' ': if (!has_backslash && !has_quote) { *pc = '\0'; (*argv)[++i] = pc+1; pc++; continue; } break; case '"': if (!has_backslash) has_quote = !has_quote; break; } /* When we get a BS we set it to two, this makes it one, next run it will still be 1, then one after that is zero... FULHACK */ if (has_backslash) has_backslash--; pc++; } /* Make last element (argc) point to null... */ (*argv)[++i] = NULL; /* (3/3) Parse arguments to remove escapings and such */ for (i = 0; (*argv)[i]; i++) { /* Set up environment */ pc = (*argv)[i]; has_backslash = 0; has_quote = 0; /* Remove leading and ending quotes, if existing */ if (*pc == '"') { int len = strlen (pc); if (len > 0 && pc[len - 1] == '"') pc[len - 1] = '\0'; memmove (pc, pc + 1, len); } /* Remove any special characters */ while (*pc) { switch (*pc) { case '\\': if (!has_backslash) { has_backslash = 2; /* FULHACK */ break; } /* Else: fall through */ case ' ': case '"': if (has_backslash) { pc--; memmove (pc, pc + 1, strlen (pc)); /* FIXME: Not cheap */ } break; } /* When we get a BS we set it to two, this makes it one, next run it will still be 1, then one after that is zero... */ if (has_backslash) has_backslash--; pc++; } } } static void help (ctrl_telnet_client *client, int argc, char **argv) { int hidden = 0; ctrl_telnet_client_execute_line (client, "banner"); if (argc < 2) { ctrl_telnet_client_send (client, "\n"); ctrl_telnet_client_send (client, "Usage: help TOPIC\n"); ctrl_telnet_client_send (client, "Valid topics are\n"); ctrl_telnet_client_send (client, " commands - For a list of registed commands\n"); ctrl_telnet_client_send (client, " syntax - For a description of the interface syntax\n"); return; } else { if (!strcmp ("commands", argv[1])) { telnet_function_list *node; node = functions; ctrl_telnet_client_send (client, "Registered command (command - description)\n"); ctrl_telnet_client_send (client, "=======================================================\n"); while (node) { /* Make functions without descriptions invisible */ if (node->description) ctrl_telnet_client_sendf (client, " %s - %s\n", node->name, node->description); else hidden++; node = node->next; } if (hidden) ctrl_telnet_client_sendf (client, "There's also %i hidden functions\n", hidden); } /* commands */ else if (!strcmp ("syntax", argv[1])) { ctrl_telnet_client_send (client, "Syntax is easy: command parameters\n"); ctrl_telnet_client_send (client, " Each new word is a new argument, unless the space is precided\n"); ctrl_telnet_client_send (client, " a backslash (\\), or if a set of words are surrounded by quotes\n"); ctrl_telnet_client_send (client, " (\"). To get a litteral quote you can escape it as \\\".\n"); ctrl_telnet_client_send (client, "\n"); ctrl_telnet_client_send (client, "STUB\n"); } else ctrl_telnet_client_send (client, "Unknown topic\n"); } } static void banner (ctrl_telnet_client *client, int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) { ctrl_telnet_client_sendf (client, "%s (%s) (Built %s)\n", PACKAGE_NAME, VERSION, __DATE__); } static void echo (ctrl_telnet_client *client, int argc, char **argv) { int i; for (i = 1; i < argc; i++) ctrl_telnet_client_sendf (client, "%s%s", (i > 1 ? " " : ""), argv[i]); ctrl_telnet_client_send (client, "\n"); } static void echod (ctrl_telnet_client *client, int argc, char **argv) { int i; ctrl_telnet_client_sendf (client, "Argc: %i\n", argc); for (i = 0; i < argc; i++) ctrl_telnet_client_sendf (client, "%i: '%s'\n", i, argv[i]); } static void ctrl_telnet_exit (ctrl_telnet_client *client, int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) { client->exiting = 1; ctrl_telnet_client_send (client, "Bye bye\n"); } static void ctrl_telnet_register_internals (void) { ctrl_telnet_register ("echo", echo, "Echos all arguments"); ctrl_telnet_register ("echod", echod, "Echos all arguments but with each argument on a new line... DEBUG"); ctrl_telnet_register ("help", help, "Display help"); ctrl_telnet_register ("banner", banner, NULL); ctrl_telnet_register ("exit", ctrl_telnet_exit, "Exits this interface (Or CTRL+D then Enter)"); /* CTRL+D... But it has to be fallowd by a new line */ ctrl_telnet_register ("\4", ctrl_telnet_exit, NULL); } ushare-1.1a/src/ushare.c0000644000175000017500000004723510726763650013346 0ustar benben/* * ushare.c : GeeXboX uShare UPnP Media Server. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * 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 #include #include #include #include #include #include #include #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) #include #include #include #endif #if (defined(__APPLE__)) #include #endif #include #include #include #include #include #include #ifdef HAVE_IFADDRS_H #include #endif #if (defined(__unix__) || defined(unix)) && !defined(USG) #include #endif #include #include #if (defined(HAVE_SETLOCALE) && defined(CONFIG_NLS)) # include #endif #include "config.h" #include "ushare.h" #include "services.h" #include "http.h" #include "metadata.h" #include "util_iconv.h" #include "content.h" #include "cfgparser.h" #include "gettext.h" #include "trace.h" #include "buffer.h" #include "ctrl_telnet.h" struct ushare_t *ut = NULL; static struct ushare_t * ushare_new (void) __attribute__ ((malloc)); static struct ushare_t * ushare_new (void) { struct ushare_t *ut = (struct ushare_t *) malloc (sizeof (struct ushare_t)); if (!ut) return NULL; ut->name = strdup (DEFAULT_USHARE_NAME); ut->interface = strdup (DEFAULT_USHARE_IFACE); ut->model_name = strdup (DEFAULT_USHARE_NAME); ut->contentlist = NULL; ut->rb = rbinit (rb_compare, NULL); ut->root_entry = NULL; ut->nr_entries = 0; ut->starting_id = STARTING_ENTRY_ID_DEFAULT; ut->init = 0; ut->dev = 0; ut->udn = NULL; ut->ip = NULL; ut->port = 0; /* Randomly attributed by libupnp */ ut->telnet_port = CTRL_TELNET_PORT; ut->presentation = NULL; ut->use_presentation = true; ut->use_telnet = true; #ifdef HAVE_DLNA ut->dlna_enabled = false; ut->dlna = NULL; ut->dlna_flags = DLNA_ORG_FLAG_STREAMING_TRANSFER_MODE | DLNA_ORG_FLAG_BACKGROUND_TRANSFERT_MODE | DLNA_ORG_FLAG_CONNECTION_STALL | DLNA_ORG_FLAG_DLNA_V15; #endif /* HAVE_DLNA */ ut->xbox360 = false; ut->verbose = false; ut->daemon = false; ut->override_iconv_err = false; ut->cfg_file = NULL; pthread_mutex_init (&ut->termination_mutex, NULL); pthread_cond_init (&ut->termination_cond, NULL); return ut; } static void ushare_free (struct ushare_t *ut) { if (!ut) return; if (ut->name) free (ut->name); if (ut->interface) free (ut->interface); if (ut->model_name) free (ut->model_name); if (ut->contentlist) content_free (ut->contentlist); if (ut->rb) rbdestroy (ut->rb); if (ut->root_entry) upnp_entry_free (ut, ut->root_entry); if (ut->udn) free (ut->udn); if (ut->ip) free (ut->ip); if (ut->presentation) buffer_free (ut->presentation); #ifdef HAVE_DLNA if (ut->dlna_enabled) { if (ut->dlna) dlna_uninit (ut->dlna); ut->dlna = NULL; } #endif /* HAVE_DLNA */ if (ut->cfg_file) free (ut->cfg_file); pthread_cond_destroy (&ut->termination_cond); pthread_mutex_destroy (&ut->termination_mutex); free (ut); } static void ushare_signal_exit (void) { pthread_mutex_lock (&ut->termination_mutex); pthread_cond_signal (&ut->termination_cond); pthread_mutex_unlock (&ut->termination_mutex); } static void handle_action_request (struct Upnp_Action_Request *request) { struct service_t *service; struct service_action_t *action; char val[256]; uint32_t ip; if (!request || !ut) return; if (request->ErrCode != UPNP_E_SUCCESS) return; if (strcmp (request->DevUDN + 5, ut->udn)) return; ip = request->CtrlPtIPAddr.s_addr; ip = ntohl (ip); sprintf (val, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF); if (ut->verbose) { DOMString str = ixmlPrintDocument (request->ActionRequest); log_verbose ("***************************************************\n"); log_verbose ("** New Action Request **\n"); log_verbose ("***************************************************\n"); log_verbose ("ServiceID: %s\n", request->ServiceID); log_verbose ("ActionName: %s\n", request->ActionName); log_verbose ("CtrlPtIP: %s\n", val); log_verbose ("Action Request:\n%s\n", str); ixmlFreeDOMString (str); } if (find_service_action (request, &service, &action)) { struct action_event_t event; event.request = request; event.status = true; event.service = service; if (action->function (&event) && event.status) request->ErrCode = UPNP_E_SUCCESS; if (ut->verbose) { DOMString str = ixmlPrintDocument (request->ActionResult); log_verbose ("Action Result:\n%s", str); log_verbose ("***************************************************\n"); log_verbose ("\n"); ixmlFreeDOMString (str); } return; } if (service) /* Invalid Action name */ strcpy (request->ErrStr, "Unknown Service Action"); else /* Invalid Service name */ strcpy (request->ErrStr, "Unknown Service ID"); request->ActionResult = NULL; request->ErrCode = UPNP_SOAP_E_INVALID_ACTION; } static int device_callback_event_handler (Upnp_EventType type, void *event, void *cookie __attribute__((unused))) { switch (type) { case UPNP_CONTROL_ACTION_REQUEST: handle_action_request ((struct Upnp_Action_Request *) event); break; case UPNP_CONTROL_ACTION_COMPLETE: case UPNP_EVENT_SUBSCRIPTION_REQUEST: case UPNP_CONTROL_GET_VAR_REQUEST: break; default: break; } return 0; } static int finish_upnp (struct ushare_t *ut) { if (!ut) return -1; log_info (_("Stopping UPnP Service ...\n")); UpnpUnRegisterRootDevice (ut->dev); UpnpFinish (); return UPNP_E_SUCCESS; } static int init_upnp (struct ushare_t *ut) { char *description = NULL; int res; size_t len; if (!ut || !ut->name || !ut->udn || !ut->ip) return -1; #ifdef HAVE_DLNA if (ut->dlna_enabled) { len = 0; description = dlna_dms_description_get (ut->name, "GeeXboX Team", "http://ushare.geexbox.org/", "uShare : DLNA Media Server", ut->model_name, "001", "http://ushare.geexbox.org/", "USHARE-01", ut->udn, "/web/ushare.html", "/web/cms.xml", "/web/cms_control", "/web/cms_event", "/web/cds.xml", "/web/cds_control", "/web/cds_event"); if (!description) return -1; } else { #endif /* HAVE_DLNA */ len = strlen (UPNP_DESCRIPTION) + strlen (ut->name) + strlen (ut->model_name) + strlen (ut->udn) + 1; description = (char *) malloc (len * sizeof (char)); memset (description, 0, len); sprintf (description, UPNP_DESCRIPTION, ut->name, ut->model_name, ut->udn); #ifdef HAVE_DLNA } #endif /* HAVE_DLNA */ log_info (_("Initializing UPnP subsystem ...\n")); res = UpnpInit (ut->ip, ut->port); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot initialize UPnP subsystem\n")); return -1; } if (UpnpSetMaxContentLength (UPNP_MAX_CONTENT_LENGTH) != UPNP_E_SUCCESS) log_info (_("Could not set Max content UPnP\n")); if (ut->xbox360) log_info (_("Starting in XboX 360 compliant profile ...\n")); #ifdef HAVE_DLNA if (ut->dlna_enabled) { log_info (_("Starting in DLNA compliant profile ...\n")); ut->dlna = dlna_init (); dlna_set_verbosity (ut->dlna, ut->verbose ? 1 : 0); dlna_set_extension_check (ut->dlna, 1); dlna_register_all_media_profiles (ut->dlna); } #endif /* HAVE_DLNA */ ut->port = UpnpGetServerPort(); log_info (_("UPnP MediaServer listening on %s:%d\n"), UpnpGetServerIpAddress (), ut->port); UpnpEnableWebserver (TRUE); res = UpnpSetVirtualDirCallbacks (&virtual_dir_callbacks); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot set virtual directory callbacks\n")); free (description); return -1; } res = UpnpAddVirtualDir (VIRTUAL_DIR); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot add virtual directory for web server\n")); free (description); return -1; } res = UpnpRegisterRootDevice2 (UPNPREG_BUF_DESC, description, 0, 1, device_callback_event_handler, NULL, &(ut->dev)); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot register UPnP device\n")); free (description); return -1; } res = UpnpUnRegisterRootDevice (ut->dev); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot unregister UPnP device\n")); free (description); return -1; } res = UpnpRegisterRootDevice2 (UPNPREG_BUF_DESC, description, 0, 1, device_callback_event_handler, NULL, &(ut->dev)); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot register UPnP device\n")); free (description); return -1; } log_info (_("Sending UPnP advertisement for device ...\n")); UpnpSendAdvertisement (ut->dev, 1800); log_info (_("Listening for control point connections ...\n")); if (description) free (description); return 0; } static bool has_iface (char *interface) { #ifdef HAVE_IFADDRS_H struct ifaddrs *itflist, *itf; if (!interface) return false; if (getifaddrs (&itflist) < 0) { perror ("getifaddrs"); return false; } itf = itflist; while (itf) { if ((itf->ifa_flags & IFF_UP) && !strncmp (itf->ifa_name, interface, IFNAMSIZ)) { log_error (_("Interface %s is down.\n"), interface); log_error (_("Recheck uShare's configuration and try again !\n")); freeifaddrs (itflist); return true; } itf = itf->ifa_next; } freeifaddrs (itf); #else int sock, i, n; struct ifconf ifc; struct ifreq ifr; char buff[8192]; if (!interface) return false; /* determine UDN according to MAC address */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return false; } /* get list of available interfaces */ ifc.ifc_len = sizeof (buff); ifc.ifc_buf = buff; if (ioctl (sock, SIOCGIFCONF, &ifc) < 0) { perror ("ioctl"); close (sock); return false; } n = ifc.ifc_len / sizeof (struct ifreq); for (i = n - 1 ; i >= 0 ; i--) { ifr = ifc.ifc_req[i]; if (strncmp (ifr.ifr_name, interface, IFNAMSIZ)) continue; if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) { perror ("ioctl"); close (sock); return false; } if (!(ifr.ifr_flags & IFF_UP)) { /* interface is down */ log_error (_("Interface %s is down.\n"), interface); log_error (_("Recheck uShare's configuration and try again !\n")); close (sock); return false; } /* found right interface */ close (sock); return true; } close (sock); #endif log_error (_("Can't find interface %s.\n"),interface); log_error (_("Recheck uShare's configuration and try again !\n")); return false; } static char * create_udn (char *interface) { int sock = -1; char *buf; unsigned char *ptr; #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) int mib[6]; size_t len; struct if_msghdr *ifm; struct sockaddr_dl *sdl; #else /* Linux */ struct ifreq ifr; #endif if (!interface) return NULL; #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; mib[5] = if_nametoindex (interface); if (mib[5] == 0) { perror ("if_nametoindex"); return NULL; } if (sysctl (mib, 6, NULL, &len, NULL, 0) < 0) { perror ("sysctl"); return NULL; } buf = malloc (len); if (sysctl (mib, 6, buf, &len, NULL, 0) < 0) { perror ("sysctl"); return NULL; } ifm = (struct if_msghdr *) buf; sdl = (struct sockaddr_dl*) (ifm + 1); ptr = (unsigned char *) LLADDR (sdl); #else /* Linux */ /* determine UDN according to MAC address */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return NULL; } strcpy (ifr.ifr_name, interface); strcpy (ifr.ifr_hwaddr.sa_data, ""); if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0) { perror ("ioctl"); return NULL; } buf = (char *) malloc (64 * sizeof (char)); memset (buf, 0, 64); ptr = (unsigned char *) ifr.ifr_hwaddr.sa_data; #endif /* (defined(BSD) || defined(__FreeBSD__)) */ snprintf (buf, 64, "%s-%02x%02x%02x%02x%02x%02x", DEFAULT_UUID, (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)); if (sock) close (sock); return buf; } static char * get_iface_address (char *interface) { int sock; uint32_t ip; struct ifreq ifr; char *val; if (!interface) return NULL; /* determine UDN according to MAC address */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return NULL; } strcpy (ifr.ifr_name, interface); ifr.ifr_addr.sa_family = AF_INET; if (ioctl (sock, SIOCGIFADDR, &ifr) < 0) { perror ("ioctl"); close (sock); return NULL; } val = (char *) malloc (16 * sizeof (char)); ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr; ip = ntohl (ip); sprintf (val, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF); close (sock); return val; } static int restart_upnp (struct ushare_t *ut) { finish_upnp (ut); if (ut->udn) free (ut->udn); ut->udn = create_udn (ut->interface); if (!ut->udn) return -1; if (ut->ip) free (ut->ip); ut->ip = get_iface_address (ut->interface); if (!ut->ip) return -1; return (init_upnp (ut)); } static void UPnPBreak (int s __attribute__ ((unused))) { ushare_signal_exit (); } static void reload_config (int s __attribute__ ((unused))) { struct ushare_t *ut2; bool reload = false; log_info (_("Reloading configuration...\n")); ut2 = ushare_new (); if (!ut || !ut2) return; if (parse_config_file (ut2) < 0) return; if (ut->name && strcmp (ut->name, ut2->name)) { free (ut->name); ut->name = ut2->name; ut2->name = NULL; reload = true; } if (ut->interface && strcmp (ut->interface, ut2->interface)) { if (!has_iface (ut2->interface)) { ushare_free (ut2); raise (SIGINT); } else { free (ut->interface); ut->interface = ut2->interface; ut2->interface = NULL; reload = true; } } if (ut->port != ut2->port) { ut->port = ut2->port; reload = true; } if (reload) { if (restart_upnp (ut) < 0) { ushare_free (ut2); raise (SIGINT); } } if (ut->contentlist) content_free (ut->contentlist); ut->contentlist = ut2->contentlist; ut2->contentlist = NULL; ushare_free (ut2); if (ut->contentlist) { free_metadata_list (ut); build_metadata_list (ut); } else { log_error (_("Error: no content directory to be shared.\n")); raise (SIGINT); } } inline void display_headers (void) { printf (_("%s (version %s), a lightweight UPnP A/V and DLNA Media Server.\n"), PACKAGE_NAME, VERSION); printf (_("Benjamin Zores (C) 2005-2007, for GeeXboX Team.\n")); printf (_("See http://ushare.geexbox.org/ for updates.\n")); } inline static void setup_i18n(void) { #ifdef CONFIG_NLS #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); #endif #if (!defined(BSD) && !defined(__FreeBSD__)) bindtextdomain (PACKAGE, LOCALEDIR); #endif textdomain (PACKAGE); #endif } #define SHUTDOWN_MSG _("Server is shutting down: other clients will be notified soon, Bye bye ...\n") static void ushare_kill (ctrl_telnet_client *client, int argc __attribute__((unused)), char **argv __attribute__((unused))) { if (ut->use_telnet) { ctrl_telnet_client_send (client, SHUTDOWN_MSG); client->exiting = true; } ushare_signal_exit (); } int main (int argc, char **argv) { ut = ushare_new (); if (!ut) return EXIT_FAILURE; setup_i18n (); setup_iconv (); /* Parse args before cfg file, as we may override the default file */ if (parse_command_line (ut, argc, argv) < 0) { ushare_free (ut); return EXIT_SUCCESS; } if (parse_config_file (ut) < 0) { /* fprintf here, because syslog not yet ready */ fprintf (stderr, _("Warning: can't parse file \"%s\".\n"), ut->cfg_file ? ut->cfg_file : SYSCONFDIR "/" USHARE_CONFIG_FILE); } if (ut->xbox360) { char *name; name = malloc (strlen (XBOX_MODEL_NAME) + strlen (ut->model_name) + 4); sprintf (name, "%s (%s)", XBOX_MODEL_NAME, ut->model_name); free (ut->model_name); ut->model_name = strdup (name); free (name); ut->starting_id = STARTING_ENTRY_ID_XBOX360; } if (ut->daemon) { /* starting syslog feature as soon as possible */ start_log (); } if (!ut->contentlist) { log_error (_("Error: no content directory to be shared.\n")); ushare_free (ut); return EXIT_FAILURE; } if (!has_iface (ut->interface)) { ushare_free (ut); return EXIT_FAILURE; } ut->udn = create_udn (ut->interface); if (!ut->udn) { ushare_free (ut); return EXIT_FAILURE; } ut->ip = get_iface_address (ut->interface); if (!ut->ip) { ushare_free (ut); return EXIT_FAILURE; } if (ut->daemon) { int err; err = daemon (0, 0); if (err == -1) { log_error (_("Error: failed to daemonize program : %s\n"), strerror (err)); ushare_free (ut); return EXIT_FAILURE; } } else { display_headers (); } signal (SIGINT, UPnPBreak); signal (SIGHUP, reload_config); if (ut->use_telnet) { if (ctrl_telnet_start (ut->telnet_port) < 0) { ushare_free (ut); return EXIT_FAILURE; } ctrl_telnet_register ("kill", ushare_kill, _("Terminates the uShare server")); } if (init_upnp (ut) < 0) { finish_upnp (ut); ushare_free (ut); return EXIT_FAILURE; } build_metadata_list (ut); /* Let main sleep until it's time to die... */ pthread_mutex_lock (&ut->termination_mutex); pthread_cond_wait (&ut->termination_cond, &ut->termination_mutex); pthread_mutex_unlock (&ut->termination_mutex); if (ut->use_telnet) ctrl_telnet_stop (); finish_upnp (ut); free_metadata_list (ut); ushare_free (ut); finish_iconv (); /* it should never be executed */ return EXIT_SUCCESS; } ushare-1.1a/src/Makefile0000644000175000017500000000250710726763650013344 0ustar benbenifeq (,$(wildcard ../config.mak)) $(error "../config.mak is not present, run configure !") endif include ../config.mak PROG = ushare EXTRADIST = ushare.1 \ cds.h \ cms.h \ msr.h \ http.h \ presentation.h \ metadata.h \ mime.h \ services.h \ buffer.h \ util_iconv.h \ content.h \ cfgparser.h \ trace.h \ redblack.h \ osdep.h \ ctrl_telnet.h \ ushare.h \ gettext.h \ minmax.h \ SRCS = \ cds.c \ cms.c \ msr.c \ http.c \ presentation.c \ metadata.c \ mime.c \ services.c \ buffer.c \ util_iconv.c \ content.c \ cfgparser.c \ trace.c \ redblack.c \ osdep.c \ ctrl_telnet.c \ ushare.c OBJS = $(SRCS:.c=.o) .SUFFIXES: .c .o all: depend $(PROG) .c.o: $(CC) -c $(CFLAGS) $(OPTFLAGS) -o $@ $< $(PROG): $(OBJS) $(CC) $(OBJS) $(LDFLAGS) $(EXTRALIBS) -o $@ clean: -$(RM) -f *.o $(PROG) -$(RM) -f .depend distclean: install: $(PROG) $(INSTALL) -d $(bindir) $(INSTALL) $(PROG) $(bindir) $(STRIP) $(INSTALLSTRIP) $(bindir)/$(PROG) depend: $(CC) -I.. -MM $(CFLAGS) $(SRCS) 1>.depend .PHONY: clean distclean install depend dist-all: cp $(EXTRADIST) $(SRCS) Makefile $(DIST) .PHONY: dist-all # # include dependency files if they exist # ifneq ($(wildcard .depend),) include .depend endif