obexpushd-0.11.2-source/CHANGELOG000644 001750 001750 00000006571 11537730263 017436 0ustar00hendrikhendrik000000 000000 0.11 (2010-11-01) - add daemon that can behaves like a modem with AT commands - add stdio transport to let obexpushd be used as backend - add support for filesystem extended attributes to store the mime type - the file browsing service protocol is now disabled by default - add option -t to enable protocols 0.10 (2010-04-10) - add USB gadget support - add OBEX FTP support including setpath, get and put-delete - make UTF8/16 conversion independent of iconv() - extended the script interface - code restructured and modularized 0.9 (2009-06-11) - fix CMake modules in case of pkg-config not being present - allow extended mime-types in the type header (fixes SF.net bug #1940844) - add bluetooth transport layer security support - add TCP wrapper support - rewrite documentation build framework to get rid of xmlto and use xsltproc, saxon-6.5.x or xalan-2.x directly 0.8 (2008-04-13) - SECURITY FIX: don't create files that previously failed the check for invalid characters. It was possible to create files outside of the current directory. - add usage of POSIX function spawn() for externally called programs/scripts and select it by default - add usage of POSIX threads for concurrency and select it by default - add inobex get_peer (forward compatible) - make GET work - add local CmakeModules/ and move FindXmlTo.cmake to it - create cmake find modules for Bluetooth and OpenObex 0.7 (2007-12-23) "Merry Xmas and a happy new year" - add support for binding to a specific bluetooth adapter - add support for binding to a specific ethernet address - catch SIGINT and SIGTERM to properly shut down - add support for properly deregistering SDP records - remove configure and Makefile and document native use of cmake in INSTALL 0.6 (2007-08-28) - change build system to cmake - tell storage scripts the client address - require storage script to allow the transfer - provide example script - change TCP support to TcpOBEX to allow for non-official ports if openobex > 1.3 is installed - rename: src/helper -> src/x-obex (must be compiled seperately) 0.5 (2007-03-04) - fix SECURITY issue with script output call - fix compilation issue with 64bit machines - fix many bugs found with splint - show file count in debug output - add x-obex helpers to ease future work (not compiled by default) - change script options - add get support (_requires_ a script) - add script header support and base script headers - add TCP support - update manpage 0.4 (2006-10-25) (REVOKED) - fix manpage install directory - use streaming mode - add option to write daemon PID to a file - add obex authentication via credential files - add script output alternative - use DocBook DTD v4.2 for documenation - change documenation compilation to xmlto - fix daemon directory change - fix segfaults on second invocation - correctly exit forked childs - clean up license - create files with mode 0666 (usually limited by umask to 0644) 0.3 (2006-09-26) - add manpage in DocBook/XML format - Makefile: add install target - clean up help output 0.2 (2006-09-23) - Reformat the code - use select/fork combination instead of only fork - fix type decoding 0.1 (2006-08-05) - Initial release obexpushd-0.11.2-source/CMakeLists.txt000644 001750 001750 00000006367 11537730263 020767 0ustar00hendrikhendrik000000 000000 cmake_minimum_required ( VERSION 2.6.3 FATAL_ERROR ) project ( obexpushd NONE ) set ( VERSION_MAJOR 0 ) set ( VERSION_MINOR 11 ) set ( VERSION_PATCH 2 ) set ( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}" ) if ( VERSION_PATCH GREATER 0 ) set ( VERSION "${VERSION}.${VERSION_PATCH}" ) endif ( VERSION_PATCH GREATER 0 ) list ( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules ) enable_language ( C ) include ( MaintainerMode ) if ( CMAKE_COMPILER_IS_GNUCC ) set ( C_COMPILER_FLAGS std=c99 ) foreach ( flag ${C_COMPILER_FLAGS} ) set ( cflag "-${flag}" ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${cflag}" ) foreach ( type DEBUG RELEASE MINSIZEREL RELWITHDEBINFO ) set ( CMAKE_C_FLAGS_${type} "${CMAKE_C_FLAGS_${type}} ${cflag}" ) endforeach ( type ) endforeach ( flag ) endif ( CMAKE_COMPILER_IS_GNUCC ) add_definitions ( -D_GNU_SOURCE ) if ( NOT CMAKE_BUILD_TYPE ) set ( CMAKE_BUILD_TYPE Release CACHE STRING "Choice of a predefined CMake ruleset" FORCE ) endif ( NOT CMAKE_BUILD_TYPE ) if ( NOT MANPAGE_INSTALL_DIR ) set ( MANPAGE_INSTALL_DIR "share/man" CACHE PATH "Where documentation files are copied to on installation" FORCE ) endif ( NOT MANPAGE_INSTALL_DIR ) if ( NOT DOCUMENTATION_INSTALL_DIR ) set ( DOCUMENTATION_INSTALL_DIR "share/doc/${PROJECT_NAME}" CACHE PATH "Where documentation files are copied to on installation" FORCE ) endif ( NOT DOCUMENTATION_INSTALL_DIR ) add_subdirectory ( src ) add_subdirectory ( doc ) install ( FILES README LICENSE GPLv2.txt DESTINATION "${DOCUMENTATION_INSTALL_DIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) # # Settings for CPack # set ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "ObexPush Server" ) set ( CPACK_PACKAGE_VENDOR "Hendrik Sattler" ) set ( CPACK_PACKAGE_CONTACT "Hendrik Sattler " ) set ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README" ) set ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" ) set ( CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README" ) #setting only CPACK_PACKAGE_VERSION does not work (cmake-2.4.5) set ( CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}" ) set ( CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}" ) set ( CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}" ) set ( CPACK_PACKAGE_VERSION "${VERSION}" ) #the compiler may have a better idea of what the target is if ( CMAKE_COMPILER_IS_GNUCC ) execute_process ( COMMAND ${CMAKE_C_COMPILER} -dumpmachine OUTPUT_VARIABLE CPACK_SYSTEM_NAME ) string ( REGEX REPLACE "[\r\n]" "" CPACK_SYSTEM_NAME ${CPACK_SYSTEM_NAME} ) else ( CMAKE_COMPILER_IS_GNUCC ) set ( CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}" ) endif ( CMAKE_COMPILER_IS_GNUCC ) set ( CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}" ) #different cpack generators need different package names set ( CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-source" ) set ( CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}_${CPACK_SYSTEM_NAME}" ) if ( UNIX ) set ( CPACK_GENERATOR "TGZ" ) set ( CPACK_SOURCE_GENERATOR "TGZ" ) endif ( UNIX ) set ( CPACK_SOURCE_IGNORE_FILES "~$" "/\\\\.git/" "/build/" ) # this must _follow_ the settings! include ( CPack ) obexpushd-0.11.2-source/CMakeModules/FindAttr.cmake000644 001750 001750 00000001271 11537730263 023242 0ustar00hendrikhendrik000000 000000 find_path ( Attr_INCLUDE_DIRS attr/xattr.h PATH_SUFFIXES include ) mark_as_advanced ( Attr_INCLUDE_DIRS ) find_library ( attr_LIBRARY attr DOC "Extended attributes library location" ) mark_as_advanced ( attr_LIBRARY ) if ( attr_LIBRARY ) set ( Attr_LIBRARIES ${attr_LIBRARY} ) endif ( attr_LIBRARY ) if ( Attr_INCLUDE_DIRS AND Attr_LIBRARIES ) set ( Attr_FOUND true ) endif ( Attr_INCLUDE_DIRS AND Attr_LIBRARIES ) if ( NOT Attr_FOUND ) if ( NOT Attr_FIND_QUIETLY ) message ( STATUS "Extended attributes (xattr) library not found." ) endif ( NOT Attr_FIND_QUIETLY ) if ( Attr_FIND_REQUIRED ) message ( FATAL_ERROR "" ) endif ( Attr_FIND_REQUIRED ) endif ( NOT Attr_FOUND ) obexpushd-0.11.2-source/CMakeModules/FindBluetooth.cmake000644 001750 001750 00000006660 11537730263 024304 0ustar00hendrikhendrik000000 000000 # - Find system default bluetooth implementation # # On Linux it will use PkgConfig if present and supported, # else and on all other architectures, it looks for it on its own. # The following standard variables get defined: # Bluetooth_FOUND: true if Bluetooth was found # Bluetooth_INCLUDE_DIRS: the directory that contains the include file # Bluetooth_LIBRARIES: full path to the libraries include ( CheckCSourceCompiles ) include ( CheckLibraryExists ) include ( CheckIncludeFile ) if ( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) find_package ( PkgConfig ) if ( PKG_CONFIG_FOUND ) pkg_check_modules ( PKGCONFIG_BLUEZ bluez ) endif ( PKG_CONFIG_FOUND ) find_path ( Bluetooth_INCLUDE_DIRS NAMES bluetooth/bluetooth.h PATH_SUFFIXES include ) mark_as_advanced ( Bluetooth_INCLUDE_DIRS ) if ( PKGCONFIG_BLUEZ_FOUND ) foreach ( i ${PKGCONFIG_BLUEZ_LIBRARIES} ) find_library ( ${i}_LIBRARY NAMES ${i} PATHS ${PKGCONFIG_BLUEZ_LIBRARY_DIRS} ) mark_as_advanced ( ${i}_LIBRARY ) if ( ${i}_LIBRARY ) list ( APPEND Bluetooth_LIBRARIES ${${i}_LIBRARY} ) endif ( ${i}_LIBRARY ) endforeach ( i ) add_definitions ( -DHAVE_SDPLIB ) else ( PKGCONFIG_BLUEZ_FOUND ) find_library ( bluetooth_LIBRARY NAMES bluetooth PATH_SUFFIXES lib ) mark_as_advanced ( bluetooth_LIBRARY ) if ( bluetooth_LIBRARY ) set ( Bluetooth_LIBRARIES ${bluetooth_LIBRARY} ) endif ( bluetooth_LIBRARY ) endif ( PKGCONFIG_BLUEZ_FOUND ) if ( Bluetooth_INCLUDE_DIRS AND Bluetooth_LIBRARIES ) set ( Bluetooth_FOUND true ) endif ( Bluetooth_INCLUDE_DIRS AND Bluetooth_LIBRARIES ) elseif ( CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" ) find_path ( Bluetooth_INCLUDE_DIRS NAMES bluetooth.h PATH_SUFFIXES include ) mark_as_advanced ( Bluetooth_INCLUDE_DIRS ) if ( Bluetooth_INCLUDE_DIRS ) set ( CMAKE_REQUIRED_INCLUDES ${Bluetooth_INLUDE_DIRS} ) CHECK_C_SOURCE_COMPILES ( "#include int main () { struct sockaddr_rfcomm f; return 0; }" Bluetooth_FOUND ) endif ( Bluetooth_INCLUDE_DIRS ) elseif ( CMAKE_SYSTEM_NAME STREQUAL "NetBSD" ) find_path ( Bluetooth_INCLUDE_DIRS NAMES bluetooth.h PATH_SUFFIXES include ) mark_as_advanced ( Bluetooth_INCLUDE_DIRS ) if ( Bluetooth_INCLUDE_DIRS ) set ( CMAKE_REQUIRED_INCLUDES ${Bluetooth_INLUDE_DIRS} ) CHECK_C_SOURCE_COMPILES ( "#include int main () { struct sockaddr_bt f; return 0; }" Bluetooth_FOUND ) endif ( Bluetooth_INCLUDE_DIRS ) elseif ( WIN32 ) CHECK_C_SOURCE_COMPILES ( "#include #include int main () { SOCKADDR_BTH f; return 0; }" Bluetooth_FOUND ) endif ( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) if ( Bluetooth_FOUND ) set ( Bluetooth_FOUND true ) else ( Bluetooth_FOUND ) set ( Bluetooth_FOUND false ) endif ( Bluetooth_FOUND ) if ( NOT Bluetooth_FOUND ) if ( NOT Bluetooth_FIND_QUIETLY ) message ( STATUS "Bluetooth not found." ) endif ( NOT Bluetooth_FIND_QUIETLY ) if ( Bluetooth_FIND_REQUIRED ) message ( FATAL_ERROR "Bluetooth not found but required." ) endif ( Bluetooth_FIND_REQUIRED ) endif ( NOT Bluetooth_FOUND ) obexpushd-0.11.2-source/CMakeModules/FindDocbook.cmake000644 001750 001750 00000005106 11537730263 023711 0ustar00hendrikhendrik000000 000000 # - Find DocBook/XML tools # This module can be used to translate Docbook/XML files to different # output formats using XSLT files. Currently supported XSLT processors # that can be used for DocBook are: # xsltproc # saxon-6.5.x # xalan-2.x # # Typical usage is: # find_package(DocBook REQUIRED) # include(${DocBook_USE_FILE}) # docbook_generate(manpage my-app.xml MANPAGE_FILE_LIST) # foreach(file ${MANPAGE_FILE_LIST}) # ... # endforeach(file) # # This modules uses the following variables that may be set before # including the USE_FILE: # DOCBOOK_XSLT_PROCESSOR - select the xslt processor to use # # The following functions are provided: # DOCBOOK_GENERATE(format inputFile output) # This function determines the output file names from the input # file, depending on the format and stores it as cmake list in # output. The currently supported formats are "manpage", "html" # and "fo" (XML formatted object). # # The following variables are set by this module: # Docbook_FOUND - True if DocBook processing is available # Docbook_USE_FILE - Name of the USE_FILE # DOCBOOK_XSLT_PROCESSOR - If not set, one of the available XSLT processors # find_file ( JAVA_DOCBOOK_XSL_SAXON_LIBRARY NAMES docbook-xsl-saxon_1.00.jar PATH_SUFFIXES share/java DOC "location of saxon 6.5.x DocBook XSL extension JAR file" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( JAVA_DOCBOOK_XSL_SAXON_LIBRARY ) set ( Xslt_SAXON_EXTENSIONS "${JAVA_DOCBOOK_XSL_SAXON_LIBRARY}" ) find_package ( Xslt ) if ( Xslt_FOUND ) if ( NOT DOCBOOK_XSLT_PROCESSOR ) if ( XSLT_XSLTPROC_EXECUTABLE ) set ( DOCBOOK_XSLT_PROCESSOR "xsltproc" ) elseif ( XSLT_SAXON_COMMAND AND JAVA_DOCBOOK_XSL_SAXON_LIBRARY ) set ( DOCBOOK_XSLT_PROCESSOR "saxon" ) elseif ( XSLT_XALAN2_COMMAND ) set ( DOCBOOK_XSLT_PROCESSOR "xalan2" ) endif ( XSLT_XSLTPROC_EXECUTABLE ) endif ( NOT DOCBOOK_XSLT_PROCESSOR ) set ( DOCBOOK_XSLT_PROCESSOR "${DOCBOOK_XSLT_PROCESSOR}" CACHE STRING "Docbook XSLT processor select (xsltproc, xalan2 or saxon)" ) set ( XSLT_PROCESSOR "${DOCBOOK_XSLT_PROCESSOR}" ) if ( DOCBOOK_XSLT_PROCESSOR ) set ( Docbook_FOUND true ) set ( Docbook_USE_FILE UseDocbook ) endif ( DOCBOOK_XSLT_PROCESSOR ) endif ( Xslt_FOUND ) if ( NOT Docbook_FOUND ) if ( NOT Docbook_FIND_QUIETLY ) message ( STATUS "No supported Docbook XSLT found." ) endif ( NOT Docbook_FIND_QUIETLY ) if ( Docbook_FIND_REQUIRED ) message ( FATAL_ERROR "No supported Docbook XSLT found but it is required." ) endif ( Docbook_FIND_REQUIRED ) endif ( NOT Docbook_FOUND ) obexpushd-0.11.2-source/CMakeModules/FindOpenObex.cmake000644 001750 001750 00000006261 11537730263 024053 0ustar00hendrikhendrik000000 000000 # - Find Open Object Exchange library # # It will use PkgConfig if present and supported, else search # it on its own. If the OPENOBEX_ROOT_DIR environment variable # is defined, it will be used as base path. # The following standard variables get defined: # OpenObex_FOUND: true if OpenObex was found # OpenObex_INCLUDE_DIRS: the directory that contains the include file # OpenObex_LIBRARIES: full path to the libraries # OpenObex_HAVE_TcpObex true if OpenObex has new TcpObex_* functions include ( CheckLibraryExists ) include ( CheckIncludeFile ) include ( CheckFunctionExists ) find_package ( PkgConfig ) if ( PKG_CONFIG_FOUND ) pkg_check_modules ( PKGCONFIG_OPENOBEX openobex ) endif ( PKG_CONFIG_FOUND ) if ( PKGCONFIG_OPENOBEX_FOUND ) set ( OpenObex_FOUND ${PKGCONFIG_OPENOBEX_FOUND} ) set ( OpenObex_INCLUDE_DIRS ${PKGCONFIG_OPENOBEX_INCLUDE_DIRS} ) foreach ( i ${PKGCONFIG_OPENOBEX_LIBRARIES} ) find_library ( ${i}_LIBRARY NAMES ${i} PATHS ${PKGCONFIG_OPENOBEX_LIBRARY_DIRS} ) if ( ${i}_LIBRARY ) list ( APPEND OpenObex_LIBRARIES ${${i}_LIBRARY} ) endif ( ${i}_LIBRARY ) mark_as_advanced ( ${i}_LIBRARY ) endforeach ( i ) else ( PKGCONFIG_OPENOBEX_FOUND ) find_path ( OpenObex_INCLUDE_DIRS NAMES openobex/obex.h PATHS $ENV{ProgramFiles}/OpenObex $ENV{OPENOBEX_ROOT_DIR} PATH_SUFFIXES include ) mark_as_advanced ( OpenObex_INCLUDE_DIRS ) # message ( STATUS "OpenObex include dir: ${OpenObex_INCLUDE_DIRS}" ) find_library ( openobex_LIBRARY NAMES libopenobex openobex PATHS $ENV{ProgramFiles}/OpenObex $ENV{OPENOBEX_ROOT_DIR} PATH_SUFFIXES lib ) mark_as_advanced ( openobex_LIBRARY ) if ( openobex_LIBRARY ) set ( OpenObex_LIBRARIES ${openobex_LIBRARY} ) endif ( openobex_LIBRARY ) if ( OpenObex_INCLUDE_DIRS AND OpenObex_LIBRARIES ) set ( OpenObex_FOUND true ) endif ( OpenObex_INCLUDE_DIRS AND OpenObex_LIBRARIES ) endif ( PKGCONFIG_OPENOBEX_FOUND ) if ( OpenObex_FOUND ) set ( CMAKE_REQUIRED_INCLUDES "${OpenObex_INCLUDE_DIRS}" ) check_include_file ( openobex.h OpenObex_FOUND ) # message ( STATUS "OpenObex: openobex.h is usable: ${OpenObex_FOUND}" ) endif ( OpenObex_FOUND ) if ( OpenObex_FOUND ) check_library_exists ( ${openobex_LIBRARY} OBEX_Init "${OpenObex_LIBRARY_DIRS}" OpenObex_FOUND ) # message ( STATUS "OpenObex: library is usable: ${OpenObex_FOUND}" ) endif ( OpenObex_FOUND ) if ( OpenObex_FOUND ) set ( CMAKE_REQUIRED_FLAGS "" ) set ( CMAKE_REQUIRED_DEFINITIONS "" ) set ( CMAKE_REQUIRED_INCLUDES ${OpenObex_INLUDE_DIRS} ) set ( CMAKE_REQUIRED_LIBRARIES ${OpenObex_LIBRARIES} ) check_function_exists ( TcpOBEX_ServerRegister OpenObex_HAVE_TcpObex ) endif ( OpenObex_FOUND ) if ( NOT OpenObex_FOUND ) if ( NOT OpenObex_FIND_QUIETLY ) message ( STATUS "OpenObex not found, try setting OPENOBEX_ROOT_DIR environment variable." ) endif ( NOT OpenObex_FIND_QUIETLY ) if ( OpenObex_FIND_REQUIRED ) message ( FATAL_ERROR "" ) endif ( OpenObex_FIND_REQUIRED ) endif ( NOT OpenObex_FOUND ) #message ( STATUS "OpenObex: ${OpenObex_FOUND}" ) ### Local Variables: ### mode: cmake ### End: obexpushd-0.11.2-source/CMakeModules/FindTcpWrap.cmake000644 001750 001750 00000001305 11537730263 023706 0ustar00hendrikhendrik000000 000000 find_path ( TcpWrap_INCLUDE_DIRS tcpd.h PATH_SUFFIXES include ) mark_as_advanced ( TcpWrap_INCLUDE_DIRS ) find_library ( wrap_LIBRARY wrap DOC "TCP wrapper library location" ) mark_as_advanced ( wrap_LIBRARY ) if ( wrap_LIBRARY ) set ( TcpWrap_LIBRARIES ${wrap_LIBRARY} ) endif ( wrap_LIBRARY ) if ( TcpWrap_INCLUDE_DIRS AND TcpWrap_LIBRARIES ) set ( TcpWrap_FOUND true ) endif ( TcpWrap_INCLUDE_DIRS AND TcpWrap_LIBRARIES ) if ( NOT TcpWrap_FOUND ) if ( NOT TcpWrap_FIND_QUIETLY ) message ( STATUS "Tcp wrapper library not found." ) endif ( NOT TcpWrap_FIND_QUIETLY ) if ( TcpWrap_FIND_REQUIRED ) message ( FATAL_ERROR "" ) endif ( TcpWrap_FIND_REQUIRED ) endif ( NOT TcpWrap_FOUND ) obexpushd-0.11.2-source/CMakeModules/FindXslt.cmake000644 001750 001750 00000014163 11537730263 023266 0ustar00hendrikhendrik000000 000000 # - Find XSLT processors. # This module provides easy integration of XSLT processors. # Currently xsltproc, Saxon 6.5.[345] and Xalan 2.x are supported. # # Typical usage is: # find_package(Xslt) # include_file(${Xslt_USE_FILE}) # xsl_transform(transform.xsl source.xml target.foo) # # The following variables are created: # Xslt_FOUND - true if at least one XSLT processor is found # Xslt_USE_FILE - name of the USE_FILE # Xslt_CLASSPATH - the Java classpath to use for XSLT processing # XSLT_XSLTPROC_EXECUTABLE - executable for xltproc # XSLT_SAXON_COMMAND - command for saxon-6.5.x # XSLT_XALAN2_COMMAND - command for xalan-2.x # # The following environment variables are considered: # CLASSPATH - initial value of Xslt_CLASSPATH (if empty) # # The following functions are provided: # xsl_transform(xsl-file xml-file ...) # This uses the xsl file to transform the xml file input to one or # more output files. Several variables can be used to change the # behaviour of the transformation: # XSLT_PARAMS: cmake list of parameters for the XSL transformation # in the form of param=value # XSLT__OPTIONS: extra option for each of XSLTPROC, # SAXON and XALAN2. # find_package ( Java ) if ( JAVA_RUNTIME ) if ( NOT Xslt_CLASSPATH ) set ( Xslt_CLASSPATH $ENV{CLASSPATH} CACHE STRING "java classpath" ) endif ( NOT Xslt_CLASSPATH ) if ( NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" ) # Non-Windows classpath may use : instead of ; # so make this a cmake list here by always using ; string ( REPLACE ":" ";" Xslt_CLASSPATH "${Xslt_CLASSPATH}" ) endif ( NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" ) mark_as_advanced ( Xslt_CLASSPATH ) find_file ( JAVA_RESOLVER_LIBRARY NAMES resolver.jar xml-commons-resolver-1.1.jar PATH_SUFFIXES share/java DOC "location of the XML commons resolver java library from the apache project" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( JAVA_RESOLVER_LIBRARY ) if ( JAVA_RESOLVER_LIBRARY ) list ( APPEND Xslt_CLASSPATH "${JAVA_RESOLVER_LIBRARY}" ) endif ( JAVA_RESOLVER_LIBRARY ) find_path ( JAVA_PROPERTIES_CATALOGMANAGER NAMES CatalogManager.properties PATHS /etc PATH_SUFFIXES xml/resolver share/java share/xml DOC "location of the catalog manager properties file from the XML commons resolver" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( JAVA_PROPERTIES_CATALOGMANAGER ) if ( JAVA_PROPERTIES_CATALOGMANAGER ) list ( APPEND Xslt_CLASSPATH "${JAVA_PROPERTIES_CATALOGMANAGER}" ) endif ( JAVA_PROPERTIES_CATALOGMANAGER ) # # Find Xalan 2 # find_file ( XALAN2 NAMES xalan2.jar PATH_SUFFIXES share/java DOC "location of Xalan2 JAR file" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( XALAN2 ) find_file ( JAVA_XML_APIS_LIBRARY NAMES xml-apis.jar PATH_SUFFIXES share/java DOC "location of Xalan2 XML-API JAR file" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( JAVA_XML_APIS_LIBRARY ) find_file ( JAVA_XERCES_IMPL_LIBRARY NAMES xercesImpl.jar PATH_SUFFIXES share/java DOC "location of Xalan2 Xerces Implementation JAR file" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( JAVA_XERCES_IMPL_LIBRARY ) if ( XALAN2 AND JAVA_XML_APIS_LIBRARY AND JAVA_XERCES_IMPL_LIBRARY ) set ( Xslt_XALAN2_CLASSPATH ${Xslt_CLASSPATH} "${XALAN2}" "${JAVA_XML_APIS_LIBRARY}" "${JAVA_XERCES_IMPL_LIBRARY}" ) if ( Xslt_XALAN2_EXTENSIONS ) list ( APPEND Xslt_XALAN2_CLASSPATH "${Xslt_XALAN2_EXTENSIONS}" ) endif ( Xslt_XALAN2_EXTENSIONS ) if ( NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" ) string ( REPLACE ";" ":" Xslt_XALAN2_CLASSPATH "${Xslt_XALAN2_CLASSPATH}" ) endif ( NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" ) set ( XSLT_XALAN2_COMMAND org.apache.xalan.xslt.Process ) if ( JAVA_RESOLVER_LIBRARY AND JAVA_PROPERTIES_CATALOGMANAGER ) list ( APPEND XSLT_XALAN2_COMMAND -ENTITYRESOLVER org.apache.xml.resolver.tools.CatalogResolver -URIRESOLVER org.apache.xml.resolver.tools.CatalogResolver ) endif ( JAVA_RESOLVER_LIBRARY AND JAVA_PROPERTIES_CATALOGMANAGER ) endif ( XALAN2 AND JAVA_XML_APIS_LIBRARY AND JAVA_XERCES_IMPL_LIBRARY ) # # Find Saxon 6.5.x # find_file ( SAXON NAMES saxon.jar saxon-6.5.5.jar saxon-6.5.4.jar saxon-6.5.3.jar PATH_SUFFIXES share/java DOC "location of saxon 6.5.x JAR file" CMAKE_FIND_ROOT_PATH_BOTH ) mark_as_advanced ( SAXON ) if ( SAXON ) set ( Xslt_SAXON_CLASSPATH ${Xslt_CLASSPATH} "${SAXON}" ) if ( Xslt_SAXON_EXTENSIONS ) list ( APPEND Xslt_SAXON_CLASSPATH "${Xslt_SAXON_EXTENSIONS}" ) endif ( Xslt_SAXON_EXTENSIONS ) if ( NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" ) string ( REPLACE ";" ":" Xslt_SAXON_CLASSPATH "${Xslt_SAXON_CLASSPATH}" ) endif ( NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" ) set ( XSLT_SAXON_COMMAND com.icl.saxon.StyleSheet ) if ( JAVA_RESOLVER_LIBRARY ) list ( APPEND XSLT_SAXON_COMMAND -x org.apache.xml.resolver.tools.ResolvingXMLReader -y org.apache.xml.resolver.tools.ResolvingXMLReader -u ) if ( JAVA_PROPERTIES_CATALOGMANAGER ) list ( APPEND XSLT_SAXON_COMMAND -r org.apache.xml.resolver.tools.CatalogResolver ) endif ( JAVA_PROPERTIES_CATALOGMANAGER ) endif ( JAVA_RESOLVER_LIBRARY ) endif ( SAXON ) endif ( JAVA_RUNTIME ) find_program ( XSLT_XSLTPROC_EXECUTABLE NAMES xsltproc DOC "path to the libxslt XSLT processor xsltproc" ) mark_as_advanced ( XSLT_XSLTPROC_EXECUTABLE ) set ( Xslt_USE_FILE UseXslt ) if ( XSLT_XSLTPROC_EXECUTABLE OR XSLT_SAXON_COMMAND OR XSLT_XALAN2_COMMAND ) set ( Xslt_FOUND true ) endif ( XSLT_XSLTPROC_EXECUTABLE OR XSLT_SAXON_COMMAND OR XSLT_XALAN2_COMMAND ) if ( NOT Xslt_FOUND ) if ( NOT Xslt_FIND_QUIETLY ) message ( STATUS "No supported XSLT processor found. Supported XSLT processors are: xsltproc, saxon-6.5.x, xalan-2.x" ) endif ( NOT Xslt_FIND_QUIETLY ) if ( Xslt_FIND_REQUIRED ) message ( FATAL_ERROR "No supported XSLT processor found but it is required." ) endif ( Xslt_FIND_REQUIRED ) endif ( NOT Xslt_FOUND ) obexpushd-0.11.2-source/CMakeModules/MaintainerMode.cmake000644 001750 001750 00000002353 11537730263 024425 0ustar00hendrikhendrik000000 000000 option ( MAINTAINER_MODE "Enable some stuff only relevant to developers" OFF ) if ( MAINTAINER_MODE ) if ( CMAKE_COMPILER_IS_GNUCC ) set ( MAINTAINER_MODE_WARN_FLAGS all extra declaration-after-statement missing-declarations redundant-decls cast-align error ) set ( MAINTAINER_MODE_FLAGS pedantic ) foreach ( flag ${MAINTAINER_MODE_WARN_FLAGS} ) list ( APPEND MAINTAINER_MODE_FLAGS "W${flag}" ) endforeach ( flag ) foreach ( flag ${MAINTAINER_MODE_FLAGS} ) set ( cflag "-${flag}" ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${cflag}" ) foreach ( type DEBUG RELEASE MINSIZEREL RELWITHDEBINFO ) set ( CMAKE_C_FLAGS_${type} "${CMAKE_C_FLAGS_${type}} ${cflag}" ) endforeach ( type ) endforeach ( flag ) elseif ( MSVC ) set ( MAINTAINER_MODE_FLAGS W3 WX ) foreach ( flag ${MAINTAINER_MODE_FLAGS} ) set ( cflag "/${flag}" ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${cflag}" ) foreach ( type DEBUG RELEASE MINSIZEREL RELWITHDEBINFO ) set ( CMAKE_C_FLAGS_${type} "${CMAKE_C_FLAGS_${type}} ${cflag}" ) endforeach ( type ) endforeach ( flag ) endif ( CMAKE_COMPILER_IS_GNUCC ) endif ( MAINTAINER_MODE ) obexpushd-0.11.2-source/CMakeModules/UseDocbook.cmake000644 001750 001750 00000011364 11537730263 023570 0ustar00hendrikhendrik000000 000000 include ( ${Xslt_USE_FILE} ) if ( NOT DOCBOOK_XSL_VERSION ) set ( DOCBOOK_XSL_VERSION current ) endif ( NOT DOCBOOK_XSL_VERSION ) set ( DOCBOOK_XSL_PREFIX "http://docbook.sourceforge.net/release/xsl/${DOCBOOK_XSL_VERSION}" CACHE STRING "prefix to locate the docbook-XSL release files" ) mark_as_advanced ( DOCBOOK_XSL_PREFIX ) function ( _DOCBOOK_GET_HTML_FILES inFile outFileList ) # This assumes that every refentry has an unique id attribute file ( READ "${inFile}" XML_FILE_CONTENTS ) string ( REPLACE ";" "" XML_FILE_CONTENTS "${XML_FILE_CONTENTS}" ) string ( REGEX MATCHALL "]*" XML_REFENTRYTITLE "${XML_FILE_CONTENTS}" ) foreach ( id ${XML_REFENTRYTITLE} ) string ( REGEX REPLACE ".*id=\"([^\"]*)\".*" "\\1" id "${id}" ) if ( "${id}" STREQUAL "" ) message ( FATAL_ERROR "At least one refentry in file ${infile} has no or an empty id attribute." ) endif ( "${id}" STREQUAL "" ) list ( APPEND FILES ${id}.html ) endforeach ( id ) string ( REGEX MATCH "]*" XML_ENTRY_ELEMENT "${XML_FILE_CONTENTS}" ) string ( REGEX REPLACE "" ENTRIES "${XML_FILE_CONTENTS}" ) string ( REPLACE "" ";" ENTRIES "${ENTRIES}" ) list ( REMOVE_ITEM ENTRIES "" ) list ( LENGTH ENTRIES COUNT ) math ( EXPR COUNT "${COUNT} - 1" ) foreach ( index RANGE ${COUNT} ) list ( GET ENTRIES ${index} entry ) string ( REGEX MATCH "[^<]*" MANPAGE_NAME "${entry}" ) string ( REGEX REPLACE "^" "" MANPAGE_NAME "${MANPAGE_NAME}" ) string ( REGEX REPLACE "[[:space:]]" "" MANPAGE_NAME "${MANPAGE_NAME}" ) if ( "${MANPAGE_NAME}" STREQUAL "" ) message ( FATAL_ERROR "At least one refentry in file ${infile} has no or an empty refname element." ) endif ( "${MANPAGE_NAME}" STREQUAL "" ) string ( REGEX MATCH "[^<]*" MANPAGE_VOLUME "${entry}" ) string ( REGEX REPLACE "^" "" MANPAGE_VOLUME "${MANPAGE_VOLUME}" ) string ( REGEX REPLACE "[[:space:]]" "" MANPAGE_VOLUME "${MANPAGE_VOLUME}" ) if ( "${MANPAGE_VOLUME}" STREQUAL "" ) message ( FATAL_ERROR "At least one refentry in file ${infile} has no or an empty manvolnum element." ) endif ( "${MANPAGE_VOLUME}" STREQUAL "" ) list ( APPEND FILES "${MANPAGE_NAME}.${MANPAGE_VOLUME}" ) endforeach ( index ) set ( ${outFileList} ${FILES} PARENT_SCOPE ) endfunction ( ) function ( _DOCBOOK_XML2MANPAGE inFile outList ) _docbook_get_manpage_files ( "${inFile}" FILES ) xsl_transform ( "${DOCBOOK_XSL_PREFIX}/manpages/docbook.xsl" "${inFile}" ${FILES} ) set ( ${outList} ${FILES} PARENT_SCOPE ) endfunction ( ) function ( _DOCBOOK_XML2HTML inFile outList ) _docbook_get_html_files ( "${inFile}" FILES ) list ( APPEND XSLT_PARAMS "use.id.as.filename=1" ) xsl_transform ( "${DOCBOOK_XSL_PREFIX}/xhtml/chunk.xsl" "${inFile}" ${FILES} ) set ( ${outList} ${FILES} PARENT_SCOPE ) endfunction ( ) function ( _DOCBOOK_XML2FO inFile outList ) get_filename_component ( inFileName "${inFile}" NAME_WE ) set ( FILE "${inFileName}.fo" ) list ( APPEND XSLT_XSLTPROC_OPTIONS -o ${FILE} ) list ( APPEND XSLT_SAXON_OPTIONS -o ${FILE} ) list ( APPEND XSLT_XALAN2_OPTIONS -o ${FILE} ) xsl_transform ( "${DOCBOOK_XSL_PREFIX}/fo/docbook.xsl" "${inFile}" ${FILE} ) set ( ${outList} ${FILE} PARENT_SCOPE ) endfunction ( ) function ( DOCBOOK_XML_GENERATE format inFile outList ) if ( format STREQUAL "manpage" ) _docbook_xml2manpage ( "${inFile}" ${outList} ) elseif ( format STREQUAL "html" ) _docbook_xml2html ( "${inFile}" ${outList} ) elseif ( format STREQUAL "fo" ) _docbook_xml2fo ( "${inFile}" ${outList} ) else ( ) message ( FATAL_ERROR "Unsupported DocBook/XML output format." ) endif ( ) set ( ${outList} ${${outList}} PARENT_SCOPE ) endfunction ( ) function ( DOCBOOK_GENERATE format inFile outList ) file ( READ "${inFile}" XML_FILE_CONTENTS ) string ( SUBSTRING "${XML_FILE_CONTENTS}" 0 5 XML_FILE_CONTENTS ) if ( "${XML_FILE_CONTENTS}" STREQUAL " ) # # The following variables are supported: # XSLT_PROCESSOR (mandatory): # select the xslt processor to use (xsltproc, xalan2, saxon) # XSLT_PARAMS (optional): # a list which may contain param=value entries. # XSLT_(XSLTPROC|XALAN2|SAXON)_OPTIONS (optional): # a list with extra options for those xslt processors. # function ( XSL_TRANSFORM xslurl infile ) if ( XSLT_PARAMS ) foreach ( param ${XSLT_PARAMS} ) set ( param_name ) string ( REGEX MATCH "[^=]+" param_name "${param}" ) if ( param_name ) set ( param_value ) string ( REGEX REPLACE "[^=]+=(.*)" "\\1" param_value "${param}" ) set ( XSLT_XSLTPROC_OPTIONS ${XSLT_XSLTPROC_OPTIONS} --param ${param_name} ${param_value} ) set ( XSLT_XALAN2_OPTIONS ${XSLT_XALAN2_OPTIONS} -param ${param_name} ${param_value} ) endif ( param_name ) endforeach ( param ) endif ( XSLT_PARAMS ) if ( XSLT_PROCESSOR STREQUAL "xsltproc" ) if ( XSLT_XSLTPROC_EXECUTABLE ) add_custom_command ( OUTPUT ${ARGN} COMMAND ${XSLT_XSLTPROC_EXECUTABLE} ${XSLT_XSLTPROC_OPTIONS} "${xslurl}" "${infile}" DEPENDS "${infile}" VERBATIM ) else ( XSLT_XSLTPROC_EXECUTABLE ) message ( FATAL_ERROR "xsltproc not found" ) endif ( XSLT_XSLTPROC_EXECUTABLE ) elseif ( XSLT_PROCESSOR STREQUAL "saxon" ) if ( XSLT_SAXON_COMMAND ) add_custom_command ( OUTPUT ${ARGN} COMMAND "${JAVA_RUNTIME}" -cp "${Xslt_SAXON_CLASSPATH}" ${XSLT_SAXON_COMMAND} ${XSLT_SAXON_OPTIONS} "${infile}" "${xslurl}" ${Xslt_PARAMS} DEPENDS "${infile}" VERBATIM ) else ( XSLT_SAXON_COMMAND ) message ( FATAL_ERROR "Saxon-6.5.x not found" ) endif ( XSLT_SAXON_COMMAND ) elseif ( XSLT_PROCESSOR STREQUAL "xalan2" ) # Xalan places the output in the source file's directory :-( get_filename_component ( infile_name "${infile}" NAME ) add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${infile_name} COMMAND ${CMAKE_COMMAND} -E copy_if_different "${infile}" "${CMAKE_CURRENT_BINARY_DIR}/${infile_name}" DEPENDS ${infile} VERBATIM ) set ( infile "${CMAKE_CURRENT_BINARY_DIR}/${infile_name}" ) if ( XSLT_XALAN2_COMMAND ) add_custom_command ( OUTPUT ${ARGN} COMMAND "${JAVA_RUNTIME}" -cp "${Xslt_XALAN2_CLASSPATH}" ${XSLT_XALAN2_COMMAND} ${XSLT_XALAN2_OPTIONS} -in "${infile}" -xsl "${xslurl}" DEPENDS "${infile}" VERBATIM ) else ( XSLT_XALAN2_COMMAND ) message ( FATAL_ERROR " Xalan 2.x not found" ) endif ( XSLT_XALAN2_COMMAND ) else ( XSLT_PROCESSOR STREQUAL "xsltproc" ) message ( FATAL_ERROR "Unsupported XSLT processor" ) endif ( XSLT_PROCESSOR STREQUAL "xsltproc" ) endfunction ( XSL_TRANSFORM ) obexpushd-0.11.2-source/GPLv2.txt000644 001750 001750 00000043103 11537730263 017647 0ustar00hendrikhendrik000000 000000 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 Lesser 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 Lesser General Public License instead of this License. obexpushd-0.11.2-source/INSTALL000644 001750 001750 00000005730 11537730263 017251 0ustar00hendrikhendrik000000 000000 Requirements: ============= You need the development files for: openobex [>= 1.1 required, >= 1.5 recommended] bluez-lib You also must have installed: cmake [>= 2.6.3] Optionally you may also install: pkg-config (to find libraries more easily) xsltproc or saxon-6.5.x or xalan-2.x (to build documentation) Docbook XSL files (or the online catalogs will be used) TCP-Wrapper (to restrict TCP connections) Building: ========= CMake is used for building. In the simplest form, you create a binary directory somewhere e.g. as ./build, change to that directory and run: $ cmake .. where ".." is the relative path to the source directory. If you want to change the installation location to "/usr", define the cmake variable CMAKE_INSTALL_PREFIX with the -D command line option: $ cmake -DCMAKE_INSTALL_PREFIX=/usr .. You can also use one of the provided interactive front-ends: $ ccmake .. or $ cmake-gui .. as replacement for the cmake calls above (see documentation of ccmake). This will create Makefiles and thus you can build the software: $ make Build options: ============== Build options are set with CMake variables by adding -DFOO=bar to the cmake command line ot set variable 'FOO' to the value 'var'. Boolean values take the values 'ON' or 'OFF'. The following build options are available: USE_SPAWN Use POSIX function spawn() (instead of fork()+exec()) for external scripts. The default is ON and this is also the suggested value. USE_THREADS Use POSIX threads (instead of fork()) for client connections. The default is ON and this is also the suggested value. ENABLE_TCPWRAP Enable support for the tcp wrapper (see /etc/host.deny and /etc/hosts.allow) BUILD_HELP_HTML Build the HTML help files. Default is OFF. BUILD_HELP_MAN Build the manpage files. Default is ON BUILD_X_OBEX_SHARED_LIBS Build libraries to handle x-obex/* mime types in your own programs. Default if OFF and the x-obex binaries are linked statically. DOCBOOK_XSLT_PROCESSOR Choose the XSLT processor to use for creating of the help file. Supported are xsltproc, saxon-6.5.x and xalan-2.x. The default is set automatically from the list of installed ones. DOCUMENTATION_INSTALL_DIR Choose the location where documentation gets installed (example, html help files, ...). Defaults to share/doc/obexpushd. MANPAGE_INSTALL_DIR Choose the location where manual pages get installed. Defaults to share/man. There are lots of other variables that affect the build. Installing: =========== Run: $ make install You can optionally define the DESTDIR variable like $ make install DESTDIR=/path/to/some/dir Using: ====== See "obexpushd -h" for help and take a look at the README file. There is also a manpage. Specification documents: ======================== You can download the spefication document from: http://www.bluetooth.com/English/Technology/Building/Pages/Specification.aspx The OBEX base secification is available seperately from the Infrared Data Association. obexpushd-0.11.2-source/LICENSE000644 001750 001750 00000001550 11537730263 017221 0ustar00hendrikhendrik000000 000000 The following files have their own license: src/md5.c: public domain, no copyight claimed For ALL other files, the following license applies: 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. obexpushd-0.11.2-source/README000644 001750 001750 00000006252 11537730263 017100 0ustar00hendrikhendrik000000 000000 Starting the OBEX-Push service ============================== Simply run: $ obexpushd It will automatically listen on bluetooth as nothing was specified. If you also want it to listen to default IrDA identifier, run: $ obexpushd -B -I If your remote device sends files with the "OBEX:IrXfer" identifier instead of using the "OBEX" identifier, you can _additionally_ listen to it: $ obexpush -B -IIrXfer Stopping the OBEX-Push service ============================== I suggest to run: $ pkill -u $USER obexpushd As an alternative, let obexpushd create a pidfile and use that: $ kill $(cat pidfile) Note that it will not automatically be killed when you log out! Why does another OBEX-Push listener get the files? ================================================= This can not be influenced as it depends on the sending entity. Usually, the service with the lower channel is contacted. Obexpushd uses channel 9 by default but you can change that: $ obexpushd -B3 will listen to channel 3 instead of channel 9. You can check local service with $ sdptool browse local Some versions of Bluez contain a buggy SDP server that does not deregister entries on disconnect or close, automatically. However, some programs rely on that previously working and documented behaviour, e.g. kdebluetooth. As a work-around, either do not use those programs or restart the SDP server after doing so. Bluez-3.36 is known to fix those problem, thus it is _strongly_ suggested to use this version. Since this bluez version also ships a obex-data-server, this may conflict with running obexpushd. Where does it save the files to? ================================ The files are stored in the directory where you start it. Some files are not stored, what happens? ======================================== The file may already exist. Existing files are not overwritten. Start obexpushd in non-detached mode (option -n) to see what happens. My OBEX client hardware does not work with obexpushd. How can I see what is going wrong? ===================================================== First start obexpushd with the debug mode (option -d). You may additionally start a dump program for your bit transport layer: bluetooth: hcidump irda: irdadump tcp: tcpdump or wireshark The combination makes it often possible to see where a problem may be. A comparison with a working hardware makes it even easier. Even in debug mode, nothing happens when sending with bluetooth. ================================================================ Make sure that ISCAN and PSCAN are enabled for your blueooth dongle. With bluez, hciconfig is the tool to take a look at the current settings (root only) or via DBUS. Working settings for bluez-3.xx: * install bluez-utils (especially hcid) * configure hcid.conf and set (some options have alternative settings that also work): options { autoinit yes; security auto; passkey "0000"; pairing multi; } device { class 0x3e0100 iscan enable; pscan enable; discovto 0; lm accept; } * remove /var/lib/bluetooth/*/config (with /var/lib/bluetooth being the runtime configuration directiory) * restart hcid obexpushd-0.11.2-source/TODO000644 001750 001750 00000000055 11537730263 016703 0ustar00hendrikhendrik000000 000000 * add obex push client for testing purposes obexpushd-0.11.2-source/doc/CMakeLists.txt000644 001750 001750 00000003103 11537730263 021515 0ustar00hendrikhendrik000000 000000 add_custom_target ( doc ) find_package ( Docbook ) if ( Docbook_FOUND ) include ( ${Docbook_USE_FILE} ) set ( OBEXPUSHD_XML_FILE "${CMAKE_CURRENT_SOURCE_DIR}/obexpushd.xml" ) option (BUILD_HELP_MAN "Build manpage application help files" ON) if ( BUILD_HELP_MAN ) docbook_generate ( manpage "${OBEXPUSHD_XML_FILE}" HELP_MAN_FILES ) foreach ( file ${HELP_MAN_FILES} ) list ( APPEND OBEXPUSHD_HELP_FILES ${file} ) get_filename_component ( fileExt ${file} EXT ) string ( REGEX REPLACE "^[.]" "" fileExt ${fileExt} ) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/${file} DESTINATION ${MANPAGE_INSTALL_DIR}/man${fileExt} PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT documentation OPTIONAL ) endforeach ( file ) endif ( BUILD_HELP_MAN ) option (BUILD_HELP_HTML "Build HTML application help files" OFF) if ( BUILD_HELP_HTML ) include ( UseDocbook ) docbook_generate ( html "${OBEXPUSHD_XML_FILE}" HELP_HTML_FILES ) foreach ( file ${HELP_HTML_FILES} ) list ( APPEND OBEXPUSHD_HELP_FILES ${file} ) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/${file} DESTINATION ${DOCUMENTATION_INSTALL_DIR}/html PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT documentation OPTIONAL ) endforeach ( file ) endif ( BUILD_HELP_HTML ) if ( OBEXPUSHD_HELP_FILES ) add_custom_target ( obexpushd-doc DEPENDS ${OBEXPUSHD_HELP_FILES} ) add_dependencies ( obexpushd obexpushd-doc ) add_dependencies ( doc obexpushd-doc ) endif ( OBEXPUSHD_HELP_FILES ) endif ( Docbook_FOUND ) obexpushd-0.11.2-source/doc/obexpushd.xml000644 001750 001750 00000035643 11537730263 021516 0ustar00hendrikhendrik000000 000000 2010-11-02 obexpushd 0.11 Hendrik Sattler conversion to docbook, all other changes post@hendrik-sattler.de Eugeniy Meshcheryakov texted the first version of the obexpushd manpage eugen@debian.org obexpushd 1 User commands obexpushd receive files with OBEX protocol via Bluetooth, IrDA or network connection obexpushd address:channel app address:port file file directory file Description obexpushd is a program that can be used to receive files using OBEX (OBject EXchange) protocol over Bluetooth, IrDA or network connection. It can be used to receive files from mobile phones and other devices. When run without -d or -n options obexpushd puts itself to the background and starts to listen for incoming connections via Bluetooth (default) and/or IrDA and/or network connection(TCP). obexpushd saves all received files to it's current directory but can alternativly forward all received data to a script for further processing. Options Listen to Bluetooth connections. It is possible to specify an address of a local adapter and a channel number to listen to. Default is to use channel 9. The address can be either a bluetooth adapter interface name (e.g. "hci0"), only the number of that interface (e.g. "0") or the interface address enclosed in brackets (e.g. "[11:22:33:44:55:66]"). Listen to IrDA connections on the default inbox and, in addition and optionally, to the inbox identified by app (example: IrXfer) Listen to network connections. If compiled with TcpOBEX support (openobex > 1.3), it is possible to specify an address and a port number to listen to (default: *:650). Note that to bind to the default TCP OBEX port, you need root priviledges. The address can either be an IPv4 address in quad-dot-notation (e.g. "127.0.0.1"), an IPv6 address enclosed in brackets (e.g. "[::1]") or a "*" as alias for "[::]". Write the process ID of the daemon to file Enable special security/filter support that is special to the transport layer. For bluetooth, this enforces bluetooth pairing (does not conform to protocol specification). For TCP, this enables usage of hosts.allow and hosts.deny files. Read user:password pairs from each line of file. Note that many client cannot handle authentication and will stop working when using this option. Note that no encoding is used, the plain byte sequence will be matched. Use directory for files to read or write. This option only affects file output (not scripts). If this option is not specified, the current working directory (".") is used. Open pipes to the script or program specified by file. These pipes are seen by the program as stdin and stdout. There is one argument which is one of the following: put This requests data to be stored to a specific file. obexpushd is waiting for an acknoledge after the list of parameters. The script must either print a line with "OK" to stdout to get the data on stdin or a line with any other content to reject the transfer. get This requests a specific file to be sent to stdout. Just exit the script with a non-zero exit status to reject the transfer. listdir This requests a directory listing to be sent to stdout. You can use the provided obex-folder-listing to achieve a correctly formatted listing. Just exit the script with a non-zero exit status to reject the transfer. capability This requests an obex capability object (XML formatted data) to be sent to stdout. Just exit the script with a non-zero exit status to reject the transfer. createdir This requests creation of a new directory. No data is transferred. Just exit the script with a non-zero exit status to reject the request. delete This requests deletion of a file. No data is transferred. Just exit the script with a non-zero exit status to reject the request. Further parameters are fed to the script via stdin. Parameters that are transmitted via stdin or stdout have the form "Parameter: value". The first empty line seperates parameters and data. The empty line can be the first line. In this case, no parameters are present. Line delimiter is system specific. The possible parameters are: "From: type/client-identifier" This specifies the client address. Currently, types can be "bluetooth", "irda", "tcp" or "usb". Usage: always present on stdin. "Name: utf8-string" This specifies the file name. Usage: present on stdin for "put", "get" and "delete". "Length: uint32" This specifies the amount of data in bytes in the data section that follows. Usage: required on stdout for "get", else optional. "Type: ascii-string" This specifies the mime type of the data. Usage: completely optional. "Time: time-string" This defines a time stamp where time-string is a time in ISO-8601 format (YYYYMMDDThhmmssZ). Usage: completely optional. "Path: ascii-string" This defines a relative path to the published base directory. Usage: present on stdin for "put", "get", "listdir", "createdir" and "delete". Unknown parameters shall be ignored. Do not detach from terminal. Enable debug messages (implies -n). Show summary of options. Show version of program. obexpush_atd 1 User commands obexpush_atd Simulate an AT modem to use obexpushd with serial lines obexpush_atd ttyPort subOption Description To use obexpushd over simple serial lines, obexpush_atd handles the standard AT command set to let programs switch to OBEX mode transparently. Options Use serial line ttyPort for input and output. Add additional option to submode handlers. The format for subOption is "mode,option". The only available mode is currently "o" for the OBEX mode, realized by obexpushd. Example (for enabling FBS): -Xo,-t -Xo,FTP Show debug output. Show versions. Show the help message. obex-folder-listing 1 User commands obex-folder-listing create an obex folder-listing object obex-folder-listing Description An OBEX folder-listing is a XML formatted description of a directory. Options Show parent folder indicator. This should be used on all directories that are not the exported root directory. Also list hidden files/directories. Show time attributes. Show permission attributes. Show file owner attribute. Show file group attribute. Show the help message. obexpushd-0.11.2-source/src/CMakeLists.txt000644 001750 001750 00000010470 11537730263 021544 0ustar00hendrikhendrik000000 000000 # # ObexPush server daemon # list ( APPEND obexpushd_SOURCES obexpushd.c checks.c utf.c pipe.c action/core.c action/connect.c action/disconnect.c action/get.c action/put.c action/setpath.c auth/core.c auth/file.c io/core.c io/internal/common.c io/internal/file.c io/internal/dir.c io/internal/caps.c io/script.c net/core.c net/btobex.c net/publish/sdp.c net/irobex.c net/fdobex.c net/fdobex_ctrans.c ) set ( OBEXPUSHD_VERSION ${VERSION} ) set ( OBEXPUSH_ATD_VERSION 1.0 ) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h ) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) add_subdirectory ( obex_auth ) list ( APPEND obexpushd_LIBRARIES obex_auth ) add_subdirectory ( x-obex ) list ( APPEND obexpushd_LIBRARIES obex-capability obex-folder-listing ) # # Configure USB gadget support (Linux only) # set ( ENABLE_USB_GADGET_SUPPORT OFF ) if ( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) set ( ENABLE_USB_GADGET_SUPPORT ON ) endif ( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) if ( ENABLE_USB_GADGET_SUPPORT ) list ( APPEND obexpushd_DEFINITIONS USB_GADGET_SUPPORT ) list ( APPEND obexpushd_SOURCES net/usbgobex.c net/usbgobex_ctrans.c ) endif ( ENABLE_USB_GADGET_SUPPORT ) # # Posix spawn is the preferred way to use the script support # option ( USE_SPAWN "Use POSIX spawn function instead of fork+exec" ON ) if ( USE_SPAWN ) list ( APPEND DEFINITIONS USE_SPAWN ) endif ( USE_SPAWN ) # # Concurrency can be done using threads (preferred) or processes # option ( USE_THREADS "Use POSIX threads instead of fork (if supported by system)" ON ) if ( USE_THREADS ) find_package ( Threads ) if ( Threads_FOUND AND CMAKE_USE_PTHREADS_INIT ) list ( APPEND obexpushd_DEFINITIONS USE_THREADS ) if ( CMAKE_THREAD_LIBS_INIT ) list ( APPEND obexpushd_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} ) endif ( CMAKE_THREAD_LIBS_INIT ) endif ( Threads_FOUND AND CMAKE_USE_PTHREADS_INIT ) endif ( USE_THREADS ) # # TcpWrapper can be used for access control # option ( ENABLE_TCPWRAP "Use the tcp wrapper library to check for restrictions on incoming connections" ON ) if ( ENABLE_TCPWRAP ) find_package ( TcpWrap ) endif ( ENABLE_TCPWRAP ) if ( TcpWrap_FOUND ) include_directories ( ${TcpWrap_INCLUDE_DIRS} ) list ( APPEND obexpushd_DEFINITIONS ENABLE_TCPWRAP ) list ( APPEND obexpushd_LIBRARIES ${TcpWrap_LIBRARIES} ) endif ( TcpWrap_FOUND ) # # Extended Attributes can be used for mime type storage # find_package( Attr QUIET ) if (Attr_FOUND) include_directories ( ${Attr_INCLUDE_DIRS} ) list ( APPEND obexpushd_DEFINITIONS USE_XATTR ) list ( APPEND obexpushd_LIBRARIES ${ATTR_LIBRARIES} ) endif (Attr_FOUND) # # Absolute necessary: bluetooth and openobex # foreach ( i Bluetooth OpenObex ) find_package ( ${i} REQUIRED ) if ( ${i}_FOUND ) include_directories ( ${${i}_INCLUDE_DIRS} ) if ( ${i}_LIBRARIES ) list ( APPEND obexpushd_LIBRARIES ${${i}_LIBRARIES} ) endif ( ${i}_LIBRARIES ) endif ( ${i}_FOUND ) endforeach ( i ) # # Check if openobex has TcpObex or the old InObex # if ( OpenObex_HAVE_TcpObex ) list ( APPEND obexpushd_DEFINITIONS OPENOBEX_TCPOBEX=1 ) list ( APPEND obexpushd_SOURCES net/tcpobex.c ) else ( OpenObex_HAVE_TcpObex ) list ( APPEND obexpushd_SOURCES net/inobex.c ) endif ( OpenObex_HAVE_TcpObex ) # # The ObexPushD command line front-end # add_executable ( obexpushd ${obexpushd_SOURCES} ) target_link_libraries ( obexpushd ${obexpushd_LIBRARIES} ) list ( APPEND obexpushd_DEFINITIONS DEFINITIONS ) set_property ( TARGET obexpushd PROPERTY COMPILE_DEFINITIONS ${obexpushd_DEFINITIONS} ) # # The wrapper around ObexPushD to handle AT commands # add_executable (obexpush_atd obexpush_atd.c ) set_property ( TARGET obexpush_atd PROPERTY COMPILE_DEFINITIONS ${DEFINITIONS} ) install ( TARGETS obexpushd obexpush_atd RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) install ( FILES storage/file_storage.sh DESTINATION ${DOCUMENTATION_INSTALL_DIR}/examples PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) set ( CPACK_PACKAGE_EXECUTABLES "obexpushd" ) if ( UNIX ) set ( CPACK_STRIP_FILES "bin/obexpushd" ) endif ( UNIX ) obexpushd-0.11.2-source/src/action.h000644 001750 001750 00000000144 11537730263 020427 0ustar00hendrikhendrik000000 000000 #include void obex_action_eventcb (obex_t*, obex_object_t*, int, int, int, int); obexpushd-0.11.2-source/src/action/connect.c000644 001750 001750 00000010655 11537730263 022063 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2009 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obexpushd.h" #include "net.h" #include "core.h" static uint8_t obex_uuid_ftp[] = { 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2, 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 }; static struct { enum obex_target target; const struct obex_target_ops *target_ops; enum net_obex_protocol protocol; struct { size_t size; uint8_t *data; } uuid; } obex_target_map[] = { { .target = OBEX_TARGET_FTP, .target_ops = &obex_target_ops_ftp, .protocol = NET_OBEX_FTP, .uuid = { .size = sizeof(obex_uuid_ftp), .data = obex_uuid_ftp, }, } }; #define TARGET_MAP_COUNT (sizeof(obex_target_map)/sizeof(*obex_target_map)) static int check_target_header(file_data_t* data, obex_headerdata_t value, uint32_t vsize) { for (unsigned int i = 0; i < TARGET_MAP_COUNT; ++i) { struct net_data *n = data->net_data; if (vsize == obex_target_map[i].uuid.size && memcmp(value.bs, obex_target_map[i].uuid.data, vsize) == 0 && (n->enabled_protocols & (1 << obex_target_map[i].protocol))) { data->target = obex_target_map[i].target; data->target_ops = obex_target_map[i].target_ops; return 1; } } return 0; } static int check_headers(file_data_t* data, obex_object_t* obj) { obex_t* handle = data->net_data->obex; uint8_t id = 0; obex_headerdata_t value; uint32_t vsize; struct io_transfer_data *transfer; int target_found = 0; if (!data) return 0; transfer = &data->transfer; while (OBEX_ObjectGetNextHeader(handle,obj,&id,&value,&vsize)) { dbg_printf(data, "Got header 0x%02x with value length %u\n", (unsigned int)id, (unsigned int)vsize); if (!vsize) continue; switch (id) { case OBEX_HDR_DESCRIPTION: /* this would be a self-description of the client */ break; case OBEX_HDR_TARGET: /* only accept the first target */ if (!target_found) target_found = check_target_header(data, value, vsize); break; case OBEX_HDR_AUTHCHAL: /* not implemented: when the client wants the server to authenticate itself */ break; case OBEX_HDR_AUTHRESP: data->net_data->auth_success = auth_verify(data->auth,value,vsize); break; default: break; } } return 1; } static void add_connection_header(obex_t* handle, obex_object_t* obj, unsigned int id) { obex_headerdata_t hv; hv.bq4 = id; OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_CONNECTION, hv, 4, OBEX_FL_FIT_ONE_PACKET); } static void add_who_header(obex_t* handle, obex_object_t* obj, enum obex_target target) { obex_headerdata_t hv; /* add who header with same content as target header from client */ for (unsigned int i = 0; i < TARGET_MAP_COUNT; ++i) { if (target == obex_target_map[i].target) { hv.bs = obex_target_map[i].uuid.data; OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_WHO, hv, obex_target_map[i].uuid.size, OBEX_FL_FIT_ONE_PACKET); } } } static void connect_request(file_data_t* data, obex_object_t* obj) { obex_t* handle = data->net_data->obex; uint8_t respCode = 0; /* Default to ObjectPush */ data->target = OBEX_TARGET_OPP; data->target_ops = &obex_target_ops_opp; if (!check_headers(data, obj)) respCode = OBEX_RSP_BAD_REQUEST; else { /* we must tell the client that the UUID was recognized */ if (data->target != OBEX_TARGET_OPP) { add_connection_header(handle, obj, data->id); add_who_header(handle, obj, data->target); } if (data->transfer.path) { free(data->transfer.path); data->transfer.path = NULL; } respCode = net_security_init(data->net_data, data->auth, obj); } obex_send_response(data, obj, respCode); } const struct obex_target_event_ops obex_action_connect = { .request = connect_request, }; obexpushd-0.11.2-source/src/action/core.c000644 001750 001750 00000015751 11537730263 021364 0ustar00hendrikhendrik000000 000000 #include "action.h" #include "utf.h" #include "net.h" #include "checks.h" #include "obexpushd.h" #include "core.h" #include "time.h" #include "compiler.h" static int obex_obj_hdr_name (file_data_t* data, obex_headerdata_t *value, uint32_t vsize) { struct io_transfer_data *transfer = &data->transfer; int len = (vsize / 2) + 1; if (transfer->name) free(transfer->name); transfer->name = calloc(len, sizeof(*transfer->name)); if (!transfer->name) return 0; memcpy(transfer->name, value->bs, vsize); utf16_ntoh(transfer->name, len); if (debug) { uint8_t* n = utf16to8(transfer->name); dbg_printf(data, "name: \"%s\"\n", (char*)n); free(n); } if (!check_wrap_utf16(transfer->name, check_name)) { dbg_printf(data, "CHECK FAILED: %s\n", "Invalid name string"); return 0; } return 1; } static int obex_obj_hdr_type (file_data_t* data, obex_headerdata_t *value, uint32_t vsize) { struct io_transfer_data *transfer = &data->transfer; int len = vsize + 1; if (transfer->type) free(transfer->type); transfer->type = calloc(len, sizeof(*transfer->type)); if (!transfer->type) return 0; memcpy(transfer->type, value->bs, vsize); dbg_printf(data, "type: \"%s\"\n", transfer->type); if (!check_type((uint8_t*)transfer->type)) { dbg_printf(data, "CHECK FAILED: %s\n", "Invalid type string"); return 0; } return 1; } static int obex_obj_hdr_time (file_data_t* data, obex_headerdata_t *value, uint32_t vsize) { /* ISO8601 formatted ASCII string */ struct io_transfer_data *transfer = &data->transfer; struct tm time; char* tmp = calloc(vsize + 1, sizeof(*tmp)); char* ptr; if (!tmp) return 0; memcpy(tmp, value->bs, vsize); dbg_printf(data, "time: \"%s\"\n", tmp); tzset(); ptr = strptime(tmp, "%Y%m%dT%H%M%S", &time); if (ptr != NULL) { time.tm_isdst = -1; transfer->time = mktime(&time); if (*ptr == 'Z') transfer->time -= timezone; } free(tmp); return 1; } static int obex_obj_hdr_time2 (file_data_t* data, obex_headerdata_t *value) { struct io_transfer_data *transfer = &data->transfer; /* seconds since Januar 1st, 1970 */ transfer->time = value->bq4; if (debug && transfer->time) { struct tm t; char tmp[17]; memset(tmp, 0, sizeof(tmp)); (void)gmtime_r(&transfer->time, &t); if (strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%SZ", &t) != 0) { dbg_printf(data, "time: \"%s\"\n", tmp); } } return 1; } static int obex_obj_hdr_descr (file_data_t* data, obex_headerdata_t *value, uint32_t vsize) { uint16_t* desc16 = (uint16_t*)value->bs; if (desc16[vsize/2] == 0x0000) { uint8_t* desc8 = utf16to8(desc16); dbg_printf(data, "description: \"%s\"\n", (char*)desc8); free(desc8); } return 1; } int obex_object_headers (file_data_t* data, obex_object_t* obj) { uint8_t id = 0; obex_headerdata_t value; uint32_t vsize; obex_t* handle = data->net_data->obex; struct io_transfer_data *transfer; int err = 1; if (!data) return 0; transfer = &data->transfer; while (OBEX_ObjectGetNextHeader(handle,obj,&id,&value,&vsize)) { dbg_printf(data, "Got header 0x%02x with value length %u\n", (unsigned int)id, (unsigned int)vsize); if (!vsize) continue; switch (id) { case OBEX_HDR_NAME: err = obex_obj_hdr_name(data, &value, vsize); break; case OBEX_HDR_TYPE: err = obex_obj_hdr_type(data, &value, vsize); break; case OBEX_HDR_LENGTH: transfer->length = value.bq4; dbg_printf(data, "size: %d bytes\n", value.bq4); break; case OBEX_HDR_TIME: err = obex_obj_hdr_time(data, &value, vsize); break; case OBEX_HDR_TIME2: err = obex_obj_hdr_time2(data, &value); break; case OBEX_HDR_DESCRIPTION: err = obex_obj_hdr_descr(data, &value, vsize); break; default: /* some unexpected header, may be a bug */ break; } } return 1; } static void obex_action (file_data_t *data, obex_object_t *obj, int event, const struct obex_target_event_ops *ops) { if (!ops) return; switch (event) { case OBEX_EV_REQHINT: obex_send_response(data, obj, 0); if (ops->request_hint) ops->request_hint(data, obj); break; case OBEX_EV_REQCHECK: if (ops->request_check) ops->request_check(data, obj); break; case OBEX_EV_REQ: if (ops->request) ops->request(data, obj); break; case OBEX_EV_REQDONE: if (ops->request_done) ops->request_done(data, obj); break; case OBEX_EV_STREAMAVAIL: if (ops->stream_in) ops->stream_in(data, obj); break; case OBEX_EV_STREAMEMPTY: if (ops->stream_out) ops->stream_out(data, obj); break; case OBEX_EV_LINKERR: case OBEX_EV_PARSEERR: case OBEX_EV_ABORT: if (ops->error) ops->error(data, obj, event); break; } } static void obex_action_send_bad_request (file_data_t *data, obex_object_t *obj) { obex_send_response(data, obj, OBEX_RSP_BAD_REQUEST); } static const struct obex_target_event_ops obex_invalid_action = { .request_hint = obex_action_send_bad_request, }; static void obex_action_send_not_impl (file_data_t *data, obex_object_t *obj) { obex_send_response(data, obj, OBEX_RSP_NOT_IMPLEMENTED); } static const struct obex_target_event_ops obex_unknown_action = { .request_hint = obex_action_send_not_impl, }; const struct obex_target_ops obex_target_ops_opp = { .put = &obex_action_put, .get = &obex_action_get, .setpath = &obex_invalid_action, }; const struct obex_target_ops obex_target_ops_ftp = { .put = &obex_action_ftp_put, .get = &obex_action_get, .setpath = &obex_action_setpath, }; void obex_action_eventcb (obex_t* handle, obex_object_t* obj, int __unused mode, int event, int obex_cmd, int __unused obex_rsp) { file_data_t* data = OBEX_GetUserData(handle); /* re-route the abort command */ if (obex_cmd == OBEX_CMD_ABORT) { obex_cmd = data->command; event = OBEX_EV_ABORT; } /* work-around for openobex bug */ switch (event) { case OBEX_EV_REQHINT: data->command = obex_cmd; break; case OBEX_EV_STREAMAVAIL: case OBEX_EV_STREAMEMPTY: case OBEX_EV_LINKERR: case OBEX_EV_PARSEERR: obex_cmd = data->command; break; } if (obex_cmd == OBEX_CMD_PUT || obex_cmd == OBEX_CMD_GET || obex_cmd == OBEX_CMD_SETPATH) { if (!net_security_check(data->net_data)) return; } switch (obex_cmd) { case OBEX_CMD_CONNECT: if (data->target_ops) obex_action(data, obj, event, data->target_ops->pre_disconnect); obex_action(data, obj, event, &obex_action_connect); if (data->target_ops) obex_action(data, obj, event, data->target_ops->post_connect); break; case OBEX_CMD_PUT: if (data->target_ops) obex_action(data, obj, event, data->target_ops->put); break; case OBEX_CMD_GET: if (data->target_ops) obex_action(data, obj, event, data->target_ops->get); break; case OBEX_CMD_SETPATH: if (data->target_ops) obex_action(data, obj, event, data->target_ops->setpath); break; case OBEX_CMD_DISCONNECT: if (data->target_ops) obex_action(data, obj, event, data->target_ops->pre_disconnect); obex_action(data, obj, event, &obex_action_disconnect); break; default: obex_action(data, obj, event, &obex_unknown_action); break; } } obexpushd-0.11.2-source/src/action/core.h000644 001750 001750 00000001052 11537730263 021356 0ustar00hendrikhendrik000000 000000 int obex_object_headers (file_data_t* data, obex_object_t* obj); extern const struct obex_target_event_ops obex_action_connect; extern const struct obex_target_event_ops obex_action_disconnect; extern const struct obex_target_event_ops obex_action_put; extern const struct obex_target_event_ops obex_action_ftp_put; extern const struct obex_target_event_ops obex_action_get; extern const struct obex_target_event_ops obex_action_setpath; extern const struct obex_target_ops obex_target_ops_opp; extern const struct obex_target_ops obex_target_ops_ftp; obexpushd-0.11.2-source/src/action/disconnect.c000644 001750 001750 00000002767 11537730263 022570 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obexpushd.h" #include "net.h" #include "core.h" #include "compiler.h" #include static void disconnect_reqhint(file_data_t *data, obex_object_t *obj) { /* A new request is coming in */ obex_send_response(data, obj, 0); } static void disconnect_request(file_data_t *data, obex_object_t __unused *obj) { if (data->transfer.path) { free(data->transfer.path); data->transfer.path = NULL; } } static void disconnect_done(file_data_t *data, obex_object_t __unused *obj) { sleep(1); net_disconnect(data->net_data); } const struct obex_target_event_ops obex_action_disconnect = { .request_hint = disconnect_reqhint, .request = disconnect_request, .request_done = disconnect_done, }; obexpushd-0.11.2-source/src/action/get.c000644 001750 001750 00000017023 11537730263 021205 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obexpushd.h" #include "utf.h" #include "io.h" #include "net.h" #include "action.h" #include "core.h" #include #include #include #include #include #include #include #include #include #include #include "compiler.h" static void add_name_header(file_data_t *data, obex_object_t *obj) { obex_t *handle = data->net_data->obex; struct io_transfer_data *transfer = &data->transfer; size_t len = utf16len(transfer->name); if (len) { void *bs = utf16dup(transfer->name); if (bs) { size_t size = (len+1)*sizeof(*transfer->name); obex_headerdata_t hv; utf16_hton(bs, len); hv.bs = bs; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_NAME, hv, size, 0); hv.bs = NULL; free(bs); } } } static void add_type_header(file_data_t *data, obex_object_t *obj) { obex_t *handle = data->net_data->obex; struct io_transfer_data *transfer = &data->transfer; obex_headerdata_t hv; hv.bs = (uint8_t *)transfer->type; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_TYPE, hv, strlen((char*)hv.bs), 0); } static void add_length_header(file_data_t *data, obex_object_t *obj) { obex_t *handle = data->net_data->obex; struct io_transfer_data *transfer = &data->transfer; obex_headerdata_t hv; /* If length exceeds 4GiB-1, a HTTP header is used instead*/ if (transfer->length <= UINT32_MAX) { hv.bq4 = transfer->length; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_LENGTH, hv, sizeof(hv.bq4), 0); } else { char header[16+19+3]; snprintf(header, sizeof(header), "Content-Length: %zu\r\n", transfer->length); hv.bs = (uint8_t*)header; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_HTTP, hv, strlen(header), 0); } } static void add_time_header(file_data_t *data, obex_object_t *obj) { obex_t *handle = data->net_data->obex; struct io_transfer_data *transfer = &data->transfer; obex_headerdata_t hv; char bs[17]; struct tm t; memset(bs, 0, sizeof(bs)); (void)gmtime_r(&transfer->time, &t); if (strftime(bs, sizeof(bs), "%Y%m%dT%H%M%SZ", &t) != 0) { hv.bs = (uint8_t*)bs; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_TIME, hv, strlen(bs), 0); } } static void add_data_header(file_data_t *data, obex_object_t *obj) { obex_t *handle = data->net_data->obex; obex_headerdata_t hv; hv.bs = NULL; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_BODY, hv, 0, OBEX_FL_STREAM_START); } static void add_headers(file_data_t *data, obex_object_t *obj) { struct io_transfer_data *transfer = &data->transfer; if (transfer->name) { add_name_header(data, obj); } if (transfer->type) { add_type_header(data, obj); } add_length_header(data, obj); if (transfer->time) { add_time_header(data, obj); } add_data_header(data, obj); } static int get_check(struct io_transfer_data *transfer, enum obex_target target) { /* either type or name must be set */ if (!transfer->type || strlen(transfer->type) == 0) return (utf16len(transfer->name) != 0); if (strncmp(transfer->type, "x-obex/", 7) == 0) { if (strcmp(transfer->type+7, "folder-listing") == 0) { return (target == OBEX_TARGET_FTP); } else if (strcmp(transfer->type+7, "capability") == 0) { return 1; } else if (strcmp(transfer->type+7, "object-profile") == 0) { /* NAME is the mime-type that the object profile is * request for */ return (utf16len(transfer->name) != 0); } else { /* unknown x-obex type */ return 0; } } else { /* request generic file objects with a specific type is not allowed */ return (utf16len(transfer->name) && strlen(transfer->type)); } } static int get_open (file_data_t* data) { struct io_transfer_data *transfer = &data->transfer; int err = 0; if (transfer->type && strncmp(transfer->type, "x-obex/", 7) == 0) { if (strcmp(transfer->type+7, "folder-listing") == 0) { err = io_open(data->io, transfer, IO_TYPE_LISTDIR); } else if (strcmp(transfer->type+7, "capability") == 0) { err = io_open(data->io, transfer, IO_TYPE_CAPS); /* } else if (strcmp(transfer->type+7, "object-profile") == 0) { */ } else { /* unknown x-obex type */ err = -EINVAL; } } else err = io_open(data->io, transfer, IO_TYPE_GET); return err; } static void get_reqhint(file_data_t *data, obex_object_t __unused *obj) { /* A new request is coming in */ struct io_transfer_data *transfer = &data->transfer; if (transfer->name) { free(transfer->name); transfer->name = NULL; } if (transfer->type) { free(transfer->type); transfer->type = NULL; } data->count += 1; data->error = 0; transfer->length = 0; transfer->time = 0; } static void get_request(file_data_t *data, obex_object_t *obj) { struct io_transfer_data *transfer = &data->transfer; if (!obex_object_headers(data, obj)) data->error = OBEX_RSP_BAD_REQUEST; else if (!get_check(transfer, data->target)) { dbg_printf(data, "%s\n", "Forbidden request"); data->error = OBEX_RSP_FORBIDDEN; } else { int err = get_open(data); if (err < 0 || transfer->length == 0) { dbg_printf(data, "%s: %s\n", "Running script failed or no output data", strerror(-err)); data->error = OBEX_RSP_INTERNAL_SERVER_ERROR; } add_headers(data, obj); } obex_send_response(data, obj, data->error); } static void get_stream_out(file_data_t *data, obex_object_t *obj) { struct io_transfer_data *transfer = &data->transfer; if (!data->error) { size_t tLen = sizeof(data->buffer); int len; if (transfer->length < tLen) tLen = transfer->length; len = (int)io_read(data->io, data->buffer, tLen); if (len >= 0) { obex_headerdata_t hv; unsigned int flags = OBEX_FL_STREAM_DATA; obex_t* handle = data->net_data->obex; hv.bs = data->buffer; if (len == 0) flags = OBEX_FL_STREAM_DATAEND; (void)OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_BODY, hv, len, flags); transfer->length -= len; } else { perror("Reading script output failed"); data->error = OBEX_RSP_INTERNAL_SERVER_ERROR; } } obex_send_response(data, obj, data->error); } static void get_done(file_data_t *data, obex_object_t __unused *obj) { struct io_transfer_data *transfer = &data->transfer; int err = io_close(data->io, &data->transfer, true);; if (err) dbg_printf(data, "%s\n", strerror(-err)); if (transfer->name) { free(transfer->name); transfer->name = NULL; } if (transfer->type) { free(transfer->type); transfer->type = NULL; } transfer->length = 0; transfer->time = 0; } static void get_abort(file_data_t *data, obex_object_t __unused *obj, int __unused event) { get_done(data, obj); } const struct obex_target_event_ops obex_action_get = { .request_hint = get_reqhint, .request = get_request, .request_done = get_done, .stream_out = get_stream_out, .error = get_abort, }; obexpushd-0.11.2-source/src/action/put.c000644 001750 001750 00000007703 11537730263 021242 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obexpushd.h" #include "io.h" #include "utf.h" #include "net.h" #include "action.h" #include "core.h" #include #include #include #include #include #include #include #include #include "compiler.h" static int put_open (file_data_t* data) { int err; if (io_state(data->io) & IO_STATE_OPEN) return 0; err = io_open(data->io, &data->transfer, IO_TYPE_PUT); if (err) return err; return 0; } static int put_write (file_data_t* data, const uint8_t* buf, int len) { if (!(io_state(data->io) & IO_STATE_OPEN)) return -EBADF; return io_write(data->io, buf,(size_t)len); } static void put_reqhint(file_data_t *data, obex_object_t *obj) { obex_t* handle = data->net_data->obex; struct io_transfer_data *transfer = &data->transfer; /* A new request is coming in */ (void)OBEX_ObjectReadStream(handle,obj,NULL); if (transfer->name) { free(transfer->name); transfer->name = NULL; } if (transfer->type) { free(transfer->type); transfer->type = NULL; } data->count += 1; data->error = 0; transfer->length = 0; transfer->time = 0; } static void put_stream_in(file_data_t *data, obex_object_t *obj) { obex_t* handle = data->net_data->obex; if (!(io_state(data->io) & IO_STATE_OPEN)) { if (!obex_object_headers(data, obj)) data->error = OBEX_RSP_BAD_REQUEST; } if (!data->error) { const uint8_t* buf = NULL; int len = OBEX_ObjectReadStream(handle,obj,&buf); /* Always create the file even when no data is received */ if (put_open(data)) data->error = OBEX_RSP_FORBIDDEN; dbg_printf(data, "got %d bytes of streamed data\n", len); if (len) { if (put_write(data, buf, len)) data->error = OBEX_RSP_FORBIDDEN; } } obex_send_response(data, obj, data->error); } static void put_request(file_data_t *data, obex_object_t *obj) { obex_send_response(data, obj, data->error); } static void put_request_ftp(file_data_t *data, obex_object_t *obj) { /* Support for deleting files */ if (!(io_state(data->io) & IO_STATE_OPEN)) { if (!obex_object_headers(data, obj)) data->error = OBEX_RSP_BAD_REQUEST; else (void)io_delete(data->io, &data->transfer);; } put_request(data, obj); } static void put_done(file_data_t *data, obex_object_t __unused *obj) { struct io_transfer_data *transfer = &data->transfer; if (io_state(data->io) & IO_STATE_OPEN) { int keep = (data->error == 0); (void)io_close(data->io, &data->transfer, keep); } if (transfer->name) { free(transfer->name); transfer->name = NULL; } if (transfer->type) { free(transfer->type); transfer->type = NULL; } transfer->length = 0; transfer->time = 0; } static void put_abort(file_data_t *data, obex_object_t *obj, int __unused event) { data->error = 0xFF; put_done(data, obj); } const struct obex_target_event_ops obex_action_put = { .request_hint = put_reqhint, .request = put_request, .request_done = put_done, .stream_in = put_stream_in, .error = put_abort, }; const struct obex_target_event_ops obex_action_ftp_put = { .request_hint = put_reqhint, .request = put_request_ftp, .request_done = put_done, .stream_in = put_stream_in, .error = put_abort, }; obexpushd-0.11.2-source/src/action/setpath.c000644 001750 001750 00000007465 11537730263 022107 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2009 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obexpushd.h" #include "checks.h" #include "net.h" #include "core.h" #include "utf.h" #include #define OBEX_FLAG_SETPATH_LEVELUP (1 << 0) #define OBEX_FLAG_SETPATH_NOCREATE (1 << 1) static int update_path( struct io_handler *io, struct io_transfer_data *transfer, const uint16_t *name, uint8_t *flags ) { size_t len = utf16len(name); int err = 0; if ((flags[0] & OBEX_FLAG_SETPATH_LEVELUP) && transfer->path) { /* go one level up */ char* last = strrchr(transfer->path, (int)'/'); if (last) *last = '\0'; else { free(transfer->path); transfer->path = NULL; } } if (!name) { /* do nothing */ } else if (len == 0) { /* name is empty -> go back to root path */ if (transfer->path) { free(transfer->path); transfer->path = NULL; } } else { /* name is non-empty -> change to directory */ uint8_t *n = utf16to8(name); if (!n) return -errno; if (!check_name(n)) return -EINVAL; if (strcmp((char*)n, "..") == 0) return -EINVAL; len = utf8len((uint8_t*)transfer->path) + 1 + utf8len(n) + 1; if (transfer->path) { char *newpath = realloc(transfer->path, len); if (!newpath) err = -errno; else { transfer->path = newpath; strcat(transfer->path, "/"); strcat(transfer->path, (char*)n); } free(n); } else { transfer->path = (char*)n; } n = NULL; if (!err) { err = io_check_dir(io, transfer->path); if (err == -ENOENT && !(flags[0] & OBEX_FLAG_SETPATH_NOCREATE)) { err = io_create_dir(io, transfer->path); } if (err) { char* last = strrchr(transfer->path, (int)'/'); if (last) *last = '\0'; else { free(transfer->path); transfer->path = NULL; } } } } return err; } static int check_setpath_headers (file_data_t* data, obex_object_t* obj) { uint8_t id = 0; obex_headerdata_t value; uint32_t vsize; obex_t* handle = data->net_data->obex; uint16_t *name = NULL; uint8_t *flags = NULL; int len; if (!data) return -EINVAL; if (OBEX_ObjectGetNonHdrData(obj, &flags) != 2) return -EINVAL; if (debug) dbg_printf(data, "setpath flags=0x%02x\n", flags[0]); while (OBEX_ObjectGetNextHeader(handle,obj,&id,&value,&vsize)) { dbg_printf(data, "Got header 0x%02x with value length %u\n", (unsigned int)id, (unsigned int)vsize); switch (id) { case OBEX_HDR_NAME: if (name) free(name); len = (vsize / 2) + 1; name = calloc(len, sizeof(*name)); if (!name) return -errno; memcpy(name, value.bs, vsize); utf16_ntoh(name, len); if (debug) { uint8_t* n = utf16to8(name); dbg_printf(data, "name: \"%s\"\n", (char*)n); free(n); } break; default: break; } } return update_path(data->io, &data->transfer, name, flags); } static void setpath_request(file_data_t* data, obex_object_t* obj) { uint8_t respCode = 0; if (check_setpath_headers(data, obj) < 0) { respCode = OBEX_RSP_BAD_REQUEST; } obex_send_response(data, obj, respCode); } const struct obex_target_event_ops obex_action_setpath = { .request = setpath_request, }; obexpushd-0.11.2-source/src/auth.h000644 001750 001750 00000004032 11537730263 020113 0ustar00hendrikhendrik000000 000000 #include #include #include "obex_auth.h" #ifndef OBEXPUSHD_AUTH_H #define OBEXPUSHD_AUTH_H typedef int (*auth_verify_cb)(void*, const uint8_t *pass, size_t plen); struct auth_handler; struct auth_handler_ops { /** Get the number or realm available by this handler * * @return number of available realms or a negative error number */ int (*get_realm_count)(struct auth_handler *self); /** Get the realm name * * @param id a zero based sequential value * @return an UCS-2 encoded string */ const uint16_t* (*get_realm_name)(struct auth_handler *self, int id); /** Get the challenge options that are valid for a realm * * @param realm the realm * @return a bitfields with the allowed OBEX_AUTH_OPT_* bits set */ uint8_t (*get_realm_opts)(struct auth_handler *self, const uint16_t *realm); /** Verify a user/password pair in a given realm * * @param realm the realm to verify in * @param user the user value (no format implied) * @param ulen size of the user data * @param cb callback function to verify the password * @param cb_data the first argument for cb * @return 0 is verification failed, else 1 */ int (*verify)(struct auth_handler *self, const uint16_t *realm, const uint8_t *user, size_t ulen, auth_verify_cb cb, void *cb_data); struct auth_handler* (*copy)(struct auth_handler *self); void (*cleanup)(struct auth_handler *self); }; enum auth_state { AUTH_STATE_NONE = 0, AUTH_STATE_REQUEST_SENT, AUTH_STATE_SUCCESS, }; struct auth_handler { struct auth_handler_ops *ops; enum auth_state state; struct { uint8_t nonce[16]; } *session; void *private_data; }; struct auth_handler* auth_file_init (char* file, uint16_t *realm, uint8_t opts); struct auth_handler* auth_copy (struct auth_handler *h); void auth_destroy (struct auth_handler *h); int auth_init (struct auth_handler *self, obex_t *handle, obex_object_t *obj); int auth_verify (struct auth_handler *self, obex_headerdata_t h, uint32_t size); #endif /* OBEXPUSHD_AUTH_H */ obexpushd-0.11.2-source/src/auth/core.c000644 001750 001750 00000010277 11537730263 021046 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "auth.h" #include "obex_auth.h" #include "io.h" #include "utf.h" #include #include #include #include #include #include #include #include #include "compiler.h" struct auth_handler* auth_copy (struct auth_handler *h) { if (!h) return NULL; if (h->ops && h->ops->copy) { /* deep copy */ return h->ops->copy(h); } else { /* flat copy */ struct auth_handler *hnew = malloc(sizeof(*h)); if (hnew) { int count = 0; if (h->ops && h->ops->get_realm_count) count = h->ops->get_realm_count(h); memcpy(hnew, h, sizeof(*h)); hnew->session = calloc(count, sizeof(*hnew->session)); if (!hnew->session) { free(hnew); hnew = NULL; } } return hnew; } } void auth_destroy (struct auth_handler* h) { if (h) { if (h->ops && h->ops->cleanup) h->ops->cleanup(h); free(h); } } #define RANDOM_FILE "/dev/urandom" static int auth_get_nonce (uint8_t nonce[16]) { int status; int fd = open(RANDOM_FILE, O_RDONLY); if (fd < 0) return -errno; status = (int)read(fd, nonce, 16); (void)close(fd); if (status < 0) return -errno; else if (status != 16) return -EIO; else return 0; } int auth_init (struct auth_handler *self, obex_t *handle, obex_object_t *obj) { struct obex_auth_challenge *chal; int count = 0; int i; if (!(self && self->ops && self->ops->get_realm_count)) return 0; count = self->ops->get_realm_count(self); if (count == 0) return 0; switch (self->state) { case AUTH_STATE_NONE: for (i = 0; i < count; ++i) { if (auth_get_nonce(self->session[i].nonce) < 0) return 0; } self->state = AUTH_STATE_REQUEST_SENT; /* no break */ case AUTH_STATE_REQUEST_SENT: chal = calloc(count, sizeof(*chal)); if (!chal) return 0; for (i = 0; i < count; ++i) { memcpy(chal[i].nonce, self->session[i].nonce, sizeof(chal->nonce)); if (self->ops && self->ops->get_realm_name) { const uint16_t *r = self->ops->get_realm_name(self, i); chal[i].realm.data = r; chal[i].realm.len = utf16len(r) * sizeof(*r); chal[i].realm.charset = 0xFF; } if (self->ops && self->ops->get_realm_opts) chal[i].opts = self->ops->get_realm_opts(self, chal[i].realm.data); } (void)OBEX_AuthAddChallenges(handle, obj, chal, count); free(chal); /* no break */ case AUTH_STATE_SUCCESS: return 1; } return 1; } static int obex_auth_verify_cb(void* resp, const uint8_t *pass, size_t plen) { return OBEX_AuthCheckResponse(resp, pass, plen); } int auth_verify (struct auth_handler *self, obex_headerdata_t h, uint32_t size) { struct obex_auth_response resp; int count = 0; int i; switch (self->state) { case AUTH_STATE_NONE: default: return 0; case AUTH_STATE_REQUEST_SENT: if (!(self && self->ops && self->ops->verify)) return 0; if (self->ops->get_realm_count) count = self->ops->get_realm_count(self); if (count == 0) return 0; memset(&resp,0,sizeof(resp)); if (OBEX_AuthUnpackResponse(h,size,&resp) < 0) return 0; for (i = 0; i < count; ++i) { if (memcmp(self->session[i].nonce, resp.nonce, sizeof(resp.nonce)) == 0) { if (!self->ops->verify(self, self->ops->get_realm_name(self, i), resp.user, resp.ulen, obex_auth_verify_cb, &resp)) { return 0; } } } self->state = AUTH_STATE_SUCCESS; /* no break */ case AUTH_STATE_SUCCESS: return 1; } } obexpushd-0.11.2-source/src/auth/file.c000644 001750 001750 00000011253 11537730263 021030 0ustar00hendrikhendrik000000 000000 #include "auth.h" #include "utf.h" #include #include #include #include #include #include #include #include "compiler.h" #include "closexec.h" struct auth_file_data { struct { char* filename; uint16_t *name; uint8_t opts; } realm[1]; }; static int get_realm_count (struct auth_handler *self) { struct auth_file_data *data = self->private_data; if (!data) return 0; return sizeof(data->realm)/sizeof(data->realm[0]); } static int get_realm_id (struct auth_handler *self, const uint16_t *realm) { struct auth_file_data *data = self->private_data; unsigned int count = get_realm_count(self); unsigned int i = 0; for (; i < count; ++i) { if (realm == NULL) { if (data->realm[i].name == NULL) return i; } else { size_t size = utf16len(data->realm[i].name) * sizeof(*realm); if (memcmp(realm, data->realm[i].name, size) == 0) return i; } } return -EINVAL; } static const uint16_t* get_realm_name (struct auth_handler *self, int id) { struct auth_file_data *data = self->private_data; if (id >= get_realm_count(self)) return NULL; return data->realm[id].name; } static uint8_t get_realm_opts(struct auth_handler *self, const uint16_t *realm) { struct auth_file_data *data = self->private_data; int id = get_realm_id(self, realm); if (id >= 0) return data->realm[id].opts; else return 0; } static int verify (struct auth_handler *self, const uint16_t *realm, const uint8_t *user, size_t ulen, auth_verify_cb cb, void *cb_data) { struct auth_file_data *data = self->private_data; int id = get_realm_id(self, realm); int fd = -1; struct stat fdinfo; const uint8_t *start = MAP_FAILED; size_t mapsize = 0; int ret = 0; if (id < 0) goto out; fd = open_closexec(data->realm[id].filename, O_RDONLY, 0); if (fd == -1) goto out; /* user + separator ':' + pass (minimum length 1) + line end */ if (fstat(fd, &fdinfo) != 0) goto out; mapsize = (size_t)fdinfo.st_size; if (mapsize < ulen) goto out; start = mmap(NULL, mapsize, PROT_READ, MAP_SHARED, fd, 0); if (start != MAP_FAILED) { const uint8_t *cur = start; const uint8_t *end = start + mapsize; while ((cur + ulen + 1) <= end) { if (memcmp(cur, user, ulen) != 0 || cur[ulen] != ':') { /* no match, skip current line or go to end of file */ while (cur != end && *cur != '\n') ++cur; if (cur != end) ++cur; } else { /* user matched */ const uint8_t *pass = cur + ulen + 1; size_t plen = 0; /* forward to end of line or end of file */ cur = pass; while (cur != end && *cur != '\n') ++cur; if (cur != end) ++cur; /* remove line end characters */ plen = cur - pass; if (pass[plen] == '\n') { if (pass[--plen] == '\r') --plen; } /* verify using callback function */ ret = cb(cb_data, pass, plen); break; } } } out: if (start != MAP_FAILED) (void)munmap((void*)start, mapsize); if (fd >= 0) close(fd); return ret; } static struct auth_handler* auth_file_copy (struct auth_handler *self) { struct auth_file_data *data = self->private_data; return auth_file_init(data->realm[0].filename, data->realm[0].name, data->realm[0].opts); } static void auth_file_cleanup (struct auth_handler *self) { struct auth_file_data *data = self->private_data; unsigned int count = get_realm_count(self); unsigned int i = 0; if (!data) return; for (; i < count; ++i) { if (data->realm[i].filename) free(data->realm[i].filename); if (data->realm[i].name) free(data->realm[i].name); } memset(data, 0, sizeof(data)); free(data); self->private_data = NULL; } static struct auth_handler_ops auth_file_ops = { .get_realm_count = get_realm_count, .get_realm_name = get_realm_name, .get_realm_opts = get_realm_opts, .verify = verify, .copy = auth_file_copy, .cleanup = auth_file_cleanup, }; struct auth_handler* auth_file_init (char* file, uint16_t *realm, uint8_t opts) { struct auth_handler *h = malloc(sizeof(*h)); if (h) { struct auth_file_data *d = malloc(sizeof(*d)); memset(h, 0, sizeof(*h)); h->ops = &auth_file_ops; h->private_data = d; if (!d) goto out; memset(d, 0, sizeof(*d)); d->realm[0].filename = strdup(file); if (!d->realm[0].filename) goto out; if (realm) { d->realm[0].name = utf16dup(realm); if (!d->realm[0].name) goto out; } d->realm[0].opts = opts; h->session = calloc(get_realm_count(h), sizeof(*h->session)); if (!h->session) goto out; } return h; out: if (h) { auth_file_cleanup(h); if (h->session) { free(h->session); h->session = NULL; } free(h); } return NULL; } obexpushd-0.11.2-source/src/checks.c000644 001750 001750 00000003423 11537730263 020410 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "utf.h" #include "checks.h" #include #include #include #include static int name_check_cb(int c) { return !(c == (int)':' || c == (int)'\\' || c == (int)'/' || iscntrl(c)); } static int strcheck (uint8_t *s, int (*check)(int c)) { for (; *s != 0; ++s) if (check((int)*s)) return 1; return 0; } int check_name (uint8_t *name) { return strcheck(name, name_check_cb); } int check_type (uint8_t *type) { size_t len = strlen((char*)type); size_t i = 0; for (; i < len; ++i) { if (type[i] == '/') break; if (!isascii((int)type[i]) || !(isalpha((int)type[i]) || type[i] == '-' || type[i] == '.')) /* "x-", "vnd.", "prs." */ return 0; } if (++i >= len) return 0; for (; i < len; ++i) { if (!isascii((int)type[i]) || !isprint((int)type[i])) return 0; } return 1; } int check_wrap_utf16 (uint16_t *name, int (*func)(uint8_t*)) { uint8_t* n = utf16to8(name); int result = func(n); free(n); return result; } obexpushd-0.11.2-source/src/checks.h000644 001750 001750 00000000226 11537730263 020413 0ustar00hendrikhendrik000000 000000 #include int check_name (uint8_t *name); int check_type (uint8_t *type); int check_wrap_utf16 (uint16_t *name, int (*func)(uint8_t*)); obexpushd-0.11.2-source/src/closexec.h000644 001750 001750 00000001227 11537730263 020762 0ustar00hendrikhendrik000000 000000 #include #include #include #include #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif #define set_closexec_flag(fd) fcntl(fd, F_SETFD, FD_CLOEXEC) static inline int open_closexec(const char *pathname, int flags, mode_t mode) { int err = open(pathname, (flags | O_CLOEXEC), mode); #if ! O_CLOEXEC if (err != -1) (void)set_closexec_flag(err); #endif return err; } static inline int pipe_closexec(int pipefd[2]) { #if O_CLOEXEC return pipe2(pipefd, O_CLOEXEC); #else int err = pipe(pipefd); if (err != -1) { (void)set_closexec_flag(pipefd[0]); (void)set_closexec_flag(pipefd[1]); } return err; #endif } obexpushd-0.11.2-source/src/compiler.h000644 001750 001750 00000000165 11537730263 020767 0ustar00hendrikhendrik000000 000000 #if __GNUC__ >= 3 #define __unused /*@unused@*/ __attribute__((unused)) #else #define __unused /*@unused@*/ #endif obexpushd-0.11.2-source/src/fork.c000644 001750 001750 00000003566 11537730263 020121 0ustar00hendrikhendrik000000 000000 #include #ifndef SIGCLD #define SIGCLD SIGCHLD #endif int obexpushd_create_instance (void* (*cb)(void*), void *cbdata) { pid_t p = fork(); switch (p) { case 0: (void)signal(SIGCHLD, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTERM, SIG_DFL); (void)cb(cbdata); exit(EXIT_SUCCESS); case -1: return -errno; } return 0; } static void obexpushd_wait (int sig) { pid_t pidOfChild; int status; if (sig != SIGCLD) return; pidOfChild = wait(&status); if (WIFEXITED(status)) fprintf(stderr, "child exited with exit code %d\n", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) fprintf(stderr, "child got signal %d\n", WTERMSIG(status)); } int obexpushd_start (struct net_data *data, unsigned int count) { unsigned int i; (void)signal(SIGCHLD, obexpushd_wait); /* initialize all enabled listeners */ for (i = 0; i < count; ++i) { int fd = -1; if (!data[i].handler) continue; net_init(&data[i], eventcb); if (!data[i].obex) exit(EXIT_FAILURE); fd = OBEX_GetFD(data[i].obex); if (fd == -1) { perror("OBEX_GetFD()"); exit(EXIT_FAILURE); } } /* run the multiplexer */ do { int topfd = 0; fd_set fds; FD_ZERO(&fds); for (i = 0; i < count; ++i) { if (!data[i].handler) continue; if (data[i].obex) { int fd = OBEX_GetFD(data[i].obex); if (fd == -1) { perror("OBEX_GetFD()"); exit(EXIT_FAILURE); } if (fd > topfd) topfd = fd; FD_SET(fd, &fds); } } select(topfd+1, &fds, NULL, NULL, NULL); for (i = 0; i < count; ++i) { int fd = -1; if (!data[i].handler) continue; if (!data[i].obex) continue; fd = net_get_listen_fd(&data[i]); if (FD_ISSET(fd,&fds)) { if (OBEX_HandleInput(data[i].obex,1) < 0) { if (net_get_life_status(&data[i]) == LIFE_STATUS_DEAD) { net_cleanup(&data[i]); break; } } } } } while (1); } obexpushd-0.11.2-source/src/io.h000644 001750 001750 00000004055 11537730263 017566 0ustar00hendrikhendrik000000 000000 #include #include #ifndef OBEXPUSH_IO_H #define OBEXPUSH_IO_H #include "pipe.h" enum io_type { IO_TYPE_PUT, /* storing data */ IO_TYPE_GET, /* retrieving data */ IO_TYPE_LISTDIR, /* list directory content */ IO_TYPE_CAPS, /* print capabilities */ }; #define IO_STATE_OPEN (1 << 0) #define IO_STATE_EOF (1 << 1) struct io_transfer_data { char *peername; uint16_t* name; char* path; char* type; size_t length; time_t time; }; struct io_handler; struct io_handler_ops { int (*open)(struct io_handler *self, struct io_transfer_data *transfer, enum io_type t); int (*close)(struct io_handler *self, struct io_transfer_data *transfer, bool keep); int (*delete)(struct io_handler *self, struct io_transfer_data *transfer); struct io_handler* (*copy)(struct io_handler *self); void (*cleanup)(struct io_handler *self); ssize_t (*read)(struct io_handler *self, void *buf, size_t bufsize); ssize_t (*write)(struct io_handler *self, const void *buf, size_t len); int (*check_dir)(struct io_handler *self, const char *dir); int (*create_dir)(struct io_handler *self, const char *dir); }; struct io_handler { struct io_handler_ops *ops; unsigned long state; void *private_data; }; struct io_handler* io_script_init(const char *script); struct io_handler* io_file_init(const char *basedir); struct io_handler* io_copy (struct io_handler *h); void io_destroy (struct io_handler *h); unsigned long io_state(struct io_handler *self); int io_open (struct io_handler *self, struct io_transfer_data *transfer, enum io_type t); int io_close (struct io_handler *self, struct io_transfer_data *transfer, bool keep); int io_delete(struct io_handler *self, struct io_transfer_data *transfer); ssize_t io_readline(struct io_handler *self, void *buf, size_t bufsize); ssize_t io_read(struct io_handler *self, void *buf, size_t bufsize); ssize_t io_write(struct io_handler *self, const void *buf, size_t len); int io_check_dir(struct io_handler *self, const char *dir); int io_create_dir(struct io_handler *self, const char *dir); #endif /* OBEXPUSH_IO_H */ obexpushd-0.11.2-source/src/io/core.c000644 001750 001750 00000006434 11537730263 020514 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "io.h" #include "errno.h" #include #include struct io_handler * io_copy ( struct io_handler *h ) { if (!h) return NULL; if (h && h->ops && h->ops->copy) { /* deep copy */ return h->ops->copy(h); } else { /* flat copy */ struct io_handler *hnew = malloc(sizeof(*hnew)); if (hnew) memcpy(hnew, h, sizeof(*hnew)); return hnew; } } void io_destroy (struct io_handler* h) { if (h) { if (h->ops && h->ops->cleanup) h->ops->cleanup(h); free(h); } } unsigned long io_state( struct io_handler *self ) { if (!self) return 0; else return self->state; } int io_open ( struct io_handler *self, struct io_transfer_data *transfer, enum io_type t ) { if (!self) return -EBADF; if (self->ops && self->ops->open) return self->ops->open(self, transfer, t); else return 0; } int io_close ( struct io_handler *self, struct io_transfer_data *transfer, bool keep ) { if (!self) return -EBADF; if (self->ops && self->ops->close) return self->ops->close(self, transfer, keep); else return 0; } int io_delete ( struct io_handler *self, struct io_transfer_data *transfer ) { if (!self) return -EBADF; if (self->ops && self->ops->delete) return self->ops->delete(self, transfer); else return 0; } ssize_t io_readline(struct io_handler *self, void *buf, size_t bufsize) { ssize_t retval = 0; ssize_t err; char *cbuf = buf; if (bufsize == 0) return 0; do { char tmp; err = io_read(self, &tmp, 1); if (err < 0) { retval = err; } else if (err > 0) { *cbuf = tmp; ++retval; } } while (--bufsize && *(cbuf++) != '\n' && err > 0); return retval; } ssize_t io_read( struct io_handler *self, void *buf, size_t bufsize ) { if (!self) return -EBADF; if (bufsize == 0) return 0; if (self->ops && self->ops->read) return self->ops->read(self, buf, bufsize); else return 0; } ssize_t io_write( struct io_handler *self, const void *buf, size_t len ) { if (!self) return -EBADF; if (len == 0) return 0; if (self->ops && self->ops->write) return self->ops->write(self, buf, len); else return 0; } int io_check_dir( struct io_handler *self, const char *dir ) { if (!self) return -EBADF; if (self->ops && self->ops->check_dir) return self->ops->check_dir(self, dir); else return 0; } int io_create_dir( struct io_handler *self, const char *dir ) { if (!self) return -EBADF; if (self->ops && self->ops->create_dir) return self->ops->create_dir(self, dir); else return -EFAULT; } obexpushd-0.11.2-source/src/io/internal/caps.c000644 001750 001750 00000001173 11537730263 022321 0ustar00hendrikhendrik000000 000000 #include "common.h" #include "caps.h" #include "closexec.h" #include "x-obex/obex-capability.h" #include static struct obex_capability caps = { .general = { .vendor = NULL, .model = NULL, }, }; int io_internal_caps_open (struct io_handler *self, struct io_transfer_data *transfer) { struct io_internal_data *data = self->private_data; int err = 0; data->in = tmpfile(); if (data->in == NULL) return -errno;; set_closexec_flag(fileno(data->in)); err = obex_capability(data->in, &caps); if (err) return err;; transfer->length = ftell(data->in); (void)fseek(data->in, 0L, SEEK_SET); return 0; } obexpushd-0.11.2-source/src/io/internal/caps.h000644 001750 001750 00000000157 11537730263 022327 0ustar00hendrikhendrik000000 000000 #include "io.h" int io_internal_caps_open (struct io_handler *self, struct io_transfer_data *transfer); obexpushd-0.11.2-source/src/io/internal/common.c000644 001750 001750 00000012604 11537730263 022664 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "checks.h" #include "common.h" #include "file.h" #include "dir.h" #include "caps.h" #include #include #include #include #include #include #include #include #include #include "io.h" #include "utf.h" #include "net.h" char* io_internal_get_fullname(const char *basedir, const char *subdir, const uint16_t *filename) { uint8_t *namebase = NULL; int err = 0; char *name; size_t namesize; if (filename) { namebase = utf16to8(filename); if (!namebase) return NULL; } namesize = strlen(basedir) + 1 + utf8len((uint8_t*)subdir) + 1 + utf8len(namebase) + 1; name = malloc(namesize); if (!name) err = -errno; else { memset(name, 0, namesize); if (strcmp(basedir, ".") != 0) { strcat(name, basedir); } if (utf8len((uint8_t*)subdir)) { if (utf8len((uint8_t*)name)) strcat(name, "/"); strcat(name, subdir); } if (utf8len(namebase)) { if (utf8len((uint8_t*)name)) strcat(name, "/"); strcat(name, (char*)namebase); } else if (utf8len((uint8_t*)name) == 0) strcat(name, basedir); } free(namebase); if (err) errno = -err; return name; } static int io_internal_delete (struct io_handler *self, struct io_transfer_data *transfer) { struct io_internal_data *data = self->private_data; char* name; int err = 0; if (!transfer) return -EINVAL; name = io_internal_get_fullname(data->basedir, transfer->path, transfer->name); if (!name) return -ENOMEM; err = io_internal_file_delete(self, name); free(name); return err; } static int io_internal_close (struct io_handler *self, struct io_transfer_data *transfer, bool keep) { struct io_internal_data *data = self->private_data; if (data->in) { if (fclose(data->in) == EOF) return -errno; data->in = NULL; } if (data->out) { if (fclose(data->out) == EOF) return -errno; data->out = NULL; if (transfer) { char *name = io_internal_get_fullname(data->basedir, transfer->path, transfer->name); if (!name) return -errno; if (!keep) io_internal_file_delete(self, name); else io_internal_file_close(self, transfer, name); free(name); } } self->state = 0; return 0; } static int io_internal_open (struct io_handler *self, struct io_transfer_data *transfer, enum io_type t) { int err = 0; char *name = NULL; struct io_internal_data *data = self->private_data; err = io_internal_close(self, NULL, true); if (err) return err; name = io_internal_get_fullname(data->basedir, transfer->path, transfer->name); if (!name) return -errno; switch (t) { case IO_TYPE_PUT: err = io_internal_open_put(self, transfer, name); if (err) fprintf(stderr, "Error: cannot create file: %s\n", strerror(-err)); break; case IO_TYPE_GET: err = io_internal_open_get(self, transfer, name); break; case IO_TYPE_LISTDIR: err = io_internal_dir_open(self, transfer, name); break; case IO_TYPE_CAPS: err = io_internal_caps_open(self, transfer); break; default: err = -EINVAL; break; } free(name); if (err) { (void)io_internal_close(self, transfer, (err != -EEXIST)); } else { self->state |= IO_STATE_OPEN; } return err; } static void io_internal_cleanup (struct io_handler *self) { if (self->private_data) { free(self->private_data); self->private_data = NULL; } } static struct io_handler* io_internal_copy(struct io_handler *self) { struct io_internal_data *data = self->private_data; return io_file_init(data->basedir); } static struct io_handler_ops io_file_ops = { .copy = io_internal_copy, .cleanup = io_internal_cleanup, .open = io_internal_open, .close = io_internal_close, .delete = io_internal_delete, .read = io_internal_file_read, .write = io_internal_file_write, .check_dir = io_internal_dir_check, .create_dir = io_internal_dir_create, }; struct io_handler * io_file_init(const char *basedir) { struct io_handler *handle = NULL; struct io_internal_data *data = NULL; if (!basedir || strlen(basedir) == 0) { errno = EINVAL; goto out; } handle = malloc(sizeof(*handle)); if (!handle) goto out; memset(handle, 0, sizeof(*handle)); handle->ops = &io_file_ops; data = malloc(sizeof(*data)); if (!data) goto out_err; memset(data, 0, sizeof(*data)); data->basedir = strdup(basedir); if (!data->basedir) goto out_err; handle->private_data = data; return handle; out_err: { int err = errno; if (data) { if (data->basedir) free(data->basedir); free(data); } if (handle) { free(handle); } errno = err; } out: return NULL; } obexpushd-0.11.2-source/src/io/internal/common.h000644 001750 001750 00000000336 11537730263 022670 0ustar00hendrikhendrik000000 000000 #include #include struct io_internal_data { char *basedir; FILE *in; FILE *out; }; char* io_internal_get_fullname(const char *basedir, const char *subdir, const uint16_t *filename); obexpushd-0.11.2-source/src/io/internal/dir.c000644 001750 001750 00000003452 11537730263 022153 0ustar00hendrikhendrik000000 000000 #include "common.h" #include "dir.h" #include "closexec.h" #include "utf.h" #include "x-obex/obex-folder-listing.h" #include #include int io_internal_dir_open(struct io_handler *self, struct io_transfer_data *transfer, char *name) { struct io_internal_data *data = self->private_data; int flags = OFL_FLAG_TIMES | OFL_FLAG_PERMS | OFL_FLAG_KEEP; struct stat s; int err = 0; data->in = tmpfile(); if (data->in == NULL) return -errno; set_closexec_flag(fileno(data->in)); if (utf8len((uint8_t*)transfer->path)) flags |= OFL_FLAG_PARENT; err = obex_folder_listing(data->in, name, flags); if (err) return err; /* stating dir to get last modification time */ if (fstat(err, &s) == -1) return -errno; transfer->length = ftell(data->in); transfer->time = s.st_mtime; /* rewinding to start of file */ (void)fseek(data->in, 0L, SEEK_SET); return err; } int io_internal_dir_check(struct io_handler *self, const char *dir) { struct io_internal_data *data = self->private_data; char *fulldir = io_internal_get_fullname(data->basedir, dir, NULL); struct stat s; int err = 0; if (!fulldir) err = -errno; else if (stat(fulldir, &s) == -1) err = -errno; else if (!S_ISDIR(s.st_mode)) err = -ENOTDIR; free(fulldir); return err; } int io_internal_dir_create(struct io_handler *self, const char *dir) { struct io_internal_data *data = self->private_data; char *fulldir = io_internal_get_fullname(data->basedir, dir, NULL); int err = 0; if (!fulldir) return -errno; if (io_internal_dir_check(self, dir) != 0) { fprintf(stderr, "Creating directory \"%s\"\n", fulldir); if (mkdir(fulldir, S_IRWXU|S_IRWXG|S_IRWXO) == -1) { err = -errno; fprintf(stderr, "Error: %s: %s\n", "cannot create directory", strerror(-err)); } } return 0; } obexpushd-0.11.2-source/src/io/internal/dir.h000644 001750 001750 00000000407 11537730263 022155 0ustar00hendrikhendrik000000 000000 #include "io.h" int io_internal_dir_open(struct io_handler *self, struct io_transfer_data *transfer, char *name); int io_internal_dir_check(struct io_handler *self, const char *dir); int io_internal_dir_create(struct io_handler *self, const char *dir); obexpushd-0.11.2-source/src/io/internal/file.c000644 001750 001750 00000006515 11537730263 022317 0ustar00hendrikhendrik000000 000000 #include "checks.h" #include "common.h" #include "file.h" #ifdef USE_XATTR #include #endif #include #include #include #include "closexec.h" #include "compiler.h" static void io_internal_file_set_time (const char *name, time_t time) { struct utimbuf times; times.actime = time; times.modtime = time; /* setting the time is non-critical */ (void)utime(name, ×); } #ifdef USE_XATTR static void io_internal_file_set_type (const char *name, const char *type) { (void)lsetxattr(name, "user.mime_type", type, strlen(type)+1, 0); } static char * io_internal_file_get_type (const char *name) { char type[256]; ssize_t status = lgetxattr(name, "user.mime_type", type, sizeof(type)); if (status < 0 || strlen(type) != (size_t)status || !check_type((uint8_t*)type)) return NULL; return strdup(type); } #endif int io_internal_open_put (struct io_handler *self, struct io_transfer_data *transfer, const char *name) { struct io_internal_data *data = self->private_data; int err = 0; if (!transfer->name) return -EINVAL; fprintf(stderr, "Creating file \"%s\"\n", name); err = open_closexec(name, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (err == -1) return -errno; if (transfer->length) (void)posix_fallocate(err, 0, transfer->length); data->out = fdopen(err, "w"); if (data->out == NULL) return -errno; return 0; } int io_internal_open_get (struct io_handler *self, struct io_transfer_data *transfer, const char *name) { struct io_internal_data *data = self->private_data; int err = 0; struct stat s; if (!transfer->name) return -EINVAL; err = open_closexec(name, O_RDONLY, 0); if (err == -1) return -errno;; data->in = fdopen(err, "r"); if (data->in == NULL) return -errno; #ifdef USE_XATTR transfer->type = io_internal_file_get_type(name); #endif if (fstat(err, &s) == -1) return 0; transfer->length = s.st_size; transfer->time = s.st_mtime; return 0; } int io_internal_file_delete (struct io_handler __unused *self, const char *name) { /* remove the file */ fprintf(stderr, "Deleting file \"%s\"\n", name); if (unlink(name) == -1) return -errno; return 0; } void io_internal_file_close (struct io_handler __unused *self, struct io_transfer_data *transfer, const char *name) { if (transfer->time) io_internal_file_set_time(name, transfer->time); #ifdef USE_XATTR if (transfer->type) io_internal_file_set_type(name, transfer->type); #endif } ssize_t io_internal_file_read (struct io_handler *self, void *buf, size_t bufsize) { struct io_internal_data *data = self->private_data; size_t status; if (!data->in) return -EBADF; if (bufsize == 0) return 0; if (buf == NULL) return -EINVAL; status = fread(buf, bufsize, 1, data->in); if (feof(data->in)) self->state |= IO_STATE_EOF; if (status != 1 && !feof(data->in)) return -ferror(data->in); else return status*bufsize; } ssize_t io_internal_file_write (struct io_handler *self, const void *buf, size_t len) { struct io_internal_data *data = self->private_data; size_t status; if (!data->out) return -EBADF; if (len == 0) return 0; if (buf == NULL) return -EINVAL; status = fwrite(buf, len, 1, data->out); if (status < len) return -ferror(data->out); else return status; } obexpushd-0.11.2-source/src/io/internal/file.h000644 001750 001750 00000001215 11537730263 022314 0ustar00hendrikhendrik000000 000000 #include #include "io.h" int io_internal_open_put (struct io_handler *self, struct io_transfer_data *transfer, const char *name); int io_internal_open_get (struct io_handler *self, struct io_transfer_data *transfer, const char *name); int io_internal_file_delete (struct io_handler *self, const char *name); void io_internal_file_close (struct io_handler *self, struct io_transfer_data *transfer, const char *name); ssize_t io_internal_file_read (struct io_handler *self, void *buf, size_t bufsize); ssize_t io_internal_file_write (struct io_handler *self, const void *buf, size_t len); obexpushd-0.11.2-source/src/io/script.c000644 001750 001750 00000025060 11537730263 021064 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obexpushd.h" #include "checks.h" #include #include #include #include #include #include #include #include #include #include #include #include "io.h" #include "utf.h" #include "compiler.h" struct io_script_data { pid_t child; const char* script; FILE *in; FILE *out; }; static int io_script_exit ( pid_t child, bool keep ) { int status; int retval = 0; int pid = 0; if (!keep) kill(child, SIGUSR1); /* signal 'undo' */ for (int i = 0; pid == 0 && i < 10; ++i) { pid = waitpid(child, &status, WNOHANG); if (pid == 0) sleep(1); } /* it not dead yet, kill it */ if (pid == 0) { kill(child, SIGKILL); pid = waitpid(child, &status, 0); } if (pid < 0) retval = -errno; else if (WIFEXITED(status)) { retval = WEXITSTATUS(status); /* fprintf(stderr, "script exited with exit code %d\n", retval); */ } else if (WIFSIGNALED(status) && keep) { retval = WTERMSIG(status); /* fprintf(stderr, "script got signal %d\n", retval); */ } return retval; } static int io_script_close ( struct io_handler *self, struct io_transfer_data __unused *transfer, bool keep ) { struct io_script_data *data = self->private_data; int retval = 0; /* kill STDIN first to signal the script that there will be no more * data */ if (data->out) { if (fclose(data->out) == EOF) retval = -errno; else data->out = NULL; } if (data->child != (pid_t)-1) { retval = io_script_exit(data->child, keep); data->child = (pid_t)-1; } if (data->in) { if (fclose(data->in) == EOF) retval = -errno; else data->in = NULL; } self->state = 0; return retval; } static int put_wait_for_ok (struct io_handler *self) { char ret[4+1]; ssize_t err; memset(ret, 0, sizeof(ret)); err = io_readline(self, ret, sizeof(ret)); if (err < 0) return err; if (strncmp(ret, "OK\n", 3) != 0 && strncmp(ret, "OK\r\n", 4) != 0) return -EPERM; else return 0; } #define EOL(n) ((n) == '\n' || (n) == '\r') static int io_script_parse_headers ( struct io_handler *self, struct io_transfer_data *transfer ) { char buffer[512+1]; while (1) { size_t len = 0; int err; memset(buffer, 0, sizeof(buffer)); err = io_readline(self, buffer, sizeof(buffer)); if (err < 0) { return err; } else if (err == 0) { return -EINVAL; } len = strlen(buffer); if (len == 0 || !EOL(buffer[len-1])) return -EINVAL; if (len && buffer[len-1] == '\n') --len; if (len && buffer[len-1] == '\r') --len; buffer[len] = 0; /* stop on the first empty line */ if (len == 0) break; /* compare the first part of buffer with known headers * and ignore unknown ones */ if (strncasecmp(buffer,"Name: ",6) == 0) { uint8_t *name = (uint8_t*)(buffer+6); if (!check_name(name)) return -EINVAL; if (transfer->name) free(transfer->name); transfer->name = utf8to16(name); } else if (strncasecmp(buffer,"Length: ",8) == 0) { char* endptr; long dlen = strtol(buffer+8, &endptr, 10); if ((dlen == LONG_MIN || dlen == LONG_MAX) && errno == ERANGE) return -errno; if (endptr != 0 && (0 <= dlen && dlen <= UINT32_MAX)) { transfer->length = (size_t)dlen; continue; } } else if (strncasecmp(buffer,"Type: ",6) == 0) { char* type = buffer+6; if (!check_type((uint8_t*)type)) return -EINVAL; if (transfer->type) free(transfer->type); transfer->type = strdup(type); } else if (strncasecmp(buffer, "Time: ", 6) == 0) { char* timestr = buffer+6; struct tm time; tzset(); /* uses GNU extensions */ strptime(timestr, "%Y-%m-%dT%H:%M:%S", &time); time.tm_isdst = -1; transfer->time = mktime(&time); if (strlen(timestr) > 17 && timestr[17] == 'Z') transfer->time -= timezone; } else continue; } return 0; } static int io_script_prepare_cmd ( struct io_handler *self, struct io_transfer_data *transfer, const char *cmd ) { int p[2] = { -1, -1}; struct io_script_data *data = self->private_data; char* args[] = {(char*)data->script, (char*)cmd, NULL}; int err = io_script_close(self, transfer, true); if (err) return err; err = pipe_open(data->script, args, p, &data->child); if (err) return err; data->in = fdopen(p[0], "r"); if (data->in) data->out = fdopen(p[1], "w"); if (!data->in || !data->out) { err = errno; pipe_close(p); io_script_close(self, transfer, true); return -err; } self->state |= IO_STATE_OPEN; return err; } static void str_subst(char *str, char a, char b) { while(*str) { if (*str == a) *str = b; ++str; } } #define IO_HT_FROM (1 << 0) #define IO_HT_LENGTH (1 << 1) #define IO_HT_TIME (1 << 2) #define IO_HT_NAME (1 << 3) #define IO_HT_TYPE (1 << 4) #define IO_HT_PATH (1 << 5) static void io_script_write_headers ( struct io_handler *self, struct io_transfer_data *transfer, int ht ) { struct io_script_data *data = self->private_data; if (ht & IO_HT_FROM) { if (transfer->peername && strlen(transfer->peername)) fprintf(data->out, "From: %s\n", transfer->peername); } if (ht & IO_HT_LENGTH) { if (transfer->length) fprintf(data->out, "Length: %zu\n", transfer->length); } if (ht & IO_HT_TIME) { if (transfer->time) { char tmp[17]; struct tm t; (void)gmtime_r(&transfer->time, &t); memset(tmp, 0, 17); if (strftime(tmp, 17, "%Y%m%dT%H%M%SZ", &t) == 16) { fprintf(data->out, "Time: %s\n", tmp); } } } if (ht & IO_HT_NAME) { char *str = (char*)utf16to8(transfer->name); if (str) { str_subst(str, '\n', ' '); fprintf(data->out, "Name: %s\n", str); free(str); } } if (ht & IO_HT_TYPE) { if (transfer->type) { char *str = strdup(transfer->type); if (str) { str_subst(str, '\n', ' '); fprintf(data->out, "Type: %s\n", str); free(str); } } } if (ht & IO_HT_PATH) { if (transfer->path) { char *str = strdup(transfer->path); if (str) { str_subst(str, '\n', ' '); fprintf(data->out, "Path: %s\n", str); free(str); } } else fprintf(data->out, "Path: .\n"); } /* empty line signals that data follows */ fprintf(data->out, "\n"); fflush(data->out); } static int io_script_open ( struct io_handler *self, struct io_transfer_data *transfer, enum io_type t ) { struct io_script_data *data = self->private_data; const char *cmd; int ht = IO_HT_FROM; int err; switch (t) { case IO_TYPE_PUT: cmd = "put"; ht |= IO_HT_LENGTH | IO_HT_TIME | IO_HT_NAME | IO_HT_TYPE | IO_HT_PATH; break; case IO_TYPE_GET: cmd = "get"; ht |= IO_HT_PATH; if (transfer->name) ht |= IO_HT_NAME; else if (transfer->type) ht |= IO_HT_TYPE; else return -EINVAL; break; case IO_TYPE_LISTDIR: cmd = "listdir"; ht |= IO_HT_PATH; break; case IO_TYPE_CAPS: cmd = "capability"; break; default: return -ENOTSUP; } err = io_script_prepare_cmd(self, transfer, cmd); if (!err) io_script_write_headers(self, transfer, ht); if (err) return err; if (feof(data->in)) self->state |= IO_STATE_EOF; switch (t) { case IO_TYPE_PUT: err = put_wait_for_ok(self); break; default: err = io_script_parse_headers(self, transfer); break; } return err; } static void io_script_cleanup (struct io_handler *self) { if (self->private_data) { free(self->private_data); self->private_data = NULL; } } static ssize_t io_script_read(struct io_handler *self, void *buf, size_t bufsize) { struct io_script_data *data = self->private_data; size_t status; if (!data->in) return -EBADF; if (bufsize == 0) return 0; if (buf == NULL) return -EINVAL; status = fread(buf, bufsize, 1, data->in); if (feof(data->in)) self->state |= IO_STATE_EOF; if (status != 1 && !feof(data->in)) return -ferror(data->in); else return status*bufsize; } static ssize_t io_script_write(struct io_handler *self, const void *buf, size_t len) { struct io_script_data *data = self->private_data; size_t status; if (!data->out) return -EBADF; if (len == 0) return 0; if (buf == NULL) return -EINVAL; status = fwrite(buf, len, 1, data->out); if (status < len) return -ferror(data->out); else return status; } static int io_script_create_dir(struct io_handler *self, const char *dir) { struct io_script_data *data = self->private_data; struct io_transfer_data transfer; int err; transfer.path = strdup(dir), err = io_script_prepare_cmd(self, &transfer, "createdir"); if (!err) { io_script_write_headers(self, &transfer, IO_HT_FROM | IO_HT_PATH); err = io_script_exit(data->child, true); } if (err > 0) err = -EFAULT; free(transfer.path); return err; } static int io_script_delete(struct io_handler *self, struct io_transfer_data *transfer) { struct io_script_data *data = self->private_data; int err = io_script_prepare_cmd(self, transfer, "delete"); if (!err) { io_script_write_headers(self, transfer, IO_HT_FROM | IO_HT_NAME | IO_HT_PATH); err = io_script_exit(data->child, true); } if (err > 0) err = -EFAULT; return err; } static struct io_handler* io_script_copy(struct io_handler *self) { struct io_script_data *data = self->private_data; return io_script_init(data->script); } static struct io_handler_ops io_script_ops = { .open = io_script_open, .close = io_script_close, .delete = io_script_delete, .copy = io_script_copy, .cleanup = io_script_cleanup, .read = io_script_read, .write = io_script_write, .create_dir = io_script_create_dir, }; struct io_handler * io_script_init(const char* script) { struct io_handler *handle = malloc(sizeof(*handle)); struct io_script_data *data; if (!handle) return NULL; data = malloc(sizeof(*data)); if (!data) { free(handle); return NULL; } memset(handle, 0, sizeof(*handle)); handle->ops = &io_script_ops; handle->private_data = data; memset(data, 0, sizeof(*data)); data->child = (pid_t)-1; data->script = script; return handle; } obexpushd-0.11.2-source/src/net.h000644 001750 001750 00000004626 11537730263 017751 0ustar00hendrikhendrik000000 000000 #ifndef OBEXPUSHD_NET_H #define OBEXPUSHD_NET_H #include "net/core.h" #include "auth.h" enum net_obex_protocol { NET_OBEX_PUSH = 0, NET_OBEX_FTP = 1, }; enum net_life_status { LIFE_STATUS_DEAD = 0, LIFE_STATUS_ALIVE = 1, }; struct net_handler; struct net_handler_ops { obex_t* (*init)(struct net_handler*, obex_event_t); void (*cleanup)(struct net_handler*); void (*set_protocol)(struct net_handler*, enum net_obex_protocol); /* Functions to implement authentication */ int (*security_init)(struct net_handler*, obex_t*); int (*security_check)(struct net_handler*, obex_t*); /* Writes the peer address string * "/[]\0" * to buffer and cuts at bufsiz. * The return value is the valid length of buffer * or a negated error number (see errno) on error. */ int (*get_peer)(struct net_handler*, obex_t*, char* buffer, size_t bufsiz); int (*get_listen_fd)(struct net_handler*); enum net_life_status (*get_life_status)(struct net_handler*); }; struct net_handler { struct net_handler_ops* ops; void* args; }; struct net_handler* net_handler_alloc(struct net_handler_ops *ops, size_t argsize); void net_handler_cleanup(struct net_handler*); struct net_handler* bluetooth_setup(char* device_addr, uint8_t); struct net_handler* irda_setup(char*); #if OPENOBEX_TCPOBEX struct net_handler* tcp_setup(const char*, uint16_t); #else /* OPENOBEX_TCPOBEX */ struct net_handler* inet_setup(); #endif /* OPENOBEX_TCPOBEX */ struct net_handler* usb_gadget_setup(const char* device, time_t timeout); struct net_handler* fdobex_setup(int in, int out, time_t timeout); struct net_data { obex_t* obex; struct net_handler *handler; /* auth */ int auth_success; #define AUTH_LEVEL_OBEX (1 << 0) #define AUTH_LEVEL_TRANSPORT (1 << 1) uint8_t auth_level; uint8_t enabled_protocols; }; struct net_data* net_data_new (); void net_init (struct net_data* data, obex_event_t eventcb); uint8_t net_security_init ( struct net_data* data, struct auth_handler* auth, obex_object_t* obj ); int net_security_check (struct net_data* data); void net_security_cleanup (struct net_data* data); void net_get_peer (struct net_data* data, char* buffer, size_t bufsiz); void net_disconnect (struct net_data* data); void net_cleanup (struct net_data* data); int net_get_listen_fd(struct net_data* data); enum net_life_status net_get_life_status(struct net_data* data); #endif /* OBEXPUSHD_NET_H */ obexpushd-0.11.2-source/src/net/btobex.c000644 001750 001750 00000010431 11537730263 021216 0ustar00hendrikhendrik000000 000000 #include "net.h" #include "compiler.h" #include "publish/sdp.h" #include #include #include #include #include #include #include struct bluetooth_args { void* session_data; bdaddr_t device; uint8_t channel; unsigned long protocols; }; static obex_t* bluetooth_init ( struct net_handler *h, obex_event_t eventcb ) { struct bluetooth_args* args = h->args; obex_t* handle = OBEX_Init(OBEX_TRANS_BLUETOOTH,eventcb,OBEX_FL_KEEPSERVER); char device[18]; if (!handle) return NULL; if (args->channel) { /* the user selected a specific channel */ if (BtOBEX_ServerRegister(handle, &args->device, args->channel) == -1) { perror("BtOBEX_ServerRegister"); return NULL; } } else { /* automatically find a free channel: * Our previous default was channel 9, so try it first. */ unsigned int i = 9; if (BtOBEX_ServerRegister(handle, &args->device, i) != -1) { for (i = 1; i < UINT8_MAX; ++i) { if (i != 9 && BtOBEX_ServerRegister(handle, &args->device, i) != -1) break; } } if (i >= UINT8_MAX) { fprintf(stderr, "Cannot find a free RFCOMM channel\n"); return NULL; } args->channel = (uint8_t)i; } OBEX_SetTransportMTU(handle, OBEX_MAXIMUM_MTU, OBEX_MAXIMUM_MTU); (void)ba2str(&args->device, device); fprintf(stderr, "Listening on bluetooth/[%s]:%u\n", device, (unsigned int)args->channel); args->session_data = bt_sdp_session_open(&args->device, args->channel, args->protocols); if (!args->session_data) { fprintf(stderr, "SDP session setup failed, disabling bluetooth\n"); OBEX_Cleanup(handle); return NULL; } return handle; } static void bluetooth_cleanup( struct net_handler *h ) { struct bluetooth_args* args = h->args; if (args->session_data) { bt_sdp_session_close(args->session_data, &args->device); args->session_data = NULL; } } static int bluetooth_security_init( struct net_handler __unused *h, obex_t *ptr ) { int sock = OBEX_GetFD(ptr); int err = 0; const uint32_t options = (RFCOMM_LM_AUTH | RFCOMM_LM_SECURE); uint32_t optval = 0; socklen_t optlen = sizeof(optval); if (sock < 0) return -ENOTSOCK; err = getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &optval, &optlen); if (err < 0) { perror("Getting RFCOMM_LM"); return -errno; } if (optlen != sizeof(optval)) return -EINVAL; if ((optval & options) != options) { optval |= options; err = setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &optval, optlen); if (err < 0) { perror("Setting RFCOMM_LM"); return -errno; } } return 0; } static int bluetooth_get_peer( struct net_handler __unused *h, obex_t* handle, char* buffer, size_t bufsiz ) { struct sockaddr_rc addr; socklen_t addrlen = sizeof(addr); char addrstr[128]; char tmp[256]; int status; int sock = OBEX_GetFD(handle); if (sock == -1) return -EBADF; status = getpeername(sock, (struct sockaddr*) &addr, &addrlen); if (status == -1) return -errno; if (addr.rc_family != AF_BLUETOOTH) return -EBADF; memset(addrstr, 0, sizeof(addrstr)); ba2str(&addr.rc_bdaddr, addrstr); status = snprintf(tmp, sizeof(tmp), "bluetooth/[%s]:%u", addrstr, addr.rc_channel); if (buffer) strncpy(buffer, tmp, bufsiz); return status; } static void bluetooth_set_protocol ( struct net_handler *h, enum net_obex_protocol prot ) { struct bluetooth_args* args = h->args; switch (prot) { case NET_OBEX_PUSH: args->protocols |= BT_SDP_PROT_OBEX_PUSH; break; case NET_OBEX_FTP: args->protocols |= BT_SDP_PROT_OBEX_FTP; break; } } static struct net_handler_ops bluetooth_ops = { .init = bluetooth_init, .cleanup = bluetooth_cleanup, .set_protocol = bluetooth_set_protocol, .get_peer = bluetooth_get_peer, .security_init = bluetooth_security_init }; struct net_handler* bluetooth_setup( char* device, uint8_t channel ) { struct bluetooth_args* args; struct net_handler *h = net_handler_alloc(&bluetooth_ops, sizeof(*args)); int hciId = -1; if (!h) return NULL; args = h->args; if (device) { int id; if (strlen(device) == 17) /* 11:22:33:44:55:66 */ id = hci_devid(device); else if (1 != sscanf(device, "hci%d", &id)) id = -1; hciId = id; } if (hciId >= 0) hci_devba(hciId, &args->device); else bacpy(&args->device, BDADDR_ANY); args->channel = channel; return h; } obexpushd-0.11.2-source/src/net/core.c000644 001750 001750 00000006606 11537730263 020674 0ustar00hendrikhendrik000000 000000 #include "net.h" #include "auth.h" #include #include #include #include struct net_handler* net_handler_alloc(struct net_handler_ops *ops, size_t argsize) { struct net_handler *h = malloc(sizeof(*h)); if (!h) return NULL; if (argsize) { h->args = malloc(argsize); if (!h->args) { int err = errno; free(h); errno = err; return NULL; } memset(h->args, 0, argsize); } else h->args = NULL; h->ops = ops; return h; } void net_handler_cleanup(struct net_handler *h) { if (h->args) { if (h->ops && h->ops->cleanup) h->ops->cleanup(h); free(h->args); h->args = NULL; } h->ops = NULL; } struct net_data* net_data_new () { struct net_data* data = malloc(sizeof(*data)); if (!data) return NULL; data->obex = NULL; data->handler = NULL; data->auth_success = 0; return data; } void net_init ( struct net_data* data, obex_event_t eventcb ) { struct net_handler *h = data->handler; /* enable protocols */ if (h && h->ops->set_protocol) { if ((data->enabled_protocols & (1 << NET_OBEX_PUSH)) != 0) h->ops->set_protocol(h, NET_OBEX_PUSH); if ((data->enabled_protocols & (1 << NET_OBEX_FTP)) != 0) h->ops->set_protocol(h, NET_OBEX_FTP); } if (h && h->ops->init) { if (data->obex) OBEX_Cleanup(data->obex); data->obex = h->ops->init(h, eventcb); } if (data->obex) { int fd = OBEX_GetFD(data->obex); if (fd >= 0) (void)fcntl(fd, F_SETFD, FD_CLOEXEC); OBEX_SetUserData(data->obex, data); } if ((data->auth_level & AUTH_LEVEL_TRANSPORT) && h && h->ops->security_init) { h->ops->security_init(h, data->obex); } } void net_disconnect ( struct net_data* data ) { (void)OBEX_TransportDisconnect(data->obex); } uint8_t net_security_init ( struct net_data* data, struct auth_handler* auth, obex_object_t* obj ) { struct net_handler *h = data->handler; if ((data->auth_level & AUTH_LEVEL_TRANSPORT) && h && h->ops->security_check && !h->ops->security_check(h, data->obex)) { return OBEX_RSP_FORBIDDEN; } if ((data->auth_level & AUTH_LEVEL_OBEX) && !data->auth_success) { if (auth && auth_init(auth, data->obex, obj)) return OBEX_RSP_UNAUTHORIZED; else return OBEX_RSP_SERVICE_UNAVAILABLE; } return 0; } int net_security_check (struct net_data* data) { int transport = 1; int obex = 1; struct net_handler *h = data->handler; if ((data->auth_level & AUTH_LEVEL_TRANSPORT) && h && h->ops->security_check) transport = h->ops->security_check(h, data->obex); if ((data->auth_level & AUTH_LEVEL_OBEX)) obex = data->auth_success; return transport && obex; } void net_get_peer (struct net_data* data, char* buffer, size_t bufsiz) { struct net_handler *h = data->handler; if (h && h->ops->get_peer) (void)h->ops->get_peer(h, data->obex, buffer, bufsiz); } int net_get_listen_fd(struct net_data* data) { struct net_handler *h = data->handler; if (h && h->ops->get_listen_fd) return h->ops->get_listen_fd(h); else return OBEX_GetFD(data->obex); } enum net_life_status net_get_life_status(struct net_data* data) { struct net_handler *h = data->handler; if (h && h->ops->get_life_status) return h->ops->get_life_status(h); else return LIFE_STATUS_ALIVE; } void net_cleanup (struct net_data* data) { if (data->obex) { OBEX_Cleanup(data->obex); data->obex = NULL; } if (data->handler) { net_handler_cleanup(data->handler); data->handler = NULL; } } obexpushd-0.11.2-source/src/net/core.h000644 001750 001750 00000000074 11537730263 020672 0ustar00hendrikhendrik000000 000000 #include #include obexpushd-0.11.2-source/src/net/fdobex.c000644 001750 001750 00000005005 11537730263 021203 0ustar00hendrikhendrik000000 000000 /* Information typical usage of standard I/O descriptors: * - SIGHUP is raised when the client is disconnected */ #include "fdobex.h" #include #include #include #include #include /* #include */ #include "compiler.h" static obex_t* fdobex_init ( struct net_handler *h, obex_event_t eventcb ) { struct fdobex_args *args = h->args; obex_t *handle = NULL; args->buf = malloc(OBEX_MAXIMUM_MTU); if (args->buf) handle = OBEX_Init(OBEX_TRANS_CUSTOM, eventcb, 0); if (handle) { int ret = OBEX_RegisterCTransport(handle, &args->ctrans); if (ret == -1) { fprintf(stderr, "Registering OBEX custom transport failed\n"); OBEX_Cleanup(handle); handle = NULL; } else { if (OBEX_ServerRegister(handle, NULL, 0) < 0) { OBEX_Cleanup(handle); handle = NULL; fprintf(stderr, "Error: initialising standard-I/O server failed\n"); } else { OBEX_SetTransportMTU(handle, OBEX_MAXIMUM_MTU, OBEX_MAXIMUM_MTU); fprintf(stderr, "Listening on fd@%d:%d\n", args->in, args->out); } } } if (handle == NULL) { free(args->buf); args->buf = NULL; } return handle; } static void fdobex_cleanup ( struct net_handler *h ) { struct fdobex_args *args = h->args; #if HAS_SIGNALFD if (args->sig_fd != -1) { close(args->sig_fd); args->sig_fd = -1; } #endif if (args->buf) { free(args->buf); args->buf = NULL; } } static int fdobex_get_peer( struct net_handler __unused *h, obex_t __unused *handle, char* buffer, size_t bufsiz ) { return snprintf(buffer, bufsiz, "unknown"); } static int fdobex_get_listen_fd ( struct net_handler *h ) { struct fdobex_args *args = h->args; return args->in; } static enum net_life_status fdobex_life_status ( struct net_handler *h ) { struct fdobex_args *args = h->args; if (args->in == -1 || args->out == -1) return LIFE_STATUS_DEAD; else return LIFE_STATUS_ALIVE; } static struct net_handler_ops fdobex_ops = { .init = fdobex_init, .cleanup = fdobex_cleanup, .get_peer = fdobex_get_peer, .get_listen_fd = fdobex_get_listen_fd, .get_life_status = fdobex_life_status, }; struct net_handler* fdobex_setup( int in, int out, time_t __unused timeout ) { struct fdobex_args* args; struct net_handler *h = net_handler_alloc(&fdobex_ops, sizeof(*args)); if (!h) return NULL; args = h->args; args->in = in; args->out = out; fdobex_ctrans_set(&args->ctrans); args->ctrans.customdata = args; #if HAS_SIGNALFD (void)sigemptyset(&args->sig_mask); args->sig_fd = -1; #endif return h; } obexpushd-0.11.2-source/src/net/fdobex.h000644 001750 001750 00000000546 11537730263 021215 0ustar00hendrikhendrik000000 000000 #include "net.h" #include #ifndef HAS_SIGNALFD #define HAS_SIGNALFD 1 #endif #if HAS_SIGNALFD # include # include #endif struct fdobex_args { int in; int out; obex_ctrans_t ctrans; #if HAS_SIGNALFD sigset_t sig_mask; int sig_fd; #endif uint8_t *buf; }; void fdobex_ctrans_set (obex_ctrans_t *ctrans); obexpushd-0.11.2-source/src/net/fdobex_ctrans.c000644 001750 001750 00000004675 11537730263 022571 0ustar00hendrikhendrik000000 000000 #include "fdobex.h" #include #include #include "compiler.h" static int fdobex_ctrans_listen(obex_t __unused *handle, void * customdata) { struct fdobex_args *args = customdata; #if HAS_SIGNALFD args->sig_fd = signalfd(args->sig_fd, &args->sig_mask, SFD_CLOEXEC); if (args->sig_fd == -1) return -1; #endif if (args->in != -1) { (void)fcntl(args->in, F_SETFD, FD_CLOEXEC); } if (args->out != -1) { (void)fcntl(args->out, F_SETFD, FD_CLOEXEC); } return 0; } static int fdobex_ctrans_disconnect(obex_t __unused *handle, void *customdata) { struct fdobex_args *args = customdata; args->in = -1; args->out = -1; return 0; } static int fdobex_ctrans_read(obex_t __unused *handle, void *customdata, void *buf, int max) { struct fdobex_args *args = customdata; return (int)read(args->in, buf, max); } static int fdobex_ctrans_write(obex_t __unused *handle, void *customdata, uint8_t *buf, int buflen) { struct fdobex_args *args = customdata; return write(args->out, buf, buflen); } static int fdobex_ctrans_handleinput(obex_t *handle, void *customdata, int timeout) { struct fdobex_args *args = customdata; struct timeval time = { .tv_sec = timeout, .tv_usec = 0, }; struct timeval *timep = &time; fd_set fdset; int ret; int maxfd = 0; if (args->in == -1 || args->sig_fd == -1) return -1; FD_ZERO(&fdset); FD_SET(args->in, &fdset); if (args->in > maxfd) maxfd = args->in; #if HAS_SIGNALFD FD_SET(args->sig_fd, &fdset); if (args->sig_fd > maxfd) maxfd = args->sig_fd; #endif if (timeout < 0) timep = NULL; ret = select(maxfd+1, &fdset, NULL, NULL, timep); if (ret > 0) { if (FD_ISSET(args->in, &fdset)) { int n = fdobex_ctrans_read(handle, customdata, args->buf, OBEX_MAXIMUM_MTU); if (n > 0) ret = OBEX_CustomDataFeed(handle, args->buf, n); else { /* This can happens when the client disappears early */ OBEX_TransportDisconnect(handle); ret = -1; } #if HAS_SIGNALFD } else if (FD_ISSET(args->sig_fd, &fdset)) { struct signalfd_siginfo info; memset(&info, 0, sizeof(info)); (void)read(args->sig_fd, &info, sizeof(info)); if (info.ssi_signo == SIGHUP) { OBEX_TransportDisconnect(handle); ret = -1; } #endif } } return ret; } void fdobex_ctrans_set (obex_ctrans_t *ctrans) { ctrans->disconnect = fdobex_ctrans_disconnect; ctrans->listen = fdobex_ctrans_listen; ctrans->write = fdobex_ctrans_write; ctrans->handleinput = fdobex_ctrans_handleinput; } obexpushd-0.11.2-source/src/net/inobex.c000644 001750 001750 00000004714 11537730263 021226 0ustar00hendrikhendrik000000 000000 #include "net.h" #include #include #ifdef ENABLE_TCPWRAP #include int allow_severity; int deny_severity; #endif static obex_t* inet_init ( struct net_handler __unused *h, obex_event_t eventcb ) { obex_t* handle = OBEX_Init(OBEX_TRANS_INET,eventcb,OBEX_FL_KEEPSERVER); if (!handle) return NULL; { if (InOBEX_ServerRegister(handle) == -1) { perror("InOBEX_ServerRegister"); return NULL; } OBEX_SetTransportMTU(handle, OBEX_MAXIMUM_MTU, OBEX_MAXIMUM_MTU); fprintf(stderr,"Listening on tcp/*:650\n"); } return handle; } static int inet_security_check( struct net_handler *h, obex_t* ptr ) { #ifdef ENABLE_TCPWRAP int err = 1; int sock = OBEX_GetFD(ptr); struct sockaddr_in client, server; socklen_t len; struct request_info req; len = sizeof(client); err = getpeername(sock, (struct sockaddr*)&client, &len); if (err < 0) return 0; len = sizeof(server); err = getsockname(sock, (struct sockaddr*)&server, &len); if (err < 0) return 0; request_init(&req, RQ_FILE, sock, RQ_CLIENT_SIN, client, RQ_SERVER_SIN, server, RQ_DAEMON, "obexpushd"); fromhost(&req); return hosts_access(&req); #else return 1; #endif } static int inet_get_peer( struct net_handler __unused *h, obex_t* handle, char* buffer, size_t bufsiz ) { struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); char addrstr[INET6_ADDRSTRLEN]; uint16_t port; char tmp[256]; int status; int sock = OBEX_GetFD(handle); if (sock == -1) return -EBADF; status = getpeername(sock, (struct sockaddr*) &addr, &addrlen); if (status == -1) return -errno; memset(addrstr, 0, sizeof(addrstr)); switch (((struct sockaddr_in*)&addr)->sin_family) { case AF_INET: if (inet_ntop(AF_INET, &((struct sockaddr_in*)&addr)->sin_addr, addrstr, sizeof(addrstr)) == NULL) return -errno; port = ((struct sockaddr_in*)&addr)->sin_port; break; case AF_INET6: if (inet_ntop(AF_INET6, &((struct sockaddr_in6*)&addr)->sin6_addr, addrstr, sizeof(addrstr)) == NULL) return -errno; port = ((struct sockaddr_in6*)&addr)->sin6_port; break; default: return -EBADF; } status = snprintf(tmp, sizeof(tmp), "tcp/[%s]:%u", addrstr, port); if (buffer) strncpy(buffer, tmp, bufsiz); return status; } static struct net_handler_ops inet_ops = { .init = inet_init, .get_peer = inet_get_peer, .security_check = inet_security_check, }; struct net_handler* inet_setup() { return net_handler_alloc(&inet_ops, 0); } obexpushd-0.11.2-source/src/net/irobex.c000644 001750 001750 00000003524 11537730263 021230 0ustar00hendrikhendrik000000 000000 #include "net.h" #include "compiler.h" #include #include #include #include #include struct irda_args { char* service; }; static obex_t* irda_init ( struct net_handler *h, obex_event_t eventcb ) { struct irda_args* args = h->args; obex_t* handle = OBEX_Init(OBEX_TRANS_IRDA,eventcb,OBEX_FL_KEEPSERVER); if (!handle) return NULL; if (IrOBEX_ServerRegister(handle,args->service) == -1) { perror("IrOBEX_ServerRegister"); return NULL; } OBEX_SetTransportMTU(handle, OBEX_IRDA_OPT_MTU, OBEX_IRDA_OPT_MTU); fprintf(stderr,"Listening on IrDA service \"%s\"\n", args->service); return handle; } static int irda_get_peer( struct net_handler __unused *h, obex_t* handle, char* buffer, size_t bufsiz ) { struct sockaddr_irda addr; socklen_t addrlen = sizeof(addr); char tmp[256]; int status; int sock = OBEX_GetFD(handle); if (sock == -1) return -EBADF; status = getpeername(sock, (struct sockaddr*) &addr, &addrlen); if (status == -1) return -errno; if (addr.sir_family != AF_IRDA) return -EBADF; status = snprintf(tmp, sizeof(tmp), "irda/[%8X]%s%s", addr.sir_addr, (strlen(addr.sir_name)? ":": ""), addr.sir_name); if (buffer) strncpy(buffer, tmp, bufsiz); return status; } static struct net_handler_ops irda_ops = { .init = irda_init, .get_peer = irda_get_peer }; struct net_handler* irda_setup( char* service ) { struct irda_args* args; struct net_handler *h = net_handler_alloc(&irda_ops, sizeof(*args)); if (!h) return NULL; args = h->args; if (service) { size_t slen = 5 + strlen(service) + 1; char* s = malloc(slen); if (!s) { int err = errno; net_handler_cleanup(h); errno = err; return NULL; } (void)snprintf(s,slen,"OBEX:%s",service); args->service = s; } else { args->service = strdup("OBEX"); } return h; } obexpushd-0.11.2-source/src/net/publish/sdp.c000644 001750 001750 00000021064 11537730263 022173 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sdp.h" #include struct obex_sdp_data { uuid_t uuid_group; sdp_list_t* list_group; uuid_t uuid_l2cap; sdp_list_t* list_l2cap; uuid_t uuid_rfcomm; sdp_list_t* list_rfcomm; sdp_data_t* chan; uuid_t uuid_obex; sdp_list_t* list_obex; sdp_list_t* list_proto; sdp_list_t* list_access; }; static int bt_sdp_fill_l2cap (struct obex_sdp_data *data) { data->list_l2cap = sdp_list_append(NULL, sdp_uuid16_create(&data->uuid_l2cap, L2CAP_UUID)); if (!data->list_l2cap) return 0; data->list_proto = sdp_list_append(NULL, data->list_l2cap); if (!data->list_proto) return 0; return 1; } static int bt_sdp_fill_rfcomm (struct obex_sdp_data *data, uint8_t channel) { data->chan = sdp_data_alloc(SDP_UINT8, &channel); if (!data->chan) return 0; data->list_rfcomm = sdp_list_append(NULL, sdp_uuid16_create(&data->uuid_rfcomm, RFCOMM_UUID)); if (!data->list_rfcomm) return 0; data->list_rfcomm = sdp_list_append(data->list_rfcomm, data->chan); if (!data->list_rfcomm) return 0; data->list_proto = sdp_list_append(data->list_proto, data->list_rfcomm); if (!data->list_proto) return 0; return 1; } static int bt_sdp_fill_obex (struct obex_sdp_data *data, uint8_t channel) { data->list_group = sdp_list_append(NULL, sdp_uuid16_create(&data->uuid_group, PUBLIC_BROWSE_GROUP)); data->list_obex = sdp_list_append(NULL, sdp_uuid16_create(&data->uuid_obex, OBEX_UUID)); if (!data->list_group || !data->list_obex) return 0; if (!bt_sdp_fill_l2cap(data)) return 0; if (!bt_sdp_fill_rfcomm(data, channel)) return 0; data->list_proto = sdp_list_append(data->list_proto, data->list_obex); if (!data->list_proto) return 0; data->list_access = sdp_list_append(NULL, data->list_proto); if (!data->list_access) return 0; return 1; } static void bt_sdp_cleanup_obex(struct obex_sdp_data *data) { if (data->list_group) { sdp_list_free(data->list_group, 0); data->list_group = NULL; } if (data->list_l2cap) { sdp_list_free(data->list_l2cap, 0); data->list_l2cap = NULL; } if (data->list_rfcomm) { sdp_list_free(data->list_rfcomm, 0); data->list_rfcomm = NULL; } if (data->list_obex) { sdp_list_free(data->list_obex, 0); data->list_obex = NULL; } if (data->list_proto) { sdp_list_free(data->list_proto, 0); data->list_proto = NULL; } if (data->list_access) { sdp_list_free(data->list_access, 0); data->list_access = NULL; } if (data->chan) { sdp_data_free(data->chan); data->chan = NULL; } } static const char* SDP_SERVICE_PROVIDER = "obexpushd"; static const char* SDP_SERVICE_DESCR = "a free OBEX server"; static uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xFF }; static uint8_t fdtd = SDP_UINT8; struct obex_opp_sdp_data { struct obex_sdp_data obex; uuid_t uuid_class; sdp_list_t* list_class; sdp_profile_desc_t desc_srv; sdp_list_t* list_srv; void* dtds[sizeof(formats)]; void* values[sizeof(formats)]; sdp_data_t* list_formats; }; static int bt_sdp_fill_opp (struct obex_opp_sdp_data *data, uint8_t channel, sdp_record_t* rec) { if (!bt_sdp_fill_obex(&data->obex, channel)) return 0; sdp_set_browse_groups(rec, data->obex.list_group); sdp_set_access_protos(rec, data->obex.list_access); data->list_class = sdp_list_append(NULL, sdp_uuid16_create(&data->uuid_class, OBEX_OBJPUSH_SVCLASS_ID)); if (!data->list_class) return 0; sdp_set_service_classes(rec, data->list_class); sdp_uuid16_create(&data->desc_srv.uuid, OBEX_OBJPUSH_PROFILE_ID); data->desc_srv.version = 0x0100; data->list_srv = sdp_list_append(NULL, &data->desc_srv); if (!data->list_srv) return 0; sdp_set_profile_descs(rec, data->list_srv); for (size_t i = 0; i < sizeof(formats); ++i) { data->dtds[i] = &fdtd; data->values[i] = formats+i; } data->list_formats = sdp_seq_alloc(data->dtds, data->values, sizeof(formats)); if (!data->list_formats) return 0; sdp_attr_add(rec, SDP_ATTR_SUPPORTED_FORMATS_LIST, data->list_formats); sdp_set_info_attr(rec, "OBEX Object Push", SDP_SERVICE_PROVIDER, SDP_SERVICE_DESCR); return 1; } static void bt_sdp_cleanup_opp (struct obex_opp_sdp_data *data) { if (data->list_class) { sdp_list_free(data->list_class, 0); data->list_class = NULL; } if (data->list_srv) { sdp_list_free(data->list_srv, 0); data->list_srv = NULL; } //data->list_formats? bt_sdp_cleanup_obex(&data->obex); } struct obex_ftp_sdp_data { struct obex_sdp_data obex; uuid_t uuid_class; sdp_list_t* list_class; sdp_profile_desc_t desc_srv; sdp_list_t* list_srv; }; static int bt_sdp_fill_ftp (struct obex_ftp_sdp_data *data, uint8_t channel, sdp_record_t* rec) { if (!bt_sdp_fill_obex(&data->obex, channel)) return 0; sdp_set_browse_groups(rec, data->obex.list_group); sdp_set_access_protos(rec, data->obex.list_access); data->list_class = sdp_list_append(NULL, sdp_uuid16_create(&data->uuid_class, OBEX_FILETRANS_SVCLASS_ID)); if (!data->list_class) return 0; sdp_set_service_classes(rec, data->list_class); sdp_uuid16_create(&data->desc_srv.uuid, OBEX_FILETRANS_PROFILE_ID); data->desc_srv.version = 0x0100; data->list_srv = sdp_list_append(NULL, &data->desc_srv); if (!data->list_srv) return 0; sdp_set_profile_descs(rec, data->list_srv); sdp_set_info_attr(rec, "OBEX File Transfer", SDP_SERVICE_PROVIDER, SDP_SERVICE_DESCR); return 1; } static void bt_sdp_cleanup_ftp (struct obex_ftp_sdp_data *data) { if (data->list_class) { sdp_list_free(data->list_class, 0); data->list_class = NULL; } if (data->list_srv) { sdp_list_free(data->list_srv, 0); data->list_srv = NULL; } bt_sdp_cleanup_obex(&data->obex); } #define SDP_DATA_REC_COUNT 2 struct sdp_data { sdp_session_t* session; struct { sdp_record_t* handle; union { struct obex_opp_sdp_data opp; struct obex_ftp_sdp_data ftp; } prot; } rec[SDP_DATA_REC_COUNT]; }; static struct sdp_data* bt_sdp (bdaddr_t* device, uint8_t channel, unsigned long protocols) { struct sdp_data* data = malloc(sizeof(*data)); if (!data) return NULL; memset(data, 0, sizeof(*data)); data->session = sdp_connect(device, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); if (!data->session) { free(data); return NULL; } if ((protocols & BT_SDP_PROT_OBEX_PUSH) != 0) { data->rec[0].handle = sdp_record_alloc(); if (!data->rec[0].handle || !bt_sdp_fill_opp(&data->rec[0].prot.opp, channel, data->rec[0].handle)) { perror("Setting up OPP SDP entry failed"); bt_sdp_cleanup_opp(&data->rec[0].prot.opp); return NULL; } } if ((protocols & BT_SDP_PROT_OBEX_FTP) != 0) { data->rec[1].handle = sdp_record_alloc(); if (!data->rec[1].handle || !bt_sdp_fill_ftp(&data->rec[1].prot.ftp, channel, data->rec[1].handle)) { perror("Setting up FTP SDP entry failed"); if ((protocols & BT_SDP_PROT_OBEX_PUSH) != 0) bt_sdp_cleanup_opp(&data->rec[0].prot.opp); bt_sdp_cleanup_ftp(&data->rec[1].prot.ftp); return NULL; } } return data; } void* bt_sdp_session_open ( bdaddr_t* device, uint8_t channel, unsigned long protocols ) { int status = 0; struct sdp_data* data = bt_sdp(device, channel, protocols); if (!data) return NULL; for (int i = 0; i < SDP_DATA_REC_COUNT && status >= 0; ++i) { if (data->rec[i].handle == NULL) continue; status = sdp_device_record_register(data->session, device, data->rec[i].handle, 0); } if (status < 0) { bt_sdp_session_close(data, device); data = NULL; } return data; } void bt_sdp_session_close ( void* session_data, bdaddr_t* device ) { struct sdp_data* data = session_data; if (data->session == NULL) return; for (int i = 0; i < SDP_DATA_REC_COUNT; ++i) { if (data->rec[i].handle == NULL) continue; (void)sdp_device_record_unregister(data->session, device, data->rec[i].handle); data->rec[i].handle = NULL; if (i == 0) bt_sdp_cleanup_opp(&data->rec[0].prot.opp); else if (i == 1) bt_sdp_cleanup_ftp(&data->rec[1].prot.ftp); } sdp_close(data->session); data->session = NULL; free(data); } obexpushd-0.11.2-source/src/net/publish/sdp.h000644 001750 001750 00000000505 11537730263 022175 0ustar00hendrikhendrik000000 000000 #include #include #include #define BT_SDP_PROT_OBEX_PUSH (1 << 0) #define BT_SDP_PROT_OBEX_FTP (1 << 1) void* bt_sdp_session_open (bdaddr_t* device, uint8_t channel, unsigned long protocols); void bt_sdp_session_close (void* session_data, bdaddr_t* device); obexpushd-0.11.2-source/src/net/tcpobex.c000644 001750 001750 00000007217 11537730263 021407 0ustar00hendrikhendrik000000 000000 #include "net.h" #include "compiler.h" #include #include #include #include #include #include #ifdef ENABLE_TCPWRAP #include int allow_severity; int deny_severity; #endif struct tcp_args { char* address; uint16_t port; char* intf; }; static obex_t* tcp_init ( struct net_handler *h, obex_event_t eventcb ) { struct tcp_args* args = h->args; obex_t* handle = OBEX_Init(OBEX_TRANS_INET,eventcb,OBEX_FL_KEEPSERVER); if (!handle) return NULL; { union { struct sockaddr raw; struct sockaddr_in in4; struct sockaddr_in6 in6; } addr; char* addrstr = args->address; int af = AF_UNSPEC; if (!args->address || strcmp(args->address, "*") == 0) addrstr = "::"; if (!args->intf) { char* intf = strchr(addrstr, '%'); if (intf) { *intf = 0; args->intf = strdup(intf+1); } } if (inet_pton(AF_INET6, addrstr, &addr.in6.sin6_addr) == 1) { addr.raw.sa_family = AF_INET6; addr.in6.sin6_port = htons(args->port); addr.in6.sin6_flowinfo = 0; addr.in6.sin6_scope_id = 0; if (IN6_IS_ADDR_LINKLOCAL(&addr.in6.sin6_addr)) { if (args->intf) addr.in6.sin6_scope_id = if_nametoindex(args->intf); } } else if (inet_pton(AF_INET, args->address, &addr.in4.sin_addr) == 1) { addr.raw.sa_family = af = AF_INET; addr.in4.sin_port = htons(args->port); } else { return NULL; } if (TcpOBEX_ServerRegister(handle, &addr.raw, sizeof(addr)) == -1) { perror("TcpOBEX_ServerRegister"); return NULL; } OBEX_SetTransportMTU(handle, OBEX_MAXIMUM_MTU, OBEX_MAXIMUM_MTU); fprintf(stderr, "Listening on tcp/%s:%d\n", (args->address? args->address: "*"), args->port); } return handle; } static int tcp_security_check( struct net_handler __unused *h, obex_t *ptr ) { #ifdef ENABLE_TCPWRAP int err = 1; int sock = OBEX_GetFD(ptr); struct sockaddr_in6 client, server; socklen_t len; struct request_info req; len = sizeof(client); err = getpeername(sock, (struct sockaddr*)&client, &len); if (err < 0) return 0; len = sizeof(server); err = getsockname(sock, (struct sockaddr*)&server, &len); if (err < 0) return 0; request_init(&req, RQ_FILE, sock, RQ_CLIENT_SIN, client, RQ_SERVER_SIN, server, RQ_DAEMON, "obexpushd"); fromhost(&req); return hosts_access(&req); #else return 1; #endif } static int tcp_get_peer( struct net_handler __unused *h, obex_t* handle, char* buffer, size_t bufsiz ) { struct sockaddr_in6 addr; socklen_t addrlen = sizeof(addr); char addrstr[INET6_ADDRSTRLEN]; char tmp[256]; int status; int sock = OBEX_GetFD(handle); if (sock == -1) return -EBADF; status = getpeername(sock, (struct sockaddr*) &addr, &addrlen); if (status == -1) return -errno; if (addr.sin6_family != AF_INET6) return -EBADF; memset(addrstr, 0, sizeof(addrstr)); if (inet_ntop(AF_INET6, &addr.sin6_addr, addrstr, sizeof(addrstr)) == NULL) return -errno; status = snprintf(tmp, sizeof(tmp), "tcp/[%s]:%u", addrstr, addr.sin6_port); if (buffer) strncpy(buffer, tmp, bufsiz); return status; } static struct net_handler_ops tcp_ops = { .init = tcp_init, .get_peer = tcp_get_peer, .security_check = tcp_security_check, }; struct net_handler* tcp_setup( const char* address, uint16_t port ) { struct tcp_args* args; struct net_handler *h = net_handler_alloc(&tcp_ops, sizeof(*args)); if (!h) return NULL; args = h->args; if (address) { args->address = strdup(address); if (!args->address) { int err = errno; net_handler_cleanup(h); errno = err; return NULL; } } else args->address = NULL; args->port = port; args->intf = NULL; return h; } obexpushd-0.11.2-source/src/net/usbgobex.c000644 001750 001750 00000005450 11537730263 021556 0ustar00hendrikhendrik000000 000000 /* Information about the USB OBEX gadget device (Linux): * - SIGHUP is raised when the client is disconnected (e.g. cable removed) * - since USB CDC uses block transfers, a read must always offer a maximum size * buffer of 0xFFFF, the actual read data may be less * - the TTY device must be set into raw mode * - when the client is closing the connection, read() after select() will * return 0 bytes, the device file must be re-opened in this case * - expect freezes when using dummy_hcd.ko (something is wrong with it, 2.6.33) */ #include "compiler.h" #include "usbgobex.h" #include #include #include #include #include static obex_t* usb_gadget_init ( struct net_handler *h, obex_event_t eventcb ) { struct usb_gadget_args *args = h->args; obex_t *handle = NULL; args->buf = malloc(OBEX_MAXIMUM_MTU); if (args->buf) handle = OBEX_Init(OBEX_TRANS_CUSTOM, eventcb, 0); if (handle) { int ret = OBEX_RegisterCTransport(handle, &args->ctrans); if (ret == -1) { perror("OBEX_RegisterCTransport"); OBEX_Cleanup(handle); handle = NULL; } else { if (OBEX_ServerRegister(handle, NULL, 0) < 0) { OBEX_Cleanup(handle); handle = NULL; fprintf(stderr, "Error: cannot open %s: %s\n", args->device, strerror(errno)); } else { OBEX_SetTransportMTU(handle, OBEX_MAXIMUM_MTU, OBEX_MAXIMUM_MTU); fprintf(stderr, "Listening on file/%s\n", args->device); } } } if (handle == NULL) { free(args->buf); args->buf = NULL; } return handle; } static void usb_gadget_cleanup ( struct net_handler *h ) { struct usb_gadget_args *args = h->args; if (args->device) { free(args->device); args->device = NULL; } if (args->buf) { free(args->buf); args->buf = NULL; } } static int usb_gadget_get_peer( struct net_handler __unused *h, obex_t __unused *handle, char* buffer, size_t bufsiz ) { struct usb_gadget_args *args = h->args; return snprintf(buffer, bufsiz, "file/%s", args->device); } static int usb_gadget_get_listen_fd ( struct net_handler *h ) { struct usb_gadget_args *args = h->args; return args->fd; } static struct net_handler_ops usb_gadget_ops = { .init = usb_gadget_init, .cleanup = usb_gadget_cleanup, .get_peer = usb_gadget_get_peer, .get_listen_fd = usb_gadget_get_listen_fd, }; struct net_handler* usb_gadget_setup( const char* device, time_t timeout ) { struct usb_gadget_args* args; struct net_handler *h = net_handler_alloc(&usb_gadget_ops, sizeof(*args)); if (!h) return NULL; args = h->args; args->device = strdup(device); args->timeout = timeout; args->fd = -1; usbgobex_ctrans_set(&args->ctrans); args->ctrans.customdata = args; #if HAS_SIGNALFD (void)sigemptyset(&args->sig_mask); args->sig_fd = -1; #endif return h; } obexpushd-0.11.2-source/src/net/usbgobex.h000644 001750 001750 00000000601 11537730263 021554 0ustar00hendrikhendrik000000 000000 #include "net.h" #include #ifndef HAS_SIGNALFD #define HAS_SIGNALFD 1 #endif #if HAS_SIGNALFD # include # include #endif struct usb_gadget_args { char* device; time_t timeout; int fd; obex_ctrans_t ctrans; #if HAS_SIGNALFD sigset_t sig_mask; int sig_fd; #endif uint8_t *buf; }; void usbgobex_ctrans_set (obex_ctrans_t *ctrans); obexpushd-0.11.2-source/src/net/usbgobex_ctrans.c000644 001750 001750 00000006105 11537730263 023126 0ustar00hendrikhendrik000000 000000 #include "closexec.h" #include "compiler.h" #include "usbgobex.h" #include #include #include #include #include static int usbobex_ctrans_listen(obex_t __unused *handle, void * customdata) { int ret = -1; struct usb_gadget_args *args = customdata; #if HAS_SIGNALFD args->sig_fd = signalfd(args->sig_fd, &args->sig_mask, SFD_CLOEXEC); if (args->sig_fd == -1) return ret; #endif if (args->fd == -1) { args->fd = open_closexec(args->device, O_RDWR | O_NOCTTY, 0); if (args->fd != -1) { struct termios t; ret = tcgetattr(args->fd, &t); if (ret != -1) { cfmakeraw(&t); (void)tcsetattr(args->fd, 0, &t); (void)tcflush(args->fd, TCIOFLUSH); ret = 0; } } } return ret; } static int usbobex_ctrans_disconnect(obex_t *handle, void * customdata) { struct usb_gadget_args *args = customdata; /* re-initialize the file descriptors, else the select() will * always return after a very short time but read() returns 0. * tcflush() doesn't work. */ if (args->fd != -1) { close(args->fd); args->fd = -1; } #if HAS_SIGNALFD if (args->sig_fd != -1) { close(args->sig_fd); args->sig_fd = -1; } #endif (void)OBEX_ServerRegister(handle, NULL, 0); return 0; } static int usbobex_ctrans_read(obex_t __unused *handle, void *customdata, void *buf, int __unused max) { struct usb_gadget_args *args = customdata; return (int)read(args->fd, buf, OBEX_MAXIMUM_MTU); } static int usbobex_ctrans_write(obex_t __unused *handle, void *customdata, uint8_t *buf, int buflen) { struct usb_gadget_args *args = customdata; return write(args->fd, buf, buflen); } static int usbobex_ctrans_handleinput(obex_t *handle, void *customdata, int timeout) { struct usb_gadget_args *args = customdata; struct timeval time = { .tv_sec = timeout, .tv_usec = 0, }; struct timeval *timep = &time; fd_set fdset; int ret; int maxfd = 0; FD_ZERO(&fdset); FD_SET(args->fd, &fdset); if (args->fd > maxfd) maxfd = args->fd; #if HAS_SIGNALFD FD_SET(args->sig_fd, &fdset); if (args->sig_fd > maxfd) maxfd = args->sig_fd; #endif if (timeout < 0) timep = NULL; ret = select(maxfd+1, &fdset, NULL, NULL, timep); if (ret > 0) { if (FD_ISSET(args->fd, &fdset)) { int n = usbobex_ctrans_read(handle, customdata, args->buf, OBEX_MAXIMUM_MTU); if (n > 0) ret = OBEX_CustomDataFeed(handle, args->buf, n); else { /* This can happen when the client * disappears early */ OBEX_TransportDisconnect(handle); ret = -1; } #if HAS_SIGNALFD } else if (FD_ISSET(args->sig_fd, &fdset)) { struct signalfd_siginfo info; memset(&info, 0, sizeof(info)); (void)read(args->sig_fd, &info, sizeof(info)); if (info.ssi_signo == SIGHUP) { OBEX_TransportDisconnect(handle); ret = -1; } #endif } } return ret; } void usbgobex_ctrans_set (obex_ctrans_t *ctrans) { ctrans->disconnect = usbobex_ctrans_disconnect; ctrans->listen = usbobex_ctrans_listen; ctrans->write = usbobex_ctrans_write; ctrans->handleinput = usbobex_ctrans_handleinput; } obexpushd-0.11.2-source/src/obex_auth.h000644 001750 001750 00000003553 11537730263 021137 0ustar00hendrikhendrik000000 000000 #include #include #ifndef OBEX_AUTH_H #define OBEX_AUTH_H #define OBEX_AUTH_OPT_USER_REQ (1 << 0) /* request user identifier */ #define OBEX_AUTH_OPT_FULL_ACC (1 << 1) /* full access can be granted */ /** OBEX authentication challenge data */ struct obex_auth_challenge { /** NONCE value */ uint8_t nonce[16]; /** options, see OBEX_AUTH_OPT_* */ uint8_t opts; struct { /** points to the realm data * For Unicode characters, this must be in host byte order. */ const void *data; /** number of valid bytes in data */ size_t len; /** character set for data * The definition is the same as for IrDA IAS entries: * 0:ASCII, 1-9:ISO-8859-x, 255:Unicode */ uint8_t charset; } realm; }; /** OBEX authentication response data */ struct obex_auth_response { /** MD5 digest value */ uint8_t digest[16]; /** NONCE value */ uint8_t nonce[16]; /** user identification value */ const uint8_t *user; /** number of valid bytes in the 'user' field */ size_t ulen; }; /* * OBEX authentication helper */ int OBEX_AuthAddChallenges(obex_t *self, obex_object_t *object, const struct obex_auth_challenge *chal, unsigned int count); int OBEX_AuthUnpackResponse(const obex_headerdata_t h, uint32_t size, struct obex_auth_response *resp); int OBEX_AuthCheckResponse(const struct obex_auth_response *resp, const uint8_t *pass, size_t len); int OBEX_AuthUnpackChallenge(const obex_headerdata_t h, uint32_t hsize, struct obex_auth_challenge *chal, size_t csize); int OBEX_AuthChallenge2Response(obex_t *self, struct obex_auth_response *resp, const struct obex_auth_challenge *chal, const uint8_t *user, size_t ulen, const uint8_t *pass, size_t plen); int OBEX_AuthAddResponse(obex_t *self, obex_object_t *object, const struct obex_auth_response *resp); #endif /* OBEX_AUTH_H */ obexpushd-0.11.2-source/src/obex_auth/CMakeLists.txt000644 001750 001750 00000000214 11537730263 023515 0ustar00hendrikhendrik000000 000000 set(SOURCES core.c md5.c obex_auth.c ) set(HEADERS md5.h obex_auth.h ) add_library(obex_auth STATIC ${SOURCES} ${HEADERS} ) obexpushd-0.11.2-source/src/obex_auth/core.c000644 001750 001750 00000006757 11537730263 022073 0ustar00hendrikhendrik000000 000000 #include "obex_auth.h" #include "stdlib.h" #include "errno.h" /* remove this define when moving the code to openobex */ #define obex_return_val_if_fail(test, val) do { if (!(test)) return val; } while(0); /** Add the OBEX authentication challenge header \param self OBEX handle \param object OBEX object \param chal authentication challenge data \return 0 on success, else a negative error code value */ int OBEX_AuthAddChallenges(obex_t *self, obex_object_t *object, const struct obex_auth_challenge *chal, unsigned int count) { obex_return_val_if_fail(self != NULL, -EINVAL); obex_return_val_if_fail(object != NULL, -EINVAL); obex_return_val_if_fail(chal != NULL, -EINVAL); return obex_auth_add_challenges(self, object, chal, count); } /** Unpack the OBEX authentication reponse header \param h header data that contains the response header \param size size of the header data \param resp where to write the unpacked data to \return 0 on success, else a negative error code value */ int OBEX_AuthUnpackResponse(const obex_headerdata_t h, uint32_t size, struct obex_auth_response *resp) { obex_return_val_if_fail(resp != NULL, -EINVAL); return obex_auth_unpack_response(h, size, resp); } /** Check the obex authentication reponse \param resp the OBEX authentication response data \param pass the password to check against \param len length of pass \return 1 on success, 0 on failure */ int OBEX_AuthCheckResponse(const struct obex_auth_response *resp, const uint8_t *pass, size_t len) { obex_return_val_if_fail(resp != NULL, 0); return obex_auth_check_response(resp, pass, len); } /** Unpack the OBEX authentication challenge header \param h header data that contains the response header \param hsize size of the header data \param chal where to write the unpacked data to (array) \param csize array size of chal \return number of successfully unpacked challenges, else a negative error code value */ int OBEX_AuthUnpackChallenge(const obex_headerdata_t h, uint32_t hsize, struct obex_auth_challenge *chal, size_t csize) { obex_return_val_if_fail(chal != NULL, -EINVAL); return obex_auth_unpack_challenge(h, hsize, chal, csize); } /** Process a challenge and get the reponse \param self OBEX handle \param chal OBEX authentication challenge data \param resp where to write the OBEX authentication response data to \param get_pass callback to get the password from \return 0 on success, else a negative error code value */ int OBEX_AuthChallenge2Response(obex_t *self, struct obex_auth_response *resp, const struct obex_auth_challenge *chal, const uint8_t *user, size_t ulen, const uint8_t *pass, size_t plen) { obex_return_val_if_fail(self != NULL, -EINVAL); obex_return_val_if_fail(resp != NULL, -EINVAL); obex_return_val_if_fail(chal != NULL, -EINVAL); obex_return_val_if_fail(!user && ulen, -EINVAL); obex_return_val_if_fail(!pass && plen, -EINVAL); return obex_auth_challenge2response(self, resp, chal, user, ulen, pass, plen); } /** Add the OBEX authentication response header \param self OBEX handle \param object OBEX object \param resp authentication response data \return 0 on success, else a negative error code value */ int OBEX_AuthAddResponse(obex_t *self, obex_object_t *object, const const struct obex_auth_response *resp) { obex_return_val_if_fail(self != NULL, -EINVAL); obex_return_val_if_fail(object != NULL, -EINVAL); obex_return_val_if_fail(resp != NULL, -EINVAL); return obex_auth_add_response(self, object, resp); } obexpushd-0.11.2-source/src/obex_auth/md5.c000644 001750 001750 00000017310 11537730263 021613 0ustar00hendrikhendrik000000 000000 #include #include #include #include #include /* MD5 implementation according to OBEX specification * chapter 12.5 * Source: http://www.pbm.com/dice/rnd.txt * * Replaces: word32 -> uint32_t/size_t, byte -> uint8_t * and using inttypes.h; * using static where useful; * rearrange order of functions */ /* Send comments to: skrenta@pbm.com (Rich Skrenta) */ /* This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include "md5.h" /* * Shuffle the bytes into little-endian order within words, as per the * MD5 spec. Note: this code works regardless of the byte order. */ static void byteSwap(uint32_t *buf, unsigned int words) { uint8_t *p = (uint8_t *)buf; do { *buf++ = (uint32_t)((uint32_t)p[3] << 8 | p[2]) << 16 | ((uint32_t)p[1] << 8 | p[0]); p += 4; } while (--words != 0); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bytes[0] = 0; ctx->bytes[1] = 0; } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<>(32-s)) + x) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { register uint32_t a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, uint8_t const *buf, size_t len) { size_t t; /* Update byte count */ t = ctx->bytes[0]; if ((ctx->bytes[0] = t + len) < t) ctx->bytes[1]++; /* Carry from low to high */ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ if (t > len) { memcpy((uint8_t *)ctx->in + 64 - t, buf, len); return; } /* First chunk is an odd size */ memcpy((uint8_t *)ctx->in + 64 - t, buf, t); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += t; len -= t; /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(uint8_t digest[16], struct MD5Context *ctx) { ssize_t count = (ssize_t)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */ uint8_t *p = (uint8_t *)ctx->in + count; /* First unused byte */ /* Set the first char of padding to 0x80. There is always room. */ *p++ = 0x80; /* Bytes of padding needed to make 56 bytes (-8..55) */ count = 56 - 1 - count; if (count < 0) { /* Padding forces an extra block */ memset(p, 0, (size_t)count+8); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); p = (uint8_t *)ctx->in; count = 56; } memset(p, 0, (size_t)count+8); byteSwap(ctx->in, 14); /* Append length in bits and transform */ ctx->in[14] = ctx->bytes[0] << 3; ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; MD5Transform(ctx->buf, ctx->in); byteSwap(ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx,0,sizeof(ctx)); } void MD5(uint8_t* dest, uint8_t const *orig, size_t len) { struct MD5Context context; MD5Init(&context); MD5Update(&context, orig, len); MD5Final(dest, &context); } obexpushd-0.11.2-source/src/obex_auth/md5.h000644 001750 001750 00000000560 11537730263 021617 0ustar00hendrikhendrik000000 000000 #include #include struct MD5Context { uint32_t buf[4]; uint32_t bytes[2]; uint32_t in[16]; }; void MD5Init(struct MD5Context *ctx); void MD5Update(struct MD5Context *ctx, uint8_t const *buf, size_t len); void MD5Final(uint8_t digest[16], struct MD5Context *ctx); /* all-in-one */ void MD5(uint8_t* dest, uint8_t const *orig, size_t len); obexpushd-0.11.2-source/src/obex_auth/obex_auth.c000644 001750 001750 00000015512 11537730263 023106 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2008 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obex_auth.h" #include "md5.h" #if !defined(_WIN32) #include "arpa/inet.h" #endif #include #include #include #include "compiler.h" static void obex_auth_calc_digest (uint8_t digest[16], const uint8_t nonce[16], const uint8_t* pass, size_t len) { struct MD5Context context; MD5Init(&context); MD5Update(&context, nonce, 16); MD5Update(&context, (uint8_t*)":", 1); MD5Update(&context, pass, len); MD5Final(digest, &context); } /* Function for an OBEX server. */ int obex_auth_add_challenges (obex_t* handle, obex_object_t* obj, const struct obex_auth_challenge* chal, unsigned int count) { int err = 0; obex_headerdata_t ah; uint8_t* ptr; unsigned int realm_check = 1; uint32_t total = 0; unsigned int i; size_t l; for (i = 0; i < count; ++i) { total += 2 + sizeof(chal[0].nonce); if (chal[i].opts) total += 3; if (chal[i].realm.data && chal[i].realm.len) total += 3 + chal[i].realm.len; else { if (--realm_check == 0) return -EINVAL; } } ptr = malloc(total); if (!ptr) return -ENOMEM; for (i = 0; i < count; ++i) { /* add nonce */ *ptr++ = 0x00; *ptr++ = sizeof(chal[0].nonce); memcpy(ptr, chal[0].nonce, sizeof(chal[0].nonce)); ptr += sizeof(chal[0].nonce); if (chal[i].opts) { /* add flags */ *ptr++ = 0x01; *ptr++ = 0x01; *ptr++ = chal[i].opts; } /* add realm */ if (chal[i].realm.data && chal[i].realm.len) { *ptr++ = 0x02; *ptr++ = chal[i].realm.len; *ptr++ = chal[i].realm.charset; memcpy(ptr, chal[i].realm.data, chal[i].realm.len); if (chal[i].realm.charset == 0xFF) { for (l = 0; l < (chal[i].realm.len/2)*2; l += 2) { uint16_t c = htons((ptr[l] << 8) | ptr[l+1]); ptr[l] = (c >> 8) & 0xFF; ptr[l+1] = c & 0xFF; } } ptr += chal[i].realm.len; } }; ah.bs = ptr; errno = 0; if (0 > OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_AUTHCHAL, ah, (uint32_t)(ptr-ah.bs), OBEX_FL_FIT_ONE_PACKET)) err = ((errno != 0)? -errno: -EINVAL); ah.bs = NULL; free(ptr); return err; } int obex_auth_unpack_response (const obex_headerdata_t h, uint32_t size, struct obex_auth_response* resp) { uint32_t i = 0; for (; i < size; i += h.bs[i+1]+2) { uint8_t htype = h.bs[i]; uint8_t hlen = h.bs[i+1]; const uint8_t* hdata = h.bs+i+2; switch (htype){ case 0x00: /* digest */ if (hlen != sizeof(resp->digest)) return -EINVAL; memcpy(resp->digest,hdata,sizeof(resp->digest)); break; case 0x01: /* user ID */ { uint8_t *user = malloc(hlen); if (!user) return -ENOMEM; memcpy(user,hdata,hlen); resp->user = user; resp->ulen = (size_t)hlen; break; } case 0x02: /* nonce */ if (hlen != sizeof(resp->nonce)) return -EINVAL; memcpy(resp->nonce,hdata,sizeof(resp->nonce)); break; default: return -EINVAL; } } return 0; } int obex_auth_check_response (const struct obex_auth_response* resp, const uint8_t* pass, size_t len) { uint8_t d[16]; memset(d,0,sizeof(d)); obex_auth_calc_digest(d,resp->nonce,pass,len); if (memcmp(d,resp->digest,sizeof(d)) != 0) return 0; return 1; } /* Functions for an OBEX client. */ int obex_auth_unpack_challenge (const obex_headerdata_t h, uint32_t hsize, struct obex_auth_challenge* chal, size_t csize) { uint32_t i = 0; size_t k = 0; size_t l; for (; i < hsize; i += h.bs[i+1]+2) { uint8_t htype = h.bs[i]; size_t hlen = h.bs[i+1]; const uint8_t* hdata = h.bs+i+2; void *r = NULL;; switch (htype){ case 0x00: /* nonce */ if (k >= csize) return k; if (hlen != 16) return -EINVAL; ++k; memcpy(chal[k].nonce, hdata, 16); chal[k].opts = 0; memset(&chal[k].realm, 0, sizeof(chal[k].realm)); break; case 0x01: /* options */ if (hlen != 1) return -EINVAL; chal[k].opts = *hdata; break; case 0x02: /* realm */ if (hlen > 0) chal[k].realm.charset = *hdata; r = malloc(hlen); if (!r) return -errno; memcpy(r, hdata, hlen); if (chal[k].realm.charset == 0xFF) {/* Unicode */ uint16_t *r16 = r; for (l = 0; l < hlen/2; ++l) r16[l] = ntohs(r16[l]); } chal[k].realm.data = r; chal[k].realm.len = hlen; break; default: return -EINVAL; } } return k; } int obex_auth_challenge2response (obex_t __unused *handle, struct obex_auth_response* r, const struct obex_auth_challenge* c, const uint8_t *user, size_t ulen, const uint8_t *pass, size_t plen) { memcpy(r->nonce, c->nonce, sizeof(r->nonce)); obex_auth_calc_digest(r->digest, r->nonce, pass, plen); if (c->opts & OBEX_AUTH_OPT_USER_REQ) { uint8_t *u = malloc(ulen); if (!u) return -ENOMEM; memcpy(u, user, ulen); r->user = u; r->ulen = ulen; } else { r->user = NULL; r->ulen = 0; } return 0; } int obex_auth_add_response (obex_t* handle, obex_object_t* obj, const struct obex_auth_response* resp) { int err = 0; obex_headerdata_t ah; uint8_t* ptr; ah.bs = malloc(2+sizeof(resp->digest) + 2+resp->ulen + 2+sizeof(resp->nonce)); if (!ah.bs) return -ENOMEM; ptr = (uint8_t*)ah.bs; /* add digest */ *ptr++ = 0x00; *ptr++ = sizeof(resp->digest); memcpy(ptr,resp->digest,sizeof(resp->digest)); ptr += sizeof(resp->digest); /* add user */ if (resp->ulen) { *ptr++ = 0x01; *ptr++ = resp->ulen; memcpy(ptr,resp->user,resp->ulen); ptr += resp->ulen; } /* add nonce */ *ptr++ = 0x00; *ptr++ = sizeof(resp->nonce); memcpy(ptr,resp->nonce,sizeof(resp->nonce)); ptr += sizeof(resp->nonce); errno = 0; if (0 > OBEX_ObjectAddHeader(handle, obj, OBEX_HDR_AUTHRESP, ah, (uint32_t)(ptr-ah.bs), OBEX_FL_FIT_ONE_PACKET)) err = ((errno != 0)? -errno: -EINVAL); free((void*)ah.bs); return err; } obexpushd-0.11.2-source/src/obex_auth/obex_auth.h000644 001750 001750 00000001473 11537730263 023114 0ustar00hendrikhendrik000000 000000 #include "../obex_auth.h" int obex_auth_add_challenges ( obex_t* handle, obex_object_t* obj, const struct obex_auth_challenge* chal, unsigned int count ); int obex_auth_unpack_response ( const obex_headerdata_t h, uint32_t size, struct obex_auth_response* resp ); int obex_auth_check_response ( const struct obex_auth_response* resp, const uint8_t* pass, size_t len ); int obex_auth_unpack_challenge ( const obex_headerdata_t h, uint32_t hsize, struct obex_auth_challenge* chal, /*array*/ size_t csize ); int obex_auth_challenge2response ( obex_t* handle, struct obex_auth_response* r, const struct obex_auth_challenge* c, const uint8_t *user, size_t ulen, const uint8_t *pass, size_t plen ); int obex_auth_add_response ( obex_t* handle, obex_object_t* obj, const struct obex_auth_response* resp ); obexpushd-0.11.2-source/src/obexpush_atd.c000644 001750 001750 00000025740 11537730263 021643 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2010 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(USE_SPAWN) #include #endif #include "compiler.h" #include "version.h" #define VENDOR "Hendrik Sattler" #define MODEL "ObexPushD AT wrapper, use AT+CPROT=1 to CONNECT" #define REVISION OBEXPUSH_ATD_VERSION enum at_status { AT_STATUS_OK = 0, AT_STATUS_ERROR, }; static struct termios t; static char buffer[2048]; static size_t buflen; static char s3 = '\r'; static char s4 = '\n'; static char s5 = '\b'; static bool echo = true; static bool quiet = false; static bool verbose = true; static struct { const char *cmd; int argc; char **argv; } obex_server_def = { .cmd = NULL, .argc = 0, .argv = NULL, }; #define debug_print(line, ...) fprintf(stderr, line, ##__VA_ARGS__) static void print_line(const char *line) { debug_print("<- \"%s\" (verbose=%d)\n", line, verbose); if (verbose) { printf("%c%c%s%c%c", s3, s4, line, s3, s4); } else { printf("%s%c%c", line, s3, s4); } } static void print_result_code(const char *line, int code) { debug_print("<- \"%s\" (quiet=%d, verbose=%d)\n", line, quiet, verbose); if (!quiet) { if (verbose) { printf("%c%c%s%c%c", s3, s4, line, s3, s4); } else { printf("%d%c", code, s3); } } } static int at_none(const char __unused *cmd, size_t __unused cmdlen) { return AT_STATUS_OK; } static int at_reset(const char __unused *cmd, size_t __unused cmdlen) { s3 = '\r'; s4 = '\n'; s5 = '\b'; echo = true; quiet = false; verbose = true; return AT_STATUS_OK; } static int at_set_s(char *s, const char *cmd, size_t cmdlen) { if (cmd[cmdlen] == '=') { char *endptr; long value = strtol(cmd+cmdlen+1, &endptr, 10); if (cmd+cmdlen == endptr && 0 <= value && value <= CHAR_MAX) { *s = (char)value; return AT_STATUS_OK; } } else if (cmd[cmdlen] == '?') { char line[4]; snprintf(line, 4, "%03d", *s); print_line(line); return AT_STATUS_OK; } return AT_STATUS_ERROR; } static int at_set_s3(const char *cmd, size_t cmdlen) { return at_set_s(&s3, cmd, cmdlen); } static int at_set_s4(const char *cmd, size_t cmdlen) { return at_set_s(&s4, cmd, cmdlen); } static int at_set_s5(const char *cmd, size_t cmdlen) { return at_set_s(&s5, cmd, cmdlen); } static int at_disable_echo(const char __unused *cmd, size_t __unused cmdlen) { echo = false; return AT_STATUS_OK; } static int at_enable_echo(const char __unused *cmd, size_t __unused cmdlen) { echo = true; return AT_STATUS_OK; } static int at_disable_quiet(const char __unused *cmd, size_t __unused cmdlen) { quiet = false; return AT_STATUS_OK; } static int at_enable_quiet(const char __unused *cmd, size_t __unused cmdlen) { quiet = true; return AT_STATUS_OK; } static int at_disable_verbose(const char __unused *cmd, size_t __unused cmdlen) { verbose = false; return AT_STATUS_OK; } static int at_enable_verbose(const char __unused *cmd, size_t __unused cmdlen) { verbose = true; return AT_STATUS_OK; } static int at_me_vendor(const char *cmd, size_t cmdlen) { if (strlen(cmd+cmdlen) == 0) { print_line(VENDOR); return AT_STATUS_OK; } else return AT_STATUS_ERROR; } static int at_me_model(const char *cmd, size_t cmdlen) { if (strlen(cmd+cmdlen) == 0) { print_line(MODEL); return AT_STATUS_OK; } else return AT_STATUS_ERROR; } static int at_me_revision(const char *cmd, size_t cmdlen) { if (strlen(cmd+cmdlen) == 0) { print_line(REVISION); return AT_STATUS_OK; } else return AT_STATUS_ERROR; } static int start_obex_server(pid_t *p) { const char *cmd = obex_server_def.cmd; char **args = obex_server_def.argv; #if defined(USE_SPAWN) return posix_spawnp(p, cmd, NULL, NULL, args, environ); #else *p = fork(); if (*p == 0) { /* child */ execvp(cmd, args); perror("execvp"); exit(EXIT_FAILURE); } else { if (*p == -1) return errno; else return 0; } #endif } static int waitfor_obex_server(pid_t p) { int err; waitpid(p, &err, 0); return err; } static int init_obex_server_args (char *cmd) { obex_server_def.argv = malloc(2*sizeof(char*)); if (!obex_server_def.argv) return -errno; obex_server_def.cmd = cmd; obex_server_def.argv[obex_server_def.argc++] = cmd; obex_server_def.argv[obex_server_def.argc] = NULL; return 0; } static int add_obex_server_arg (char *arg) { size_t new_size; void *tmp; new_size = (obex_server_def.argc+2)*sizeof(char*); tmp = realloc(obex_server_def.argv, new_size); if (tmp == NULL) return -errno; obex_server_def.argv = tmp; obex_server_def.argv[obex_server_def.argc++] = arg; obex_server_def.argv[obex_server_def.argc] = NULL; return 0; } static int at_enter_protocol(const char *cmd, size_t cmdlen) { cmd += cmdlen; if (strcmp(cmd, "=?") == 0) { print_line("+CPROT: 0"); /* OBEX */ return AT_STATUS_OK; } else if (cmd[0] == '=') { pid_t p; int err; if (cmd[1] != '0' && cmd[2] != 0) return AT_STATUS_ERROR; err = start_obex_server(&p); if (err) { print_result_code("NO CARRIER", 3); return AT_STATUS_ERROR; } else { print_result_code("CONNECT", 1); waitfor_obex_server(p); return AT_STATUS_OK; } } return AT_STATUS_ERROR; } static void handle_at_command(const char *cmd) { static const struct { const char *cmd; int (*func)(const char*, size_t); } commands[] = { {"", &at_none}, {"E0", &at_disable_echo}, {"E1", &at_enable_echo}, {"Q0", &at_disable_quiet}, {"Q1", &at_enable_quiet}, {"S3", &at_set_s3}, {"S4", &at_set_s4}, {"S5", &at_set_s5}, {"V0", &at_disable_verbose}, {"V1", &at_enable_verbose}, {"Z", &at_reset}, {"&F0", &at_reset}, {"+GMI", &at_me_vendor}, {"+GMM", &at_me_model}, {"+GMR", &at_me_revision}, {"+CGMI", &at_me_vendor}, {"+CGMM", &at_me_model}, {"+CGMR", &at_me_revision}, {"+CPROT", &at_enter_protocol}, {NULL, NULL} /* last entry */ }; int err = AT_STATUS_ERROR; size_t i = 0; size_t cmdlen = 0; debug_print("-> \"AT%s\"\n", buffer); for (; commands[i].cmd; ++i) { size_t len = strlen(commands[i].cmd); if (strncasecmp(commands[i].cmd, cmd, len) == 0 && (cmd[len] == 0 || cmd[len] == '=' || cmd[len] == '?')) { cmdlen = len; break; } } if (commands[i].func) err = commands[i].func(cmd, cmdlen); switch (err) { case AT_STATUS_OK: print_result_code("OK", 0); break; case AT_STATUS_ERROR: print_result_code("ERROR", 4); break; default: break; } } static int handle_input() { size_t state = 0; for (;;) { ssize_t result; char buf[128]; bool valid = true; result = read(STDIN_FILENO, buf, sizeof(buf)); if (result < 0) { return -errno; } else if (result == 0) { return -EPIPE; } for (ssize_t i = 0; i < result; ++i) { if (state == 0) { if (buf[i] == 'A') { state = 1; } else { valid = false; } } else if (state == 1) { if (buf[i] == 'T') { state = 2; memset(buffer, 0, buflen); buflen = 0; } else if (buf[i] == '/') { handle_at_command(buffer); state = 0; } else { state = 0; } } else { if (buf[i] == s3) { handle_at_command(buffer); state = 0; } else if (buf[i] == s5) { if (buflen > 0) buffer[buflen--] = 0; else state = 1; } else { if (buflen+1 < sizeof(buffer)) buffer[buflen++] = buf[i]; else valid = false; } } if (valid && echo) (void)write(STDOUT_FILENO, &buf[i], 1); } } return 0; } static int open_tty_device(const char *device) { int fd; fd = open(device, O_RDWR | O_NOCTTY, 0); if (fd == -1) return -errno; if (isatty(fd)) { if (tcgetattr(fd, &t) == -1) return -errno; cfmakeraw(&t); t.c_cc[VMIN] = 255; t.c_cc[VTIME] = 1; } fclose(stdin); dup2(fd, STDIN_FILENO); if (isatty(fd)) { (void)tcsetattr(STDIN_FILENO, 0, &t); (void)tcflush(STDIN_FILENO, TCIFLUSH); } stdin = fdopen(STDIN_FILENO, "r"); fclose(stdout); dup2(fd, STDOUT_FILENO); if (isatty(fd)) { (void)tcsetattr(STDOUT_FILENO, 0, &t); (void)tcflush(STDOUT_FILENO, TCIFLUSH); } stdout = fdopen(STDOUT_FILENO, "w"); close(fd); return 0; } static void print_disclaimer () { fprintf(stderr, "ObexPushD AT wrapper " REVISION " Copyright (C) 2010 Hendrik Sattler\n" "This software comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions.\n"); } static void print_help (char* me) { print_disclaimer(); printf("\n"); printf("Usage: %s []\n", me); printf("\n" "Options:\n" " -S use device for I/O (default: stdin/stdout)\n" " -d enable debug output\n" " -X add an extra option for submodes\n" " -h this help message\n" " -v show version\n"); printf("\n" "See manual page %s(1) for details.\n",me); } static void print_version (char* me) { printf("%s %s\n", me, REVISION); if (!add_obex_server_arg("-v")) { pid_t p; start_obex_server(&p); (void)waitfor_obex_server(p); } } int main(int argc, char **argv) { int c = 0; const char *device = NULL; bool debug = false; if (init_obex_server_args("obexpushd")) return EXIT_FAILURE; while (c != -1) { c = getopt(argc, argv, "S:dX:hv"); switch (c) { case -1: /* processed all options, no error */ break; case 'S': /* any TTY device */ device = optarg; break; case 'd': debug = true; break; case 'X': if (optarg && strlen(optarg) > 2 && optarg[0] == 'o' && optarg[1] == ',') { add_obex_server_arg(optarg+2); } break; case 'h': print_help("obexpush_atd"); exit(EXIT_SUCCESS); case 'v': print_version("obexpush_atd"); exit(EXIT_SUCCESS); default: break; } } if (add_obex_server_arg("-S")) return EXIT_FAILURE; if (!debug) fclose(stderr); print_disclaimer(); if (device) { debug_print("Using device \"%s\"\n", device); if (open_tty_device(device)) { perror("Opening device failed"); return EXIT_FAILURE; } } else { debug_print("Using %s\n", "stdin/stdout"); } if (handle_input()) { perror("Reading from device failed"); return EXIT_FAILURE; } return EXIT_SUCCESS; } obexpushd-0.11.2-source/src/obexpushd.c000644 001750 001750 00000034313 11537730263 021153 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "obex_auth.h" #include "obexpushd.h" #include "io.h" #include "utf.h" #include "net.h" #include "action.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PROGRAM_NAME "obexpushd" #include "version.h" #include "compiler.h" /* global settings */ int debug = 0; static int nofork = 0; static int id = 0; static struct auth_handler* auth = NULL; static struct io_handler* io = NULL; #define EOL(n) ((n) == '\n' || (n) == '\r') void dbg_printf (file_data_t *data, const char *format, ...) { if (debug) { va_list ap; if (data) { if (data->count) (void)fprintf(stderr, "%u.%u: ", data->id, data->count); else (void)fprintf(stderr, "%u: ", data->id); } va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } } static const char* obex_event_string(uint8_t event) { static const char* obex_events[] = { "PROGRESS", "REQHINT", "REQ", "REQDONE", "LINKERR", "PARSEERR", "ACCEPTHINT", "ABORT", "STREAMEMPTY", "STREAMAVAIL", "UNEXPECTED", "REQCHECK", }; return obex_events[event]; } static const char* obex_command_string(uint8_t cmd) { static const char* obex_commands[] = { "CONNECT", "DISCONNECT", "PUT", "GET", "SETPATH", "SESSION", "ABORT" }; switch (cmd) { case OBEX_CMD_CONNECT: case OBEX_CMD_DISCONNECT: case OBEX_CMD_PUT: case OBEX_CMD_GET: return obex_commands[cmd]; case OBEX_CMD_SETPATH: return obex_commands[4]; case OBEX_CMD_SESSION: return obex_commands[5]; case OBEX_CMD_ABORT: return obex_commands[6]; default: return "UNKNOWN"; } } void obex_send_response (file_data_t* data, obex_object_t* obj, uint8_t respCode) { dbg_printf(data, "Sending response code %u\n", ((respCode >> 4) * 100) + (respCode & 0xF)); switch (respCode) { case 0: case OBEX_RSP_CONTINUE: case OBEX_RSP_SUCCESS: (void)OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); break; default: (void)OBEX_ObjectSetRsp(obj, respCode, respCode); break; } } static void client_eventcb (obex_t* handle, obex_object_t* obj, int mode, int event, int obex_cmd, int obex_rsp) { file_data_t* data = OBEX_GetUserData(handle); if (debug) dbg_printf(data, "OBEX_EV_%s, OBEX_CMD_%s\n", obex_event_string(event), obex_command_string(obex_cmd)); obex_action_eventcb(handle, obj, mode, event, obex_cmd, obex_rsp); } static file_data_t* create_client (struct net_data *net) { file_data_t* data = malloc(sizeof(*data)); if (data) { memset(data,0,sizeof(*data)); data->id = id++; data->net_data = net; data->auth = auth_copy(auth); data->io = io_copy(io); } return data; } static void cleanup_client (file_data_t *data) { if (data->transfer.peername) { free(data->transfer.peername); data->transfer.peername = NULL; } if (data->transfer.name) { free(data->transfer.name); data->transfer.name = NULL; } if (data->transfer.path) { free(data->transfer.path); data->transfer.path = NULL; } if (data->transfer.type) { free(data->transfer.type); data->transfer.type = NULL; } if (data->auth) { auth_destroy(data->auth); data->auth = NULL; } if (data->io) { io_destroy(data->io); data->io = NULL; } free(data); } static void* handle_client (void* arg) { obex_t *obex = arg; struct net_data *old_net = OBEX_GetUserData(obex); file_data_t *data = create_client(old_net); if (data) { /* create new net_data for this client */ struct net_data *net = net_data_new(); if (net) { char buffer[256]; memcpy(net, data->net_data, sizeof(*net)); net->obex = obex; data->net_data = net; OBEX_SetUserData(obex, data); memset(buffer, 0, sizeof(buffer)); net_get_peer(data->net_data, buffer, sizeof(buffer)); dbg_printf(data, "Connection from \"%s\"\n", buffer); data->transfer.peername = strdup(buffer); do { if (OBEX_HandleInput(data->net_data->obex, 10) < 0) break; } while (1); } if (data->net_data) { OBEX_Cleanup(data->net_data->obex); free(data->net_data); } cleanup_client(data); } return NULL; } int obexpushd_create_instance (void* (*cb)(void*), void *cbdata); int obexpushd_start (struct net_data *data, unsigned int count); static void create_instance (void* (*cb)(void*), void *cbdata) { if (nofork >= 2) { (void)cb(cbdata); } else { int err = obexpushd_create_instance(cb, cbdata); if (err != 0) { errno = -err; perror("Failed to create instance"); } } } static void eventcb (obex_t* handle, obex_object_t __unused *obj, int mode, int event, int obex_cmd, int obex_rsp) { dbg_printf(NULL, "OBEX_EV_%s, OBEX_CMD_%s\n", obex_event_string(event), obex_command_string(obex_cmd)); if (event == OBEX_EV_ACCEPTHINT) { obex_t *client = OBEX_ServerAccept(handle, client_eventcb, NULL); if (client) { int fd; fd = OBEX_GetFD(client); if (fd >= 0) (void)fcntl(fd, F_SETFD, FD_CLOEXEC); create_instance(handle_client, client); } } else { file_data_t *data; struct net_data *net; /* This handles connections that can only handle one client at a time. */ if (event == OBEX_EV_REQHINT && obex_cmd == OBEX_CMD_CONNECT) { net = OBEX_GetUserData(handle); data = create_client(net); OBEX_SetUserData(handle, data); } else { data = OBEX_GetUserData(handle); net = data->net_data; } obex_action_eventcb(handle, obj, mode, event, obex_cmd, obex_rsp); if (event == OBEX_EV_REQDONE && obex_cmd == OBEX_CMD_DISCONNECT) { OBEX_SetUserData(handle, net); cleanup_client(data); } } } #if defined(USE_THREADS) #include "pthreads.c" #else #include "fork.c" #endif static void print_disclaimer () { fprintf(stderr, PROGRAM_NAME " " OBEXPUSHD_VERSION " Copyright (C) 2006-2010 Hendrik Sattler\n" "This software comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions.\n"); } static void print_help (char* me) { print_disclaimer(); printf("\n"); printf("Usage: %s [] []\n", me); printf("\n" "Interfaces:\n" " -B[] listen to bluetooth connections (default: channel 9)\n" " -I[] listen to IrDA connections (app example: IrXfer)\n" #if OPENOBEX_TCPOBEX " -N[] listen to IPv4/v6 network connections (default: port 650)\n" #else " -N listen to IPv4 network connections on port 650\n" #endif #ifdef USB_GADGET_SUPPORT " -G listen on an USB gadget device file\n" #endif " -S handle one connection via stdin/stdout\n" "\n" "Options:\n" " -n do not detach from terminal\n" " -d enable debug messages (implies -n)\n" " -p write pid to file when getting detached\n" " -A use transport layer specific access rules if available\n" " -a authenticate against credentials from file (EXPERIMENTAL)\n" " -o change base directory\n" " -s define script/program for input/output\n" " -t add a protocol (OPP, FTP)\n" " -h this help message\n" " -v show version\n"); printf("\n" "See manual page %s(1) for details.\n",me); } static char* parse_bluetooth_arg (char* optarg, uint8_t* btchan) { char* tmp; char* device = NULL; if (strlen(optarg) >= 19 && optarg[0] == '[' && optarg[18] == ']') { device = optarg+1; device[17] = 0; tmp = optarg+19; } else if (strncmp(optarg, "hci", 3) == 0) { device = optarg; tmp = strchr(optarg, (int)':'); } else { tmp = optarg; } if (tmp) { long arg = 0; if (*tmp == ':') { *tmp = 0; ++tmp; } arg = strtol(tmp, NULL, 10); if (0 < arg && arg < (1 << 8)) *btchan = (uint8_t)arg; } return device; } #if OPENOBEX_TCPOBEX static char* parse_ip_arg (char* optarg, uint16_t* port) { char* device = NULL; char* tmp = strchr(optarg, (int)']'); if (tmp && optarg[0] == '[') { /* IPv6 address */ device = optarg+1; *tmp = 0; ++tmp; } else if (strchr(optarg, (int)'.') != NULL) { /* IPv4 address */ device = optarg; tmp = strchr(optarg, (int)':'); } else if (optarg[0] == '*' && optarg[1] == ':') { device = optarg; tmp = optarg+1; } else { /* no address */ tmp = optarg; } if (tmp) { long portnum = 0; if (*tmp == ':') { *tmp = 0; ++tmp; } portnum = strtol(tmp, NULL, 10); if (portnum > 0 && portnum < (1 << 16)) *port = portnum; } return device; } #endif enum net_index { IDX_BT = 0, IDX_IRDA, IDX_IRDA_EXTRA, IDX_INET, #ifdef USB_GADGET_SUPPORT IDX_GADGET, #endif IDX_STDIO, NET_INDEX_MAX }; static struct net_data data[NET_INDEX_MAX]; static void obexpushd_shutdown (int sig) { size_t i; (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTERM, SIG_DFL); for (i = 0; i < NET_INDEX_MAX; ++i) net_cleanup(&data[i]); (void)kill(getpid(), sig); } int main (int argc, char** argv) { size_t i; char* pidfile = NULL; uint8_t auth_level = 0; int c = 0; struct net_handler* handle[NET_INDEX_MAX]; uint8_t protocols = 0; (void)setlocale(LC_CTYPE, ""); io = io_file_init("."); for (i = 0; i < NET_INDEX_MAX; ++i) { handle[i] = NULL; } memset(data, 0, sizeof(data)); while (c != -1) { c = getopt(argc,argv,"B::I::N::G:SAa:dhnp:r:o:s:t:v"); switch (c) { case -1: /* processed all options, no error */ break; case 'B': { char* device = NULL; uint8_t btchan = 9; if (handle[IDX_BT]) net_handler_cleanup(handle[IDX_BT]); if (optarg) { device = parse_bluetooth_arg(optarg, &btchan); } handle[IDX_BT] = bluetooth_setup(device, btchan); if (!handle[IDX_BT]) { perror("Setting up bluetooth failed"); } break; } case 'I': if (handle[IDX_IRDA_EXTRA]) { net_handler_cleanup(handle[IDX_IRDA_EXTRA]); handle[IDX_IRDA_EXTRA] = NULL; } if (handle[IDX_IRDA]) net_handler_cleanup(handle[IDX_IRDA]); handle[IDX_IRDA] = irda_setup(NULL); if (!handle[IDX_IRDA]) { perror("Setting up IrDA failed"); } if (optarg) { handle[IDX_IRDA_EXTRA] = irda_setup(optarg); if (!handle[IDX_IRDA_EXTRA]) { perror("Setting up IrDA failed"); } } break; case 'N': { #if OPENOBEX_TCPOBEX char* address = NULL; uint16_t port = 650; if (optarg) { address = parse_ip_arg(optarg, &port); } #endif if (handle[IDX_INET]) net_handler_cleanup(handle[IDX_INET]); #if OPENOBEX_TCPOBEX handle[IDX_INET] = tcp_setup(address, port); #else handle[IDX_INET] = inet_setup(); #endif if (!handle[IDX_INET]){ perror("Setting up TCP failed"); } break; } #ifdef USB_GADGET_SUPPORT case 'G': if (optarg) { if (handle[IDX_GADGET]) net_handler_cleanup(handle[IDX_GADGET]); handle[IDX_GADGET] = usb_gadget_setup(optarg, 0); } break; #endif case 'S': if (handle[IDX_STDIO]) net_handler_cleanup(handle[IDX_STDIO]); handle[IDX_STDIO] = fdobex_setup(STDIN_FILENO, STDOUT_FILENO, 0); break; case 'd': debug = 1; /* no break */ case 'n': ++nofork; break; case 'p': pidfile = optarg; break; case 'A': auth_level |= AUTH_LEVEL_TRANSPORT; break; case 'a': if (auth) auth_destroy(auth); auth = auth_file_init(optarg, NULL, OBEX_AUTH_OPT_USER_REQ); auth_level |= AUTH_LEVEL_OBEX; break; case 'r': fprintf(stderr, "This version does not support obex server authentication.\n"); return EXIT_FAILURE; break; case 'o': if (io) io_destroy(io); io = io_file_init(optarg); break; case 's': if (io) io_destroy(io); io = io_script_init(optarg); break; case 't': if (optarg) { if (strcasecmp(optarg, "FTP") == 0) protocols |= (1 << NET_OBEX_FTP); } break; case 'h': print_help(PROGRAM_NAME); exit(EXIT_SUCCESS); case 'v': printf("%s %s\n", PROGRAM_NAME, OBEXPUSHD_VERSION); exit(EXIT_SUCCESS); } } /* check that the file/script output is valid */ if (!io) { fprintf(stderr, "Invalid output options\n"); exit(EXIT_SUCCESS); } /* check that at least one listener was enabled */ for (i = 0; i < NET_INDEX_MAX; ++i) { if (handle[i]) break; } if (i == NET_INDEX_MAX) { handle[IDX_BT] = bluetooth_setup(NULL, 9); if (!handle[IDX_BT]) { perror("Setting up bluetooth failed"); exit(EXIT_FAILURE); } } /* fork if allowed (detach from terminal) */ if (nofork < 1 && !handle[IDX_STDIO]) { if (daemon(1,0) < 0) { perror("daemon()"); exit(EXIT_FAILURE); } if (pidfile) { FILE* p = fopen(pidfile,"w+"); if (p) { fprintf(p,"%u\n",(unsigned int)getpid()); (void)fclose(p); } } } else { print_disclaimer(); if (strcasecmp(nl_langinfo(CODESET), "UTF-8") != 0) fprintf(stderr, "Warning: local character set is not Unicode.\n"); } /* setup the signal handlers */ (void)signal(SIGINT, obexpushd_shutdown); (void)signal(SIGTERM, obexpushd_shutdown); protocols |= (1 << NET_OBEX_PUSH); /* initialize all enabled listeners */ for (i = 0; i < NET_INDEX_MAX; ++i) { if (!handle[i]) continue; data[i].handler = handle[i]; data[i].auth_level = auth_level; data[i].enabled_protocols = protocols; } if (obexpushd_start(data, NET_INDEX_MAX) != 0) perror("Failed to start"); /* never reached */ return EXIT_FAILURE; } obexpushd-0.11.2-source/src/obexpushd.h000644 001750 001750 00000003057 11537730263 021161 0ustar00hendrikhendrik000000 000000 #ifndef OBEXPUSHD_H #define OBEXPUSHD_H #include #include #include #include #include #include #include "io.h" enum obex_target { OBEX_TARGET_OPP = 0, /* ObjectPush */ OBEX_TARGET_FTP, /* File Browsing Service */ OBEX_TARGET_MAX_NB }; struct obex_target_ops; /* private data for a client connection */ typedef struct { unsigned int id; unsigned int count; uint8_t error; uint8_t buffer[1000]; enum obex_target target; const struct obex_target_ops *target_ops; int command; struct net_data* net_data; struct auth_handler *auth; struct io_handler *io; struct io_transfer_data transfer; } file_data_t; struct obex_target_event_ops { void (*request_hint)(file_data_t*, obex_object_t*); void (*request_check)(file_data_t*, obex_object_t*); void (*request)(file_data_t*, obex_object_t*); void (*request_done)(file_data_t*, obex_object_t*); void (*stream_in)(file_data_t*, obex_object_t*); void (*stream_out)(file_data_t*, obex_object_t*); void (*error)(file_data_t*, obex_object_t*, int); }; struct obex_target_ops { const struct obex_target_event_ops *post_connect; const struct obex_target_event_ops *put; const struct obex_target_event_ops *get; const struct obex_target_event_ops *setpath; const struct obex_target_event_ops *pre_disconnect; }; void obex_send_response (file_data_t* data, obex_object_t* obj, uint8_t respCode); extern int debug; void dbg_printf (file_data_t *data, const char *format, ...) __attribute__((format(printf,2,3))); #endif obexpushd-0.11.2-source/src/pipe.c000644 001750 001750 00000005471 11537730263 020112 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006-2007 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pipe.h" #include #include #include #include #include #include #include #include #include #if defined(USE_SPAWN) #include #endif #include "closexec.h" void pipe_close (int client_fds[2]) { if (client_fds) { close(client_fds[0]); close(client_fds[1]); } } int pipe_open ( const char* command, char** args, int client_fds[2], pid_t *pid ) { int fds[2][2] = {{ -1, -1 }, {-1, -1}}; #define PIPE_CLIENT_STDIN fds[0][0] #define PIPE_SERVER_WRITE fds[0][1] #define PIPE_SERVER_READ fds[1][0] #define PIPE_CLIENT_STDOUT fds[1][1] int err = 0; pid_t p; #if defined(USE_SPAWN) posix_spawn_file_actions_t actions; #endif if (pipe_closexec(fds[0]) == -1) return -errno; if (pipe_closexec(fds[1]) == -1) { err = errno; pipe_close(fds[0]); return -err; } #if defined(USE_SPAWN) /* In theory, using spawn() is more efficient that fork()+exec(). */ if (posix_spawn_file_actions_init(&actions) || posix_spawn_file_actions_adddup2(&actions, PIPE_CLIENT_STDIN, STDIN_FILENO) || posix_spawn_file_actions_adddup2(&actions, PIPE_CLIENT_STDOUT, STDOUT_FILENO) || posix_spawnp(&p, command, &actions, NULL, args, environ) || posix_spawn_file_actions_destroy(&actions)) { #else p = fork(); if (p == 0) { /* child */ if (PIPE_CLIENT_STDIN != STDIN_FILENO) { if (dup2(PIPE_CLIENT_STDIN, STDIN_FILENO) < 0) { perror("dup2"); exit(EXIT_FAILURE); } } if (PIPE_CLIENT_STDOUT != STDOUT_FILENO) { if (dup2(PIPE_CLIENT_STDOUT, STDOUT_FILENO) < 0) { perror("dup2"); exit(EXIT_FAILURE); } } execvp(command, args); perror("execvp"); exit(EXIT_FAILURE); } else if (p == -1) { #endif err = errno; pipe_close(fds[0]); pipe_close(fds[1]); return -err; } /* parent */ close(PIPE_CLIENT_STDIN); close(PIPE_CLIENT_STDOUT); if (client_fds) { client_fds[0] = PIPE_SERVER_READ; client_fds[1] = PIPE_SERVER_WRITE; } if (pid) *pid = p; return 0; } obexpushd-0.11.2-source/src/pipe.h000644 001750 001750 00000000216 11537730263 020107 0ustar00hendrikhendrik000000 000000 #include int pipe_open (const char* command, char** args, int client_fds[2], pid_t *pid); void pipe_close (int client_fds[2]); obexpushd-0.11.2-source/src/pthreads.c000644 001750 001750 00000002770 11537730263 020766 0ustar00hendrikhendrik000000 000000 #include int obexpushd_create_instance (void* (*cb)(void*), void *cbdata) { pthread_t t; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (pthread_create(&t, &attr, cb, cbdata) != 0) return -errno; return 0; } static void obexpushd_listen_thread_cleanup (void* arg) { net_cleanup(arg); } static void* obexpushd_listen_thread (void* arg) { struct net_data* data = arg; pthread_cleanup_push(obexpushd_listen_thread_cleanup, arg); net_init(data, eventcb); if (!data->obex) { fprintf(stderr, "net_init() failed\n"); pthread_exit(NULL); } do { if (OBEX_HandleInput(data->obex, 3600) < 0) { /* OpenOBEX sometimes return -1 anyway, must be a bug * thus the break is commented -> go on anyway except * when the transport is dead (e.g. one-shot). */ if (net_get_life_status(data) == LIFE_STATUS_DEAD) break; } } while (1); pthread_cleanup_pop(1); return NULL; } int obexpushd_start (struct net_data *data, unsigned int count) { unsigned int i; pthread_t *thread = calloc(count, sizeof(*thread)); if (!thread) return -errno; /* initialize all enabled listeners */ for (i = 0; i < count; ++i) { if (!data[i].handler) continue; if (pthread_create(&thread[i], NULL, obexpushd_listen_thread, &data[i]) != 0) perror("pthread_create()"); } for (i = 0; i < count; ++i) { if (data[i].handler) { void* retval; pthread_join(thread[i], &retval); } } free(thread); pthread_exit(NULL); } obexpushd-0.11.2-source/src/storage/file_storage.sh000755 001750 001750 00000003552 11537730263 023455 0ustar00hendrikhendrik000000 000000 #!/bin/bash set -e #DIALOG=Xdialog --default-no DIALOG=kdialog ROOT_PATH="" # # compatible with obexpushd >= 0.6 # MODE="$1" FROM="" NAME="" SUB_PATH="${ROOT_PATH}./" LENGTH="0" MIMETYPE="" while read LINE; do echo "${LINE}" 1>&2 if ( test -z "${LINE}" ); then break fi TAG=$(echo "${LINE}" | cut -f 1 -d ":") VALUE=$(echo "${LINE}" | cut -f 2- -d " ") case $TAG in From) FROM="${VALUE}";; Name) NAME="${VALUE}";; Path) SUB_PATH="${ROOT_PATH}${VALUE}/";; Length) LENGTH="${VALUE}";; Type) MIMETYPE="${VALUE}";; esac done case "${MODE}" in put) FILE="${SUB_PATH}${NAME}" echo "script: testing ${FILE}..." 1>&2 test -z "${FILE}" && exit 1 echo "script: testing for existence of ${FILE}..." 1>&2 test -e "${FILE}" && exit 1 #tell obexpushd to go on echo "script: asking user for permission..." 1>&2 ${DIALOG} --title "Obex-Push" \ --yesno \ "Allow receiving the file\n\"${FILE}\"\n(${LENGTH} bytes) from\n${FROM}" \ 10 40 if ( test "$?" -eq "0" ); then echo "OK" else echo "ABORT" exit 1 fi echo "script: storing file on disk..." 1>&2 cat > "${FILE}" echo "script: file saved to disk." 1>&2 setfattr -n "user.mime_type" -v "${MIMETYPE}" "${FILE}" sleep 1 echo "script: done" 1>&2 ;; get) FILE=${SUB_PATH}${NAME} test -z "${FILE}" && exit 1 test -f "${FILE}" || exit 1 stat --printf="Length: %s\n" ${FILE} stat --format="%y" "${FILE}" | date -u +"Time: %Y%m%dT%H%M%SZ" MIMETYPE=$(getfattr -n "user.mime_type" "${FILE}") if [ "${MIMETYPE}" ]; then echo "Type: ${MIMETYPE}" fi echo "" cat "${FILE}" ;; delete) FILE=${SUB_PATH}${NAME} exec rm -rf "${FILE}" ;; listdir) FILE=$(mktemp) obex-folder-listing ${SUB_PATH} >${FILE} 2>/dev/null stat --printf="Length: %s\n" ${FILE} echo "" cat ${FILE} rm -f ${FILE} ;; createdir) exec mkdir -p ${SUB_PATH} ;; capability) ;; esac exit 0 obexpushd-0.11.2-source/src/utf.c000644 001750 001750 00000015217 11537730263 017752 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "utf.h" #include #include #include #include size_t utf16len (const uint16_t* s) { size_t n = 0; if (s != 0) while (s[n] != 0x0000) ++n; return n; } size_t utf8len (const uint8_t* s) { if (s) return strlen((char*)(s)); return 0; } uint16_t* utf16dup (const uint16_t* s) { size_t len = utf16len(s) + 1; uint16_t *s2; if (!s) { errno = EINVAL; return NULL; } s2 = calloc(len, sizeof(*s)); if (!s2) return NULL; memcpy(s2, s, len*sizeof(*s)); return s2; } void utf16_ntoh (uint16_t* s, size_t len) { size_t i = 0; for (; i < len; ++i) s[i] = ntohs(s[i]); } void utf16_hton (uint16_t* s, size_t len) { size_t i = 0; for (; i < len; ++i) s[i] = htons(s[i]); } size_t utf16count(const uint16_t* s) { size_t n = 0; size_t i = 0; if (s != NULL) for (; s[i] != 0x0000; ++i) { /* surrogates, 0xD8** is the first word * so do not count the second one (0xDC**) */ if ((s[i] & 0xDC00) != 0xDC00) ++n; } return n; } size_t utf8count(const uint8_t* s) { size_t n = 0; size_t i = 0; if (s != NULL) for (; s[i] != 0x00; ++i) { if ((s[i] & 0xC0) != 0x80) ++n; } return n; } static uint8_t* utf8to32 (const uint8_t* in, uint32_t *out) { uint32_t onechar = 0; if ((in[0] & 0x80) == 0x00) { onechar = *(in++); } else { const uint8_t prefix[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; const uint8_t mask[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; size_t count = 0; do { ++count; } while ((in[count] & 0xC0) == 0x80 && count <= 6); /* check the maximum number of bytes that can be * converted to 32bit integer. * check the first character to validate count value. */ if (count > 6 || (in[0] & mask[count - 1]) != prefix[count - 1]) { errno = EILSEQ; return NULL; } onechar = *(in++) ^ prefix[count - 1]; while (--count) { onechar <<= 6; onechar |= *(in++) & 0x3F; } } *out = onechar; return (uint8_t*)in; } static uint16_t* utf16to32 (const uint16_t* in, uint32_t *out) { uint32_t onechar = 0; /* surrogates */ if ((in[0] & 0xD800) == 0xD800) { if ((in[1] & 0xDC00) == 0xDC00) { onechar |= (*(in++) & 0x03FF) << 10; onechar |= *(in++) & 0x03FF; onechar += 0x10000; } else { onechar = *(in++); } } else { onechar = *(in++); } *out = onechar; return (uint16_t*)in; } static uint8_t* utf32to8 (uint32_t in, uint8_t* out) { if (in <= 0x7F) { *(out++) = (in & 0x7F); } else { struct { uint32_t max_value; uint8_t mask; } unicode[6] = { { 0x0000007F, 0x00 }, { 0x000007FF, 0xC0 }, { 0x0000FFFF, 0xE0 }, { 0x001FFFFF, 0xF0 }, { 0x03FFFFFF, 0xF8 }, { 0x7FFFFFFF, 0xFC } }; unsigned int i = 0, k = 1; for (; i < 6; ++i) { if (in <= unicode[i].max_value) { break; } } if (i >= 6) { errno = ERANGE; return NULL; } *(out++) = unicode[i].mask | ((in >> (i * 6)) & (unicode[i].max_value >> (i * 6))); for (; k <= i; ++k) { *(out++) = 0x80 | ((in >> ((i - k) * 6)) & 0x3F); } } return out; } static uint16_t* utf32to16 (uint32_t in, uint16_t* out) { if (in <= 0xFFFF) { *(out++) = (in & 0xFFFF); } else if (in <= 0x10FFFF) { in -= 0x10000; *(out++) = 0xD800 | ((in >> 10) & 0x3FF); *(out++) = 0xDC00 | (in & 0x3FF); } else { errno = ERANGE; out = NULL; } return out; } uint8_t* utf16to8 (const uint16_t* c) { size_t sd = (4 * utf16count(c)) + 1; uint8_t *buf; if (!c) { errno = EINVAL; return NULL; } buf = malloc(sd); if (buf) { size_t sc = utf16len(c); uint8_t *d = buf; const uint16_t *k = c; memset(d, 0, sd); while (k < c+sc) { uint32_t t; k = utf16to32(k, &t); d = utf32to8(t, d); } } return buf; } uint16_t* utf8to16 (const uint8_t* c) { size_t sd = (2 * utf8count(c)) + 2; uint16_t *buf; if (!c) { errno = EINVAL; return NULL; } buf = malloc(sd); if (buf) { size_t sc = utf8len(c); uint16_t *d = buf; const uint8_t *k = c; memset(d, 0, sd); while (k && d && k < c+sc) { uint32_t t; k = utf8to32(k, &t); if (k) d = utf32to16(t, d); } } return buf; } #ifdef TEST static int test_utf8 (uint32_t from, uint32_t to) { uint32_t i, k; uint8_t tmp[6]; void *status; printf("Testing UTF-8...\n"); for (i = from; i <= to; ++i) { printf("\rTest value: 0x%08x", i); memset(tmp, 0, sizeof(tmp)); status = utf32to8(i, tmp); if (!status) { printf("\nutf32to8() failed"); break; } status = utf8to32(tmp, &k); if (!status || i != k) { printf("\nutf8to32() failed"); break; } } printf("\n"); return (i > to); } static int test_utf16 (uint32_t from, uint32_t to) { uint32_t i, k; uint16_t tmp[2]; void *status; printf("Testing UTF-16...\n"); for (i = from; i <= to; ++i) { if (i == 0xD800 && 0xE000 < to) i = 0xE000; printf("\rTest value: 0x%08x", i); memset(tmp, 0, sizeof(tmp)); status = utf32to16(i, tmp); if (!status) { printf("\nutf32to16() failed"); break; } status = utf16to32(tmp, &k); if (!status || i != k) { printf("\nutf16to32() failed"); break; } } printf("\n"); return (i > to); } static int test_string () { uint8_t teststr[] = "abcdefghijklmnopqrstuvwxyz0123456789"; uint16_t *conv1; uint8_t *conv2; uint16_t *zeroconv1; uint8_t *zeroconv2; int ret = 0; printf("Testing with test string...\n"); conv1 = utf8to16(teststr); conv2 = utf16to8(conv1); zeroconv1 = utf8to16(NULL); zeroconv2 = utf16to8(NULL); if (!conv1) ret |= (1 << 0); else free(conv1); if (strcmp((char*)teststr, (char*)conv2) != 0) ret |= (1 << 2); if (!conv2) ret |= (1 << 1); else free(conv2); if (zeroconv1) ret |= (1 << 2); if (zeroconv2) ret |= (1 << 2); return ret; } int main () { int ret; if (!test_utf16(0, 0x10FFFF)) printf("failed\n"); else printf("passed\n"); if (!test_utf8(0, 0x10FFFF)) printf("failed\n"); else printf("passed\n"); ret = test_string(); if (ret) printf("failed (0x%x)\n", ret); else printf("passed\n"); return 0; } #endif obexpushd-0.11.2-source/src/utf.h000644 001750 001750 00000001533 11537730263 017753 0ustar00hendrikhendrik000000 000000 #include #include /* count the number of used elements (NOT characters) * This works independent of byte order. */ size_t utf8len (const uint8_t* s); size_t utf16len (const uint16_t* s); /* copy the UTF-16 string to a new allocated one */ uint16_t* utf16dup (const uint16_t* s); /* convert to network byte order and back */ void utf16_ntoh (uint16_t* s, size_t len); void utf16_hton (uint16_t* s, size_t len); /* Count the unicode characters * (does _not_ check for validity) */ size_t utf8count(const uint8_t* s); /* s MUST be in host byte order */ size_t utf16count(const uint16_t* s); /* convert between UTF-8 and UTF-16 * UTF-16 values MUST be in host byte order * returned pointer must be free'd and is * in host byte order */ uint8_t* utf16to8 (const uint16_t* c); uint16_t* utf8to16 (const uint8_t* c); obexpushd-0.11.2-source/src/version.h.in000644 001750 001750 00000000146 11537730263 021246 0ustar00hendrikhendrik000000 000000 #define OBEXPUSHD_VERSION "@OBEXPUSHD_VERSION@" #define OBEXPUSH_ATD_VERSION "@OBEXPUSH_ATD_VERSION@" obexpushd-0.11.2-source/src/x-obex/CMakeLists.txt000644 001750 001750 00000004657 11537730263 022760 0ustar00hendrikhendrik000000 000000 project ( x-obex C ) option ( BUILD_X_OBEX_SHARED_LIBS "Build the x-obex libraries as shared libraries" OFF ) if ( BUILD_X_OBEX_SHARED_LIBS ) set ( X_OBEX_BUILD_TYPE SHARED ) else ( BUILD_X_OBEX_SHARED_LIBS ) set ( X_OBEX_BUILD_TYPE STATIC ) endif ( BUILD_X_OBEX_SHARED_LIBS ) if ( NOT CMAKE_BUILD_TYPE ) set ( CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE ) endif ( NOT CMAKE_BUILD_TYPE ) if (WIN32 AND NOT UNIX) link_libraries ( shlwapi ) endif (WIN32 AND NOT UNIX) set ( obex-capability_VERSION 0.1.0 ) set ( obex-capability_SOVERSION 0 ) set ( obex-capability_PRIVATE_HEADER obex-capability.h ) set ( obex-folder-listing_VERSION 1.0.0 ) set ( obex-folder-listing_SOVERSION 0 ) set ( obex-folder-listing_PRIVATE_HEADER obex-folder-listing.h ) # # Extended Attributes can be used for mime type storage # find_package( Attr QUIET ) if (Attr_FOUND) include_directories ( ${Attr_INCLUDE_DIRS} ) list ( APPEND obex-folder-listing_COMPILE_DEFINITIONS USE_XATTR ) list ( APPEND obex-folder-listing_LIBRARIES ${ATTR_LIBRARIES} ) endif (Attr_FOUND) foreach ( lib capability folder-listing ) add_library ( obex-${lib} ${X_OBEX_BUILD_TYPE} obex-${lib}.c ) if ( obex-${lib}_LIBRARIES ) target_link_libraries ( obex-${lib} ${obex-${lib}_LIBRARIES} ) endif ( obex-${lib}_LIBRARIES ) foreach ( property VERSION SOVERSION PRIVATE_HEADER COMPILE_DEFINITIONS ) if ( DEFINED obex-${lib}_${property} ) set_property ( TARGET obex-${lib} PROPERTY ${property} ${obex-${lib}_${property}} ) endif ( DEFINED obex-${lib}_${property} ) endforeach ( property ) if ( BUILD_X_OBEX_SHARED_LIBS ) install ( TARGETS obex-${lib} RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PRIVATE_HEADER DESTINATION include/x-obex PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) endif ( BUILD_X_OBEX_SHARED_LIBS ) endforeach ( lib ) foreach ( app folder-listing ) add_executable ( obex-${app}-app obex-${app}-app.c ) set_property ( TARGET obex-${app}-app PROPERTY OUTPUT_NAME obex-${app} ) install ( TARGETS obex-${app}-app RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) target_link_libraries ( obex-${app}-app obex-${app} ) endforeach ( app ) obexpushd-0.11.2-source/src/x-obex/README000644 001750 001750 00000002302 11537730263 021061 0ustar00hendrikhendrik000000 000000 What are these files for? ========================= These are meant for helper scripts that want to handle advanced obex features. Compiling without -DAPP gives you object files that you can use in your program (GPLv2 applies). obex-capability: Create an OBEX capability object. Currently, it only creates required elements. obex-folder-listing: Create an OBEX folder listing object. You _must_ be in the root folder (from the OBEX client's view not the real root directory) and use a relative path or use a chroot or equivalent with absolute paths. Having ".." in the path is not allowed (use a chroot and "readlink -f" in that case), only regular files and directories are displayed. How do I use them in a program? =============================== For linked usage: See the header files. You can use your systems tmpfile() function to create a safe temporary file that the functions can use. For usage as programs: All output goes to stdout, so you can use pipes or redirections. Where are the DTD files? ======================== The DTDs are only printed in the IrOBEX specification which is not free to copy. Thus, the DTDs are not freely available. They are not actually needed, though. obexpushd-0.11.2-source/src/x-obex/obex-capability-app.c000644 001750 001750 00000004272 11537730263 024207 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #define _GNU_SOURCE #include "obex-capability.h" #include #include #include #include #include #define PROGRAM_NAME "obex-capability" #define PROGRAM_VERSION "0.1" static void print_disclaimer () { fprintf(stderr, PROGRAM_NAME" "PROGRAM_VERSION " Copyright (C) 2006 Hendrik Sattler\n" "This software comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions.\n"); } static void print_help () { print_disclaimer(); fprintf(stderr, "\n" "Usage: %s []\n", PROGRAM_NAME); fprintf(stderr, "\n" "Options:\n" " -V vendor name (default: dummy vendor)\n" " -M model description (default: dummy model)\n" " -h this help message\n"); } int main (int argc, char** argv) { struct obex_capability caps = { .general = { .vendor = NULL, .model = NULL, }, }; int err = 0; FILE* fd = stdout; int c; while ((c = getopt(argc,argv,"V:M:h")) != -1) { switch (c) { case 'V': if (optarg) caps.general.vendor = optarg; break; case 'M': if (optarg) caps.general.model = optarg; break; case 'h': print_help(); exit(EXIT_SUCCESS); } } print_disclaimer(); err = obex_capability(fd,&caps); if (err) { fprintf(stderr,"%s\n",strerror(-err)); exit(EXIT_FAILURE); } else { exit(EXIT_SUCCESS); } } obexpushd-0.11.2-source/src/x-obex/obex-capability.c000644 001750 001750 00000015762 11537730263 023437 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obex-capability.h" #include "xml_simple.h" #include #include #include #include #include #include #include #include #include #include static void obex_caps_version (FILE* fd, unsigned int indent, const char* name, struct obex_caps_version* caps) { if (caps->version) { if (caps->date) { xml_el_open(fd, indent, name, 1, " version=\"%s\" date=\"%s\"", caps->version, caps->date); } else { xml_el_open(fd, indent, name, 1, " version=\"%s\"", caps->version); } } else { if (caps->date) { xml_el_open(fd, indent, name, 1, " date=\"%s\"", caps->date); } else { xml_el_open(fd, indent, name, 1, NULL, 0); } } } static void obex_caps_limit (FILE* fd, unsigned int indent, char* prefix, struct obex_caps_limit* caps) { char* s = malloc(strlen(prefix)+5); sprintf(s, "%sSize", prefix); xml_open(fd, indent, s); fprintf(fd, "%lu", caps->size_max); xml_close(fd,indent,s); sprintf(s, "%sNLen", prefix); xml_open(fd, indent, s); fprintf(fd, "%lu", caps->namelen_max); xml_close(fd,indent,s); free(s); } static void obex_caps_ext (FILE* fd, unsigned int indent, struct obex_caps_ext* caps) { for (; caps != NULL; ++caps) { if (!caps->name) continue; xml_open(fd, indent, "Ext"); xml_print(fd, indent, "XNam", "%s", caps->name); if (caps->value) { char* value = *caps->value; for (; value; ++value) xml_print(fd, indent, "XVal", "%s", value); } xml_close(fd, indent, "Ext"); } } static void obex_caps_mem (FILE* fd, unsigned int indent, struct obex_caps_mem* caps) { for (; caps != NULL; ++caps) { xml_open(fd, indent++, "Memory"); if (caps->type) xml_print(fd, indent, "MemType", "%s", caps->type); if (caps->location) xml_print(fd, indent, "Location", "%s", caps->location); if (caps->free) xml_print(fd, indent, "Free", "%u", caps->free); if (caps->used) xml_print(fd, indent, "Used", "%u", caps->used); if (caps->flags & OBEX_CAPS_MEM_SHARED) xml_print(fd, indent, "Shared", NULL, 0); if (caps->file) obex_caps_limit(fd, indent, "File", caps->file); if (caps->folder) obex_caps_limit(fd, indent, "Folder", caps->folder); if (caps->flags & OBEX_CAPS_MEM_CASESENSE) xml_print(fd, indent, "CaseSenN", NULL, 0); if (caps->ext) obex_caps_ext(fd, indent, *caps->ext); xml_close(fd, --indent, "Memory"); } } static void obex_caps_general (FILE* fd, struct obex_caps_general* caps) { xml_open(fd, 1, "General"); xml_print(fd, 2, "Manufacturer", "%s", (caps->vendor? caps->vendor: "dummy vendor")); xml_print(fd, 2, "Model", "%s", (caps->model? caps->model: "dummy model")); if (caps->serial) xml_print(fd, 2, "SN", "%s", caps->serial); if (caps->oem) xml_print(fd, 2, "OEM", "%s", caps->oem); if (caps->sw) obex_caps_version(fd, 2, "SW", caps->sw); if (caps->fw) obex_caps_version(fd, 2, "FW", caps->fw); if (caps->hw) obex_caps_version(fd, 2, "HW", caps->hw); if (strlen(caps->lang)) xml_print(fd, 2, "Language", "%s", caps->lang); if (caps->mem) obex_caps_mem(fd, 2, *caps->mem); if (caps->ext) obex_caps_ext(fd, 2, *caps->ext); xml_close(fd, 1, "General"); } static void obex_caps_object (FILE* fd, unsigned int indent, struct obex_caps_obj* caps) { for (; caps != NULL; ++caps) { if (!caps->type && (!caps->name_ext || !*caps->name_ext)) continue; xml_open(fd, indent++, "Object"); if (caps->type) xml_print(fd, indent, "Type", "%s", caps->type); if (caps->name_ext) { char *name_ext = *caps->name_ext; for (; name_ext; ++name_ext) xml_print(fd, indent, "Name-Ext", "%s", name_ext); } if (caps->size) xml_print(fd, indent, "Size", "%ul", caps->size); if (caps->ext) obex_caps_ext(fd, 2, *caps->ext); xml_close(fd, --indent, "Object"); } } static void obex_caps_inbox (FILE* fd, struct obex_caps_inbox* caps) { xml_open(fd, 1, "Inbox"); if (caps->obj) obex_caps_object(fd, 2, *caps->obj); if (caps->ext) obex_caps_ext(fd, 2, *caps->ext); xml_close(fd, 1, "Inbox"); } static void obex_caps_uuid (FILE* fd, unsigned int indent, struct obex_caps_uuid *caps) { size_t i = 0, k = 0; char tmp[37]; memset(tmp, 0, sizeof(tmp)); switch (caps->type) { case OBEX_CAPS_UUID_ASCII: memcpy(tmp, caps->data, sizeof(caps->data)); break; case OBEX_CAPS_UUID_BINARY: for (; i < sizeof(caps->data); ++i) { if (i == 4 || i == 6 || i == 8 || i == 10) tmp[(2*i) + k++] = '-'; snprintf(tmp+(2*i)+k, 3, "%02X", (unsigned int)caps->data[i]); } break; } xml_print(fd, indent, "UUID", "%s", tmp); } static void obex_caps_access (FILE* fd, unsigned int indent, struct obex_caps_access* caps) { for (; caps != NULL; ++caps) { xml_open(fd, indent++, "Access"); if (caps->protocol) xml_print(fd, indent, "Protocol", "%s", caps->protocol); if (caps->endpoint) xml_print(fd, indent, "Endpoint", "%s", caps->endpoint); if (caps->target) xml_print(fd, indent, "Target", "%s", caps->target); if (caps->ext) obex_caps_ext(fd, 2, *caps->ext); xml_close(fd, --indent, "Access"); } } static void obex_caps_service (FILE* fd, struct obex_caps_service* caps) { if (!caps->name && !caps->uuid) return; xml_open(fd, 1, "Service"); if (caps->name) xml_print(fd, 2, "Name", "%s", caps->name); if (caps->uuid) obex_caps_uuid(fd, 2, caps->uuid); if (caps->version) xml_print(fd, 2, "Version", "%s", caps->version); if (caps->obj) obex_caps_object(fd, 2, *caps->obj); if (caps->access) obex_caps_access(fd, 2, *caps->access); if (caps->ext) obex_caps_ext(fd, 2, *caps->ext); xml_close(fd, 1, "Service"); } int obex_capability (FILE* fd, struct obex_capability* caps) { int err = 0; fprintf(fd, "charset) fprintf(fd, "charset=\"%s\"", caps->charset); fprintf(fd, "?>\n" "\n"); xml_open(fd,0,"Capability Version=\"1.0\""); obex_caps_general(fd,&caps->general); if (caps->inbox) obex_caps_inbox(fd, caps->inbox); if (caps->service) obex_caps_service(fd, caps->service); xml_close(fd,0,"Capability"); return err; } obexpushd-0.11.2-source/src/x-obex/obex-capability.h000644 001750 001750 00000004057 11537730263 023437 0ustar00hendrikhendrik000000 000000 #include #include #if __STDC_VERSION__ >= 199901L #include #else #define bool unsigned int #define true 1 #define false 0 #endif struct obex_caps_version { char* version; char* date; }; struct obex_caps_limit { unsigned long size_max; unsigned long namelen_max; }; struct obex_caps_ext { char* name; char** value; }; struct obex_caps_obj { /* type or at least one ext must be defined */ char* type; char** name_ext; unsigned long* size; struct obex_caps_ext** ext; /* NULL terminated list */ }; struct obex_caps_access { char* protocol; char* endpoint; char* target; struct obex_caps_ext** ext; /* NULL terminated list */ }; struct obex_caps_mem { char* type; char* location; unsigned long* free; unsigned long* used; struct obex_caps_limit* file; struct obex_caps_limit* folder; unsigned int flags; #define OBEX_CAPS_MEM_SHARED (1 << 0) #define OBEX_CAPS_MEM_CASESENSE (1 << 1) struct obex_caps_ext** ext; /* NULL terminated list */ }; struct obex_caps_general { char* vendor; char* model; char* serial; char* oem; struct obex_caps_version* sw; struct obex_caps_version* fw; struct obex_caps_version* hw; char lang[2+1]; struct obex_caps_mem** mem; struct obex_caps_ext** ext; }; struct obex_caps_inbox { struct obex_caps_obj** obj; struct obex_caps_ext** ext; }; struct obex_caps_uuid { enum { OBEX_CAPS_UUID_ASCII, OBEX_CAPS_UUID_BINARY, } type; uint8_t data[16]; }; #define OBEX_UUID_FBS \ { 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2, \ 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 } #define OBEX_UUID_IRMC \ { 'I', 'R', 'M', 'C', '-', 'S', 'Y', 'N', 'C' } struct obex_caps_service { /* name or uuid must be defined */ char* name; struct obex_caps_uuid* uuid; char* version; struct obex_caps_obj** obj; struct obex_caps_access** access; struct obex_caps_ext** ext; }; struct obex_capability { char* charset; struct obex_caps_general general; struct obex_caps_inbox* inbox; struct obex_caps_service* service; }; int obex_capability (FILE* fd, struct obex_capability* caps); obexpushd-0.11.2-source/src/x-obex/obex-folder-listing-app.c000644 001750 001750 00000004735 11537730263 025014 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obex-folder-listing.h" #include #include #include #include #include #include #define PROGRAM_NAME "obex-folder-listing" #define PROGRAM_VERSION "0.1" static void print_disclaimer () { fprintf(stderr, PROGRAM_NAME" "PROGRAM_VERSION " Copyright (C) 2006 Hendrik Sattler\n" "This software comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions.\n"); } static void print_help () { print_disclaimer(); fprintf(stderr, "\n" "Usage: %s []\n", PROGRAM_NAME); fprintf(stderr, "\n" "Options:\n" " -P show parent folder indicator\n" " -H also list hidden files/directories\n" " -t show time attributes\n" " -p show permission attributes\n" " -o show file owner attribute\n" " -g show file group attribute\n" " -h this help message\n"); } int main (int argc, char** argv) { char* name = "."; FILE* fd = stdout; int err; int c; int flags = 0; while ((c = getopt(argc,argv,"PHtpogh")) != -1) { switch (c) { case 'P': flags |= OFL_FLAG_PARENT; break; case 'H': flags |= OFL_FLAG_HIDDEN; break; case 't': flags |= OFL_FLAG_TIMES; break; case 'p': flags |= OFL_FLAG_PERMS; break; case 'o': flags |= OFL_FLAG_OWNER; break; case 'g': flags |= OFL_FLAG_GROUP; break; case 'h': print_help(); exit(EXIT_SUCCESS); } } if (optind < argc) name = argv[optind]; print_disclaimer(); setlocale(LC_ALL, ""); err = obex_folder_listing(fd, name, flags); if (err) { fprintf(stderr,"%s\n",strerror(-err)); exit(EXIT_FAILURE); } else { exit(EXIT_SUCCESS); } } obexpushd-0.11.2-source/src/x-obex/obex-folder-listing.c000644 001750 001750 00000014701 11537730263 024230 0ustar00hendrikhendrik000000 000000 /* Copyright (C) 2006,2010 Hendrik Sattler * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "obex-folder-listing.h" #include "xml_simple.h" #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #define strdup(s) StrDup(s) #else #ifdef USE_XATTR #include #endif #endif enum ft { FT_FILE, FT_FOLDER, FT_OTHER, }; static mode_t mode_fixup(uid_t uid, uid_t gid, mode_t mode, int flags) { uid_t e; if (!(flags & OFL_FLAG_OWNER)) { e = geteuid(); if (0 != e && uid != e) mode &= ~(S_IRUSR | S_IWUSR); } if (!(flags & OFL_FLAG_GROUP)) { e = getegid(); if (0 != e && gid != e) mode &= ~(S_IRGRP | S_IWGRP); } return mode; } static mode_t filemode (const char* name, int flags) { struct stat s; if (name == NULL || stat(name,&s) == -1) return 0; else return mode_fixup(s.st_uid, s.st_gid, s.st_mode, flags);; } static enum ft filetype (mode_t m) { if (S_ISREG(m)) return FT_FILE; else if (S_ISDIR(m)) return FT_FOLDER; else return FT_OTHER; } #ifdef USE_XATTR static int get_mime_type ( const char *filename, char *type, size_t size ) { ssize_t status = lgetxattr(filename, "user.mime_type", type, size); if (status >= 0) return 0; if (strlen(type) != (size_t)status) errno = EINVAL; return -errno; } #endif static void print_filename (FILE* fd, const char* filename, mode_t st_parent, int flags) { struct stat s; const char *name; #ifdef USE_XATTR char type[256]; #endif char create_time[17]; char mod_time[17]; char acc_time[17]; if (filename == NULL || stat(filename,&s) == -1) return; s.st_mode = mode_fixup(s.st_uid, s.st_gid, s.st_mode, flags); name = strrchr(filename,(int)'/'); if (name == NULL) name = filename; else ++name; if (name[0] == '.' && !(flags & OFL_FLAG_HIDDEN)) return; xml_indent(fd,1); switch(filetype(s.st_mode)) { case FT_FILE: fprintf(fd,"\n"); } static void print_dir (FILE* fd, const char* dir, int flags) { DIR* d; char* filename = NULL; size_t flen; mode_t mode; struct dirent* entry = NULL; char* seperator; char *tmp; if (dir == NULL) return; mode = filemode(dir, flags); if (mode == 0) return; seperator = (dir[strlen(dir)-1] == '/')? "" : "/"; d = opendir(dir); flen = strlen(dir)+strlen(seperator)+1; while ((entry = readdir(d))) { if (strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0) continue; tmp = realloc(filename,flen+strlen(entry->d_name)); if (!tmp) break; else filename = tmp; sprintf(filename,"%s%s%s",dir,seperator,entry->d_name); print_filename(fd,filename,mode,flags); } if (filename) free(filename); closedir(d); } #include static char* get_system_charset () { return nl_langinfo(CODESET); } static char* get_parent_folder_name (const char* path) { char* p = strdup(path); char* tmp = NULL; if (!p) return NULL; do { tmp = strrchr(p,(int)'/'); if (!tmp) { free(p); return strdup("."); } tmp[0] = 0; } while (tmp[1] == 0 || strcmp(tmp+1,".") == 0); return p; } int obex_folder_listing (FILE* fd, char* name, int flags) { mode_t m = 0; int err = 0; size_t namelen = (name? strlen(name): 0); char* parent; #if _WIN32 /* backslash dir seperator must be converted to unix format*/ unsigned int i = 0; for (; i < namelen; ++) if (name[i] == '\\') name[i] = '/'; #endif if (strncmp(name,"../", 3) == 0 || strcmp(name, "..") == 0 || (namelen > 3 && (strstr(name,"/../") != NULL || strncmp(name+namelen-3,"/..",3) == 0))) { return -EINVAL; } fprintf(fd, "\n", get_system_charset()); fprintf(fd, "\n"); xml_open(fd,0,"folder-listing version=\"1.0\""); parent = get_parent_folder_name(name); if (parent) { if (flags & OFL_FLAG_PARENT) xml_print(fd,1,"parent-folder",NULL,0); m = filemode(parent, flags); free(parent); } switch (filetype(filemode(name, flags))) { case FT_FOLDER: print_dir(fd,name,flags); break; case FT_FILE: print_filename(fd,name,m,flags); break; default: err = -ENOTDIR; goto out; } out: xml_close(fd,0,"folder-listing"); return err; } obexpushd-0.11.2-source/src/x-obex/obex-folder-listing.h000644 001750 001750 00000001464 11537730263 024237 0ustar00hendrikhendrik000000 000000 #include #define OFL_FLAG_PARENT (1 << 0) /* show parent folder indicator */ #define OFL_FLAG_HIDDEN (1 << 1) /* also list hidden files/directories */ #define OFL_FLAG_TIMES (1 << 2) /* show time attributes */ #define OFL_FLAG_PERMS (1 << 3) /* show permission attributes */ #define OFL_FLAG_OWNER (1 << 4) /* show file owner attribute */ #define OFL_FLAG_GROUP (1 << 5) /* show file group attribute */ #define OFL_FLAG_KEEP (1 << 6) /* keep files: writing existing file is not supported */ #define OFL_FLAG_NODEL (1 << 7) /* deleting is not supported */ /** write the OBEX folder listing * @param fd the output * @param name name of file or directory * @param flags flags that trigger the output of various elements or attributes */ int obex_folder_listing (FILE* fd, char* name, int flags); obexpushd-0.11.2-source/src/x-obex/xml_simple.h000644 001750 001750 00000002156 11537730263 022532 0ustar00hendrikhendrik000000 000000 #include #include #include #ifndef XML_SIMPLE_H #define XML_SIMPLE_H #define XML_INDENT_CHAR ' ' #define XML_INDENT_COUNT 2 #define xml_indent(fd,level) {\ char i[XML_INDENT_COUNT*level+1];\ memset(i,(int)XML_INDENT_CHAR,sizeof(i)-1);\ i[sizeof(i)-1] = 0;\ fprintf(fd,"%s",i);\ } #define xml_el_open(fd,level,el,close,args,...) {\ xml_indent(fd, level);\ fprintf(fd, "<%s", el);\ if (args) {\ const char* a = args;\ fprintf(fd, a, __VA_ARGS__);\ }\ if (close) fprintf(fd, " />\n");\ else fprintf(fd, ">");\ } #define xml_open(fd,level,attr)\ xml_el_open(fd,level,attr,0,NULL,0); \ fprintf(fd, "\n"); #define xml_close(fd,level,attr) {\ xml_indent(fd,level);\ fprintf(fd,"\n",attr);\ } #define xml_print(fd,level,attr,format,...) {\ xml_indent(fd,level);\ fprintf(fd,"<%s",attr);\ if (format) {\ const char* f = format;\ fprintf(fd,">");\ fprintf(fd,f, __VA_ARGS__ );\ fprintf(fd,"\n",attr);\ } else {\ fprintf(fd," />\n");\ }\ } #endif /* XML_SIMPLE_H */